@kizenapps/cli 1.13.0-poc-bcd37de → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import*as Sp from"http";var Nt="If you're behind a proxy, upgrade Node to 24.14+ or set NODE_USE_ENV_PROXY=1 on a Node version that supports it.",ma=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy"],Ln=e=>e!==void 0&&e!=="",Pe="not-configured";function Un({env:e,http:t}){return Pe==="applied"||(ma.some(r=>Ln(e[r]))?Ln(e.NODE_USE_ENV_PROXY)?Pe="already-set":typeof t.setGlobalProxyFromEnv!="function"?Pe="unavailable":(t.setGlobalProxyFromEnv(e),Pe="applied"):Pe="not-configured"),Pe}var Dt=()=>Pe;import{readFileSync as bp}from"fs";import{dirname as wp,join as xp}from"path";import{fileURLToPath as vp}from"url";import{Command as kp}from"commander";import{createElement as Hc}from"react";import{render as Vc}from"ink";import{PluginValidationError as Wc}from"@kizenapps/packager";import{spawn as ha}from"child_process";import{platform as Hn}from"process";function ga(){return Hn==="darwin"?[{cmd:"pbcopy",args:[]}]:Hn==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var ya=2e3;function ba(e,{cmd:t,args:r}){return new Promise(o=>{let n;try{n=ha(t,r,{stdio:["pipe","ignore","ignore"]})}catch{o(!1);return}let i=n,s=!1;function l(p){s||(s=!0,clearTimeout(a),o(p))}let a=setTimeout(()=>{i.kill(),l(!1)},ya);a.unref(),i.on("error",()=>{l(!1)}),i.on("close",p=>{l(p===0)}),i.stdin.on("error",()=>{l(!1)});try{i.stdin.end(e)}catch{l(!1)}})}async function Rt(e){for(let t of ga())if(await ba(e,t))return!0;return!1}import{BLOCKS_DIRECTORY_NAME as ja,CONFIG_FILE_NAME as Fa,MANIFEST_FILE_NAME as Oa,sanitizeToAPIName as za}from"@kizenapps/packager";import{mkdir as Pa,writeFile as Ea}from"fs/promises";import{join as Ta}from"path";import{PluginValidationError as Ia,packagePlugin as Aa,parseManifestFromFiles as Na,transformDeployablePlugin as Da,transformFiles as Ra,validatePluginApp as Ba}from"@kizenapps/packager";import{readdir as wa,readFile as Vn}from"fs/promises";import{join as Wn,relative as xa}from"path";var va=new Set([".png",".svg"]),ka=new Set([".kzn"]),Ca=new Set([".DS_Store"]),Bt=new Set(["node_modules",".git",".kizenapp",".github",".claude","__pycache__"]),Sa=8e3;function _a(e){return e.subarray(0,Sa).includes(0)}async function Kn(e,t){let r=await wa(e,{withFileTypes:!0}),o=[];for(let n of r)if(n.isDirectory()){if(Bt.has(n.name))continue;o.push(...await Kn(Wn(e,n.name),t))}else n.isFile()&&(Ca.has(n.name)||o.push(Wn(e,n.name)));return o}async function $t(e,{detectBinaryByContent:t=!1}={}){let r=await Kn(e,e);return Promise.all(r.map(async o=>{let n=xa(e,o).split("\\").join("/"),i=n.lastIndexOf("."),s=i>=0?n.slice(i).toLowerCase():"";if(va.has(s)){let a=await Vn(o);return{path:n,content:"",base64Image:a.toString("base64")}}let l=await Vn(o);return ka.has(s)||t&&_a(l)?{path:n,content:"",binaryData:l}:{path:n,content:l.toString("utf-8")}}))}var $a=(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 Tr(e,t){t?.("reading-files");let r=await $t(e);t?.("validating");let o=Ba(r);if(o.some(a=>a.severity==="error"))throw new Ia(o);t?.("minifying");let n=await Ra(r);t?.("packaging");let i=Na(n),s=Aa(n,i),l=Object.values(s).map(Da);return{files:r,deployable:l,issues:o}}async function jt(e,t,r){await Pa(t,{recursive:!0});let{files:o,deployable:n}=await Tr(e,r);r?.("writing-bundle");let i=n.map(p=>{let h=p.release_notes_directory?.replace(/\/$/,""),w=h?o.filter(x=>x.path.startsWith(h+"/")&&x.path.endsWith(".md")&&x.content).map(x=>({version:x.path.slice(x.path.lastIndexOf("/")+1,-3),notes:x.content})).sort((x,d)=>d.version.localeCompare(x.version,void 0,{numeric:!0})):[];return $a(p,w)}),s=JSON.stringify(i,null,2),l=(p,h)=>p==="allReleaseNotes"?void 0:h,a=Buffer.byteLength(JSON.stringify(i,l,2),"utf-8");return await Ea(Ta(t,"bundle.json"),s,"utf-8"),{bundleSize:a}}var Ar=["min_w","max_w","min_h","max_h"],qn=[["min_w","max_w"],["min_h","max_h"]],Ft={default_w:["min_w","max_w"],default_h:["min_h","max_h"]},Gn=Object.keys(Ft),Ma=[...Ar,...Gn],Yn=[...Ma,"host_chrome"],La=["\0","{__ref:"],qe=class extends Error{reason;available;field;constructor(t,r,o={}){super(r),this.name="BlockExportError",this.reason=t,this.available=o.available??[],this.field=o.field}};function Nr(e){let t=new Set(e.map(r=>r.pluginApiName)).size>1;return e.map(r=>t?`${r.pluginApiName}/${r.apiName}`:r.apiName).join(", ")}function Dr(e,t){let r=e.flatMap(s=>s.artifacts.custom_blocks.map(l=>({block:l,pluginApiName:s.api_name}))),o=r.map(({block:s,pluginApiName:l})=>({pluginApiName:l,apiName:s.api_name}));if(r.length===0)return{ok:!1,reason:"no_blocks",available:o};if(t===void 0){let[s]=r;return r.length===1&&s?{ok:!0,...s}:{ok:!1,reason:"ambiguous",available:o}}let n=r.filter(({block:s})=>s.api_name===t),[i]=n;return i?n.length>1?{ok:!1,reason:"ambiguous",available:n.map(({block:s,pluginApiName:l})=>({pluginApiName:l,apiName:s.api_name}))}:{ok:!0,...i}:{ok:!1,reason:"not_found",available:o}}var Rr=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),Jn=e=>typeof e=="number"&&Number.isInteger(e)&&e>0,Ir=e=>La.some(t=>e.includes(t));function Br(e){let t=e,{name:r,script:o,styles:n,event_scripts:i}=t;if(typeof o!="string"||!o.trim())return"script";if(r!==void 0&&typeof r!="string")return"name";if(n!==void 0&&typeof n!="string")return"styles";if(i!==void 0){if(!Rr(i))return"event_scripts";let h=Object.entries(i).find(([w,x])=>typeof x!="string"||Ir(w)||Ir(x));if(h)return`event_scripts.${h[0]}`}let s=[["name",r],["script",o],["styles",n]].find(([,h])=>typeof h=="string"&&Ir(h));if(s)return s[0];let l=Ar.find(h=>t[h]!==void 0&&!Jn(t[h]));if(l)return l;let a=qn.find(([h,w])=>{let x=t[h],d=t[w];return typeof x=="number"&&typeof d=="number"&&x>d});if(a)return a[0];let p=Gn.find(h=>{let w=t[h];if(w===void 0)return!1;if(typeof w!="number"||!Jn(w))return!0;let[x,d]=Ft[h],c=t[x],y=t[d];return typeof c=="number"&&w<c||typeof y=="number"&&w>y});if(p)return p;if(t.host_chrome!==void 0&&typeof t.host_chrome!="boolean")return"host_chrome"}var $r=(e,t)=>{if(t==="script")return`Block "${e}" has no script. Add a non-empty script.js to the block directory.`;if(t==="host_chrome")return`Block "${e}" has an invalid host_chrome: it must be true or false.`;let r=qn.find(([o])=>o===t);if(r)return`Block "${e}" has an invalid ${t}: it must be a positive integer no greater than ${r[1]}.`;if(Ar.includes(t))return`Block "${e}" has an invalid ${t}: it must be a positive integer.`;if(t in Ft){let[o,n]=Ft[t];return`Block "${e}" has an invalid ${t}: it must be a positive integer between ${o} and ${n}.`}return`Block "${e}" has an invalid ${t}: it must be a string without NUL characters or "{__ref:".`},Ua=(e,t)=>{let{reason:r,available:o}=e,n=Nr(o);return r==="no_blocks"?new qe(r,"This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.",{available:o}):r==="not_found"?new qe(r,`No block with api_name "${t??""}". Available blocks: ${n}`,{available:o}):new qe(r,t===void 0?`This plugin has several blocks; pass the api_name of the one to export: ${n}`:`More than one plugin has a block with api_name "${t}": ${n}`,{available:o})},Ha=e=>{try{let t=JSON.parse(e);return Rr(t)?t:void 0}catch{return}},Va=e=>{let t=e.find(i=>i.path===Oa),r=t?JSON.parse(t.content):[],o=Array.isArray(r)?r:[r],n=new Map;for(let i of o)Rr(i)&&typeof i.api_name=="string"&&typeof i.entry=="string"&&n.set(i.api_name,i.entry);return n},Wa=(e,t)=>{let r=`${t.replace(/\/+$/,"")}/${ja}/`,o=new Map;for(let n of e){if(!n.path.startsWith(r))continue;let[i,s,...l]=n.path.slice(r.length).split("/");if(!i||s!==Fa||l.length>0)continue;let a=Ha(n.content);if(!a)continue;let p=typeof a.api_name=="string"&&a.api_name!==""?a.api_name:za(i),h={};for(let w of Yn)a[w]!==void 0&&(h[w]=a[w]);o.set(p,h)}return o},Ka=(e,t={})=>({...Object.fromEntries(Object.entries(e).filter(([o])=>!Yn.includes(o))),...t});function Ja(e,t){let r=Va(t);return e.map(o=>{let n=r.get(o.api_name),i=n===void 0?new Map:Wa(t,n);return{...o,artifacts:{...o.artifacts,custom_blocks:o.artifacts.custom_blocks.map(s=>Ka(s,i.get(s.api_name)))}}})}async function jr(e){let{files:t,deployable:r,issues:o}=await Tr(e);return{deployable:Ja(r,t),warnings:o.filter(n=>n.severity==="warning")}}async function Xn(e,t){let{deployable:r,warnings:o}=await jr(e),n=Dr(r,t);if(!n.ok)throw Ua(n,t);let i=Br(n.block);if(i!==void 0)throw new qe("invalid_block",$r(n.block.api_name,i),{field:i});return{block:n.block,pluginApiName:n.pluginApiName,warnings:o}}var Fr=(e,t,r)=>`${String(e)} ${e===1?t:r}`,qa=e=>{let t=new Map;for(let r of e){let o=r.path??r.pluginApiName??"general",n=t.get(o)??[];n.push(r),t.set(o,n)}return t},Ga=e=>{let t=e.filter(n=>n.severity==="error").length,r=e.length-t;if(t===0)return`\u26A0 ${Fr(r,"validation warning","validation warnings")}`;let o=`\u2717 ${Fr(t,"validation error","validation errors")}`;return r===0?o:`${o}, ${Fr(r,"warning","warnings")}`};function me(e){if(e.length===0)return"";let t=[...qa(e)].map(([r,o])=>[r,...o.map(n=>` ${n.severity==="error"?"\u2717":"\u26A0"} ${n.message} (${n.rule})`)].join(`
2
+ import*as Sp from"http";var Nt="If you're behind a proxy, upgrade Node to 24.14+ or set NODE_USE_ENV_PROXY=1 on a Node version that supports it.",ma=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy"],Ln=e=>e!==void 0&&e!=="",Pe="not-configured";function Hn({env:e,http:t}){return Pe==="applied"||(ma.some(r=>Ln(e[r]))?Ln(e.NODE_USE_ENV_PROXY)?Pe="already-set":typeof t.setGlobalProxyFromEnv!="function"?Pe="unavailable":(t.setGlobalProxyFromEnv(e),Pe="applied"):Pe="not-configured"),Pe}var Dt=()=>Pe;import{readFileSync as bp}from"fs";import{dirname as wp,join as xp}from"path";import{fileURLToPath as vp}from"url";import{Command as kp}from"commander";import{createElement as Uc}from"react";import{render as Vc}from"ink";import{PluginValidationError as Wc}from"@kizenapps/packager";import{spawn as ha}from"child_process";import{platform as Un}from"process";function ga(){return Un==="darwin"?[{cmd:"pbcopy",args:[]}]:Un==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var ya=2e3;function ba(e,{cmd:t,args:r}){return new Promise(o=>{let n;try{n=ha(t,r,{stdio:["pipe","ignore","ignore"]})}catch{o(!1);return}let i=n,s=!1;function l(p){s||(s=!0,clearTimeout(a),o(p))}let a=setTimeout(()=>{i.kill(),l(!1)},ya);a.unref(),i.on("error",()=>{l(!1)}),i.on("close",p=>{l(p===0)}),i.stdin.on("error",()=>{l(!1)});try{i.stdin.end(e)}catch{l(!1)}})}async function Rt(e){for(let t of ga())if(await ba(e,t))return!0;return!1}import{BLOCKS_DIRECTORY_NAME as ja,CONFIG_FILE_NAME as Fa,MANIFEST_FILE_NAME as Oa,sanitizeToAPIName as za}from"@kizenapps/packager";import{mkdir as Pa,writeFile as Ea}from"fs/promises";import{join as Ta}from"path";import{PluginValidationError as Ia,packagePlugin as Aa,parseManifestFromFiles as Na,transformDeployablePlugin as Da,transformFiles as Ra,validatePluginApp as Ba}from"@kizenapps/packager";import{readdir as wa,readFile as Vn}from"fs/promises";import{join as Wn,relative as xa}from"path";var va=new Set([".png",".svg"]),ka=new Set([".kzn"]),Ca=new Set([".DS_Store"]),Bt=new Set(["node_modules",".git",".kizenapp",".github",".claude","__pycache__"]),Sa=8e3;function _a(e){return e.subarray(0,Sa).includes(0)}async function Kn(e,t){let r=await wa(e,{withFileTypes:!0}),o=[];for(let n of r)if(n.isDirectory()){if(Bt.has(n.name))continue;o.push(...await Kn(Wn(e,n.name),t))}else n.isFile()&&(Ca.has(n.name)||o.push(Wn(e,n.name)));return o}async function $t(e,{detectBinaryByContent:t=!1}={}){let r=await Kn(e,e);return Promise.all(r.map(async o=>{let n=xa(e,o).split("\\").join("/"),i=n.lastIndexOf("."),s=i>=0?n.slice(i).toLowerCase():"";if(va.has(s)){let a=await Vn(o);return{path:n,content:"",base64Image:a.toString("base64")}}let l=await Vn(o);return ka.has(s)||t&&_a(l)?{path:n,content:"",binaryData:l}:{path:n,content:l.toString("utf-8")}}))}var $a=(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 Tr(e,t){t?.("reading-files");let r=await $t(e);t?.("validating");let o=Ba(r);if(o.some(a=>a.severity==="error"))throw new Ia(o);t?.("minifying");let n=await Ra(r);t?.("packaging");let i=Na(n),s=Aa(n,i),l=Object.values(s).map(Da);return{files:r,deployable:l,issues:o}}async function jt(e,t,r){await Pa(t,{recursive:!0});let{files:o,deployable:n}=await Tr(e,r);r?.("writing-bundle");let i=n.map(p=>{let h=p.release_notes_directory?.replace(/\/$/,""),w=h?o.filter(x=>x.path.startsWith(h+"/")&&x.path.endsWith(".md")&&x.content).map(x=>({version:x.path.slice(x.path.lastIndexOf("/")+1,-3),notes:x.content})).sort((x,d)=>d.version.localeCompare(x.version,void 0,{numeric:!0})):[];return $a(p,w)}),s=JSON.stringify(i,null,2),l=(p,h)=>p==="allReleaseNotes"?void 0:h,a=Buffer.byteLength(JSON.stringify(i,l,2),"utf-8");return await Ea(Ta(t,"bundle.json"),s,"utf-8"),{bundleSize:a}}var Ar=["min_w","max_w","min_h","max_h"],qn=[["min_w","max_w"],["min_h","max_h"]],Ft={default_w:["min_w","max_w"],default_h:["min_h","max_h"]},Gn=Object.keys(Ft),Ma=[...Ar,...Gn],Yn=[...Ma,"host_chrome"],La=["\0","{__ref:"],qe=class extends Error{reason;available;field;constructor(t,r,o={}){super(r),this.name="BlockExportError",this.reason=t,this.available=o.available??[],this.field=o.field}};function Nr(e){let t=new Set(e.map(r=>r.pluginApiName)).size>1;return e.map(r=>t?`${r.pluginApiName}/${r.apiName}`:r.apiName).join(", ")}function Dr(e,t){let r=e.flatMap(s=>s.artifacts.custom_blocks.map(l=>({block:l,pluginApiName:s.api_name}))),o=r.map(({block:s,pluginApiName:l})=>({pluginApiName:l,apiName:s.api_name}));if(r.length===0)return{ok:!1,reason:"no_blocks",available:o};if(t===void 0){let[s]=r;return r.length===1&&s?{ok:!0,...s}:{ok:!1,reason:"ambiguous",available:o}}let n=r.filter(({block:s})=>s.api_name===t),[i]=n;return i?n.length>1?{ok:!1,reason:"ambiguous",available:n.map(({block:s,pluginApiName:l})=>({pluginApiName:l,apiName:s.api_name}))}:{ok:!0,...i}:{ok:!1,reason:"not_found",available:o}}var Rr=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),Jn=e=>typeof e=="number"&&Number.isInteger(e)&&e>0,Ir=e=>La.some(t=>e.includes(t));function Br(e){let t=e,{name:r,script:o,styles:n,event_scripts:i}=t;if(typeof o!="string"||!o.trim())return"script";if(r!==void 0&&typeof r!="string")return"name";if(n!==void 0&&typeof n!="string")return"styles";if(i!==void 0){if(!Rr(i))return"event_scripts";let h=Object.entries(i).find(([w,x])=>typeof x!="string"||Ir(w)||Ir(x));if(h)return`event_scripts.${h[0]}`}let s=[["name",r],["script",o],["styles",n]].find(([,h])=>typeof h=="string"&&Ir(h));if(s)return s[0];let l=Ar.find(h=>t[h]!==void 0&&!Jn(t[h]));if(l)return l;let a=qn.find(([h,w])=>{let x=t[h],d=t[w];return typeof x=="number"&&typeof d=="number"&&x>d});if(a)return a[0];let p=Gn.find(h=>{let w=t[h];if(w===void 0)return!1;if(typeof w!="number"||!Jn(w))return!0;let[x,d]=Ft[h],c=t[x],y=t[d];return typeof c=="number"&&w<c||typeof y=="number"&&w>y});if(p)return p;if(t.host_chrome!==void 0&&typeof t.host_chrome!="boolean")return"host_chrome"}var $r=(e,t)=>{if(t==="script")return`Block "${e}" has no script. Add a non-empty script.js to the block directory.`;if(t==="host_chrome")return`Block "${e}" has an invalid host_chrome: it must be true or false.`;let r=qn.find(([o])=>o===t);if(r)return`Block "${e}" has an invalid ${t}: it must be a positive integer no greater than ${r[1]}.`;if(Ar.includes(t))return`Block "${e}" has an invalid ${t}: it must be a positive integer.`;if(t in Ft){let[o,n]=Ft[t];return`Block "${e}" has an invalid ${t}: it must be a positive integer between ${o} and ${n}.`}return`Block "${e}" has an invalid ${t}: it must be a string without NUL characters or "{__ref:".`},Ha=(e,t)=>{let{reason:r,available:o}=e,n=Nr(o);return r==="no_blocks"?new qe(r,"This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.",{available:o}):r==="not_found"?new qe(r,`No block with api_name "${t??""}". Available blocks: ${n}`,{available:o}):new qe(r,t===void 0?`This plugin has several blocks; pass the api_name of the one to export: ${n}`:`More than one plugin has a block with api_name "${t}": ${n}`,{available:o})},Ua=e=>{try{let t=JSON.parse(e);return Rr(t)?t:void 0}catch{return}},Va=e=>{let t=e.find(i=>i.path===Oa),r=t?JSON.parse(t.content):[],o=Array.isArray(r)?r:[r],n=new Map;for(let i of o)Rr(i)&&typeof i.api_name=="string"&&typeof i.entry=="string"&&n.set(i.api_name,i.entry);return n},Wa=(e,t)=>{let r=`${t.replace(/\/+$/,"")}/${ja}/`,o=new Map;for(let n of e){if(!n.path.startsWith(r))continue;let[i,s,...l]=n.path.slice(r.length).split("/");if(!i||s!==Fa||l.length>0)continue;let a=Ua(n.content);if(!a)continue;let p=typeof a.api_name=="string"&&a.api_name!==""?a.api_name:za(i),h={};for(let w of Yn)a[w]!==void 0&&(h[w]=a[w]);o.set(p,h)}return o},Ka=(e,t={})=>({...Object.fromEntries(Object.entries(e).filter(([o])=>!Yn.includes(o))),...t});function Ja(e,t){let r=Va(t);return e.map(o=>{let n=r.get(o.api_name),i=n===void 0?new Map:Wa(t,n);return{...o,artifacts:{...o.artifacts,custom_blocks:o.artifacts.custom_blocks.map(s=>Ka(s,i.get(s.api_name)))}}})}async function jr(e){let{files:t,deployable:r,issues:o}=await Tr(e);return{deployable:Ja(r,t),warnings:o.filter(n=>n.severity==="warning")}}async function Xn(e,t){let{deployable:r,warnings:o}=await jr(e),n=Dr(r,t);if(!n.ok)throw Ha(n,t);let i=Br(n.block);if(i!==void 0)throw new qe("invalid_block",$r(n.block.api_name,i),{field:i});return{block:n.block,pluginApiName:n.pluginApiName,warnings:o}}var Fr=(e,t,r)=>`${String(e)} ${e===1?t:r}`,qa=e=>{let t=new Map;for(let r of e){let o=r.path??r.pluginApiName??"general",n=t.get(o)??[];n.push(r),t.set(o,n)}return t},Ga=e=>{let t=e.filter(n=>n.severity==="error").length,r=e.length-t;if(t===0)return`\u26A0 ${Fr(r,"validation warning","validation warnings")}`;let o=`\u2717 ${Fr(t,"validation error","validation errors")}`;return r===0?o:`${o}, ${Fr(r,"warning","warnings")}`};function me(e){if(e.length===0)return"";let t=[...qa(e)].map(([r,o])=>[r,...o.map(n=>` ${n.severity==="error"?"\u2717":"\u26A0"} ${n.message} (${n.rule})`)].join(`
3
3
  `));return[Ga(e),...t].join(`
4
4
 
5
5
  `)}import{randomUUID as Gl}from"crypto";import{join as Yl}from"path";import{PluginValidationError as Go}from"@kizenapps/packager";var Zn={go:"https://app.go.kizen.com/api",fmo:"https://app.fmo.kizen.com/api",staging:"https://staging.kizen.com/api",integration:"https://integration.kizen.dev/api",test1:"https://test1.kizen.dev/api"},Qn={go:"https://go.kizen.com",fmo:"https://fmo.kizen.com",staging:"https://v2.staging.kizen.com",integration:"https://v2.integration.kizen.dev",test1:"https://test1.kizen.dev"},Ya=["go","fmo"];function Or(e){return Ya.includes(e)}import{mkdir as Xa,readFile as Za,writeFile as Qa}from"fs/promises";import{join as eo}from"path";async function he(e){try{let t=await Za(eo(e,"config.json"),"utf-8");return JSON.parse(t)}catch{return{}}}async function Ee(e,t){await Xa(e,{recursive:!0}),await Qa(eo(e,"config.json"),JSON.stringify(t,null,2),"utf-8")}import{mkdir as to,readFile as ro,readdir as el,writeFile as no}from"fs/promises";import{homedir as tl}from"os";import{dirname as rl,join as Ot}from"path";var X=["go","fmo","staging","integration","test1"];function Ge(e){return typeof e=="string"?e.trim():""}function at(e){return{apiKey:Ge(e.apiKey),userId:Ge(e.userId),businessId:Ge(e.businessId)}}var ze=Ot(tl(),".kizenappbuilder"),xe=Ot(ze,"credentials.json"),Te="credentials";function oo(e){return X.includes(e)}function io(e){return typeof e=="string"?e.trim():e}function so(e){if(typeof e!="object"||e===null)throw new Error("Credentials must be a JSON object");let t=e,r=io(t.environment);return{...at(t),environment:oo(r)?r:"go"}}async function Ie(e){let t=await ro(e,"utf-8");return so(JSON.parse(t))}function nl(e){let t=io(e.environment);return t==null||t===""?"missing":oo(t)?"explicit":"invalid"}async function zr(e){let t=await ro(e,"utf-8"),r=JSON.parse(t);return{credentials:so(r),environmentSource:nl(r)}}async function te(){try{return await Ie(xe)}catch{return null}}async function ol(e){await to(rl(xe),{recursive:!0,mode:448}),await no(xe,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384})}function ao(e){return Ot(ze,`${e}.json`)}async function Ae(){let e=[{name:Te,path:xe,isDefault:!0}];try{let t=await el(ze);for(let r of t){if(!r.endsWith(".json"))continue;let o=r.slice(0,-5);o!==Te&&e.push({name:o,path:Ot(ze,r),isDefault:!1})}}catch{}return e}async function lo(e,t){if(e===Te){await ol(t);return}await to(ze,{recursive:!0,mode:448}),await no(ao(e),JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}async function ve(e){try{return await Ie(ao(e))}catch{return null}}async function co(){let e=await Ae(),t=await Promise.all(e.map(r=>zr(r.path).then(()=>!0,()=>!1)));return e.filter((r,o)=>t[o]===!0)}import*as Ye from"fs";import*as uo from"path";function Ne(e){let t=uo.join(e,".gitignore"),r=".kizenapp/",o="";if(Ye.existsSync(t)){o=Ye.readFileSync(t,"utf8");let i=o.split(`
@@ -7,8 +7,8 @@ import*as Sp from"http";var Nt="If you're behind a proxy, upgrade Node to 24.14+
7
7
  `)?r+`
8
8
  `:`
9
9
  `+r+`
10
- `;Ye.writeFileSync(t,o+n)}var il="The API key is invalid for this business, or the user id doesn't match. Check the credentials file's apiKey, userId and businessId.",sl="The API key's user needs the Standard API Keys permission and edit access to this dashboard. Homepages also need the Customize Homepages permission.",al=100,ll=new Set(["detail","non_field_errors"]),re=class extends Error{kind;status;hint;constructor(t,r,o={}){super(r),this.name="KizenApiError",this.kind=t,this.status=o.status,this.hint=o.hint}},Xe=e=>typeof e=="object"&&e!==null&&!Array.isArray(e);function Mr(e,t,r){let o=n=>{r.push(t===""?n:`${t}: ${n}`)};if(typeof e=="string"){e.trim()!==""&&o(e);return}if(typeof e=="number"||typeof e=="boolean"){o(String(e));return}if(Array.isArray(e)){let n=e.filter(i=>typeof i=="string"&&i.trim()!==""||typeof i=="number"||typeof i=="boolean");n.length>0&&o(n.map(String).join(" "));for(let i of e)typeof i=="object"&&i!==null&&Mr(i,t,r);return}if(Xe(e))for(let[n,i]of Object.entries(e)){let s=t===""&&ll.has(n)?"":t===""?n:`${t}.${n}`;Mr(i,s,r)}}function cl(e){if(typeof e!="object"||e===null)return;let t=[];return Mr(e,"",t),t.length>0?t.join("; "):void 0}function po(e){let t=e;return t.cause?.code??t.code??t.cause?.message??t.message??String(e)}async function dl(e){let t=await e.text();if(t==="")return{text:t,json:void 0};try{return{text:t,json:JSON.parse(t)}}catch{return{text:t,json:void 0}}}function ul(e,t,r,o){let n=cl(o),i=`${e} ${t} failed with ${String(r)}${n===void 0?"":`: ${n}`}`;return r===401?new re("auth_failed",i,{status:r,hint:il}):r===403?new re("forbidden",i,{status:r,hint:sl}):r===404?new re("not_found",i,{status:r}):new re("api_error",i,{status:r})}function fo(e,t,r){if(Array.isArray(r))return{results:r,next:null};if(Xe(r)&&Array.isArray(r.results))return{results:r.results,next:r.next};throw new re("api_error",`${e} ${t} returned an unexpected response shape`)}function mo(e){let{credentials:t}=e,r=e.fetch??fetch,o=e.baseUrl??Zn[t.environment],n=async(l,a,p)=>{let h=/^https?:\/\//.test(a)?a:`${o}${a}`,w=h.startsWith(o)?h.slice(o.length):h,x={"X-API-KEY":t.apiKey,"X-USER-ID":t.userId,"X-BUSINESS-ID":t.businessId,Accept:"application/json"},d={method:l,headers:x};p!==void 0&&(x["Content-Type"]="application/json",d.body=JSON.stringify(p));let c;try{c=await r(h,d)}catch(P){throw new re("network_error",`Couldn't reach Kizen at ${o}: ${po(P)}${Dt()==="unavailable"?` ${Nt}`:""}`)}let y,v;try{({text:y,json:v}=await dl(c))}catch(P){throw new re("network_error",`${l} ${w}: couldn't read the response: ${po(P)}. The request may have been applied; check Kizen before retrying.`,{status:c.status})}if(!c.ok)throw ul(l,w,c.status,v);if(v===void 0&&y!=="")throw new re("api_error",`${l} ${w} returned a response that is not JSON`,{status:c.status});return v},i=encodeURIComponent,s=l=>{let a=new URL(o),p=new URL(l,a.origin);if(p.hostname!==a.hostname)throw new re("api_error",`GET /custom-objects pagination pointed at an unexpected host ${p.hostname}`);return new URL(`${p.pathname}${p.search}`,a.origin).toString()};return{async listDashboards(l,a){let p=new URLSearchParams({size:"10000",include_sharing:"true",dashboard_type:l});a!==void 0&&p.set("custom_object_id",a);let h=`/dashboards/mine?${p.toString()}`;return fo("GET",h,await n("GET",h)).results},async listCustomObjects(){let l=[],a=new Set,p="/custom-objects?page_size=200";for(;p!==void 0&&!a.has(p)&&a.size<al;){a.add(p);let h=fo("GET",p,await n("GET",p));l.push(...h.results),p=typeof h.next=="string"&&h.next!==""?s(h.next):void 0}return l},async getCustomObject(l){let a=`/custom-objects/${i(l)}`,p=await n("GET",a);if(!Xe(p)||typeof p.id!="string"||typeof p.fetch_url!="string")throw new re("api_error",`GET ${a} returned an unexpected response shape`);return p},async getClientObjectId(){let l=await n("GET","/auth/bootstrap"),a=Xe(l)?l.business:void 0,p=Xe(a)?a.client_object:void 0,h=Xe(p)?p.id:void 0;return typeof h=="string"&&h!==""?h:null},async getDashboard(l){return await n("GET",`/dashboards/${i(l)}`)},async createDashlet(l,a){return await n("POST",`/dashboards/${i(l)}/dashlet`,a)},async updateDashlet(l,a,p){return await n("PATCH",`/dashboards/${i(l)}/dashlet/${i(a)}`,p)}}}import{createHash as pl}from"crypto";import{mkdir as fl,readFile as ml,writeFile as hl}from"fs/promises";import{dirname as gl,join as yo}from"path";var Lr="appbuilder:",Me=".kizenapp/pushes.json",yl=["min_w","max_w","min_h","max_h","default_w","default_h"],bl=["environment","businessId","pluginApiName","blockApiName","dashboardId","dashletId","contentHash","pushedAt"];function de(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Ur(e){return typeof e=="number"&&Number.isFinite(e)}function zt(e,t,r){return Math.min(Math.max(e,t),r)}function wl(e){let t={...e};return delete t.custom_object,t}function bo(e,t){return`${Lr}${e}/${t}`}function wo(e){if(!e.startsWith(Lr))return null;let t=e.slice(Lr.length).split("/");if(t.length!==2)return null;let[r,o]=t;return!r||!o?null:{pluginApiName:r,blockApiName:o}}function xo(e){let t={};for(let r of yl){let o=e[r];Ur(o)&&(t[r]=o)}return t}function vo(e){return typeof e.host_chrome=="boolean"?{host_chrome:e.host_chrome}:{}}function ko(e){return{kind:"custom_code",version:1,name:e.name,script:e.script,styles:e.styles,event_scripts:Object.entries(e.event_scripts).map(([t,r])=>({name:t,script:r})),...xo(e),...vo(e)}}function xl(e){return{object_id:e.objectId,entity_type:"static_content",report_type:"html",chart_type:"html",content:e.content,fe_extra_info:{}}}function vl(e){let t=0;for(let r of e){let o=r.layout;if(!de(o))continue;let{y:n,h:i}=o;!Ur(n)||!Ur(i)||(t=Math.max(t,n+i))}return t}function kl(e,t,r){let o=zt(t.default_w??t.min_w??6,t.min_w??1,t.max_w??12),n=zt(t.default_h??t.min_h??3,t.min_h??1,t.max_h??99);return{i:r,x:0,y:vl(e),w:zt(o,2,12),h:zt(n,1,99)}}function Co(e){return{name:bo(e.pluginApiName,e.blockApiName),layout:kl(e.dashlets,e.content,e.layoutId),config:xl({content:e.content,objectId:e.objectId})}}function So(e,t){let r=e.config;return{config:{...wl(de(r)?r:{}),content:t}}}function _o(e){let t=e.config;return de(t)?t.content:void 0}function Ze(e){let t=e.config;if(!de(t)||t.chart_type!=="html")return!1;let r=t.content;return de(r)&&r.kind==="custom_code"}function Po(e){return e.dashlets.filter(Ze)}function Mt(e){let t=_o(e);return de(t)&&typeof t.name=="string"?t.name:e.name}function Cl(e){let t=r=>typeof r=="string"?r:"";return Array.isArray(e)?e.filter(de).map(r=>({name:t(r.name),script:t(r.script)})):de(e)?Object.entries(e).map(([r,o])=>({name:r,script:t(o)})):[]}function Hr(e){if(Array.isArray(e))return e.map(Hr);if(de(e)){let t={};for(let r of Object.keys(e).sort())t[r]=Hr(e[r]);return t}return e}function Sl(e){return typeof e=="string"?e.trim():typeof e=="number"||typeof e=="boolean"?String(e).trim():""}function Vr(e){let t=de(e)?e:{},r={name:Sl(t.name),script:typeof t.script=="string"?t.script:"",styles:typeof t.styles=="string"?t.styles:"",event_scripts:Cl(t.event_scripts),...xo(t),...vo(t)};return pl("sha256").update(JSON.stringify(Hr(r))).digest("hex")}function Lt(e){let{entry:t}=e;if(t?.dashboardId===e.dashboardId){let i=e.dashlets.find(s=>s.id===t.dashletId);if(i&&Ze(i))return{kind:"map",dashlet:i,entry:t}}let r=bo(e.pluginApiName,e.blockApiName),o=e.dashlets.filter(i=>i.name===r&&Ze(i)),[n]=o;return o.length===1&&n?{kind:"name",dashlet:n}:o.length>1?{kind:"ambiguous",dashlets:o}:{kind:"none"}}function Eo(e,t){return t?.dashletId!==e.id?!1:Vr(_o(e))!==t.contentHash}function Wr(e,t){return e.environment===t.environment&&e.businessId===t.businessId&&e.pluginApiName===t.pluginApiName&&e.blockApiName===t.blockApiName}function lt(e,t){return e.find(r=>Wr(r,t))}function To(e,t){let r=e.findIndex(o=>Wr(o,t));return r===-1?[...e,t]:e.map((o,n)=>n===r?t:o)}function ct(e,t){return e.filter(r=>!Wr(r,t))}function _l(e){if(!de(e))return null;for(let r of bl)if(typeof e[r]!="string")return null;let t=e;return{environment:t.environment,businessId:Ge(t.businessId),pluginApiName:t.pluginApiName,blockApiName:t.blockApiName,dashboardId:t.dashboardId,dashletId:t.dashletId,contentHash:t.contentHash,pushedAt:t.pushedAt}}var ho=e=>Date.parse(e.pushedAt)||0;function Pl(e){let t=new Map;for(let r of e){let o=[r.environment,r.businessId,r.pluginApiName,r.blockApiName].join("\0"),n=t.get(o);(n===void 0||ho(r)>ho(n))&&t.set(o,r)}return[...t.values()]}var El=e=>e instanceof Error&&e.code==="ENOENT",go=e=>e instanceof Error?e.message:String(e);async function Io(e){let t;try{t=await ml(yo(e,Me),"utf8")}catch(o){if(El(o))return[];throw new Error(`Couldn't read ${Me}: ${go(o)}. Fix its permissions, or delete it to start a fresh push map.`)}let r;try{r=JSON.parse(t)}catch(o){throw new Error(`${Me} is not valid JSON (${go(o)}). Fix it, or delete it to start a fresh push map.`)}if(!Array.isArray(r))throw new Error(`${Me} must contain a JSON array of push entries. Fix it, or delete it to start a fresh push map.`);return Pl(r.map(_l).filter(o=>o!==null))}async function Ao(e,t){let r=yo(e,Me);await fl(gl(r),{recursive:!0}),await hl(r,`${JSON.stringify(t,null,2)}
11
- `,"utf8")}var Tl={generic_dashboard:"dashboard",homepage:"homepage",chart_group:"chart_group"},Il={dashboard:"generic_dashboard",homepage:"homepage",chart_group:"chart_group"};function No(e){return Tl[e]}function Do(e){return Il[e]}function Ro(e){let t=e.appBaseUrl.replace(/\/+$/,""),r=e.dashboardId;return e.surface==="homepage"?`${t}/home/${r}`:e.surface==="chart_group"&&e.customObject?e.customObject.fetchUrl==="client"?`${t}/clients/charts/${r}`:`${t}/custom-objects/${e.customObject.id}/charts/${r}`:`${t}/dashboard/${r}`}import{access as Fl,mkdir as Ol,readFile as zl,writeFile as Ml}from"fs/promises";import{dirname as Ll,join as dt,posix as Ul}from"path";var Bo="---\nname: kizen-custom-block\ndescription: Use this skill when the user asks to build, change or publish a Kizen content block, custom block, chart, or dashboard/homepage visualization in this plugin. It covers the block file layout, the plugin engine runtime rules, and the appbuilder validate, preview and push loop.\n---\n\n# Kizen custom blocks\n\nFollow these rules exactly. The runtime is strict, and a push changes a live Kizen dashlet.\n\n## Keep this skill current\n\nAt the start of any block task, run `appbuilder setup-claude` in the plugin directory.\n\n- If it reports `updated` for `.claude/skills/kizen-custom-block/SKILL.md`, your loaded copy of this skill is stale. Re-read `.claude/skills/kizen-custom-block/SKILL.md` before doing anything else, and follow the new copy.\n- If it reports `created` for any file, or `updated` for `.claude/skills/kizen-custom-block/design.md`, read that file before writing any markup or styles.\n- If it reports `created` or `updated` for `lib/kizenData.js` (under the plugin's entry directory, usually `src/`), re-read its exports before using them.\n- If every file line reports `unchanged`, continue.\n- If the command doesn't exist (an older CLI), skip it and continue.\n- If it fails (for example, you aren't in the plugin directory that holds `kizen.json`), switch to that directory and run it once more. If it still fails, continue without it.\n\n`setup-claude` only rewrites the CLI-managed files: the ones in this skill directory and `src/lib/kizenData.js`. It never touches block code, so it's always safe to run.\n\n## What a block is\n\nA block is a directory under `src/blocks/<dir>/`:\n\n- `config.json` (required): `name`, `api_name` (always set it explicitly), `types` (any of `homepages`, `dashboards`, `charts` for chart groups, and `records`; a block only appears on the surfaces it lists), and the optional sizes `min_w`, `max_w`, `min_h`, `max_h`, `default_w` and `default_h`. Widths are grid columns (1 to 12) and heights are grid rows. Each size you set is a positive integer, each `min_*` is no greater than its `max_*`, and each `default_*` falls within whichever of its `min_*` and `max_*` you set. `default_w` and `default_h` are the starting size when `block push` creates a new dashlet; updates never resize an existing dashlet. Only the sizes you write are exported and pushed.\n - `host_chrome` (optional boolean, default `true`): whether the host paints the dashlet card around the block. Omit it unless you are turning chrome off. Only a value you write is exported and pushed, and any value other than `true` or `false` fails validation.\n- `script.js` (required): the render script.\n- `styles.css` (optional).\n- `eventScripts/<name>.js` (optional): one file per interactive handler.\n\nShared helpers live in `src/lib/*.js`. Import them with relative named imports only, for example `import { formatMoney } from '../../lib/format.js';`. No default imports, no bare package names.\n\n`src/lib/kizenData.js` is managed by appbuilder: `setup-claude` and CLI updates replace it. Never edit it. Put your own helpers in another file under `src/lib/`.\n\n### Host chrome\n\nDecide the mode yourself from the request. Ask the user only if they already raised it and their choice is unclear.\n\n- Keep host chrome (omit `host_chrome`) for standard data dashlets such as charts, KPIs, tables and lists that should match native cards.\n- Set `\"host_chrome\": false` for full-bleed heroes, imagery, custom-shaped cards, or any design whose background is part of the visual.\n\nChrome off, in `config.json`:\n\n```json\n{\n \"name\": \"Welcome hero\",\n \"api_name\": \"welcome_hero\",\n \"types\": [\"homepages\", \"dashboards\"],\n \"host_chrome\": false\n}\n```\n\nFollow \"Chrome off\" in `design.md` for the layout rules. In your summary to the user, state which mode you chose and why in one line. `block push --dry-run --json` shows the value as `body.config.content.host_chrome` (absent when chrome is on by default), so check it there. Changing `host_chrome` on a block you already pushed is an ordinary update: validate, then `block push <api_name> --yes --json`.\n\n## Runtime rules\n\nBlocks run in the plugin engine web worker.\n\n- `script.js` is the body of an async function, and `this` is the worker context. Use `await` at the top level.\n- There is no DOM: no `document` or `window`. There are no npm packages. Don't use `eval` or `Function`.\n- Render with `this.outputUI(htmlString)`. The output is sanitized with DOMPurify, so `<script>` tags and `on*` attributes are stripped. Don't rely on them.\n- Charts are hand-built inline SVG strings. There are no chart libraries.\n- Interactivity: put `data-script=\"<eventScriptName>\"` on a `<button>` whose content is text only. Clicking it runs `eventScripts/<eventScriptName>.js` in a fresh worker, so no state carries over from `script.js`.\n- Args:\n - `this.args.dateFilter`: `{ start, end }`, or `undefined`.\n - `this.args.teamFilter`.\n - `this.args.objectId`: set on chart groups.\n - Homepages have no date or team filter. Handle both being absent.\n- Data: read records with the `kizenData.js` helpers (see \"Reading Kizen data\"). They call `this.getWithErrors` and `this.postWithErrors`, which use relative URLs and run as the viewing user.\n- Toasts: `this.showToast(message, options)`. `message` MUST be a string. Passing an object crashes the host app.\n- Styling:\n - The host applies `* { font-size: 10px }`. Set explicit px font sizes on everything.\n - With host chrome (the default), the host paints the card (background, border, border radius and shadow) from the dashboard's style settings, like native dashlets. The block root is transparent, fills the card, and paints no card of its own.\n - With `\"host_chrome\": false`, the host paints nothing: no background, border, radius or shadow. The block root fills the card edge to edge and owns its whole look (see \"Chrome off\" in `design.md`).\n - Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n- The code is stored in a Kizen dashlet. Never include a NUL character or the literal text `{__ref:` anywhere in any file.\n\n## Reading Kizen data\n\nRead records through `src/lib/kizenData.js`. Always import it from `../../lib/kizenData.js`. Its helpers take the worker context as their first argument, so pass `this`.\n\n- `getFields(this, object)` loads an object's fields. `object` is the object's id or name, and Contacts is `client_client`. Match fields by `name`.\n- `blockFilters(this.args, fields)` returns `{ filters, unapplied }`. Always apply `filters`, so the block reacts to the dashboard's date and team filters the way native dashlets do (date on `created`, team on `owner`). When `unapplied` contains `'teamFilter'`, the team filter couldn't be applied (a roles-only selection, or an object with no owner field). Show \"(team filter not applied)\".\n- `dropdownFilter(field, 'Name')` or `dropdownFilter(field, ['A', 'B'])` filters a dropdown by option names.\n- `searchRecords(this, { object, fieldNames, filters })` returns `{ records, count, truncated }`. When `truncated` is true, show \"Showing first N\" with N = `records.length`.\n- `fieldValue(record, name)`, `fieldLabel(record, name)`, `countBy(records, name, field?)`, `sumBy(records, name, valueOf?)` and `formatNumber(n, prefix)` read and summarize the results. `countBy` groups empty values under `key: ''`. Filter that group out, or give it a label.\n- Every record value or label you put into markup goes through `escapeHtml(value)`, including option names, owner names and text fields. `this.outputUI` sanitizes scripts, but it keeps images, links, forms and styles, and the block renders for every viewer. `escapeHtml` is the only escaping helper; never write your own.\n- Never hand-build filter or search JSON when a helper exists. Every helper throws a readable `Error`, so wrap the fetch in `try` and render the error state from `design.md`.\n\nCount Contacts by a dropdown field named `status` for the current dashboard filters. Use a field name from `getFields`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\ntry {\n const fields = await getFields(this, 'client_client');\n const { filters, unapplied } = blockFilters(this.args, fields);\n const search = { object: 'client_client', fieldNames: ['status'], filters };\n const { records, count, truncated } = await searchRecords(this, search);\n const rows = countBy(records, 'status').filter((row) => row.key !== '');\n const items = rows.map((row) => `<li>${escapeHtml(row.label)}: ${row.count}</li>`).join('');\n const note = truncated ? `Showing first ${records.length} of ${count}. ` : '';\n const team = unapplied.includes('teamFilter') ? '(team filter not applied)' : '';\n this.outputUI(`<ul>${items}</ul><p>${note}${team}</p>`);\n} catch {\n this.outputUI('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n}\n```\n\n## Design\n\nBefore writing any markup or styles, read `design.md` in this skill directory and follow it exactly.\n\n## The loop\n\nRun these exact commands. The flags and JSON keys are the contract. `<api_name>` is the block's `config.json` `api_name`. `block targets` and `block push` both accept `-c/--credentials <path>` and `--profile <name>` to pick the credential.\n\n1. **Validate.** Run `appbuilder block export <api_name>`. Fix every validation error it prints, then run it again until it passes.\n2. **Choose the target with the user (first publish only).**\n - `appbuilder block targets --json` returns `{ surfaces: { dashboard: [...], homepage: [...] }, customObjects: [{ id, objectName, fetchUrl }] }`. Contacts appears in `customObjects` when available.\n - `appbuilder block targets --object <id> --json` returns `{ surfaces: { chart_group: [...] } }` for that object.\n - Only offer rows where `canEdit !== false`. Ask the user which surface and which specific one. Don't pick for them.\n - Optionally run `appbuilder block push <api_name> --dashboard <id> --json` to get a `needs_choice` result listing the existing custom blocks and \"new\".\n3. **Preview.** Run `appbuilder block push <api_name> --dashboard <id> [--dashlet <id> | --create] --dry-run --json`. Show the user the `environment`, `businessId`, `dashboard.name`, `action` and any `warnings`.\n4. **Apply** once the user agrees: run the same command with `--yes` in place of `--dry-run`. Treat the push as done only when `applied === true`. Give the user the block URL (below), then refresh the browser (below).\n5. **Change requests.** Edit the files, validate again (step 1), then run `appbuilder block push <api_name> --yes --json`. With no target flags it updates the remembered dashlet. Refresh the browser (below) after each push. Repeat for each change.\n\nA headless run without `--yes` is always a dry run.\n\n### The block URL\n\nThe block URL is the result's `url`, with one exception: when the result's `environment` is `integration`, replace the origin of `url` with `https://pr-9378.integration.kizen.dev` and keep the path and query. For example, `https://v2.integration.kizen.dev/dashboard/<id>` becomes `https://pr-9378.integration.kizen.dev/dashboard/<id>`. Every other environment uses `url` unchanged. Use the block URL everywhere this skill says to give, open, match or navigate to the block's page. This exception is temporary for the test build and will be removed once the feature is on integration.\n\n### Refresh the browser after a push\n\nDo this after every applied push, only when Claude-in-Chrome tools are available. Dashlets don't poll, so the user's open tab keeps the old block until it's refreshed. Don't reload the page.\n\n1. List the open tabs (`tabs_context_mcp`) and find the one whose URL has the same origin and path as the block URL.\n2. If there is no such tab, open the block URL in a new tab (`tabs_create_mcp`) and go to step 5.\n3. If the result has a `refresh` field, run `refresh.script` exactly as given in that tab with the page JavaScript tool (`javascript_tool`). If it has no `refresh` field, navigate that tab to the block URL (`navigate`) and go to step 5.\n4. Check what the script returned:\n - `{ refreshed: true, ... }`: the dashboard refetched in place.\n - `undefined`: the refresh hook isn't available on this page. Navigate the tab to the block URL instead. Then run `localStorage.getItem('kizen-flag-custom-code-blocks')` in that tab with `javascript_tool`. If it isn't `'true'`, tell the user once per conversation that setting that localStorage key to `'true'` in the Kizen tab enables in-place refresh. Never set it yourself.\n5. Wait a couple of seconds, take a screenshot (`computer`), and check that the block rendered: not blank, and no visible error. Report what you saw to the user. If the block is blank or shows an error, read the console and fix the block before pushing again.\n\nNever run any other injected code in the user's tabs. `refresh.script` is the only script you may run, with one exception: the read-only `localStorage.getItem('kizen-flag-custom-code-blocks')` check above.\n\n### JSON results\n\n- Dry run: `{ ok: true, applied: false, dryRun: true, action: 'create' | 'update', environment, businessId, dashboard: { id, name, type }, dashletId | null, url, method, path, body, warnings }`.\n- Applied: `{ ok: true, applied: true, dryRun: false, action: 'created' | 'updated', ..., dashletId, url, refresh?: { dashboardId, script }, remembered }`. `refresh` is absent when the dashboard id isn't a uuid.\n- If a `block push` result's `warnings` contains `Claude files managed by appbuilder are out of date; run appbuilder setup-claude`, run `appbuilder setup-claude`, re-read `.claude/skills/kizen-custom-block/SKILL.md`, then continue.\n- Error: `{ ok: false, code, message, choice?, choices? }`. `code` is one of `needs_choice`, `validation_failed`, `invalid_block`, `auth_failed`, `forbidden`, `remembered_target_missing`, `drift_detected`, `network_error`, `credentials_invalid`, `production_requires_flag`, `not_found`, `usage_error`, `api_error` or `local_error`.\n\n### `needs_choice`\n\n`choice` is `'profile'`, `'block'`, `'dashboard'` or `'target'`. `choices` is a list of `{ value, label, args, surface?, canEdit?, pushKey?, isFromThisPlugin? }`, where `args` is a string array. Ask the user using each option's `label`, then re-run the same command with the chosen option's `args` appended exactly. Never construct these flags by hand. The \"new\" option is `{ value: 'new', args: ['--dashboard', <id>, '--create'] }`.\n\n## Guardrails\n\n- Never pass `--allow-production` unless the user explicitly asked, in this conversation, to publish to production (`go` or `fmo`).\n- On `drift_detected`, stop and ask the user. Someone edited the block in Kizen since your last push, and `--force` overwrites their changes. Pass `--force` only when the user says to discard them.\n- On `needs_choice`, ask the user using the returned `choices` as described above. Never guess.\n- On `remembered_target_missing`, the remembered dashboard or dashlet is gone. Ask the user where to publish instead, then push with `--dashboard <id>` plus `--create` or a `--dashlet` choice, or use `--forget` to clear the memory. `--create` alone won't work.\n- On `credentials_invalid`, tell the user to fix the credential file named in `message`, or to pass `--profile` or `-c`.\n- On `production_requires_flag`, the target is `go` or `fmo`. Apply the production rule above.\n- Never push to a new target without first showing the user a dry run.\n- Blocks run with the viewing user's permissions for every viewer. Don't write code that creates, updates or deletes data unless the user asked for it.\n";var $o=`# Designing a Kizen custom block
10
+ `;Ye.writeFileSync(t,o+n)}var il="The API key is invalid for this business, or the user id doesn't match. Check the credentials file's apiKey, userId and businessId.",sl="The API key's user needs the Standard API Keys permission and edit access to this dashboard. Homepages also need the Customize Homepages permission.",al=100,ll=new Set(["detail","non_field_errors"]),re=class extends Error{kind;status;hint;constructor(t,r,o={}){super(r),this.name="KizenApiError",this.kind=t,this.status=o.status,this.hint=o.hint}},Xe=e=>typeof e=="object"&&e!==null&&!Array.isArray(e);function Mr(e,t,r){let o=n=>{r.push(t===""?n:`${t}: ${n}`)};if(typeof e=="string"){e.trim()!==""&&o(e);return}if(typeof e=="number"||typeof e=="boolean"){o(String(e));return}if(Array.isArray(e)){let n=e.filter(i=>typeof i=="string"&&i.trim()!==""||typeof i=="number"||typeof i=="boolean");n.length>0&&o(n.map(String).join(" "));for(let i of e)typeof i=="object"&&i!==null&&Mr(i,t,r);return}if(Xe(e))for(let[n,i]of Object.entries(e)){let s=t===""&&ll.has(n)?"":t===""?n:`${t}.${n}`;Mr(i,s,r)}}function cl(e){if(typeof e!="object"||e===null)return;let t=[];return Mr(e,"",t),t.length>0?t.join("; "):void 0}function po(e){let t=e;return t.cause?.code??t.code??t.cause?.message??t.message??String(e)}async function dl(e){let t=await e.text();if(t==="")return{text:t,json:void 0};try{return{text:t,json:JSON.parse(t)}}catch{return{text:t,json:void 0}}}function ul(e,t,r,o){let n=cl(o),i=`${e} ${t} failed with ${String(r)}${n===void 0?"":`: ${n}`}`;return r===401?new re("auth_failed",i,{status:r,hint:il}):r===403?new re("forbidden",i,{status:r,hint:sl}):r===404?new re("not_found",i,{status:r}):new re("api_error",i,{status:r})}function fo(e,t,r){if(Array.isArray(r))return{results:r,next:null};if(Xe(r)&&Array.isArray(r.results))return{results:r.results,next:r.next};throw new re("api_error",`${e} ${t} returned an unexpected response shape`)}function mo(e){let{credentials:t}=e,r=e.fetch??fetch,o=e.baseUrl??Zn[t.environment],n=async(l,a,p)=>{let h=/^https?:\/\//.test(a)?a:`${o}${a}`,w=h.startsWith(o)?h.slice(o.length):h,x={"X-API-KEY":t.apiKey,"X-USER-ID":t.userId,"X-BUSINESS-ID":t.businessId,Accept:"application/json"},d={method:l,headers:x};p!==void 0&&(x["Content-Type"]="application/json",d.body=JSON.stringify(p));let c;try{c=await r(h,d)}catch(P){throw new re("network_error",`Couldn't reach Kizen at ${o}: ${po(P)}${Dt()==="unavailable"?` ${Nt}`:""}`)}let y,v;try{({text:y,json:v}=await dl(c))}catch(P){throw new re("network_error",`${l} ${w}: couldn't read the response: ${po(P)}. The request may have been applied; check Kizen before retrying.`,{status:c.status})}if(!c.ok)throw ul(l,w,c.status,v);if(v===void 0&&y!=="")throw new re("api_error",`${l} ${w} returned a response that is not JSON`,{status:c.status});return v},i=encodeURIComponent,s=l=>{let a=new URL(o),p=new URL(l,a.origin);if(p.hostname!==a.hostname)throw new re("api_error",`GET /custom-objects pagination pointed at an unexpected host ${p.hostname}`);return new URL(`${p.pathname}${p.search}`,a.origin).toString()};return{async listDashboards(l,a){let p=new URLSearchParams({size:"10000",include_sharing:"true",dashboard_type:l});a!==void 0&&p.set("custom_object_id",a);let h=`/dashboards/mine?${p.toString()}`;return fo("GET",h,await n("GET",h)).results},async listCustomObjects(){let l=[],a=new Set,p="/custom-objects?page_size=200";for(;p!==void 0&&!a.has(p)&&a.size<al;){a.add(p);let h=fo("GET",p,await n("GET",p));l.push(...h.results),p=typeof h.next=="string"&&h.next!==""?s(h.next):void 0}return l},async getCustomObject(l){let a=`/custom-objects/${i(l)}`,p=await n("GET",a);if(!Xe(p)||typeof p.id!="string"||typeof p.fetch_url!="string")throw new re("api_error",`GET ${a} returned an unexpected response shape`);return p},async getClientObjectId(){let l=await n("GET","/auth/bootstrap"),a=Xe(l)?l.business:void 0,p=Xe(a)?a.client_object:void 0,h=Xe(p)?p.id:void 0;return typeof h=="string"&&h!==""?h:null},async getDashboard(l){return await n("GET",`/dashboards/${i(l)}`)},async createDashlet(l,a){return await n("POST",`/dashboards/${i(l)}/dashlet`,a)},async updateDashlet(l,a,p){return await n("PATCH",`/dashboards/${i(l)}/dashlet/${i(a)}`,p)}}}import{createHash as pl}from"crypto";import{mkdir as fl,readFile as ml,writeFile as hl}from"fs/promises";import{dirname as gl,join as yo}from"path";var Lr="appbuilder:",Me=".kizenapp/pushes.json",yl=["min_w","max_w","min_h","max_h","default_w","default_h"],bl=["environment","businessId","pluginApiName","blockApiName","dashboardId","dashletId","contentHash","pushedAt"];function de(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Hr(e){return typeof e=="number"&&Number.isFinite(e)}function zt(e,t,r){return Math.min(Math.max(e,t),r)}function wl(e){let t={...e};return delete t.custom_object,t}function bo(e,t){return`${Lr}${e}/${t}`}function wo(e){if(!e.startsWith(Lr))return null;let t=e.slice(Lr.length).split("/");if(t.length!==2)return null;let[r,o]=t;return!r||!o?null:{pluginApiName:r,blockApiName:o}}function xo(e){let t={};for(let r of yl){let o=e[r];Hr(o)&&(t[r]=o)}return t}function vo(e){return typeof e.host_chrome=="boolean"?{host_chrome:e.host_chrome}:{}}function ko(e){return{kind:"custom_code",version:1,name:e.name,script:e.script,styles:e.styles,event_scripts:Object.entries(e.event_scripts).map(([t,r])=>({name:t,script:r})),...xo(e),...vo(e)}}function xl(e){return{object_id:e.objectId,entity_type:"static_content",report_type:"html",chart_type:"html",content:e.content,fe_extra_info:{}}}function vl(e){let t=0;for(let r of e){let o=r.layout;if(!de(o))continue;let{y:n,h:i}=o;!Hr(n)||!Hr(i)||(t=Math.max(t,n+i))}return t}function kl(e,t,r){let o=zt(t.default_w??t.min_w??6,t.min_w??1,t.max_w??12),n=zt(t.default_h??t.min_h??3,t.min_h??1,t.max_h??99);return{i:r,x:0,y:vl(e),w:zt(o,2,12),h:zt(n,1,99)}}function Co(e){return{name:bo(e.pluginApiName,e.blockApiName),layout:kl(e.dashlets,e.content,e.layoutId),config:xl({content:e.content,objectId:e.objectId})}}function So(e,t){let r=e.config;return{config:{...wl(de(r)?r:{}),content:t}}}function _o(e){let t=e.config;return de(t)?t.content:void 0}function Ze(e){let t=e.config;if(!de(t)||t.chart_type!=="html")return!1;let r=t.content;return de(r)&&r.kind==="custom_code"}function Po(e){return e.dashlets.filter(Ze)}function Mt(e){let t=_o(e);return de(t)&&typeof t.name=="string"?t.name:e.name}function Cl(e){let t=r=>typeof r=="string"?r:"";return Array.isArray(e)?e.filter(de).map(r=>({name:t(r.name),script:t(r.script)})):de(e)?Object.entries(e).map(([r,o])=>({name:r,script:t(o)})):[]}function Ur(e){if(Array.isArray(e))return e.map(Ur);if(de(e)){let t={};for(let r of Object.keys(e).sort())t[r]=Ur(e[r]);return t}return e}function Sl(e){return typeof e=="string"?e.trim():typeof e=="number"||typeof e=="boolean"?String(e).trim():""}function Vr(e){let t=de(e)?e:{},r={name:Sl(t.name),script:typeof t.script=="string"?t.script:"",styles:typeof t.styles=="string"?t.styles:"",event_scripts:Cl(t.event_scripts),...xo(t),...vo(t)};return pl("sha256").update(JSON.stringify(Ur(r))).digest("hex")}function Lt(e){let{entry:t}=e;if(t?.dashboardId===e.dashboardId){let i=e.dashlets.find(s=>s.id===t.dashletId);if(i&&Ze(i))return{kind:"map",dashlet:i,entry:t}}let r=bo(e.pluginApiName,e.blockApiName),o=e.dashlets.filter(i=>i.name===r&&Ze(i)),[n]=o;return o.length===1&&n?{kind:"name",dashlet:n}:o.length>1?{kind:"ambiguous",dashlets:o}:{kind:"none"}}function Eo(e,t){return t?.dashletId!==e.id?!1:Vr(_o(e))!==t.contentHash}function Wr(e,t){return e.environment===t.environment&&e.businessId===t.businessId&&e.pluginApiName===t.pluginApiName&&e.blockApiName===t.blockApiName}function lt(e,t){return e.find(r=>Wr(r,t))}function To(e,t){let r=e.findIndex(o=>Wr(o,t));return r===-1?[...e,t]:e.map((o,n)=>n===r?t:o)}function ct(e,t){return e.filter(r=>!Wr(r,t))}function _l(e){if(!de(e))return null;for(let r of bl)if(typeof e[r]!="string")return null;let t=e;return{environment:t.environment,businessId:Ge(t.businessId),pluginApiName:t.pluginApiName,blockApiName:t.blockApiName,dashboardId:t.dashboardId,dashletId:t.dashletId,contentHash:t.contentHash,pushedAt:t.pushedAt}}var ho=e=>Date.parse(e.pushedAt)||0;function Pl(e){let t=new Map;for(let r of e){let o=[r.environment,r.businessId,r.pluginApiName,r.blockApiName].join("\0"),n=t.get(o);(n===void 0||ho(r)>ho(n))&&t.set(o,r)}return[...t.values()]}var El=e=>e instanceof Error&&e.code==="ENOENT",go=e=>e instanceof Error?e.message:String(e);async function Io(e){let t;try{t=await ml(yo(e,Me),"utf8")}catch(o){if(El(o))return[];throw new Error(`Couldn't read ${Me}: ${go(o)}. Fix its permissions, or delete it to start a fresh push map.`)}let r;try{r=JSON.parse(t)}catch(o){throw new Error(`${Me} is not valid JSON (${go(o)}). Fix it, or delete it to start a fresh push map.`)}if(!Array.isArray(r))throw new Error(`${Me} must contain a JSON array of push entries. Fix it, or delete it to start a fresh push map.`);return Pl(r.map(_l).filter(o=>o!==null))}async function Ao(e,t){let r=yo(e,Me);await fl(gl(r),{recursive:!0}),await hl(r,`${JSON.stringify(t,null,2)}
11
+ `,"utf8")}var Tl={generic_dashboard:"dashboard",homepage:"homepage",chart_group:"chart_group"},Il={dashboard:"generic_dashboard",homepage:"homepage",chart_group:"chart_group"};function No(e){return Tl[e]}function Do(e){return Il[e]}function Ro(e){let t=e.appBaseUrl.replace(/\/+$/,""),r=e.dashboardId;return e.surface==="homepage"?`${t}/home/${r}`:e.surface==="chart_group"&&e.customObject?e.customObject.fetchUrl==="client"?`${t}/clients/charts/${r}`:`${t}/custom-objects/${e.customObject.id}/charts/${r}`:`${t}/dashboard/${r}`}import{access as Fl,mkdir as Ol,readFile as zl,writeFile as Ml}from"fs/promises";import{dirname as Ll,join as dt,posix as Hl}from"path";var Bo="---\nname: kizen-custom-block\ndescription: Use this skill when the user asks to build, change or publish a Kizen content block, custom block, chart, or dashboard/homepage visualization in this plugin. It covers the block file layout, the plugin engine runtime rules, and the appbuilder validate, preview and push loop.\n---\n\n# Kizen custom blocks\n\nFollow these rules exactly. The runtime is strict, and a push changes a live Kizen dashlet.\n\n## Keep this skill current\n\nAt the start of any block task, run `appbuilder setup-claude` in the plugin directory.\n\n- If it reports `updated` for `.claude/skills/kizen-custom-block/SKILL.md`, your loaded copy of this skill is stale. Re-read `.claude/skills/kizen-custom-block/SKILL.md` before doing anything else, and follow the new copy.\n- If it reports `created` for any file, or `updated` for `.claude/skills/kizen-custom-block/design.md`, read that file before writing any markup or styles.\n- If it reports `created` or `updated` for `lib/kizenData.js` (under the plugin's entry directory, usually `src/`), re-read its exports before using them.\n- If every file line reports `unchanged`, continue.\n- If the command doesn't exist (an older CLI), skip it and continue.\n- If it fails (for example, you aren't in the plugin directory that holds `kizen.json`), switch to that directory and run it once more. If it still fails, continue without it.\n\n`setup-claude` only rewrites the CLI-managed files: the ones in this skill directory and `src/lib/kizenData.js`. It never touches block code, so it's always safe to run.\n\n## What a block is\n\nA block is a directory under `src/blocks/<dir>/`:\n\n- `config.json` (required): `name`, `api_name` (always set it explicitly), `types` (any of `homepages`, `dashboards`, `charts` for chart groups, and `records`; a block only appears on the surfaces it lists), and the optional sizes `min_w`, `max_w`, `min_h`, `max_h`, `default_w` and `default_h`. Widths are grid columns (1 to 12) and heights are grid rows. Each size you set is a positive integer, each `min_*` is no greater than its `max_*`, and each `default_*` falls within whichever of its `min_*` and `max_*` you set. `default_w` and `default_h` are the starting size when `block push` creates a new dashlet; updates never resize an existing dashlet. Only the sizes you write are exported and pushed.\n - `host_chrome` (optional boolean, default `true`): whether the host paints the dashlet card around the block. Omit it unless you are turning chrome off. Only a value you write is exported and pushed, and any value other than `true` or `false` fails validation.\n- `script.js` (required): the render script.\n- `styles.css` (optional).\n- `eventScripts/<name>.js` (optional): one file per interactive handler.\n\nShared helpers live in `src/lib/*.js`. Import them with relative named imports only, for example `import { formatMoney } from '../../lib/format.js';`. No default imports, no bare package names.\n\n`src/lib/kizenData.js` is managed by appbuilder: `setup-claude` and CLI updates replace it. Never edit it. Put your own helpers in another file under `src/lib/`.\n\n### Host chrome\n\nDecide the mode yourself from the request. Ask the user only if they already raised it and their choice is unclear.\n\n- Keep host chrome (omit `host_chrome`) for standard data dashlets such as charts, KPIs, tables and lists that should match native cards.\n- Set `\"host_chrome\": false` for full-bleed heroes, imagery, custom-shaped cards, or any design whose background is part of the visual.\n\nChrome off, in `config.json`:\n\n```json\n{\n \"name\": \"Welcome hero\",\n \"api_name\": \"welcome_hero\",\n \"types\": [\"homepages\", \"dashboards\"],\n \"host_chrome\": false\n}\n```\n\nFollow \"Chrome off\" in `design.md` for the layout rules. In your summary to the user, state which mode you chose and why in one line. `block push --dry-run --json` shows the value as `body.config.content.host_chrome` (absent when chrome is on by default), so check it there. Changing `host_chrome` on a block you already pushed is an ordinary update: validate, then `block push <api_name> --yes --json`.\n\n## Runtime rules\n\nBlocks run in the plugin engine web worker.\n\n- `script.js` is the body of an async function, and `this` is the worker context. Use `await` at the top level.\n- There is no DOM: no `document` or `window`. There are no npm packages. Don't use `eval` or `Function`.\n- Render with `this.outputUI(htmlString)`. The output is sanitized with DOMPurify, so `<script>` tags and `on*` attributes are stripped. Don't rely on them.\n- Charts are hand-built inline SVG strings. There are no chart libraries.\n- Interactivity: put `data-script=\"<eventScriptName>\"` on a `<button>` whose content is text only. Clicking it runs `eventScripts/<eventScriptName>.js` in a fresh worker, so no state carries over from `script.js`.\n- Args:\n - `this.args.dateFilter`: `{ start, end }`, or `undefined`.\n - `this.args.teamFilter`.\n - `this.args.objectId`: set on chart groups.\n - Homepages have no date or team filter. Handle both being absent.\n- Data: read records with the `kizenData.js` helpers (see \"Reading Kizen data\"). They call `this.getWithErrors` and `this.postWithErrors`, which use relative URLs and run as the viewing user.\n- Toasts: `this.showToast(message, options)`. `message` MUST be a string. Passing an object crashes the host app.\n- Styling:\n - The host applies `* { font-size: 10px }`. Set explicit px font sizes on everything.\n - With host chrome (the default), the host paints the card (background, border, border radius and shadow) from the dashboard's style settings, like native dashlets. The block root is transparent, fills the card, and paints no card of its own.\n - With `\"host_chrome\": false`, the host paints nothing: no background, border, radius or shadow. The block root fills the card edge to edge and owns its whole look (see \"Chrome off\" in `design.md`).\n - Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n- The code is stored in a Kizen dashlet. Never include a NUL character or the literal text `{__ref:` anywhere in any file.\n\n## Reading Kizen data\n\nRead records through `src/lib/kizenData.js`. Always import it from `../../lib/kizenData.js`. Its helpers take the worker context as their first argument, so pass `this`.\n\n- `getFields(this, object)` loads an object's fields. `object` is the object's id or name, and Contacts is `client_client`. Match fields by `name`.\n- `blockFilters(this.args, fields)` returns `{ filters, unapplied }`. Always apply `filters`, so the block reacts to the dashboard's date and team filters the way native dashlets do (date on `created`, team on `owner`). When `unapplied` contains `'teamFilter'`, the team filter couldn't be applied (a roles-only selection, or an object with no owner field). Show \"(team filter not applied)\".\n- `dropdownFilter(field, 'Name')` or `dropdownFilter(field, ['A', 'B'])` filters a dropdown by option names.\n- `searchRecords(this, { object, fieldNames, filters })` returns `{ records, count, truncated }`. When `truncated` is true, show \"Showing first N\" with N = `records.length`.\n- `fieldValue(record, name)`, `fieldLabel(record, name)`, `countBy(records, name, field?)`, `sumBy(records, name, valueOf?)` and `formatNumber(n, prefix)` read and summarize the results. `countBy` groups empty values under `key: ''`. Filter that group out, or give it a label.\n- Every record value or label you put into markup goes through `escapeHtml(value)`, including option names, owner names and text fields. `this.outputUI` sanitizes scripts, but it keeps images, links, forms and styles, and the block renders for every viewer. `escapeHtml` is the only escaping helper; never write your own.\n- Never hand-build filter or search JSON when a helper exists. Every helper throws a readable `Error`, so wrap the fetch in `try` and render the error state from `design.md`.\n\nCount Contacts by a dropdown field named `status` for the current dashboard filters. Use a field name from `getFields`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\ntry {\n const fields = await getFields(this, 'client_client');\n const { filters, unapplied } = blockFilters(this.args, fields);\n const search = { object: 'client_client', fieldNames: ['status'], filters };\n const { records, count, truncated } = await searchRecords(this, search);\n const rows = countBy(records, 'status').filter((row) => row.key !== '');\n const items = rows.map((row) => `<li>${escapeHtml(row.label)}: ${row.count}</li>`).join('');\n const note = truncated ? `Showing first ${records.length} of ${count}. ` : '';\n const team = unapplied.includes('teamFilter') ? '(team filter not applied)' : '';\n this.outputUI(`<ul>${items}</ul><p>${note}${team}</p>`);\n} catch {\n this.outputUI('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n}\n```\n\n## Design\n\nBefore writing any markup or styles, read `design.md` in this skill directory and follow it exactly.\n\n## The loop\n\nRun these exact commands. The flags and JSON keys are the contract. `<api_name>` is the block's `config.json` `api_name`. `block targets` and `block push` both accept `-c/--credentials <path>` and `--profile <name>` to pick the credential.\n\n1. **Validate.** Run `appbuilder block export <api_name>`. Fix every validation error it prints, then run it again until it passes.\n2. **Choose the target with the user (first publish only).**\n - `appbuilder block targets --json` returns `{ surfaces: { dashboard: [...], homepage: [...] }, customObjects: [{ id, objectName, fetchUrl }] }`. Contacts appears in `customObjects` when available.\n - `appbuilder block targets --object <id> --json` returns `{ surfaces: { chart_group: [...] } }` for that object.\n - Only offer rows where `canEdit !== false`. Ask the user which surface and which specific one. Don't pick for them.\n - Optionally run `appbuilder block push <api_name> --dashboard <id> --json` to get a `needs_choice` result listing the existing custom blocks and \"new\".\n3. **Preview.** Run `appbuilder block push <api_name> --dashboard <id> [--dashlet <id> | --create] --dry-run --json`. Show the user the `environment`, `businessId`, `dashboard.name`, `action` and any `warnings`.\n4. **Apply** once the user agrees: run the same command with `--yes` in place of `--dry-run`. Treat the push as done only when `applied === true`. Give the user the returned `url`, then refresh the browser (below).\n5. **Change requests.** Edit the files, validate again (step 1), then run `appbuilder block push <api_name> --yes --json`. With no target flags it updates the remembered dashlet. Refresh the browser (below) after each push. Repeat for each change.\n\nA headless run without `--yes` is always a dry run.\n\n### Refresh the browser after a push\n\nDo this after every applied push, only when Claude-in-Chrome tools are available. Dashlets don't poll, so the user's open tab keeps the old block until it's refreshed. Don't reload the page.\n\n1. List the open tabs (`tabs_context_mcp`) and find the one whose URL has the same origin and path as the result's `url`.\n2. If there is no such tab, open `url` in a new tab (`tabs_create_mcp`) and go to step 5.\n3. If the result has a `refresh` field, run `refresh.script` exactly as given in that tab with the page JavaScript tool (`javascript_tool`). If it has no `refresh` field, navigate that tab to `url` (`navigate`) and go to step 5.\n4. Check what the script returned:\n - `{ refreshed: true, ... }`: the dashboard refetched in place.\n - `undefined`: the refresh hook isn't available on this page. Navigate the tab to `url` instead. Then run `localStorage.getItem('kizen-flag-custom-code-blocks')` in that tab with `javascript_tool`. If it isn't `'true'`, tell the user once per conversation that setting that localStorage key to `'true'` in the Kizen tab enables in-place refresh. Never set it yourself.\n5. Wait a couple of seconds, take a screenshot (`computer`), and check that the block rendered: not blank, and no visible error. Report what you saw to the user. If the block is blank or shows an error, read the console and fix the block before pushing again.\n\nNever run any other injected code in the user's tabs. `refresh.script` is the only script you may run, with one exception: the read-only `localStorage.getItem('kizen-flag-custom-code-blocks')` check above.\n\n### JSON results\n\n- Dry run: `{ ok: true, applied: false, dryRun: true, action: 'create' | 'update', environment, businessId, dashboard: { id, name, type }, dashletId | null, url, method, path, body, warnings }`.\n- Applied: `{ ok: true, applied: true, dryRun: false, action: 'created' | 'updated', ..., dashletId, url, refresh?: { dashboardId, script }, remembered }`. `refresh` is absent when the dashboard id isn't a uuid.\n- If a `block push` result's `warnings` contains `Claude files managed by appbuilder are out of date; run appbuilder setup-claude`, run `appbuilder setup-claude`, re-read `.claude/skills/kizen-custom-block/SKILL.md`, then continue.\n- Error: `{ ok: false, code, message, choice?, choices? }`. `code` is one of `needs_choice`, `validation_failed`, `invalid_block`, `auth_failed`, `forbidden`, `remembered_target_missing`, `drift_detected`, `network_error`, `credentials_invalid`, `production_requires_flag`, `not_found`, `usage_error`, `api_error` or `local_error`.\n\n### `needs_choice`\n\n`choice` is `'profile'`, `'block'`, `'dashboard'` or `'target'`. `choices` is a list of `{ value, label, args, surface?, canEdit?, pushKey?, isFromThisPlugin? }`, where `args` is a string array. Ask the user using each option's `label`, then re-run the same command with the chosen option's `args` appended exactly. Never construct these flags by hand. The \"new\" option is `{ value: 'new', args: ['--dashboard', <id>, '--create'] }`.\n\n## Guardrails\n\n- Never pass `--allow-production` unless the user explicitly asked, in this conversation, to publish to production (`go` or `fmo`).\n- On `drift_detected`, stop and ask the user. Someone edited the block in Kizen since your last push, and `--force` overwrites their changes. Pass `--force` only when the user says to discard them.\n- On `needs_choice`, ask the user using the returned `choices` as described above. Never guess.\n- On `remembered_target_missing`, the remembered dashboard or dashlet is gone. Ask the user where to publish instead, then push with `--dashboard <id>` plus `--create` or a `--dashlet` choice, or use `--forget` to clear the memory. `--create` alone won't work.\n- On `credentials_invalid`, tell the user to fix the credential file named in `message`, or to pass `--profile` or `-c`.\n- On `production_requires_flag`, the target is `go` or `fmo`. Apply the production rule above.\n- Never push to a new target without first showing the user a dry run.\n- Blocks run with the viewing user's permissions for every viewer. Don't write code that creates, updates or deletes data unless the user asked for it.\n";var $o=`# Designing a Kizen custom block
12
12
 
13
13
  With host chrome (the default), a block must look like a native Kizen dashlet. Follow every rule here exactly. Where a rule says "use judgment", pick the option that looks most native. A block whose \`config.json\` sets \`"host_chrome": false\` follows section M for its card and outer box, and skips every rule marked "with host chrome".
14
14
 
@@ -739,10 +739,10 @@ export const sumBy = (records, name, valueOf) =>
739
739
  total + (valueOf ? numberOf(valueOf(record)) : numberOf(fieldValue(record, name))),
740
740
  0,
741
741
  );
742
- `;function Lo(){return[{path:".github/copilot-instructions.md",content:jo},{path:".github/instructions/security.instructions.md",content:Fo},{path:".github/instructions/version-discipline.instructions.md",content:Oo}]}var Mo="lib/kizenData.js",jl=(e="src")=>e===""?Mo:`${e}/${Mo}`;function Le(e=["src"]){return[{path:".claude/skills/kizen-custom-block/SKILL.md",content:Bo},{path:".claude/skills/kizen-custom-block/design.md",content:$o},...[...new Set(e)].map(t=>({path:jl(t),content:zo}))]}var Uo=".claude/skills/kizen-custom-block/SKILL.md",Ho="Claude files managed by appbuilder are out of date; run appbuilder setup-claude",Hl=e=>e instanceof Error&&"code"in e&&e.code==="ENOENT",ut={readFile:async e=>{try{return await zl(e,"utf-8")}catch(t){if(Hl(t))return;throw t}},writeFile:async(e,t)=>{await Ol(Ll(e),{recursive:!0}),await Ml(e,t,"utf-8")},exists:async e=>{try{return await Fl(e),!0}catch{return!1}}},Vl=e=>{if(typeof e!="string"||e.trim()==="")return;let t=Ul.normalize(e.trim().replaceAll("\\","/")).replace(/\/+$/,"");if(!(t===".."||t.startsWith("../")||t.startsWith("/")))return t==="."?"":t};function Wl(e){let r=(Array.isArray(e)?e:[e]).map(o=>typeof o=="object"&&o!==null&&"entry"in o?Vl(o.entry):void 0).filter(o=>o!==void 0);return r.length>0?[...new Set(r)]:["src"]}async function Vo(e,t=ut){try{let r=await t.readFile(dt(e,"kizen.json"));return Le(r===void 0?void 0:Wl(JSON.parse(r)))}catch{return Le()}}var Kl=(e,t)=>e===void 0?"created":e===t?"unchanged":"updated";async function Wo(e,t=ut,r=Le()){return Promise.all(r.map(async o=>({path:o.path,status:Kl(await t.readFile(dt(e,o.path)),o.content)})))}async function Jl(e,t={},r=ut,o=Le()){let n=await Wo(e,r,o);return t.dryRun===!0||await Promise.all(o.filter((i,s)=>n[s]?.status!=="unchanged").map(i=>r.writeFile(dt(e,i.path),i.content))),n}async function Ko(e,t=ut,r){try{let o=r??await Vo(e,t);return!o.some(i=>i.path===Uo)||await t.readFile(dt(e,Uo))===void 0?!1:(await Wo(e,t,o)).some(i=>i.status!=="unchanged")}catch{return!1}}var ql={fs:ut,log:e=>{console.log(e)},error:e=>{console.error(e)},setExitCode:e=>{process.exitCode=e}},Kr=(e,t)=>`${String(e.filter(r=>r.status===t).length)} ${t}`;async function Jo(e,t,r=ql,o){if(!await r.fs.exists(dt(e,"kizen.json"))){r.error("Error: kizen.json not found. Run this command from a plugin directory."),r.setExitCode(1);return}let n=t.dryRun===!0,i;try{i=await Jl(e,{dryRun:n},r.fs,o??await Vo(e,r.fs))}catch(a){r.error(`Error: ${a instanceof Error?a.message:String(a)}`),r.setExitCode(1);return}for(let a of i)r.log(`${a.status.padEnd(9)} ${a.path}`);let s=`${Kr(i,"created")}, ${Kr(i,"updated")}, ${Kr(i,"unchanged")}`,l="these files are managed by appbuilder, so local edits to them are replaced";r.log(n?`Dry run: ${s}; nothing written (${l}).`:`Claude files: ${s} (${l}).`)}function Ht(e){return{cwd:e,loadCredentialsDetailed:zr,listLoadableCredentialProfiles:co,loadConfig:he,packageBlocks:jr,createClient:t=>mo({credentials:t}),readPushMap:Io,writePushMap:Ao,ensureGitignore:Ne,isClaudeSkillStale:t=>Ko(t),randomUUID:Gl,now:()=>new Date,writeStdout:t=>{process.stdout.write(t)},writeStderr:t=>{process.stderr.write(t)},setExitCode:t=>{process.exitCode=t}}}var Xl=new Set(["owner","admin","edit"]),Zl="Chart groups are not listed here; find them with `appbuilder block targets --object <id> --json` and pass --dashboard <id>.",Yr=e=>e instanceof Error?e.message:typeof e=="string"?e:"Unknown error";function L(e,t,r={}){return{ok:!1,code:e,message:t,...r}}var ge=e=>({ok:!0,value:e});function Ue(e){return e instanceof re?L(e.kind,e.message,e.hint===void 0?{}:{hint:e.hint}):e instanceof Go?L("validation_failed",me(e.issues),{issues:e.issues}):L("local_error",Yr(e))}var Ql=()=>X.join(", ");async function Ut(e,t){let r;try{r=await t.loadCredentialsDetailed(e.path)}catch(i){return L("credentials_invalid",`Couldn't read credentials from ${e.path}: ${Yr(i)}`)}if(r.environmentSource!=="explicit"){let i=r.environmentSource==="missing"?'has no "environment"':'has an invalid "environment"';return L("credentials_invalid",`${e.path} ${i}. Set it to one of: ${Ql()}. The CLI won't default to production.`)}let{credentials:o}=r,n=["apiKey","userId","businessId"].filter(i=>o[i].trim()==="");return n.length>0?L("credentials_invalid",`${e.path} is missing ${n.map(i=>`"${i}"`).join(", ")}.`):ge({credentials:o,source:e})}var Jr=e=>({kind:"profile",name:e.name,path:e.path});async function Vt(e,t){if(e.credentials!==void 0)return Ut({kind:"file",path:e.credentials},t);let r=await t.listLoadableCredentialProfiles(),o=r.map(l=>l.name);if(e.profile!==void 0){let l=r.find(a=>a.name===e.profile);return l?Ut(Jr(l),t):L("credentials_invalid",o.length===0?`No loadable credential profile named "${e.profile}". No profiles are loadable; create ${xe} or pass -c <path>.`:`No loadable credential profile named "${e.profile}". Loadable profiles: ${o.join(", ")}`)}let n=await t.loadConfig(Yl(t.cwd,".kizenapp"));if(n.credentialMode==="local")return L("credentials_invalid","This plugin is set to use local browser-only credentials the CLI can't read. Pass -c <path> or --profile <name>.");let i=n.activeCredentialProfile===void 0?void 0:r.find(l=>l.name===n.activeCredentialProfile);if(i)return Ut(Jr(i),t);let[s]=r;return r.length===1&&s?Ut(Jr(s),t):r.length===0?L("credentials_invalid",`No credentials found. Create ${xe} or pass -c <path>.`):L("needs_choice",`Several credential profiles are available; pass --profile <name>: ${o.join(", ")}`,{choice:"profile",choices:r.map(l=>({value:l.name,label:l.isDefault?`${l.name} (default)`:l.name,args:["--profile",l.name]}))})}function ec(e,t){let r=new Set(t.map(o=>o.pluginApiName)).size>1;return t.map(({pluginApiName:o,apiName:n})=>{let i=e.find(l=>l.api_name===o)?.artifacts.custom_blocks.find(l=>l.api_name===n),s=r?`${o}/${n}`:n;return{value:n,label:`${i?.name??n} (${s})`,args:[n]}})}function tc(e,t){let r=Nr(e.available);return e.reason==="no_blocks"?"This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.":e.reason==="not_found"?`No block with api_name "${t??""}". Available blocks: ${r}`:t===void 0?`This plugin has several blocks; pass the api_name of the one to push: ${r}`:`More than one plugin has a block with api_name "${t}": ${r}`}async function Xr(e,t){let r;try{r=await t.packageBlocks(t.cwd)}catch(s){if(s instanceof Go)return L("validation_failed",me(s.issues),{issues:s.issues});throw s}let o=Dr(r.deployable,e);if(!o.ok){let s=tc(o,e);return o.reason==="no_blocks"?L("invalid_block",s):L("needs_choice",s,{choice:"block",choices:ec(r.deployable,o.available)})}let n=Br(o.block);if(n!==void 0)return L("invalid_block",$r(o.block.api_name,n),{field:n});let i=ko(o.block);return ge({block:o.block,pluginApiName:o.pluginApiName,content:i,contentHash:Vr(i),warnings:r.warnings})}var Yo=e=>e==null?null:Xl.has(e.toLowerCase());function pt(e,t){return{id:e.id,name:e.name,type:t,dashletsCount:e.dashlets_count??null,employeeAccess:e.employee_access??null,hidden:e.hidden??!1,canEdit:Yo(e.employee_access)}}var Xo=e=>({id:e.id,objectName:e.object_name,fetchUrl:e.fetch_url}),rc="Contacts";async function Zr(e){let[t,r]=await Promise.all([e.listCustomObjects(),e.getClientObjectId().catch(()=>null)]),o=t.map(Xo).sort((n,i)=>n.objectName.localeCompare(i.objectName));return r!==null&&r!==""&&!o.some(n=>n.id===r)&&o.push({id:r,objectName:rc,fetchUrl:"client"}),o}async function nc(e,t,r){let{environment:o,businessId:n}=t;try{if(r.object!==void 0){let a=r.object,[p,h]=await Promise.all([e.getCustomObject(a).catch(()=>null),e.listDashboards("chart_group",a)]);return ge({ok:!0,environment:o,businessId:n,object:p?Xo(p):null,surfaces:{chart_group:h.map(w=>pt(w,"chart_group"))}})}let[i,s,l]=await Promise.all([e.listDashboards("generic_dashboard"),e.listDashboards("homepage"),Zr(e)]);return ge({ok:!0,environment:o,businessId:n,surfaces:{dashboard:i.map(a=>pt(a,"dashboard")),homepage:s.map(a=>pt(a,"homepage"))},customObjects:l})}catch(i){return Ue(i)}}var Qr=(e,t)=>t.dashboard===e.id;function Wt(e,t){return[...Po(e).filter(o=>Qr(e,o)).map(o=>{let n=wo(o.name);return{value:o.id,label:Mt(o),args:["--dashboard",e.id,"--dashlet",o.id],pushKey:n?o.name:null,isFromThisPlugin:n?.pluginApiName===t.pluginApiName}}),{value:"new",label:"Create a new block",args:["--dashboard",e.id,"--create"]}]}function Qe(e,t,r,o){return ge({dashboard:e,surface:No(e.type),action:t,dashlet:r,resolvedBy:o})}async function oc(e){let[t,r]=await Promise.all([e.client.listDashboards("generic_dashboard"),e.client.listDashboards("homepage")]),o=n=>i=>({value:i.id,label:i.name,args:["--dashboard",i.id],surface:n,canEdit:Yo(i.employee_access)});return L("needs_choice",`Choose where to push; pass --dashboard <id>. ${Zl}`,{choice:"dashboard",choices:[...t.map(o("dashboard")),...r.map(o("homepage"))]})}async function ic(e,t,r){let o=await e.client.getDashboard(t);if(r.create)return Qe(o,"create",void 0,"flag");let n=()=>Wt(o,e.block);if(r.dashlet!==void 0){let s=r.dashlet,l=o.dashlets.find(a=>a.id===s&&Qr(o,a));return l?Ze(l)?Qe(o,"update",l,"flag"):L("usage_error",`Dashlet ${s} is not a custom code block, so it can't be updated with a pushed block. Pass --create to add a new one.`):L("not_found",`Dashlet ${s} is not on dashboard "${o.name}" (${o.id}).`,{choice:"target",choices:n()})}let i=Lt({dashboardId:o.id,dashlets:o.dashlets,pluginApiName:e.block.pluginApiName,blockApiName:e.block.block.api_name,entry:e.entry});return i.kind==="map"?Qe(o,"update",i.dashlet,"push_map"):i.kind==="name"?Qe(o,"update",i.dashlet,"name"):L("needs_choice",i.kind==="ambiguous"?`Dashboard "${o.name}" has ${String(i.dashlets.length)} blocks pushed from this block; pass --dashlet <id> to pick one, or --create.`:`Choose a block to update on "${o.name}", or create a new one; pass --dashlet <id> or --create.`,{choice:"target",choices:n()})}async function sc(e,t,r){let o;try{o=await e.client.getDashboard(t.dashboardId)}catch(i){if(i instanceof re&&i.kind==="not_found")return L("remembered_target_missing",`The remembered dashboard ${t.dashboardId} no longer exists. Pass --dashboard <id> to choose another, or --forget to clear it.`);throw i}if(r.create)return Qe(o,"create",void 0,"remembered");let n=o.dashlets.find(i=>i.id===t.dashletId&&Qr(o,i));return n&&Ze(n)?Qe(o,"update",n,"remembered"):L("remembered_target_missing",`The remembered block (dashlet ${t.dashletId}) is no longer on "${o.name}". Choose a block to update, or create a new one.`,{choice:"target",choices:Wt(o,e.block)})}async function en(e,t){if(t.dashlet!==void 0&&t.create)return L("usage_error","Pass either --dashlet <id> or --create, not both.");if(t.dashlet!==void 0&&t.dashboard===void 0)return L("usage_error","--dashlet <id> needs --dashboard <id>.");try{return t.dashboard!==void 0?await ic(e,t.dashboard,t):e.entry?await sc(e,e.entry,t):await oc(e)}catch(r){return Ue(r)}}async function ac(e,t,r){let o=t.custom_object;if(o==null||o==="")return null;if(typeof o!="string"){if(typeof o!="object"||typeof o.id!="string")return null;let{id:n,fetch_url:i}=o;return typeof i=="string"?{id:n,fetchUrl:i}:{id:n}}if(r!=="chart_group")return{id:o};try{let n=await e.getCustomObject(o);return{id:o,fetchUrl:n.fetch_url}}catch{return{id:o}}}var qr=encodeURIComponent;async function tn(e,t,r,o){let{credentials:n,block:i}=e,{dashboard:s,surface:l,dashlet:a}=t,p=[],h,w,x;if(t.action==="update"){if(!a)return L("usage_error","An update needs a dashlet to update.");if(Eo(a,e.entry)){let y=`"${Mt(a)}" (dashlet ${a.id}) was changed in Kizen since the last push.`;if(!r.force)return L("drift_detected",`${y} Pushing would overwrite those changes; pass --force to overwrite them.`);p.push(`${y} Overwriting it because of --force.`)}h=So(a,i.content),w=`/dashboards/${qr(s.id)}/dashlet/${qr(a.id)}`,x=`Update "${Mt(a)}" (dashlet ${a.id})`}else h=Co({pluginApiName:i.pluginApiName,blockApiName:i.block.api_name,content:i.content,dashlets:s.dashlets,objectId:o.randomUUID(),layoutId:o.randomUUID()}),w=`/dashboards/${qr(s.id)}/dashlet`,x=`Create a new block on "${s.name}"`;let d=t.action==="update"&&a?a.id:null,c=Ro({appBaseUrl:Qn[n.environment],surface:l,dashboardId:s.id,customObject:await ac(e.client,s,l)});return ge({action:t.action,method:t.action==="update"?"PATCH":"POST",path:w,body:h,dashboard:{id:s.id,name:s.name,type:l},dashletId:d,url:c,resolvedBy:t.resolvedBy,warnings:p,summary:{environment:n.environment,businessId:n.businessId,isProduction:Or(n.environment),surface:l,dashboardId:s.id,dashboardName:s.name,action:t.action,actionLine:x,dashletId:d,blockName:i.block.name,blockApiName:i.block.api_name,pluginApiName:i.pluginApiName,scriptBytes:Buffer.byteLength(i.content.script,"utf8"),stylesBytes:Buffer.byteLength(i.content.styles,"utf8")}})}var et=e=>({environment:e.credentials.environment,businessId:e.credentials.businessId,pluginApiName:e.block.pluginApiName,blockApiName:e.block.block.api_name});async function rn(e,t,r){let o;try{if(t.action==="create"){let a=(await e.client.createDashlet(t.dashboard.id,t.body)).id;if(typeof a!="string"||a==="")return L("api_error",`POST ${t.path} succeeded but the response had no dashlet id; check "${t.dashboard.name}" before pushing again.`);o=a}else{if(t.dashletId===null)return L("usage_error","An update needs a dashlet to update.");await e.client.updateDashlet(t.dashboard.id,t.dashletId,t.body),o=t.dashletId}}catch(l){return Ue(l)}let n=[...t.warnings],i={...et(e),dashboardId:t.dashboard.id,dashletId:o,contentHash:e.block.contentHash,pushedAt:r.now().toISOString()},s=!1;try{r.ensureGitignore(r.cwd),await r.writePushMap(r.cwd,To(e.pushMap,i)),s=!0}catch(l){n.push(`The push succeeded, but ${Me} couldn't be written, so this target isn't remembered: ${Yr(l)}`)}return ge({dashletId:o,remembered:s,warnings:n})}var lc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function nn(e){return lc.test(e)?{dashboardId:e,script:`await window.__kizenCustomBlocks?.refresh('${e}')`}:null}async function on(e,t){let r=et(e);return lt(e.pushMap,r)?(await t.writePushMap(t.cwd,ct(e.pushMap,r)),!0):!1}function sn(e,t){return e.dryRun?ge({kind:"dry-run",reason:"flag"}):e.yes?Or(t)&&!e.allowProduction?L("production_requires_flag",`${t} is a production environment. Pass --allow-production with --yes to write to it.`):ge({kind:"apply"}):ge({kind:"dry-run",reason:"no_yes"})}var cc="Dry run only: pass --yes to write.";function ft(e){return[`Environment: ${e.environment}${e.isProduction?" (production)":""}`,`Business: ${e.businessId}`,`Surface: ${e.surface}`,`Dashboard: "${e.dashboardName}" (${e.dashboardId})`,`Action: ${e.actionLine}`,`Block: ${e.blockName} (${e.pluginApiName}/${e.blockApiName})`,`Size: script ${String(e.scriptBytes)} bytes, styles ${String(e.stylesBytes)} bytes`]}var dc=e=>`${e.path===void 0?"":`${e.path}: `}${e.message} (${e.rule})`,uc=e=>/^[\w./:@=-]+$/.test(e)?e:JSON.stringify(e);function pc(e,t,r){let o=[`Error: ${e.message}`];if(e.hint!==void 0&&o.push(`Hint: ${e.hint}`),e.choices&&e.choices.length>0){o.push("Choices:");for(let n of e.choices){let i=r(n,e.choice).map(uc).join(" ");o.push(` ${n.label} \u2192 ${t} ${i}`)}}return`${o.join(`
742
+ `;function Lo(){return[{path:".github/copilot-instructions.md",content:jo},{path:".github/instructions/security.instructions.md",content:Fo},{path:".github/instructions/version-discipline.instructions.md",content:Oo}]}var Mo="lib/kizenData.js",jl=(e="src")=>e===""?Mo:`${e}/${Mo}`;function Le(e=["src"]){return[{path:".claude/skills/kizen-custom-block/SKILL.md",content:Bo},{path:".claude/skills/kizen-custom-block/design.md",content:$o},...[...new Set(e)].map(t=>({path:jl(t),content:zo}))]}var Ho=".claude/skills/kizen-custom-block/SKILL.md",Uo="Claude files managed by appbuilder are out of date; run appbuilder setup-claude",Ul=e=>e instanceof Error&&"code"in e&&e.code==="ENOENT",ut={readFile:async e=>{try{return await zl(e,"utf-8")}catch(t){if(Ul(t))return;throw t}},writeFile:async(e,t)=>{await Ol(Ll(e),{recursive:!0}),await Ml(e,t,"utf-8")},exists:async e=>{try{return await Fl(e),!0}catch{return!1}}},Vl=e=>{if(typeof e!="string"||e.trim()==="")return;let t=Hl.normalize(e.trim().replaceAll("\\","/")).replace(/\/+$/,"");if(!(t===".."||t.startsWith("../")||t.startsWith("/")))return t==="."?"":t};function Wl(e){let r=(Array.isArray(e)?e:[e]).map(o=>typeof o=="object"&&o!==null&&"entry"in o?Vl(o.entry):void 0).filter(o=>o!==void 0);return r.length>0?[...new Set(r)]:["src"]}async function Vo(e,t=ut){try{let r=await t.readFile(dt(e,"kizen.json"));return Le(r===void 0?void 0:Wl(JSON.parse(r)))}catch{return Le()}}var Kl=(e,t)=>e===void 0?"created":e===t?"unchanged":"updated";async function Wo(e,t=ut,r=Le()){return Promise.all(r.map(async o=>({path:o.path,status:Kl(await t.readFile(dt(e,o.path)),o.content)})))}async function Jl(e,t={},r=ut,o=Le()){let n=await Wo(e,r,o);return t.dryRun===!0||await Promise.all(o.filter((i,s)=>n[s]?.status!=="unchanged").map(i=>r.writeFile(dt(e,i.path),i.content))),n}async function Ko(e,t=ut,r){try{let o=r??await Vo(e,t);return!o.some(i=>i.path===Ho)||await t.readFile(dt(e,Ho))===void 0?!1:(await Wo(e,t,o)).some(i=>i.status!=="unchanged")}catch{return!1}}var ql={fs:ut,log:e=>{console.log(e)},error:e=>{console.error(e)},setExitCode:e=>{process.exitCode=e}},Kr=(e,t)=>`${String(e.filter(r=>r.status===t).length)} ${t}`;async function Jo(e,t,r=ql,o){if(!await r.fs.exists(dt(e,"kizen.json"))){r.error("Error: kizen.json not found. Run this command from a plugin directory."),r.setExitCode(1);return}let n=t.dryRun===!0,i;try{i=await Jl(e,{dryRun:n},r.fs,o??await Vo(e,r.fs))}catch(a){r.error(`Error: ${a instanceof Error?a.message:String(a)}`),r.setExitCode(1);return}for(let a of i)r.log(`${a.status.padEnd(9)} ${a.path}`);let s=`${Kr(i,"created")}, ${Kr(i,"updated")}, ${Kr(i,"unchanged")}`,l="these files are managed by appbuilder, so local edits to them are replaced";r.log(n?`Dry run: ${s}; nothing written (${l}).`:`Claude files: ${s} (${l}).`)}function Ut(e){return{cwd:e,loadCredentialsDetailed:zr,listLoadableCredentialProfiles:co,loadConfig:he,packageBlocks:jr,createClient:t=>mo({credentials:t}),readPushMap:Io,writePushMap:Ao,ensureGitignore:Ne,isClaudeSkillStale:t=>Ko(t),randomUUID:Gl,now:()=>new Date,writeStdout:t=>{process.stdout.write(t)},writeStderr:t=>{process.stderr.write(t)},setExitCode:t=>{process.exitCode=t}}}var Xl=new Set(["owner","admin","edit"]),Zl="Chart groups are not listed here; find them with `appbuilder block targets --object <id> --json` and pass --dashboard <id>.",Yr=e=>e instanceof Error?e.message:typeof e=="string"?e:"Unknown error";function L(e,t,r={}){return{ok:!1,code:e,message:t,...r}}var ge=e=>({ok:!0,value:e});function He(e){return e instanceof re?L(e.kind,e.message,e.hint===void 0?{}:{hint:e.hint}):e instanceof Go?L("validation_failed",me(e.issues),{issues:e.issues}):L("local_error",Yr(e))}var Ql=()=>X.join(", ");async function Ht(e,t){let r;try{r=await t.loadCredentialsDetailed(e.path)}catch(i){return L("credentials_invalid",`Couldn't read credentials from ${e.path}: ${Yr(i)}`)}if(r.environmentSource!=="explicit"){let i=r.environmentSource==="missing"?'has no "environment"':'has an invalid "environment"';return L("credentials_invalid",`${e.path} ${i}. Set it to one of: ${Ql()}. The CLI won't default to production.`)}let{credentials:o}=r,n=["apiKey","userId","businessId"].filter(i=>o[i].trim()==="");return n.length>0?L("credentials_invalid",`${e.path} is missing ${n.map(i=>`"${i}"`).join(", ")}.`):ge({credentials:o,source:e})}var Jr=e=>({kind:"profile",name:e.name,path:e.path});async function Vt(e,t){if(e.credentials!==void 0)return Ht({kind:"file",path:e.credentials},t);let r=await t.listLoadableCredentialProfiles(),o=r.map(l=>l.name);if(e.profile!==void 0){let l=r.find(a=>a.name===e.profile);return l?Ht(Jr(l),t):L("credentials_invalid",o.length===0?`No loadable credential profile named "${e.profile}". No profiles are loadable; create ${xe} or pass -c <path>.`:`No loadable credential profile named "${e.profile}". Loadable profiles: ${o.join(", ")}`)}let n=await t.loadConfig(Yl(t.cwd,".kizenapp"));if(n.credentialMode==="local")return L("credentials_invalid","This plugin is set to use local browser-only credentials the CLI can't read. Pass -c <path> or --profile <name>.");let i=n.activeCredentialProfile===void 0?void 0:r.find(l=>l.name===n.activeCredentialProfile);if(i)return Ht(Jr(i),t);let[s]=r;return r.length===1&&s?Ht(Jr(s),t):r.length===0?L("credentials_invalid",`No credentials found. Create ${xe} or pass -c <path>.`):L("needs_choice",`Several credential profiles are available; pass --profile <name>: ${o.join(", ")}`,{choice:"profile",choices:r.map(l=>({value:l.name,label:l.isDefault?`${l.name} (default)`:l.name,args:["--profile",l.name]}))})}function ec(e,t){let r=new Set(t.map(o=>o.pluginApiName)).size>1;return t.map(({pluginApiName:o,apiName:n})=>{let i=e.find(l=>l.api_name===o)?.artifacts.custom_blocks.find(l=>l.api_name===n),s=r?`${o}/${n}`:n;return{value:n,label:`${i?.name??n} (${s})`,args:[n]}})}function tc(e,t){let r=Nr(e.available);return e.reason==="no_blocks"?"This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.":e.reason==="not_found"?`No block with api_name "${t??""}". Available blocks: ${r}`:t===void 0?`This plugin has several blocks; pass the api_name of the one to push: ${r}`:`More than one plugin has a block with api_name "${t}": ${r}`}async function Xr(e,t){let r;try{r=await t.packageBlocks(t.cwd)}catch(s){if(s instanceof Go)return L("validation_failed",me(s.issues),{issues:s.issues});throw s}let o=Dr(r.deployable,e);if(!o.ok){let s=tc(o,e);return o.reason==="no_blocks"?L("invalid_block",s):L("needs_choice",s,{choice:"block",choices:ec(r.deployable,o.available)})}let n=Br(o.block);if(n!==void 0)return L("invalid_block",$r(o.block.api_name,n),{field:n});let i=ko(o.block);return ge({block:o.block,pluginApiName:o.pluginApiName,content:i,contentHash:Vr(i),warnings:r.warnings})}var Yo=e=>e==null?null:Xl.has(e.toLowerCase());function pt(e,t){return{id:e.id,name:e.name,type:t,dashletsCount:e.dashlets_count??null,employeeAccess:e.employee_access??null,hidden:e.hidden??!1,canEdit:Yo(e.employee_access)}}var Xo=e=>({id:e.id,objectName:e.object_name,fetchUrl:e.fetch_url}),rc="Contacts";async function Zr(e){let[t,r]=await Promise.all([e.listCustomObjects(),e.getClientObjectId().catch(()=>null)]),o=t.map(Xo).sort((n,i)=>n.objectName.localeCompare(i.objectName));return r!==null&&r!==""&&!o.some(n=>n.id===r)&&o.push({id:r,objectName:rc,fetchUrl:"client"}),o}async function nc(e,t,r){let{environment:o,businessId:n}=t;try{if(r.object!==void 0){let a=r.object,[p,h]=await Promise.all([e.getCustomObject(a).catch(()=>null),e.listDashboards("chart_group",a)]);return ge({ok:!0,environment:o,businessId:n,object:p?Xo(p):null,surfaces:{chart_group:h.map(w=>pt(w,"chart_group"))}})}let[i,s,l]=await Promise.all([e.listDashboards("generic_dashboard"),e.listDashboards("homepage"),Zr(e)]);return ge({ok:!0,environment:o,businessId:n,surfaces:{dashboard:i.map(a=>pt(a,"dashboard")),homepage:s.map(a=>pt(a,"homepage"))},customObjects:l})}catch(i){return He(i)}}var Qr=(e,t)=>t.dashboard===e.id;function Wt(e,t){return[...Po(e).filter(o=>Qr(e,o)).map(o=>{let n=wo(o.name);return{value:o.id,label:Mt(o),args:["--dashboard",e.id,"--dashlet",o.id],pushKey:n?o.name:null,isFromThisPlugin:n?.pluginApiName===t.pluginApiName}}),{value:"new",label:"Create a new block",args:["--dashboard",e.id,"--create"]}]}function Qe(e,t,r,o){return ge({dashboard:e,surface:No(e.type),action:t,dashlet:r,resolvedBy:o})}async function oc(e){let[t,r]=await Promise.all([e.client.listDashboards("generic_dashboard"),e.client.listDashboards("homepage")]),o=n=>i=>({value:i.id,label:i.name,args:["--dashboard",i.id],surface:n,canEdit:Yo(i.employee_access)});return L("needs_choice",`Choose where to push; pass --dashboard <id>. ${Zl}`,{choice:"dashboard",choices:[...t.map(o("dashboard")),...r.map(o("homepage"))]})}async function ic(e,t,r){let o=await e.client.getDashboard(t);if(r.create)return Qe(o,"create",void 0,"flag");let n=()=>Wt(o,e.block);if(r.dashlet!==void 0){let s=r.dashlet,l=o.dashlets.find(a=>a.id===s&&Qr(o,a));return l?Ze(l)?Qe(o,"update",l,"flag"):L("usage_error",`Dashlet ${s} is not a custom code block, so it can't be updated with a pushed block. Pass --create to add a new one.`):L("not_found",`Dashlet ${s} is not on dashboard "${o.name}" (${o.id}).`,{choice:"target",choices:n()})}let i=Lt({dashboardId:o.id,dashlets:o.dashlets,pluginApiName:e.block.pluginApiName,blockApiName:e.block.block.api_name,entry:e.entry});return i.kind==="map"?Qe(o,"update",i.dashlet,"push_map"):i.kind==="name"?Qe(o,"update",i.dashlet,"name"):L("needs_choice",i.kind==="ambiguous"?`Dashboard "${o.name}" has ${String(i.dashlets.length)} blocks pushed from this block; pass --dashlet <id> to pick one, or --create.`:`Choose a block to update on "${o.name}", or create a new one; pass --dashlet <id> or --create.`,{choice:"target",choices:n()})}async function sc(e,t,r){let o;try{o=await e.client.getDashboard(t.dashboardId)}catch(i){if(i instanceof re&&i.kind==="not_found")return L("remembered_target_missing",`The remembered dashboard ${t.dashboardId} no longer exists. Pass --dashboard <id> to choose another, or --forget to clear it.`);throw i}if(r.create)return Qe(o,"create",void 0,"remembered");let n=o.dashlets.find(i=>i.id===t.dashletId&&Qr(o,i));return n&&Ze(n)?Qe(o,"update",n,"remembered"):L("remembered_target_missing",`The remembered block (dashlet ${t.dashletId}) is no longer on "${o.name}". Choose a block to update, or create a new one.`,{choice:"target",choices:Wt(o,e.block)})}async function en(e,t){if(t.dashlet!==void 0&&t.create)return L("usage_error","Pass either --dashlet <id> or --create, not both.");if(t.dashlet!==void 0&&t.dashboard===void 0)return L("usage_error","--dashlet <id> needs --dashboard <id>.");try{return t.dashboard!==void 0?await ic(e,t.dashboard,t):e.entry?await sc(e,e.entry,t):await oc(e)}catch(r){return He(r)}}async function ac(e,t,r){let o=t.custom_object;if(o==null||o==="")return null;if(typeof o!="string"){if(typeof o!="object"||typeof o.id!="string")return null;let{id:n,fetch_url:i}=o;return typeof i=="string"?{id:n,fetchUrl:i}:{id:n}}if(r!=="chart_group")return{id:o};try{let n=await e.getCustomObject(o);return{id:o,fetchUrl:n.fetch_url}}catch{return{id:o}}}var qr=encodeURIComponent;async function tn(e,t,r,o){let{credentials:n,block:i}=e,{dashboard:s,surface:l,dashlet:a}=t,p=[],h,w,x;if(t.action==="update"){if(!a)return L("usage_error","An update needs a dashlet to update.");if(Eo(a,e.entry)){let y=`"${Mt(a)}" (dashlet ${a.id}) was changed in Kizen since the last push.`;if(!r.force)return L("drift_detected",`${y} Pushing would overwrite those changes; pass --force to overwrite them.`);p.push(`${y} Overwriting it because of --force.`)}h=So(a,i.content),w=`/dashboards/${qr(s.id)}/dashlet/${qr(a.id)}`,x=`Update "${Mt(a)}" (dashlet ${a.id})`}else h=Co({pluginApiName:i.pluginApiName,blockApiName:i.block.api_name,content:i.content,dashlets:s.dashlets,objectId:o.randomUUID(),layoutId:o.randomUUID()}),w=`/dashboards/${qr(s.id)}/dashlet`,x=`Create a new block on "${s.name}"`;let d=t.action==="update"&&a?a.id:null,c=Ro({appBaseUrl:Qn[n.environment],surface:l,dashboardId:s.id,customObject:await ac(e.client,s,l)});return ge({action:t.action,method:t.action==="update"?"PATCH":"POST",path:w,body:h,dashboard:{id:s.id,name:s.name,type:l},dashletId:d,url:c,resolvedBy:t.resolvedBy,warnings:p,summary:{environment:n.environment,businessId:n.businessId,isProduction:Or(n.environment),surface:l,dashboardId:s.id,dashboardName:s.name,action:t.action,actionLine:x,dashletId:d,blockName:i.block.name,blockApiName:i.block.api_name,pluginApiName:i.pluginApiName,scriptBytes:Buffer.byteLength(i.content.script,"utf8"),stylesBytes:Buffer.byteLength(i.content.styles,"utf8")}})}var et=e=>({environment:e.credentials.environment,businessId:e.credentials.businessId,pluginApiName:e.block.pluginApiName,blockApiName:e.block.block.api_name});async function rn(e,t,r){let o;try{if(t.action==="create"){let a=(await e.client.createDashlet(t.dashboard.id,t.body)).id;if(typeof a!="string"||a==="")return L("api_error",`POST ${t.path} succeeded but the response had no dashlet id; check "${t.dashboard.name}" before pushing again.`);o=a}else{if(t.dashletId===null)return L("usage_error","An update needs a dashlet to update.");await e.client.updateDashlet(t.dashboard.id,t.dashletId,t.body),o=t.dashletId}}catch(l){return He(l)}let n=[...t.warnings],i={...et(e),dashboardId:t.dashboard.id,dashletId:o,contentHash:e.block.contentHash,pushedAt:r.now().toISOString()},s=!1;try{r.ensureGitignore(r.cwd),await r.writePushMap(r.cwd,To(e.pushMap,i)),s=!0}catch(l){n.push(`The push succeeded, but ${Me} couldn't be written, so this target isn't remembered: ${Yr(l)}`)}return ge({dashletId:o,remembered:s,warnings:n})}var lc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function nn(e){return lc.test(e)?{dashboardId:e,script:`await window.__kizenCustomBlocks?.refresh('${e}')`}:null}async function on(e,t){let r=et(e);return lt(e.pushMap,r)?(await t.writePushMap(t.cwd,ct(e.pushMap,r)),!0):!1}function sn(e,t){return e.dryRun?ge({kind:"dry-run",reason:"flag"}):e.yes?Or(t)&&!e.allowProduction?L("production_requires_flag",`${t} is a production environment. Pass --allow-production with --yes to write to it.`):ge({kind:"apply"}):ge({kind:"dry-run",reason:"no_yes"})}var cc="Dry run only: pass --yes to write.";function ft(e){return[`Environment: ${e.environment}${e.isProduction?" (production)":""}`,`Business: ${e.businessId}`,`Surface: ${e.surface}`,`Dashboard: "${e.dashboardName}" (${e.dashboardId})`,`Action: ${e.actionLine}`,`Block: ${e.blockName} (${e.pluginApiName}/${e.blockApiName})`,`Size: script ${String(e.scriptBytes)} bytes, styles ${String(e.stylesBytes)} bytes`]}var dc=e=>`${e.path===void 0?"":`${e.path}: `}${e.message} (${e.rule})`,uc=e=>/^[\w./:@=-]+$/.test(e)?e:JSON.stringify(e);function pc(e,t,r){let o=[`Error: ${e.message}`];if(e.hint!==void 0&&o.push(`Hint: ${e.hint}`),e.choices&&e.choices.length>0){o.push("Choices:");for(let n of e.choices){let i=r(n,e.choice).map(uc).join(" ");o.push(` ${n.label} \u2192 ${t} ${i}`)}}return`${o.join(`
743
743
  `)}
744
744
  `}function Zo(e,t,r,o){e.json?e.deps.writeStdout(`${JSON.stringify(t,null,2)}
745
- `):e.deps.writeStderr(pc(t,r,o)),e.deps.setExitCode(1)}var qo=e=>e.credentials!==void 0?["-c",e.credentials]:e.profile===void 0?[]:["--profile",e.profile];async function fc(e){try{return await e.isClaudeSkillStale(e.cwd)?[Ho]:[]}catch{return[]}}async function Qo(e,t,r){let o={json:t.json===!0,deps:r},n="appbuilder block push",i=e===void 0?[]:[e],s=(a,p)=>p==="profile"?[...i,...a.args]:p==="block"?[...a.args,...qo(t)]:[...i,...qo(t),...a.args],l=a=>{Zo(o,a,n,s)};try{let a=await Vt(t,r);if(!a.ok){l(a);return}let{credentials:p}=a.value,h=r.createClient(p),w=await Xr(e,r);if(!w.ok){l(w);return}let x=w.value;i=[x.block.api_name],x.warnings.length>0&&r.writeStderr(`${me(x.warnings)}
745
+ `):e.deps.writeStderr(pc(t,r,o)),e.deps.setExitCode(1)}var qo=e=>e.credentials!==void 0?["-c",e.credentials]:e.profile===void 0?[]:["--profile",e.profile];async function fc(e){try{return await e.isClaudeSkillStale(e.cwd)?[Uo]:[]}catch{return[]}}async function Qo(e,t,r){let o={json:t.json===!0,deps:r},n="appbuilder block push",i=e===void 0?[]:[e],s=(a,p)=>p==="profile"?[...i,...a.args]:p==="block"?[...a.args,...qo(t)]:[...i,...qo(t),...a.args],l=a=>{Zo(o,a,n,s)};try{let a=await Vt(t,r);if(!a.ok){l(a);return}let{credentials:p}=a.value,h=r.createClient(p),w=await Xr(e,r);if(!w.ok){l(w);return}let x=w.value;i=[x.block.api_name],x.warnings.length>0&&r.writeStderr(`${me(x.warnings)}
746
746
  `);let d={client:h,credentials:p,block:x,pushMap:[],entry:void 0};d.pushMap=await r.readPushMap(r.cwd);let c=!1;t.forget&&(c=await on(d,r),c&&(d.pushMap=ct(d.pushMap,et(d)),r.writeStderr(`Forgot the remembered target for ${x.block.api_name}.
747
747
  `))),d.entry=lt(d.pushMap,et(d));let y=await en(d,t);if(!y.ok){l(y);return}let v=sn(t,p.environment);if(!v.ok){l(v);return}let P=await tn(d,y.value,t,r);if(!P.ok){l(P);return}let C=P.value,_={pluginApiName:x.pluginApiName,apiName:x.block.api_name,name:x.block.name},S={environment:p.environment,businessId:p.businessId,dashboard:C.dashboard},g=[...x.warnings.map(dc),...await fc(r)],f=v.value;if(f.kind==="dry-run"){let R=[...g,...C.warnings],M={ok:!0,applied:!1,dryRun:!0,reason:f.reason,action:C.action,...S,dashletId:C.dashletId,url:C.url,resolvedBy:C.resolvedBy,block:_,method:C.method,path:C.path,body:C.body,warnings:R,...c?{forgotten:!0}:{}};o.json?(r.writeStdout(`${JSON.stringify(M,null,2)}
748
748
  `),r.writeStderr([...ft(C.summary),...R.map(W=>`Warning: ${W}`),""].join(`
@@ -750,10 +750,10 @@ export const sumBy = (records, name, valueOf) =>
750
750
  `)),f.reason==="no_yes"&&r.writeStderr(`${cc}
751
751
  `);return}let u=await rn(d,C,r);if(!u.ok){l(u);return}let m=u.value,b=[...g,...m.warnings],k=nn(C.dashboard.id),I={ok:!0,applied:!0,dryRun:!1,action:C.action==="create"?"created":"updated",...S,dashletId:m.dashletId,url:C.url,...k?{refresh:k}:{},resolvedBy:C.resolvedBy,block:_,remembered:m.remembered,warnings:b,...c?{forgotten:!0}:{}},E=[`\u2713 ${I.action==="created"?"Created":"Updated"} ${x.block.name} on "${C.dashboard.name}" (dashlet ${m.dashletId})`,...ft(C.summary),`URL: ${C.url}`,...k?[`Refresh an open tab: ${k.script}`]:[],...b.map(R=>`Warning: ${R}`),""].join(`
752
752
  `);o.json?(r.writeStdout(`${JSON.stringify(I,null,2)}
753
- `),r.writeStderr(E)):r.writeStdout(E)}catch(a){l(Ue(a))}}var mc=(e,t)=>e.padEnd(t);function Gr(e,t){if(t.length===0)return[e," (none)"];let r=["NAME","ID","DASHLETS","ACCESS"],o=t.map(s=>[`${s.name}${s.hidden?" (hidden)":""}`,s.id,s.dashletsCount===null?"-":String(s.dashletsCount),`${s.employeeAccess??"-"}${s.canEdit===!1?" (no edit access)":""}`]),n=r.map((s,l)=>Math.max(s.length,...o.map(a=>(a[l]??"").length))),i=s=>` ${s.map((l,a)=>mc(l,n[a]??0)).join(" ")}`.trimEnd();return[e,i(r),...o.map(i)]}function hc(e){let t=[`Environment: ${e.environment}`,`Business: ${e.businessId}`,""];return"object"in e?t.push(e.object===null?"Custom object: not found in /custom-objects":`Custom object: ${e.object.objectName} (${e.object.id})`,"",...Gr("Chart groups",e.surfaces.chart_group)):t.push(...Gr("Dashboards",e.surfaces.dashboard),"",...Gr("Homepages",e.surfaces.homepage),"","Custom objects",...e.customObjects.length===0?[" (none)"]:e.customObjects.map(r=>` ${r.objectName} ${r.id}`),"","List an object\u2019s chart groups with `appbuilder block targets --object <id>`."),`${t.join(`
753
+ `),r.writeStderr(E)):r.writeStdout(E)}catch(a){l(He(a))}}var mc=(e,t)=>e.padEnd(t);function Gr(e,t){if(t.length===0)return[e," (none)"];let r=["NAME","ID","DASHLETS","ACCESS"],o=t.map(s=>[`${s.name}${s.hidden?" (hidden)":""}`,s.id,s.dashletsCount===null?"-":String(s.dashletsCount),`${s.employeeAccess??"-"}${s.canEdit===!1?" (no edit access)":""}`]),n=r.map((s,l)=>Math.max(s.length,...o.map(a=>(a[l]??"").length))),i=s=>` ${s.map((l,a)=>mc(l,n[a]??0)).join(" ")}`.trimEnd();return[e,i(r),...o.map(i)]}function hc(e){let t=[`Environment: ${e.environment}`,`Business: ${e.businessId}`,""];return"object"in e?t.push(e.object===null?"Custom object: not found in /custom-objects":`Custom object: ${e.object.objectName} (${e.object.id})`,"",...Gr("Chart groups",e.surfaces.chart_group)):t.push(...Gr("Dashboards",e.surfaces.dashboard),"",...Gr("Homepages",e.surfaces.homepage),"","Custom objects",...e.customObjects.length===0?[" (none)"]:e.customObjects.map(r=>` ${r.objectName} ${r.id}`),"","List an object\u2019s chart groups with `appbuilder block targets --object <id>`."),`${t.join(`
754
754
  `)}
755
755
  `}async function ei(e,t){let r={json:e.json===!0,deps:t},o="appbuilder block targets",n=e.object===void 0?[]:["--object",e.object],i=l=>[...l.args,...n],s=l=>{Zo(r,l,o,i)};try{let l=await Vt(e,t);if(!l.ok){s(l);return}let{credentials:a}=l.value,p=await nc(t.createClient(a),a,e.object===void 0?{}:{object:e.object});if(!p.ok){s(p);return}t.writeStdout(r.json?`${JSON.stringify(p.value,null,2)}
756
- `:hc(p.value))}catch(l){s(Ue(l))}}import{useEffect as ii,useState as qt}from"react";import{Box as oe,Text as q,useApp as Rc,useInput as ci}from"ink";import"@kizenapps/packager";import{Box as wc,Text as xc}from"ink";import{Box as gc,Text as yc}from"ink";import{jsx as ti}from"react/jsx-runtime";var bc=[" :::::::: "," :::::: ::::::::::: "," :::::: :::::::::: "," :::::: :::::: ::::::: "," ::::: :::::: ::::::::::::::::: "," ::::: ::::: ::::::::::::::::::: "," ::::: ::::: :::::: ::::: ",":::: ::::: ::: ::::: :: ","::::: :::::: :::::::::: ","::::: :::::: ::::::::::: "," ::::: ::: ::::::: "," ::::::: ::: ::::: "," ::::::::::: :::::: :::::"," :::::::::: :::::: :::::"," :: ::::: ::: ::::: ::::"," ::::: :::::: ::::: ::::: ::: "," ::::::::::::::::::: ::::: ::::: "," ::::::::::::::::: ::::: ::::: "," ::::::::: :::::: :::::: "," :::::::::: :::::: "," ::::::::::: :::::: "," :::::::: "],ri=()=>ti(gc,{flexDirection:"column",children:bc.map((e,t)=>ti(yc,{color:"cyan",children:e},t))});import{Fragment as vc,jsx as an,jsxs as kc}from"react/jsx-runtime";var K=({marginBottom:e=0})=>kc(vc,{children:[an(ri,{}),an(wc,{flexDirection:"column",marginTop:1,marginBottom:e,children:an(xc,{bold:!0,color:"cyan",children:"Kizen App Development Toolkit"})})]});import{useMemo as Cc,useState as Sc}from"react";import{Box as ln,Text as He,useInput as _c}from"ink";var Kt=(e,t,r)=>Math.min(Math.max(e,t),r);function Jt(e,t,r,o={}){if(t<=0)return 0;let n=Kt(Math.trunc(e)||0,0,t-1),i=a=>o.disabled?.[a]!==!0;if(r===0)return n;let s=r>0?1:-1;if(Math.abs(r)===1){for(let a=1;a<=t;a++){let p=((n+s*a)%t+t)%t;if(i(p))return p}return n}let l=Kt(n+Math.trunc(r),0,t-1);for(let a=l;a>=0&&a<t;a+=s)if(i(a))return a;for(let a=l-s;a>=0&&a<t;a-=s)if(i(a))return a;return n}function ni(e,t,r=10){if(t<=0)return{start:0,end:0};let o=Math.max(1,Math.floor(r));if(t<=o)return{start:0,end:t};let n=Kt(Math.trunc(e)||0,0,t-1),i=Kt(n-Math.floor(o/2),0,t-o);return{start:i,end:i+o}}import{jsx as Ve,jsxs as cn}from"react/jsx-runtime";var Pc="\u2191/\u2193 to move, Enter to select, Esc to cancel",Ec=10,Tc=(e,t)=>{let r=Jt(t,e.length,0);if(e[r]?.disabled!==!0)return r;let o=e.findIndex(n=>n.disabled!==!0);return o===-1?r:o},We=({title:e,items:t,onSelect:r,onCancel:o,hint:n=Pc,initialIndex:i=0,windowSize:s=Ec,isActive:l=!0})=>{let[a,p]=Sc(()=>Tc(t,i)),h=Cc(()=>t.map(P=>P.disabled===!0),[t]),w=Jt(a,t.length,0),x=Math.max(1,Math.floor(s));_c((P,C)=>{let _=S=>{p(Jt(w,t.length,S,{disabled:h}))};if(C.upArrow||P==="k")_(-1);else if(C.downArrow||P==="j")_(1);else if(C.pageUp)_(-x);else if(C.pageDown)_(x);else if(C.return){let S=t[w];S!==void 0&&S.disabled!==!0&&r(S,w)}else C.escape&&o?.()},{isActive:l});let{start:d,end:c}=ni(w,t.length,x),y=d,v=t.length-c;return cn(ln,{flexDirection:"column",gap:1,children:[Ve(He,{bold:!0,children:e}),cn(ln,{flexDirection:"column",children:[y>0&&Ve(He,{dimColor:!0,children:` \u2191 ${String(y)} more`}),t.slice(d,c).map((P,C)=>{let S=d+C===w,g=P.disabled===!0,f=S&&!g;return cn(ln,{gap:2,children:[Ve(He,{...f&&{color:"cyan"},dimColor:g,children:S?"\u276F":" "}),Ve(He,{bold:f,dimColor:g,...f&&{color:"cyan"},children:P.label}),P.description!==void 0&&Ve(He,{dimColor:!0,children:P.description})]},P.key)}),v>0&&Ve(He,{dimColor:!0,children:` \u2193 ${String(v)} more`})]}),Ve(He,{dimColor:!0,children:n})]})};import{useEffect as Ic,useState as Ac}from"react";import{Text as Nc}from"ink";import{jsx as Dc}from"react/jsx-runtime";var oi=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],ye=()=>{let[e,t]=Ac(0);return Ic(()=>{let r=setInterval(()=>{t(o=>(o+1)%oi.length)},80);return()=>{clearInterval(r)}},[]),Dc(Nc,{color:"cyan",children:oi[e]??"\u280B"})};import{Fragment as Uc,jsx as B,jsxs as J}from"react/jsx-runtime";var si=[{key:"dashboard",label:"Dashboard"},{key:"homepage",label:"Homepage"},{key:"chart_group",label:"Chart group"}],Bc={dashboard:"dashboard",homepage:"homepage",chart_group:"chart group"},$c="The block was edited in Kizen since your last push. Overwriting discards those edits.",Gt=e=>e.args.includes("--create");function ai(e,t){let r=e.filter(i=>i.value===t),o=e.filter(Gt),n=e.filter(i=>i.value!==t&&!Gt(i));return r.length>0?[...r,...n,...o]:[...o,...n]}function jc(e,t){if(Gt(e))return{key:e.value,label:e.label};if(e.value===t)return{key:e.value,label:`Update "${e.label}" (last pushed here)`};let r=e.isFromThisPlugin?"pushed from this plugin":e.pushKey;return{key:e.value,label:`Update "${e.label}"`,...r?{description:r}:{}}}function Fc(e){let t=e.dashletsCount===null?e.name:`${e.name} (${String(e.dashletsCount)} dashlets)`;if(e.canEdit===!1)return{key:e.id,label:t,description:"no edit access",disabled:!0};let r=[e.employeeAccess,e.hidden?"hidden":null].filter(o=>o!==null&&o!=="").join(" \xB7 ");return{key:e.id,label:t,...r===""?{}:{description:r}}}function Oc(e,t,r){let o={...e,dashboard:t};return delete o.dashlet,delete o.create,Gt(r)?{...o,create:!0}:{...o,dashlet:r.value}}function zc(e,t,r,o){let n=d=>{t.setExitCode(1),r({type:"error",view:d})},i=d=>{d().catch(c=>{n(Ue(c))})},s=async(d,c)=>{r({type:"applying",plan:c});let y=await rn(d,c,t);if(!y.ok){n(y);return}r({type:"done",plan:c,applied:y.value})},l=async(d,c,y)=>{r({type:"loading",label:"Preparing the push\u2026"});let v=await tn(d,c,y,t);if(!v.ok){if(v.code==="drift_detected"){r({type:"confirm",kind:"drift",message:v.message,target:c,options:y,context:d});return}n(v);return}if(y.dryRun){r({type:"done",plan:v.value,applied:null});return}if(y.yes){let P=sn(y,d.credentials.environment);if(P.ok&&P.value.kind==="apply"){await s(d,v.value);return}}r({type:"confirm",kind:"push",plan:v.value,options:y,context:d})},a=async(d,c,y)=>{r({type:"loading",label:"Resolving the target\u2026"});let v=await en(d,c);if(v.ok){await l(d,v.value,c);return}let P=c.dashboard??d.entry?.dashboardId;if((v.code==="needs_choice"&&v.choice==="target"||v.code==="remembered_target_missing")&&v.choices&&v.choices.length>0&&P!==void 0){r({type:"target-select",dashboardId:P,title:"Choose a block to update, or create a new one",message:v.message,choices:ai(v.choices,null),matchedId:null,back:y,options:c,context:d});return}n(v)},p=async(d,c,y)=>{let v=et({credentials:c,block:y}),P=await t.readPushMap(t.cwd);d.forget&&await on({credentials:c,block:y,pushMap:P},t)&&(P=ct(P,v),o(_=>({..._,notices:[..._.notices,`Forgot the remembered target for ${y.block.api_name}.`]})));let C={client:t.createClient(c),credentials:c,block:y,pushMap:P,entry:lt(P,v)};if(d.dashboard!==void 0||C.entry){await a(C,d,null);return}r({type:"surface-select",options:d,context:C})},h=async(d,c,y)=>{r({type:"packaging"});let v=await Xr(y,t);if(!v.ok){if(v.choice==="block"&&v.choices){r({type:"block-select",options:d,credentials:c,choices:v.choices});return}n(v);return}o(P=>({...P,warnings:v.value.warnings})),await p(d,c,v.value)},w=async d=>{r({type:"loading",label:"Loading credentials\u2026"});let c=await Vt(d,t);if(!c.ok){if(c.choice==="profile"&&c.choices){r({type:"profile-select",options:d,choices:c.choices});return}n(c);return}let{credentials:y}=c.value;o(v=>({...v,credentials:y})),await h(d,y,e)},x=async({options:d,context:c},y,v,P)=>{let C=Bc[y];r({type:"loading",label:`Loading ${C}s\u2026`});let S=(await c.client.listDashboards(Do(y),v?.id)).map(u=>pt(u,y)),{environment:g,businessId:f}=c.credentials;if(S.length===0){n({message:`No ${C}s found${v?` on ${v.objectName}`:""} for business ${f} (${g}).`});return}r({type:"dashboard-select",surface:y,objectId:v?.id??null,title:v?`Choose a chart group on ${v.objectName}`:`Choose a ${C}`,rows:S,back:P,options:d,context:c})};return{start:d=>{i(()=>w(d))},pickProfile:(d,c)=>{i(()=>w({...d.options,profile:c.value}))},pickBlock:(d,c)=>{i(()=>h(d.options,d.credentials,c.value))},pickSurface:(d,c)=>{i(async()=>{if(c!=="chart_group"){await x(d,c,null,d);return}r({type:"loading",label:"Loading custom objects\u2026"});let y=await Zr(d.context.client);if(y.length===0){n({message:"No custom objects found, so there are no chart groups to push to."});return}r({type:"object-select",objects:y,back:d,options:d.options,context:d.context})})},pickObject:(d,c)=>{i(()=>x(d,"chart_group",c,d))},pickDashboard:(d,c)=>{i(async()=>{let{context:y}=d,v={...d.options,dashboard:c.id};if(v.dashlet!==void 0||v.create){await a(y,v,d);return}r({type:"loading",label:`Loading "${c.name}"\u2026`});let P=await y.client.getDashboard(c.id),C=Lt({dashboardId:P.id,dashlets:P.dashlets,pluginApiName:y.block.pluginApiName,blockApiName:y.block.block.api_name,entry:y.entry}),_=C.kind==="map"||C.kind==="name"?C.dashlet.id:null;r({type:"target-select",dashboardId:P.id,title:`Choose what to push to on "${P.name}"`,message:null,choices:ai(Wt(P,y.block),_),matchedId:_,back:d,options:v,context:y})})},pickTarget:(d,c)=>{i(()=>a(d.context,Oc(d.options,d.dashboardId,c),d))},acceptDrift:d=>{i(()=>l(d.context,d.target,{...d.options,force:!0}))},acceptPush:d=>{i(()=>s(d.context,d.plan))},cancel:()=>{n({message:"Cancelled."})}}}var li=({prompt:e,strict:t,onAccept:r,onCancel:o})=>(ci((n,i)=>{if(i.ctrl)return;let s=n.toLowerCase();s==="y"||!t&&i.return?r():(t||s==="n"||i.escape)&&o()}),B(q,{bold:!0,children:e})),tt=({lines:e,color:t})=>B(oe,{flexDirection:"column",children:e.map((r,o)=>B(q,{...t&&{color:t},children:r},`${String(o)}-${r}`))}),di=({plan:e})=>J(oe,{flexDirection:"column",children:[B(tt,{lines:ft(e.summary)}),J(q,{children:["URL: ",e.url]})]}),dn=({label:e})=>J(oe,{gap:1,children:[B(ye,{}),B(q,{dimColor:!0,children:e})]}),Mc=({view:e})=>J(oe,{flexDirection:"column",gap:1,children:[J(oe,{gap:1,children:[B(q,{color:"red",children:"\u2717"}),B(q,{color:"red",children:e.issues&&e.issues.length>0?me(e.issues):e.message})]}),e.hint!==void 0&&J(q,{dimColor:!0,children:["Hint: ",e.hint]}),e.choices&&e.choices.length>0&&J(oe,{flexDirection:"column",children:[B(q,{children:"Choices:"}),B(tt,{lines:e.choices.map(t=>` ${t.label}`)})]})]}),Lc=({plan:e,applied:t})=>{let r=nn(e.dashboard.id);return t===null?J(oe,{flexDirection:"column",gap:1,children:[B(q,{color:"yellow",children:"Dry run: nothing was written."}),B(di,{plan:e}),e.warnings.length>0&&B(tt,{lines:e.warnings.map(o=>`Warning: ${o}`),color:"yellow"}),J(oe,{flexDirection:"column",children:[J(q,{bold:!0,children:[e.method," ",e.path]}),B(q,{children:JSON.stringify(e.body,null,2)})]})]}):J(oe,{flexDirection:"column",gap:1,children:[J(oe,{gap:1,children:[B(q,{color:"green",children:"\u2713"}),J(q,{bold:!0,children:[e.action==="create"?"Created":"Updated"," ",e.summary.blockName,' on "',e.dashboard.name,'"']})]}),J(oe,{flexDirection:"column",children:[J(q,{children:["URL: ",e.url]}),r&&J(q,{dimColor:!0,children:["Refresh an open tab: ",r.script]})]}),t.warnings.length>0&&B(tt,{lines:t.warnings.map(o=>`Warning: ${o}`),color:"yellow"})]})},ui=({apiName:e,options:t,deps:r})=>{let o=Rc(),[n,i]=qt({type:"loading",label:"Loading credentials\u2026"}),[s,l]=qt({credentials:null,warnings:[],notices:[]}),[a]=qt(()=>zc(e,r,i,l)),[p]=qt(t);ii(()=>{a.start(p)},[a,p]),ii(()=>{(n.type==="done"||n.type==="error")&&o.exit()},[n,o]),ci((w,x)=>{x.ctrl&&w==="c"&&n.type!=="done"&&n.type!=="error"&&(r.setExitCode(130),o.exit())});let h=w=>J(oe,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(K,{}),s.credentials&&J(q,{dimColor:!0,children:["Environment: ",s.credentials.environment," \xB7 Business:"," ",s.credentials.businessId]}),s.warnings.length>0&&B(q,{dimColor:!0,children:me(s.warnings)}),s.notices.length>0&&B(tt,{lines:s.notices}),w]});switch(n.type){case"loading":return h(B(dn,{label:n.label}));case"packaging":return h(B(dn,{label:"Packaging blocks\u2026"}));case"applying":return h(B(dn,{label:`Pushing ${n.plan.summary.blockName} to "${n.plan.dashboard.name}"\u2026`}));case"profile-select":return h(B(We,{title:"Credential profile",items:n.choices.map(w=>({key:w.value,label:w.label})),onSelect:(w,x)=>{let d=n.choices[x];d&&a.pickProfile(n,d)},onCancel:a.cancel},"profile"));case"block-select":return h(B(We,{title:"Block to push",items:n.choices.map(w=>({key:w.value,label:w.label})),onSelect:(w,x)=>{let d=n.choices[x];d&&a.pickBlock(n,d)},onCancel:a.cancel},"block"));case"surface-select":return h(B(We,{title:"Where should the block go?",items:si,onSelect:(w,x)=>{let d=si[x];d&&a.pickSurface(n,d.key)},onCancel:a.cancel},"surface"));case"object-select":return h(B(We,{title:"Custom object",items:n.objects.map(w=>({key:w.id,label:w.objectName})),onSelect:(w,x)=>{let d=n.objects[x];d&&a.pickObject(n,d)},onCancel:()=>{i(n.back)},hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"},"object"));case"dashboard-select":return h(B(We,{title:n.title,items:n.rows.map(Fc),onSelect:(w,x)=>{let d=n.rows[x];d&&a.pickDashboard(n,d)},onCancel:()=>{i(n.back)},hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"},`dashboards-${n.surface}-${n.objectId??""}`));case"target-select":{let{back:w}=n;return h(J(Uc,{children:[n.message!==null&&B(q,{color:"yellow",children:n.message}),B(We,{title:n.title,items:n.choices.map(x=>jc(x,n.matchedId)),onSelect:(x,d)=>{let c=n.choices[d];c&&a.pickTarget(n,c)},onCancel:w?()=>{i(w)}:a.cancel,...w&&{hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"}},`targets-${n.dashboardId}`)]}))}case"confirm":return n.kind==="drift"?h(J(oe,{flexDirection:"column",gap:1,children:[B(q,{color:"yellow",children:$c}),B(q,{dimColor:!0,children:n.message}),B(li,{prompt:"Type y to overwrite (y/N)",strict:!0,onAccept:()=>{a.acceptDrift(n)},onCancel:a.cancel},"drift")]})):h(J(oe,{flexDirection:"column",gap:1,children:[B(di,{plan:n.plan}),n.plan.warnings.length>0&&B(tt,{lines:n.plan.warnings.map(w=>`Warning: ${w}`),color:"yellow"}),n.plan.summary.isProduction&&B(q,{color:"red",bold:!0,children:"PRODUCTION"}),B(li,{prompt:n.plan.summary.isProduction?"Type y to push to production (y/N)":"Push? (Y/n)",strict:n.plan.summary.isProduction,onAccept:()=>{a.acceptPush(n)},onCancel:a.cancel},"push")]}));case"done":return h(B(Lc,{plan:n.plan,applied:n.applied}));case"error":return h(B(Mc,{view:n.view}))}};var Kc=e=>e instanceof Wc?me(e.issues):`Error: ${e instanceof Error?e.message:String(e)}`;function pi(e){let t=e.command("block").description("Work with plugin content blocks");t.command("export").description("Print one packaged block as JSON for the Custom Block (AI Coded) paste editor").argument("[api_name]","api_name of the block to export (optional when there is only one)").option("--copy","also copy the JSON to the clipboard").action(async(r,o)=>{try{let{block:n,warnings:i}=await Xn(process.cwd(),r);i.length>0&&console.error(me(i));let s=JSON.stringify(n,null,2);console.log(s),o.copy&&console.error(await Rt(s)?`Copied block "${n.api_name}" to the clipboard.`:"Couldn't copy to the clipboard; use the JSON printed to stdout instead.")}catch(n){console.error(Kc(n)),process.exitCode=1}}),t.command("push").description("Push a block to a Kizen dashboard, homepage or chart group dashlet").argument("[api_name]","api_name of the block to push (optional when there is only one)").option("-c, --credentials <path>","path to a credentials JSON file").option("--profile <name>","stored credential profile to use").option("--dashboard <id>","dashboard, homepage or chart group to push to").option("--dashlet <id>","existing custom code dashlet to update (needs --dashboard)").option("--create","create a new dashlet instead of updating one").option("--dry-run","show the request without writing anything").option("--yes","write without asking (headless runs are dry runs without it)").option("--allow-production","allow headless writes to go/fmo").option("--force","overwrite even if the block was edited in Kizen since the last push").option("--forget","clear the remembered target for this block first").option("--json","print a JSON result to stdout (always headless)").action(async(r,o)=>{try{if(!process.stdin.isTTY||!process.stdout.isTTY||o.json===!0){await Qo(r,o,Ht(process.cwd()));return}let{waitUntilExit:n}=Vc(Hc(ui,{...r!==void 0&&{apiName:r},options:o,deps:Ht(process.cwd())}),{exitOnCtrlC:!1});await n()}catch(n){console.error(`Error: ${n instanceof Error?n.message:String(n)}`),process.exitCode=1}}),t.command("targets").description("List the dashboards, homepages and chart groups a block can be pushed to").option("-c, --credentials <path>","path to a credentials JSON file").option("--profile <name>","stored credential profile to use").option("--object <id>","list the chart groups of this custom object").option("--json","print a JSON result to stdout").action(async r=>{try{await ei(r,Ht(process.cwd()))}catch(o){console.error(`Error: ${o instanceof Error?o.message:String(o)}`),process.exitCode=1}})}import{createElement as Xc}from"react";import{render as Zc}from"ink";import{useEffect as mi,useState as gt}from"react";import{Box as yt,Text as rt,useApp as qc}from"ink";import{PluginValidationError as Gc}from"@kizenapps/packager";function mt(e){return e<1024?`${String(e)} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}import{Box as un,Text as Yt}from"ink";import{jsx as fi,jsxs as ht}from"react/jsx-runtime";var Jc=e=>{let t=new Map;for(let r of e){let o=r.path??r.pluginApiName??"general",n=t.get(o)??[];n.push(r),t.set(o,n)}return t},Xt=({issues:e})=>{let t=e.filter(r=>r.severity==="error").length;return ht(un,{flexDirection:"column",marginTop:1,children:[ht(Yt,{color:"red",children:["\u2717 ",t," validation ",t===1?"error":"errors"]}),[...Jc(e)].map(([r,o])=>ht(un,{flexDirection:"column",marginTop:1,children:[fi(Yt,{bold:!0,children:r}),o.map((n,i)=>fi(un,{paddingLeft:2,children:ht(Yt,{color:n.severity==="error"?"red":"yellow",children:[n.severity==="error"?"\u2717":"\u26A0"," ",n.message," ",ht(Yt,{dimColor:!0,children:["(",n.rule,")"]})]})},`${n.rule}-${String(i)}`))]},r))]})};import{Fragment as Yc,jsx as De,jsxs as Ke}from"react/jsx-runtime";var hi=["creating-dir","reading-files","validating","minifying","packaging","writing-bundle"],Zt={"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"},gi=({outputDir:e,pluginDir:t})=>{let r=qc(),[o,n]=gt("creating-dir"),[i,s]=gt(!1),[l,a]=gt(null),[p,h]=gt(null),[w,x]=gt(null);mi(()=>{jt(t,e,n).then(({bundleSize:y})=>{x(y),n("done")}).catch(y=>{y instanceof Gc?a(y.issues):h(y instanceof Error?y.message:String(y)),s(!0),process.exitCode=1})},[e,t]),mi(()=>{(o==="done"||i)&&r.exit()},[o,i,r]);let d=hi.indexOf(o),c=o==="done";return Ke(yt,{flexDirection:"column",paddingY:1,paddingX:2,children:[De(K,{marginBottom:1}),Ke(yt,{flexDirection:"column",gap:0,children:[hi.map((y,v)=>{let P=o===y,C=c||d>v;return De(yt,{gap:1,children:i&&v===d?Ke(rt,{color:"red",children:["\u2717 ",Zt[y]]}):C?Ke(rt,{color:"green",children:["\u2713 ",Zt[y]]}):P?Ke(Yc,{children:[De(ye,{}),De(rt,{children:Zt[y]})]}):Ke(rt,{dimColor:!0,children:[" ",Zt[y]]})},y)}),c&&w!==null&&De(yt,{marginTop:1,gap:1,children:Ke(rt,{color:"green",children:["\u2713 bundle \u2014 ",mt(w)]})}),l!==null&&De(Xt,{issues:l}),p!==null&&De(yt,{marginTop:1,borderStyle:"single",borderColor:"red",paddingX:1,children:De(rt,{color:"red",children:p})})]})]})};function yi(e){e.command("build").description("Bundle the plugin app into .kizenapp directory").action(async()=>{let t=process.cwd(),r=`${t}/.kizenapp`;Ne(t);let{waitUntilExit:o}=Zc(Xc(gi,{outputDir:r,pluginDir:t}));await o()})}import{createElement as Wd}from"react";import{render as Kd}from"ink";import{useCallback as sr,useState as nt}from"react";import{Box as V,Text as N,useApp as Od,useInput as zd}from"ink";import{join as ar}from"path";import{access as Bd,mkdir as er,writeFile as yn}from"fs/promises";import{dirname as $d,join as ke}from"path";var bi=`{
756
+ `:hc(p.value))}catch(l){s(He(l))}}import{useEffect as ii,useState as qt}from"react";import{Box as oe,Text as q,useApp as Rc,useInput as ci}from"ink";import"@kizenapps/packager";import{Box as wc,Text as xc}from"ink";import{Box as gc,Text as yc}from"ink";import{jsx as ti}from"react/jsx-runtime";var bc=[" :::::::: "," :::::: ::::::::::: "," :::::: :::::::::: "," :::::: :::::: ::::::: "," ::::: :::::: ::::::::::::::::: "," ::::: ::::: ::::::::::::::::::: "," ::::: ::::: :::::: ::::: ",":::: ::::: ::: ::::: :: ","::::: :::::: :::::::::: ","::::: :::::: ::::::::::: "," ::::: ::: ::::::: "," ::::::: ::: ::::: "," ::::::::::: :::::: :::::"," :::::::::: :::::: :::::"," :: ::::: ::: ::::: ::::"," ::::: :::::: ::::: ::::: ::: "," ::::::::::::::::::: ::::: ::::: "," ::::::::::::::::: ::::: ::::: "," ::::::::: :::::: :::::: "," :::::::::: :::::: "," ::::::::::: :::::: "," :::::::: "],ri=()=>ti(gc,{flexDirection:"column",children:bc.map((e,t)=>ti(yc,{color:"cyan",children:e},t))});import{Fragment as vc,jsx as an,jsxs as kc}from"react/jsx-runtime";var K=({marginBottom:e=0})=>kc(vc,{children:[an(ri,{}),an(wc,{flexDirection:"column",marginTop:1,marginBottom:e,children:an(xc,{bold:!0,color:"cyan",children:"Kizen App Development Toolkit"})})]});import{useMemo as Cc,useState as Sc}from"react";import{Box as ln,Text as Ue,useInput as _c}from"ink";var Kt=(e,t,r)=>Math.min(Math.max(e,t),r);function Jt(e,t,r,o={}){if(t<=0)return 0;let n=Kt(Math.trunc(e)||0,0,t-1),i=a=>o.disabled?.[a]!==!0;if(r===0)return n;let s=r>0?1:-1;if(Math.abs(r)===1){for(let a=1;a<=t;a++){let p=((n+s*a)%t+t)%t;if(i(p))return p}return n}let l=Kt(n+Math.trunc(r),0,t-1);for(let a=l;a>=0&&a<t;a+=s)if(i(a))return a;for(let a=l-s;a>=0&&a<t;a-=s)if(i(a))return a;return n}function ni(e,t,r=10){if(t<=0)return{start:0,end:0};let o=Math.max(1,Math.floor(r));if(t<=o)return{start:0,end:t};let n=Kt(Math.trunc(e)||0,0,t-1),i=Kt(n-Math.floor(o/2),0,t-o);return{start:i,end:i+o}}import{jsx as Ve,jsxs as cn}from"react/jsx-runtime";var Pc="\u2191/\u2193 to move, Enter to select, Esc to cancel",Ec=10,Tc=(e,t)=>{let r=Jt(t,e.length,0);if(e[r]?.disabled!==!0)return r;let o=e.findIndex(n=>n.disabled!==!0);return o===-1?r:o},We=({title:e,items:t,onSelect:r,onCancel:o,hint:n=Pc,initialIndex:i=0,windowSize:s=Ec,isActive:l=!0})=>{let[a,p]=Sc(()=>Tc(t,i)),h=Cc(()=>t.map(P=>P.disabled===!0),[t]),w=Jt(a,t.length,0),x=Math.max(1,Math.floor(s));_c((P,C)=>{let _=S=>{p(Jt(w,t.length,S,{disabled:h}))};if(C.upArrow||P==="k")_(-1);else if(C.downArrow||P==="j")_(1);else if(C.pageUp)_(-x);else if(C.pageDown)_(x);else if(C.return){let S=t[w];S!==void 0&&S.disabled!==!0&&r(S,w)}else C.escape&&o?.()},{isActive:l});let{start:d,end:c}=ni(w,t.length,x),y=d,v=t.length-c;return cn(ln,{flexDirection:"column",gap:1,children:[Ve(Ue,{bold:!0,children:e}),cn(ln,{flexDirection:"column",children:[y>0&&Ve(Ue,{dimColor:!0,children:` \u2191 ${String(y)} more`}),t.slice(d,c).map((P,C)=>{let S=d+C===w,g=P.disabled===!0,f=S&&!g;return cn(ln,{gap:2,children:[Ve(Ue,{...f&&{color:"cyan"},dimColor:g,children:S?"\u276F":" "}),Ve(Ue,{bold:f,dimColor:g,...f&&{color:"cyan"},children:P.label}),P.description!==void 0&&Ve(Ue,{dimColor:!0,children:P.description})]},P.key)}),v>0&&Ve(Ue,{dimColor:!0,children:` \u2193 ${String(v)} more`})]}),Ve(Ue,{dimColor:!0,children:n})]})};import{useEffect as Ic,useState as Ac}from"react";import{Text as Nc}from"ink";import{jsx as Dc}from"react/jsx-runtime";var oi=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],ye=()=>{let[e,t]=Ac(0);return Ic(()=>{let r=setInterval(()=>{t(o=>(o+1)%oi.length)},80);return()=>{clearInterval(r)}},[]),Dc(Nc,{color:"cyan",children:oi[e]??"\u280B"})};import{Fragment as Hc,jsx as B,jsxs as J}from"react/jsx-runtime";var si=[{key:"dashboard",label:"Dashboard"},{key:"homepage",label:"Homepage"},{key:"chart_group",label:"Chart group"}],Bc={dashboard:"dashboard",homepage:"homepage",chart_group:"chart group"},$c="The block was edited in Kizen since your last push. Overwriting discards those edits.",Gt=e=>e.args.includes("--create");function ai(e,t){let r=e.filter(i=>i.value===t),o=e.filter(Gt),n=e.filter(i=>i.value!==t&&!Gt(i));return r.length>0?[...r,...n,...o]:[...o,...n]}function jc(e,t){if(Gt(e))return{key:e.value,label:e.label};if(e.value===t)return{key:e.value,label:`Update "${e.label}" (last pushed here)`};let r=e.isFromThisPlugin?"pushed from this plugin":e.pushKey;return{key:e.value,label:`Update "${e.label}"`,...r?{description:r}:{}}}function Fc(e){let t=e.dashletsCount===null?e.name:`${e.name} (${String(e.dashletsCount)} dashlets)`;if(e.canEdit===!1)return{key:e.id,label:t,description:"no edit access",disabled:!0};let r=[e.employeeAccess,e.hidden?"hidden":null].filter(o=>o!==null&&o!=="").join(" \xB7 ");return{key:e.id,label:t,...r===""?{}:{description:r}}}function Oc(e,t,r){let o={...e,dashboard:t};return delete o.dashlet,delete o.create,Gt(r)?{...o,create:!0}:{...o,dashlet:r.value}}function zc(e,t,r,o){let n=d=>{t.setExitCode(1),r({type:"error",view:d})},i=d=>{d().catch(c=>{n(He(c))})},s=async(d,c)=>{r({type:"applying",plan:c});let y=await rn(d,c,t);if(!y.ok){n(y);return}r({type:"done",plan:c,applied:y.value})},l=async(d,c,y)=>{r({type:"loading",label:"Preparing the push\u2026"});let v=await tn(d,c,y,t);if(!v.ok){if(v.code==="drift_detected"){r({type:"confirm",kind:"drift",message:v.message,target:c,options:y,context:d});return}n(v);return}if(y.dryRun){r({type:"done",plan:v.value,applied:null});return}if(y.yes){let P=sn(y,d.credentials.environment);if(P.ok&&P.value.kind==="apply"){await s(d,v.value);return}}r({type:"confirm",kind:"push",plan:v.value,options:y,context:d})},a=async(d,c,y)=>{r({type:"loading",label:"Resolving the target\u2026"});let v=await en(d,c);if(v.ok){await l(d,v.value,c);return}let P=c.dashboard??d.entry?.dashboardId;if((v.code==="needs_choice"&&v.choice==="target"||v.code==="remembered_target_missing")&&v.choices&&v.choices.length>0&&P!==void 0){r({type:"target-select",dashboardId:P,title:"Choose a block to update, or create a new one",message:v.message,choices:ai(v.choices,null),matchedId:null,back:y,options:c,context:d});return}n(v)},p=async(d,c,y)=>{let v=et({credentials:c,block:y}),P=await t.readPushMap(t.cwd);d.forget&&await on({credentials:c,block:y,pushMap:P},t)&&(P=ct(P,v),o(_=>({..._,notices:[..._.notices,`Forgot the remembered target for ${y.block.api_name}.`]})));let C={client:t.createClient(c),credentials:c,block:y,pushMap:P,entry:lt(P,v)};if(d.dashboard!==void 0||C.entry){await a(C,d,null);return}r({type:"surface-select",options:d,context:C})},h=async(d,c,y)=>{r({type:"packaging"});let v=await Xr(y,t);if(!v.ok){if(v.choice==="block"&&v.choices){r({type:"block-select",options:d,credentials:c,choices:v.choices});return}n(v);return}o(P=>({...P,warnings:v.value.warnings})),await p(d,c,v.value)},w=async d=>{r({type:"loading",label:"Loading credentials\u2026"});let c=await Vt(d,t);if(!c.ok){if(c.choice==="profile"&&c.choices){r({type:"profile-select",options:d,choices:c.choices});return}n(c);return}let{credentials:y}=c.value;o(v=>({...v,credentials:y})),await h(d,y,e)},x=async({options:d,context:c},y,v,P)=>{let C=Bc[y];r({type:"loading",label:`Loading ${C}s\u2026`});let S=(await c.client.listDashboards(Do(y),v?.id)).map(u=>pt(u,y)),{environment:g,businessId:f}=c.credentials;if(S.length===0){n({message:`No ${C}s found${v?` on ${v.objectName}`:""} for business ${f} (${g}).`});return}r({type:"dashboard-select",surface:y,objectId:v?.id??null,title:v?`Choose a chart group on ${v.objectName}`:`Choose a ${C}`,rows:S,back:P,options:d,context:c})};return{start:d=>{i(()=>w(d))},pickProfile:(d,c)=>{i(()=>w({...d.options,profile:c.value}))},pickBlock:(d,c)=>{i(()=>h(d.options,d.credentials,c.value))},pickSurface:(d,c)=>{i(async()=>{if(c!=="chart_group"){await x(d,c,null,d);return}r({type:"loading",label:"Loading custom objects\u2026"});let y=await Zr(d.context.client);if(y.length===0){n({message:"No custom objects found, so there are no chart groups to push to."});return}r({type:"object-select",objects:y,back:d,options:d.options,context:d.context})})},pickObject:(d,c)=>{i(()=>x(d,"chart_group",c,d))},pickDashboard:(d,c)=>{i(async()=>{let{context:y}=d,v={...d.options,dashboard:c.id};if(v.dashlet!==void 0||v.create){await a(y,v,d);return}r({type:"loading",label:`Loading "${c.name}"\u2026`});let P=await y.client.getDashboard(c.id),C=Lt({dashboardId:P.id,dashlets:P.dashlets,pluginApiName:y.block.pluginApiName,blockApiName:y.block.block.api_name,entry:y.entry}),_=C.kind==="map"||C.kind==="name"?C.dashlet.id:null;r({type:"target-select",dashboardId:P.id,title:`Choose what to push to on "${P.name}"`,message:null,choices:ai(Wt(P,y.block),_),matchedId:_,back:d,options:v,context:y})})},pickTarget:(d,c)=>{i(()=>a(d.context,Oc(d.options,d.dashboardId,c),d))},acceptDrift:d=>{i(()=>l(d.context,d.target,{...d.options,force:!0}))},acceptPush:d=>{i(()=>s(d.context,d.plan))},cancel:()=>{n({message:"Cancelled."})}}}var li=({prompt:e,strict:t,onAccept:r,onCancel:o})=>(ci((n,i)=>{if(i.ctrl)return;let s=n.toLowerCase();s==="y"||!t&&i.return?r():(t||s==="n"||i.escape)&&o()}),B(q,{bold:!0,children:e})),tt=({lines:e,color:t})=>B(oe,{flexDirection:"column",children:e.map((r,o)=>B(q,{...t&&{color:t},children:r},`${String(o)}-${r}`))}),di=({plan:e})=>J(oe,{flexDirection:"column",children:[B(tt,{lines:ft(e.summary)}),J(q,{children:["URL: ",e.url]})]}),dn=({label:e})=>J(oe,{gap:1,children:[B(ye,{}),B(q,{dimColor:!0,children:e})]}),Mc=({view:e})=>J(oe,{flexDirection:"column",gap:1,children:[J(oe,{gap:1,children:[B(q,{color:"red",children:"\u2717"}),B(q,{color:"red",children:e.issues&&e.issues.length>0?me(e.issues):e.message})]}),e.hint!==void 0&&J(q,{dimColor:!0,children:["Hint: ",e.hint]}),e.choices&&e.choices.length>0&&J(oe,{flexDirection:"column",children:[B(q,{children:"Choices:"}),B(tt,{lines:e.choices.map(t=>` ${t.label}`)})]})]}),Lc=({plan:e,applied:t})=>{let r=nn(e.dashboard.id);return t===null?J(oe,{flexDirection:"column",gap:1,children:[B(q,{color:"yellow",children:"Dry run: nothing was written."}),B(di,{plan:e}),e.warnings.length>0&&B(tt,{lines:e.warnings.map(o=>`Warning: ${o}`),color:"yellow"}),J(oe,{flexDirection:"column",children:[J(q,{bold:!0,children:[e.method," ",e.path]}),B(q,{children:JSON.stringify(e.body,null,2)})]})]}):J(oe,{flexDirection:"column",gap:1,children:[J(oe,{gap:1,children:[B(q,{color:"green",children:"\u2713"}),J(q,{bold:!0,children:[e.action==="create"?"Created":"Updated"," ",e.summary.blockName,' on "',e.dashboard.name,'"']})]}),J(oe,{flexDirection:"column",children:[J(q,{children:["URL: ",e.url]}),r&&J(q,{dimColor:!0,children:["Refresh an open tab: ",r.script]})]}),t.warnings.length>0&&B(tt,{lines:t.warnings.map(o=>`Warning: ${o}`),color:"yellow"})]})},ui=({apiName:e,options:t,deps:r})=>{let o=Rc(),[n,i]=qt({type:"loading",label:"Loading credentials\u2026"}),[s,l]=qt({credentials:null,warnings:[],notices:[]}),[a]=qt(()=>zc(e,r,i,l)),[p]=qt(t);ii(()=>{a.start(p)},[a,p]),ii(()=>{(n.type==="done"||n.type==="error")&&o.exit()},[n,o]),ci((w,x)=>{x.ctrl&&w==="c"&&n.type!=="done"&&n.type!=="error"&&(r.setExitCode(130),o.exit())});let h=w=>J(oe,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(K,{}),s.credentials&&J(q,{dimColor:!0,children:["Environment: ",s.credentials.environment," \xB7 Business:"," ",s.credentials.businessId]}),s.warnings.length>0&&B(q,{dimColor:!0,children:me(s.warnings)}),s.notices.length>0&&B(tt,{lines:s.notices}),w]});switch(n.type){case"loading":return h(B(dn,{label:n.label}));case"packaging":return h(B(dn,{label:"Packaging blocks\u2026"}));case"applying":return h(B(dn,{label:`Pushing ${n.plan.summary.blockName} to "${n.plan.dashboard.name}"\u2026`}));case"profile-select":return h(B(We,{title:"Credential profile",items:n.choices.map(w=>({key:w.value,label:w.label})),onSelect:(w,x)=>{let d=n.choices[x];d&&a.pickProfile(n,d)},onCancel:a.cancel},"profile"));case"block-select":return h(B(We,{title:"Block to push",items:n.choices.map(w=>({key:w.value,label:w.label})),onSelect:(w,x)=>{let d=n.choices[x];d&&a.pickBlock(n,d)},onCancel:a.cancel},"block"));case"surface-select":return h(B(We,{title:"Where should the block go?",items:si,onSelect:(w,x)=>{let d=si[x];d&&a.pickSurface(n,d.key)},onCancel:a.cancel},"surface"));case"object-select":return h(B(We,{title:"Custom object",items:n.objects.map(w=>({key:w.id,label:w.objectName})),onSelect:(w,x)=>{let d=n.objects[x];d&&a.pickObject(n,d)},onCancel:()=>{i(n.back)},hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"},"object"));case"dashboard-select":return h(B(We,{title:n.title,items:n.rows.map(Fc),onSelect:(w,x)=>{let d=n.rows[x];d&&a.pickDashboard(n,d)},onCancel:()=>{i(n.back)},hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"},`dashboards-${n.surface}-${n.objectId??""}`));case"target-select":{let{back:w}=n;return h(J(Hc,{children:[n.message!==null&&B(q,{color:"yellow",children:n.message}),B(We,{title:n.title,items:n.choices.map(x=>jc(x,n.matchedId)),onSelect:(x,d)=>{let c=n.choices[d];c&&a.pickTarget(n,c)},onCancel:w?()=>{i(w)}:a.cancel,...w&&{hint:"\u2191/\u2193 to move, Enter to select, Esc to go back"}},`targets-${n.dashboardId}`)]}))}case"confirm":return n.kind==="drift"?h(J(oe,{flexDirection:"column",gap:1,children:[B(q,{color:"yellow",children:$c}),B(q,{dimColor:!0,children:n.message}),B(li,{prompt:"Type y to overwrite (y/N)",strict:!0,onAccept:()=>{a.acceptDrift(n)},onCancel:a.cancel},"drift")]})):h(J(oe,{flexDirection:"column",gap:1,children:[B(di,{plan:n.plan}),n.plan.warnings.length>0&&B(tt,{lines:n.plan.warnings.map(w=>`Warning: ${w}`),color:"yellow"}),n.plan.summary.isProduction&&B(q,{color:"red",bold:!0,children:"PRODUCTION"}),B(li,{prompt:n.plan.summary.isProduction?"Type y to push to production (y/N)":"Push? (Y/n)",strict:n.plan.summary.isProduction,onAccept:()=>{a.acceptPush(n)},onCancel:a.cancel},"push")]}));case"done":return h(B(Lc,{plan:n.plan,applied:n.applied}));case"error":return h(B(Mc,{view:n.view}))}};var Kc=e=>e instanceof Wc?me(e.issues):`Error: ${e instanceof Error?e.message:String(e)}`;function pi(e){let t=e.command("block").description("Work with plugin content blocks");t.command("export").description("Print one packaged block as JSON for the Custom Block (AI Coded) paste editor").argument("[api_name]","api_name of the block to export (optional when there is only one)").option("--copy","also copy the JSON to the clipboard").action(async(r,o)=>{try{let{block:n,warnings:i}=await Xn(process.cwd(),r);i.length>0&&console.error(me(i));let s=JSON.stringify(n,null,2);console.log(s),o.copy&&console.error(await Rt(s)?`Copied block "${n.api_name}" to the clipboard.`:"Couldn't copy to the clipboard; use the JSON printed to stdout instead.")}catch(n){console.error(Kc(n)),process.exitCode=1}}),t.command("push").description("Push a block to a Kizen dashboard, homepage or chart group dashlet").argument("[api_name]","api_name of the block to push (optional when there is only one)").option("-c, --credentials <path>","path to a credentials JSON file").option("--profile <name>","stored credential profile to use").option("--dashboard <id>","dashboard, homepage or chart group to push to").option("--dashlet <id>","existing custom code dashlet to update (needs --dashboard)").option("--create","create a new dashlet instead of updating one").option("--dry-run","show the request without writing anything").option("--yes","write without asking (headless runs are dry runs without it)").option("--allow-production","allow headless writes to go/fmo").option("--force","overwrite even if the block was edited in Kizen since the last push").option("--forget","clear the remembered target for this block first").option("--json","print a JSON result to stdout (always headless)").action(async(r,o)=>{try{if(!process.stdin.isTTY||!process.stdout.isTTY||o.json===!0){await Qo(r,o,Ut(process.cwd()));return}let{waitUntilExit:n}=Vc(Uc(ui,{...r!==void 0&&{apiName:r},options:o,deps:Ut(process.cwd())}),{exitOnCtrlC:!1});await n()}catch(n){console.error(`Error: ${n instanceof Error?n.message:String(n)}`),process.exitCode=1}}),t.command("targets").description("List the dashboards, homepages and chart groups a block can be pushed to").option("-c, --credentials <path>","path to a credentials JSON file").option("--profile <name>","stored credential profile to use").option("--object <id>","list the chart groups of this custom object").option("--json","print a JSON result to stdout").action(async r=>{try{await ei(r,Ut(process.cwd()))}catch(o){console.error(`Error: ${o instanceof Error?o.message:String(o)}`),process.exitCode=1}})}import{createElement as Xc}from"react";import{render as Zc}from"ink";import{useEffect as mi,useState as gt}from"react";import{Box as yt,Text as rt,useApp as qc}from"ink";import{PluginValidationError as Gc}from"@kizenapps/packager";function mt(e){return e<1024?`${String(e)} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}import{Box as un,Text as Yt}from"ink";import{jsx as fi,jsxs as ht}from"react/jsx-runtime";var Jc=e=>{let t=new Map;for(let r of e){let o=r.path??r.pluginApiName??"general",n=t.get(o)??[];n.push(r),t.set(o,n)}return t},Xt=({issues:e})=>{let t=e.filter(r=>r.severity==="error").length;return ht(un,{flexDirection:"column",marginTop:1,children:[ht(Yt,{color:"red",children:["\u2717 ",t," validation ",t===1?"error":"errors"]}),[...Jc(e)].map(([r,o])=>ht(un,{flexDirection:"column",marginTop:1,children:[fi(Yt,{bold:!0,children:r}),o.map((n,i)=>fi(un,{paddingLeft:2,children:ht(Yt,{color:n.severity==="error"?"red":"yellow",children:[n.severity==="error"?"\u2717":"\u26A0"," ",n.message," ",ht(Yt,{dimColor:!0,children:["(",n.rule,")"]})]})},`${n.rule}-${String(i)}`))]},r))]})};import{Fragment as Yc,jsx as De,jsxs as Ke}from"react/jsx-runtime";var hi=["creating-dir","reading-files","validating","minifying","packaging","writing-bundle"],Zt={"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"},gi=({outputDir:e,pluginDir:t})=>{let r=qc(),[o,n]=gt("creating-dir"),[i,s]=gt(!1),[l,a]=gt(null),[p,h]=gt(null),[w,x]=gt(null);mi(()=>{jt(t,e,n).then(({bundleSize:y})=>{x(y),n("done")}).catch(y=>{y instanceof Gc?a(y.issues):h(y instanceof Error?y.message:String(y)),s(!0),process.exitCode=1})},[e,t]),mi(()=>{(o==="done"||i)&&r.exit()},[o,i,r]);let d=hi.indexOf(o),c=o==="done";return Ke(yt,{flexDirection:"column",paddingY:1,paddingX:2,children:[De(K,{marginBottom:1}),Ke(yt,{flexDirection:"column",gap:0,children:[hi.map((y,v)=>{let P=o===y,C=c||d>v;return De(yt,{gap:1,children:i&&v===d?Ke(rt,{color:"red",children:["\u2717 ",Zt[y]]}):C?Ke(rt,{color:"green",children:["\u2713 ",Zt[y]]}):P?Ke(Yc,{children:[De(ye,{}),De(rt,{children:Zt[y]})]}):Ke(rt,{dimColor:!0,children:[" ",Zt[y]]})},y)}),c&&w!==null&&De(yt,{marginTop:1,gap:1,children:Ke(rt,{color:"green",children:["\u2713 bundle \u2014 ",mt(w)]})}),l!==null&&De(Xt,{issues:l}),p!==null&&De(yt,{marginTop:1,borderStyle:"single",borderColor:"red",paddingX:1,children:De(rt,{color:"red",children:p})})]})]})};function yi(e){e.command("build").description("Bundle the plugin app into .kizenapp directory").action(async()=>{let t=process.cwd(),r=`${t}/.kizenapp`;Ne(t);let{waitUntilExit:o}=Zc(Xc(gi,{outputDir:r,pluginDir:t}));await o()})}import{createElement as Wd}from"react";import{render as Kd}from"ink";import{useCallback as sr,useState as nt}from"react";import{Box as V,Text as N,useApp as Od,useInput as zd}from"ink";import{join as ar}from"path";import{access as Bd,mkdir as er,writeFile as yn}from"fs/promises";import{dirname as $d,join as ke}from"path";var bi=`{
757
757
  "name": "Hello Frame",
758
758
  "api_name": "hello_frame",
759
759
  "title": "Hello Frame",
@@ -907,14 +907,14 @@ this.outputUI(\`
907
907
  }
908
908
  `;var $i=`this.showToast('Hello from a JS action.', { variant: 'success' });
909
909
  `;var ne=["floatingFrame","block","dataAdornment","page","toolbarItem","objectSettingsItem","jsAction"],pn={floatingFrame:"Floating frame",block:"Block",dataAdornment:"Data adornment",page:"Routable page",toolbarItem:"Toolbar item",objectSettingsItem:"Object settings item",jsAction:"JS action"},yd={floatingFrame:{directory:"floatingFrames",component:"helloFrame",files:{"config.json":bi,"script.js":wi,"styles.css":xi}},block:{directory:"blocks",component:"helloBlock",files:{"config.json":vi,"script.js":ki,"styles.css":Ci}},dataAdornment:{directory:"dataAdornments",component:"helloAdornment",files:{"config.json":Si,"script.js":_i}},page:{directory:"pages",component:"helloPage",files:{"config.json":Pi,"script.js":Ei,"styles.css":Ti,"eventScripts/greet.js":Ii}},toolbarItem:{directory:"toolbarItems",component:"helloToolbarItem",files:{"config.json":Ai,"script.js":Ni}},objectSettingsItem:{directory:"objectSettingsItems",component:"helloObjectSettingsItem",files:{"config.json":Di,"script.js":Ri}},jsAction:{directory:"actions",component:"helloAction",files:{"config.json":Bi,"script.js":$i}}};function bd(e,t="src"){let{directory:r,component:o,files:n}=yd[e];return Object.entries(n).map(([i,s])=>({path:`${t}/${r}/${o}/${i}`,content:s}))}function ji(e,t="src"){return[...new Set(e)].flatMap(r=>bd(r,t))}import{deflateSync as wd}from"zlib";var mn=512,xd=150,vd=26,hn=46,Fi=.6,kd=hn*.55,Cd=.55,Sd=.47;function _d(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=t+((t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24))>>>0;return t}function Pd(e){let t=_d(e);return{hue:t%360,quarterTurns:(t>>>16)%4}}function Ed(e,t,r){let o=(1-Math.abs(2*r-1))*t,n=e/60,i=o*(1-Math.abs(n%2-1)),s=r-o/2,[l,a,p]=n<1?[o,i,0]:n<2?[i,o,0]:n<3?[0,o,i]:n<4?[0,i,o]:n<5?[i,0,o]:[o,0,i];return[Math.round((l+s)*255),Math.round((a+s)*255),Math.round((p+s)*255)]}function bt(e,t,r,o,n){let i=Math.abs(e)-r+n,s=Math.abs(t)-o+n;return Math.hypot(Math.max(i,0),Math.max(s,0))+Math.min(Math.max(i,s),0)-n}function Qt(e,t,r,o,n){return Math.hypot(e-r,t-o)-n}function Td(e,t){let r=xd,o=hn,n=o*Fi,i=kd,s=bt(e,t,r,r,vd),l=Math.min(Qt(e,t,0,-r-n,o),bt(e,t+r+n/2,i,n/2+1,0)),a=Math.min(Qt(e,t,r+n,0,o),bt(e-r-n/2,t,n/2+1,i,0));s=Math.min(s,l,a);let p=Math.min(Qt(e,t,0,r-n,o),bt(e,t-r+n/2,i,n/2+1,0)),h=Math.min(Qt(e,t,-r+n,0,o),bt(e+r-n/2,t,n/2+1,i,0));return Math.max(s,-p,-h)}function Id(e){let t=mn,r=new Uint8Array(t*t*4),[o,n,i]=Ed(e.hue,Cd,Sd),s=hn*(1+Fi),l=(t-1)/2,a=s/2;for(let p=0;p<t;p+=1)for(let h=0;h<t;h+=1){let w=h-l,x=p-l;for(let v=0;v<e.quarterTurns;v+=1)[w,x]=[-x,w];let d=Td(w+a,x-a),c=Math.min(1,Math.max(0,.5-d));if(c<=0)continue;let y=(p*t+h)*4;r[y]=o,r[y+1]=n,r[y+2]=i,r[y+3]=Math.round(c*255)}return r}var Ad=new Uint32Array(256).map((e,t)=>{let r=t;for(let o=0;o<8;o+=1)r=r&1?3988292384^r>>>1:r>>>1;return r>>>0});function Nd(e){let t=4294967295;for(let r of e)t=(Ad[(t^r)&255]??0)^t>>>8;return(t^4294967295)>>>0}function fn(e,t){let r=Buffer.from(e,"latin1"),o=Buffer.alloc(4);o.writeUInt32BE(t.length);let n=Buffer.alloc(4);return n.writeUInt32BE(Nd(Buffer.concat([r,t]))),Buffer.concat([o,r,t,n])}var Dd=Buffer.from([137,80,78,71,13,10,26,10]);function Rd(e,t,r){if(r.length!==e*t*4)throw new Error(`encodePng: expected ${String(e*t*4)} bytes of RGBA for ${String(e)}x${String(t)}, got ${String(r.length)}`);let o=Buffer.alloc(13);o.writeUInt32BE(e,0),o.writeUInt32BE(t,4),o[8]=8,o[9]=6;let n=e*4,i=Buffer.alloc((n+1)*t);for(let s=0;s<t;s+=1)i.set(r.subarray(s*n,(s+1)*n),s*(n+1)+1);return Buffer.concat([Dd,fn("IHDR",o),fn("IDAT",wd(i,{level:9})),fn("IEND",new Uint8Array(0))])}function Oi(e){return Rd(mn,mn,Id(Pd(e)))}var jd="src/thumbnail.png",Fd=["go","fmo"];async function tr(e){try{return await Bd(e),!0}catch{return!1}}async function rr(e){return await tr(ke(e,"kizen.json"))?"has-manifest":await tr(ke(e,".kizenapp"))?"has-kizenapp":"ok"}async function zi(e,t){let r=ke(e,t);if(!await tr(r))return r;for(let o=1;o<1e3;o++){let n=ke(e,`${t}-${String(o)}`);if(!await tr(n))return n}throw new Error(`Could not find an available directory name for "${t}"`)}function bn(e){let t=e.developerBusinessId.trim(),r=t!==""&&!Fd.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:r,config_template:{},base_config:{},...t?{developer_business_id:{[e.developerEnvironment]:t}}:{}}}async function gn(e,t){let r=t.map(n=>({fullPath:ke(e,...n.path.split("/")),content:n.content})),o=new Set(r.map(n=>$d(n.fullPath)));await Promise.all([...o].map(n=>er(n,{recursive:!0}))),await Promise.all(r.map(n=>yn(n.fullPath,n.content,"utf-8")))}async function nr(e){await er(e.targetDir,{recursive:!0});let t=bn(e);await yn(ke(e.targetDir,"kizen.json"),JSON.stringify(t,null,2)+`
910
- `,"utf-8"),await er(ke(e.targetDir,"src"),{recursive:!0}),await er(ke(e.targetDir,"releaseNotes"),{recursive:!0}),await Promise.all([gn(e.targetDir,ji(e.artifacts??[])),gn(e.targetDir,Lo()),gn(e.targetDir,Le()),yn(ke(e.targetDir,...jd.split("/")),Oi(e.apiName))]),Ne(e.targetDir)}var Re=["name","apiName","externalLink","description","developerBusinessId"],or={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},wn=["name","apiName","description"],xn=/^[a-z_][a-z0-9_]+$/,vn="must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)";function ir(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Mi(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function Li(e,t){let r=t.trim();if(wn.includes(e)&&!r)return`${or[e]} is required`;if(e==="apiName"&&!xn.test(r))return`${or[e]} ${vn}`}function Ui(e,t){return e==="description"?t:t.trim()}function Hi(e,t){let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),ne.filter(o=>r.has(o))}import{jsx as A,jsxs as $}from"react/jsx-runtime";var Je=({text:e})=>A(N,{dimColor:!0,children:e}),Vi=({parentDir:e,defaultBusinessId:t,defaultEnvironment:r})=>{let o=Od(),[n,i]=nt({type:"target-select",cursor:0}),[s,l]=nt("in-place"),[a,p]=nt(()=>Mi(t)),[h,w]=nt(()=>[...ne]),[x,d]=nt(""),[c,y]=nt(e),v=sr((S,g)=>{l(S),d(g.name),i({type:"field-entry",field:0,values:g})},[]),P=sr(async S=>{let g=await rr(S);if(g!=="ok"){i({type:"precheck-error",targetDir:S,reason:g});return}y(S),v("in-place",a)},[a,v]),C=sr(async(S,g)=>{try{let f=await zi(e,S.apiName);y(f),i({type:"confirm",values:S,artifacts:g})}catch(f){i({type:"error",message:f instanceof Error?f.message:String(f)})}},[e]),_=sr(async(S,g,f)=>{try{await nr({targetDir:g,name:S.name,apiName:S.apiName,externalLink:S.externalLink,description:S.description,developerBusinessId:S.developerBusinessId,developerEnvironment:r,artifacts:f}),i({type:"done",targetDir:g})}catch(u){i({type:"error",message:u instanceof Error?u.message:String(u)})}},[r]);if(zd((S,g)=>{if(g.ctrl&&S==="c"){o.exit();return}if(n.type==="target-select"){g.upArrow?i({type:"target-select",cursor:0}):g.downArrow?i({type:"target-select",cursor:1}):g.return?n.cursor===0?P(e):v("sub-dir",a):g.escape&&o.exit();return}if(n.type==="precheck-error"){(g.return||g.escape)&&o.exit();return}if(n.type==="field-entry"){let{field:f,values:u}=n,m=Re[f];if(!m)return;if(g.escape){o.exit();return}if(g.backspace||g.delete){d(b=>b.slice(0,-1));return}if(g.upArrow&&f>0){let b={...u,[m]:x},k=f-1,I=Re[k];i({type:"field-entry",field:k,values:b}),p(b),d(I?b[I]:"");return}if(g.return||g.tab||g.downArrow){let b=Li(m,x);if(b!==void 0){i({type:"field-entry",field:f,values:u,fieldError:b});return}let k=Ui(m,x),I={...u,[m]:k};p(I);let E=f+1;if(E>=Re.length)d(""),i({type:"artifact-select",values:I,cursor:0,selected:h});else{let R=Re[E],M=R?I[R]:"",W=R==="apiName"&&!M?ir(I.name):M;i({type:"field-entry",field:E,values:I}),d(W)}return}S&&!g.ctrl&&!g.meta&&d(b=>b+S);return}if(n.type==="artifact-select"){let{cursor:f,selected:u,values:m}=n;if(g.escape){let b=Re.length-1,k=Re[b];i({type:"field-entry",field:b,values:m}),d(k?m[k]:"");return}if(g.upArrow){i({...n,cursor:Math.max(0,f-1)});return}if(g.downArrow){i({...n,cursor:Math.min(ne.length-1,f+1)});return}if(S===" "){let b=ne[f];if(b){let k=Hi(u,b);w(k),i({...n,selected:k})}return}if(S==="a"){w([...ne]),i({...n,selected:[...ne]});return}if(S==="n"){w([]),i({...n,selected:[]});return}g.return&&(s==="sub-dir"?(i({type:"resolving-target"}),C(m,u)):i({type:"confirm",values:m,artifacts:u}));return}if(n.type==="confirm"){if(g.escape){i({type:"artifact-select",values:n.values,cursor:0,selected:n.artifacts});return}g.return&&(i({type:"writing"}),_(n.values,c,n.artifacts));return}(n.type==="done"||n.type==="error")&&(g.return||g.escape)&&o.exit()}),n.type==="target-select"){let S=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Where should the new plugin live?"}),S.map((g,f)=>{let u=n.cursor===f;return $(V,{gap:2,children:[A(N,{...u&&{color:"cyan"},children:u?"\u276F":" "}),A(N,{bold:u,...u&&{color:"cyan"},children:g.label}),A(N,{dimColor:!0,children:g.desc})]},g.label)})]}),A(Je,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(n.type==="precheck-error"){let{targetDir:S,reason:g}=n;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),A(N,{color:"red",bold:!0,children:"Cannot create plugin"}),$(V,{flexDirection:"column",gap:0,children:[$(N,{children:[S," already contains ",A(N,{bold:!0,children:g==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),A(N,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),A(Je,{text:"Enter or Esc to exit"})]})}if(n.type==="field-entry"){let{field:S,fieldError:g}=n,f=s==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${c}`;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Plugin details"}),A(N,{dimColor:!0,children:f})]}),g!==void 0&&$(N,{color:"red",children:["Error: ",g]}),A(V,{flexDirection:"column",gap:0,children:Re.map((u,m)=>{let b=S===m,k=b?x:a[u],I=wn.includes(u),E=`${or[u]}${I?"":" (optional)"}`;return $(V,{gap:2,children:[A(V,{width:24,children:A(N,{bold:b,...b&&{color:"cyan"},children:E})}),A(N,{...b&&{color:"cyan"},children:">"}),A(N,{children:k}),b&&A(N,{color:"cyan",children:"\u2588"})]},u)})}),A(Je,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(n.type==="artifact-select"){let{cursor:S,selected:g}=n;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Which artifacts should we scaffold?"}),A(N,{dimColor:!0,children:"Each one gets a directory with a config.json and a script that runs."})]}),A(V,{flexDirection:"column",gap:0,children:ne.map((f,u)=>{let m=S===u,b=g.includes(f);return $(V,{gap:1,children:[A(N,{...m&&{color:"cyan"},children:m?"\u276F":" "}),A(N,{...b&&{color:"green"},children:b?"\u25C9":"\u25EF"}),A(N,{bold:m,...m&&{color:"cyan"},children:pn[f]})]},f)})}),A(Je,{text:"\u2191\u2193 move \xB7 Space toggle \xB7 a all \xB7 n none \xB7 Enter continue \xB7 Esc back"})]})}if(n.type==="confirm"){let S=bn({targetDir:c,name:n.values.name,apiName:n.values.apiName,externalLink:n.values.externalLink,description:n.values.description,developerBusinessId:n.values.developerBusinessId,developerEnvironment:r});return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Ready to create"}),$(N,{dimColor:!0,children:["Target: ",c]})]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"kizen.json preview"}),A(N,{children:JSON.stringify(S,null,2)})]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Artifacts"}),n.artifacts.length===0?$(N,{dimColor:!0,children:[" ","none (src/ will hold only thumbnail.png)"]}):n.artifacts.map(g=>$(N,{dimColor:!0,children:[" ",pn[g]]},g))]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{dimColor:!0,children:"Also creates:"}),$(N,{dimColor:!0,children:[" ",ar(c,"src/")]}),$(N,{dimColor:!0,children:[" ",ar(c,"src/thumbnail.png")," (generated placeholder)"]}),$(N,{dimColor:!0,children:[" ",ar(c,"releaseNotes/")]}),$(N,{dimColor:!0,children:[" ",ar(c,".gitignore")," (adds .kizenapp/)"]})]}),A(Je,{text:"Enter to create \xB7 Esc to go back"})]})}return n.type==="resolving-target"?A(V,{paddingY:1,paddingX:2,children:A(N,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):n.type==="writing"?A(V,{paddingY:1,paddingX:2,children:A(N,{dimColor:!0,children:"Creating plugin\u2026"})}):n.type==="done"?$(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(N,{color:"green",bold:!0,children:["Plugin created at ",n.targetDir]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{dimColor:!0,children:"Next steps:"}),$(N,{children:[" ","cd ",n.targetDir]}),$(N,{children:[" ","npx --yes @kizenapps/cli dev"]}),$(N,{dimColor:!0,children:[" ","Replace src/thumbnail.png with real artwork before publishing."]})]}),A(Je,{text:"Enter or Esc to exit"})]}):$(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),A(N,{color:"red",bold:!0,children:"Failed to create plugin"}),A(N,{children:n.message}),A(Je,{text:"Enter or Esc to exit"})]})};var Md="A hello-world Kizen plugin.";function Ld(e){if(e===void 0||e.trim()===""||e.trim()==="all")return[...ne];if(e.trim()==="none")return[];let t=e.split(",").map(o=>o.trim()).filter(o=>o!==""),r=t.filter(o=>!ne.includes(o));if(r.length>0)throw new Error(`Unknown artifact type(s): ${r.join(", ")}. Valid types: ${ne.join(", ")}, or "all" / "none".`);return[...new Set(t)]}function Ud(e,t,r){let o=e.name?.trim()??"";if(o==="")throw new Error("--name is required for a non-interactive run.");let n=(e.apiName?.trim()??"")||ir(o);if(!xn.test(n))throw new Error(`api_name "${n}" is invalid: ${vn}. Pass --api-name.`);let i=e.description?.trim(),s=e.businessId?.trim()??t.businessId,l=Vd(e,t);return{targetDir:r,name:o,apiName:n,externalLink:e.externalLink?.trim()??"",description:i===void 0||i===""?Md:i,developerBusinessId:s,developerEnvironment:l,artifacts:Ld(e.artifacts)}}function Hd(e){return X.includes(e)}function Vd(e,t){let r=e.environment?.trim();if(r!==void 0&&r!==""){if(!Hd(r))throw new Error(`Unknown environment "${r}". Valid environments: ${X.join(", ")}.`);return r}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 Wi(e,t,r,o){let n;try{n=Ud(e,t,r)}catch(l){o.writeStderr(`Error: ${l instanceof Error?l.message:String(l)}
910
+ `,"utf-8"),await er(ke(e.targetDir,"src"),{recursive:!0}),await er(ke(e.targetDir,"releaseNotes"),{recursive:!0}),await Promise.all([gn(e.targetDir,ji(e.artifacts??[])),gn(e.targetDir,Lo()),gn(e.targetDir,Le()),yn(ke(e.targetDir,...jd.split("/")),Oi(e.apiName))]),Ne(e.targetDir)}var Re=["name","apiName","externalLink","description","developerBusinessId"],or={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},wn=["name","apiName","description"],xn=/^[a-z_][a-z0-9_]+$/,vn="must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)";function ir(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Mi(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function Li(e,t){let r=t.trim();if(wn.includes(e)&&!r)return`${or[e]} is required`;if(e==="apiName"&&!xn.test(r))return`${or[e]} ${vn}`}function Hi(e,t){return e==="description"?t:t.trim()}function Ui(e,t){let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),ne.filter(o=>r.has(o))}import{jsx as A,jsxs as $}from"react/jsx-runtime";var Je=({text:e})=>A(N,{dimColor:!0,children:e}),Vi=({parentDir:e,defaultBusinessId:t,defaultEnvironment:r})=>{let o=Od(),[n,i]=nt({type:"target-select",cursor:0}),[s,l]=nt("in-place"),[a,p]=nt(()=>Mi(t)),[h,w]=nt(()=>[...ne]),[x,d]=nt(""),[c,y]=nt(e),v=sr((S,g)=>{l(S),d(g.name),i({type:"field-entry",field:0,values:g})},[]),P=sr(async S=>{let g=await rr(S);if(g!=="ok"){i({type:"precheck-error",targetDir:S,reason:g});return}y(S),v("in-place",a)},[a,v]),C=sr(async(S,g)=>{try{let f=await zi(e,S.apiName);y(f),i({type:"confirm",values:S,artifacts:g})}catch(f){i({type:"error",message:f instanceof Error?f.message:String(f)})}},[e]),_=sr(async(S,g,f)=>{try{await nr({targetDir:g,name:S.name,apiName:S.apiName,externalLink:S.externalLink,description:S.description,developerBusinessId:S.developerBusinessId,developerEnvironment:r,artifacts:f}),i({type:"done",targetDir:g})}catch(u){i({type:"error",message:u instanceof Error?u.message:String(u)})}},[r]);if(zd((S,g)=>{if(g.ctrl&&S==="c"){o.exit();return}if(n.type==="target-select"){g.upArrow?i({type:"target-select",cursor:0}):g.downArrow?i({type:"target-select",cursor:1}):g.return?n.cursor===0?P(e):v("sub-dir",a):g.escape&&o.exit();return}if(n.type==="precheck-error"){(g.return||g.escape)&&o.exit();return}if(n.type==="field-entry"){let{field:f,values:u}=n,m=Re[f];if(!m)return;if(g.escape){o.exit();return}if(g.backspace||g.delete){d(b=>b.slice(0,-1));return}if(g.upArrow&&f>0){let b={...u,[m]:x},k=f-1,I=Re[k];i({type:"field-entry",field:k,values:b}),p(b),d(I?b[I]:"");return}if(g.return||g.tab||g.downArrow){let b=Li(m,x);if(b!==void 0){i({type:"field-entry",field:f,values:u,fieldError:b});return}let k=Hi(m,x),I={...u,[m]:k};p(I);let E=f+1;if(E>=Re.length)d(""),i({type:"artifact-select",values:I,cursor:0,selected:h});else{let R=Re[E],M=R?I[R]:"",W=R==="apiName"&&!M?ir(I.name):M;i({type:"field-entry",field:E,values:I}),d(W)}return}S&&!g.ctrl&&!g.meta&&d(b=>b+S);return}if(n.type==="artifact-select"){let{cursor:f,selected:u,values:m}=n;if(g.escape){let b=Re.length-1,k=Re[b];i({type:"field-entry",field:b,values:m}),d(k?m[k]:"");return}if(g.upArrow){i({...n,cursor:Math.max(0,f-1)});return}if(g.downArrow){i({...n,cursor:Math.min(ne.length-1,f+1)});return}if(S===" "){let b=ne[f];if(b){let k=Ui(u,b);w(k),i({...n,selected:k})}return}if(S==="a"){w([...ne]),i({...n,selected:[...ne]});return}if(S==="n"){w([]),i({...n,selected:[]});return}g.return&&(s==="sub-dir"?(i({type:"resolving-target"}),C(m,u)):i({type:"confirm",values:m,artifacts:u}));return}if(n.type==="confirm"){if(g.escape){i({type:"artifact-select",values:n.values,cursor:0,selected:n.artifacts});return}g.return&&(i({type:"writing"}),_(n.values,c,n.artifacts));return}(n.type==="done"||n.type==="error")&&(g.return||g.escape)&&o.exit()}),n.type==="target-select"){let S=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Where should the new plugin live?"}),S.map((g,f)=>{let u=n.cursor===f;return $(V,{gap:2,children:[A(N,{...u&&{color:"cyan"},children:u?"\u276F":" "}),A(N,{bold:u,...u&&{color:"cyan"},children:g.label}),A(N,{dimColor:!0,children:g.desc})]},g.label)})]}),A(Je,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(n.type==="precheck-error"){let{targetDir:S,reason:g}=n;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),A(N,{color:"red",bold:!0,children:"Cannot create plugin"}),$(V,{flexDirection:"column",gap:0,children:[$(N,{children:[S," already contains ",A(N,{bold:!0,children:g==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),A(N,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),A(Je,{text:"Enter or Esc to exit"})]})}if(n.type==="field-entry"){let{field:S,fieldError:g}=n,f=s==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${c}`;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Plugin details"}),A(N,{dimColor:!0,children:f})]}),g!==void 0&&$(N,{color:"red",children:["Error: ",g]}),A(V,{flexDirection:"column",gap:0,children:Re.map((u,m)=>{let b=S===m,k=b?x:a[u],I=wn.includes(u),E=`${or[u]}${I?"":" (optional)"}`;return $(V,{gap:2,children:[A(V,{width:24,children:A(N,{bold:b,...b&&{color:"cyan"},children:E})}),A(N,{...b&&{color:"cyan"},children:">"}),A(N,{children:k}),b&&A(N,{color:"cyan",children:"\u2588"})]},u)})}),A(Je,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(n.type==="artifact-select"){let{cursor:S,selected:g}=n;return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Which artifacts should we scaffold?"}),A(N,{dimColor:!0,children:"Each one gets a directory with a config.json and a script that runs."})]}),A(V,{flexDirection:"column",gap:0,children:ne.map((f,u)=>{let m=S===u,b=g.includes(f);return $(V,{gap:1,children:[A(N,{...m&&{color:"cyan"},children:m?"\u276F":" "}),A(N,{...b&&{color:"green"},children:b?"\u25C9":"\u25EF"}),A(N,{bold:m,...m&&{color:"cyan"},children:pn[f]})]},f)})}),A(Je,{text:"\u2191\u2193 move \xB7 Space toggle \xB7 a all \xB7 n none \xB7 Enter continue \xB7 Esc back"})]})}if(n.type==="confirm"){let S=bn({targetDir:c,name:n.values.name,apiName:n.values.apiName,externalLink:n.values.externalLink,description:n.values.description,developerBusinessId:n.values.developerBusinessId,developerEnvironment:r});return $(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Ready to create"}),$(N,{dimColor:!0,children:["Target: ",c]})]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"kizen.json preview"}),A(N,{children:JSON.stringify(S,null,2)})]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{bold:!0,children:"Artifacts"}),n.artifacts.length===0?$(N,{dimColor:!0,children:[" ","none (src/ will hold only thumbnail.png)"]}):n.artifacts.map(g=>$(N,{dimColor:!0,children:[" ",pn[g]]},g))]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{dimColor:!0,children:"Also creates:"}),$(N,{dimColor:!0,children:[" ",ar(c,"src/")]}),$(N,{dimColor:!0,children:[" ",ar(c,"src/thumbnail.png")," (generated placeholder)"]}),$(N,{dimColor:!0,children:[" ",ar(c,"releaseNotes/")]}),$(N,{dimColor:!0,children:[" ",ar(c,".gitignore")," (adds .kizenapp/)"]})]}),A(Je,{text:"Enter to create \xB7 Esc to go back"})]})}return n.type==="resolving-target"?A(V,{paddingY:1,paddingX:2,children:A(N,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):n.type==="writing"?A(V,{paddingY:1,paddingX:2,children:A(N,{dimColor:!0,children:"Creating plugin\u2026"})}):n.type==="done"?$(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),$(N,{color:"green",bold:!0,children:["Plugin created at ",n.targetDir]}),$(V,{flexDirection:"column",gap:0,children:[A(N,{dimColor:!0,children:"Next steps:"}),$(N,{children:[" ","cd ",n.targetDir]}),$(N,{children:[" ","npx --yes @kizenapps/cli dev"]}),$(N,{dimColor:!0,children:[" ","Replace src/thumbnail.png with real artwork before publishing."]})]}),A(Je,{text:"Enter or Esc to exit"})]}):$(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[A(K,{}),A(N,{color:"red",bold:!0,children:"Failed to create plugin"}),A(N,{children:n.message}),A(Je,{text:"Enter or Esc to exit"})]})};var Md="A hello-world Kizen plugin.";function Ld(e){if(e===void 0||e.trim()===""||e.trim()==="all")return[...ne];if(e.trim()==="none")return[];let t=e.split(",").map(o=>o.trim()).filter(o=>o!==""),r=t.filter(o=>!ne.includes(o));if(r.length>0)throw new Error(`Unknown artifact type(s): ${r.join(", ")}. Valid types: ${ne.join(", ")}, or "all" / "none".`);return[...new Set(t)]}function Hd(e,t,r){let o=e.name?.trim()??"";if(o==="")throw new Error("--name is required for a non-interactive run.");let n=(e.apiName?.trim()??"")||ir(o);if(!xn.test(n))throw new Error(`api_name "${n}" is invalid: ${vn}. Pass --api-name.`);let i=e.description?.trim(),s=e.businessId?.trim()??t.businessId,l=Vd(e,t);return{targetDir:r,name:o,apiName:n,externalLink:e.externalLink?.trim()??"",description:i===void 0||i===""?Md:i,developerBusinessId:s,developerEnvironment:l,artifacts:Ld(e.artifacts)}}function Ud(e){return X.includes(e)}function Vd(e,t){let r=e.environment?.trim();if(r!==void 0&&r!==""){if(!Ud(r))throw new Error(`Unknown environment "${r}". Valid environments: ${X.join(", ")}.`);return r}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 Wi(e,t,r,o){let n;try{n=Hd(e,t,r)}catch(l){o.writeStderr(`Error: ${l instanceof Error?l.message:String(l)}
911
911
  `),o.setExitCode(1);return}let i=await o.precheckTargetDir(r);if(i!=="ok"){let l=i==="has-manifest"?"kizen.json":".kizenapp/";o.writeStderr(`Error: ${r} already contains ${l}. Refusing to overwrite an existing plugin.
912
912
  `),o.setExitCode(1);return}try{await o.createPlugin(n)}catch(l){o.writeStderr(`Error: ${l instanceof Error?l.message:String(l)}
913
913
  `),o.setExitCode(1);return}let s=n.artifacts&&n.artifacts.length>0?n.artifacts.join(", "):"none";o.writeStdout(`Created plugin ${n.apiName} at ${r}
914
914
  `),o.writeStdout(`Artifacts: ${s}
915
915
  `),o.writeStdout(`Thumbnail: src/thumbnail.png (generated placeholder; replace it before publishing)
916
916
  `),n.developerBusinessId.trim()===""&&o.writeStderr(`Warning: no developer_business_id configured, so this plugin cannot be preview-published yet.
917
- `)}function Ki(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: ${X.join(", ")} (defaults to saved credentials)`).option("--artifacts <list>",`comma-separated artifact types, or "all" / "none" (default: all). Types: ${ne.join(", ")}`).action(async t=>{let r=process.cwd(),o=await te(),n=o?.businessId??"",i=o?.environment??"go",s=Object.values(t).some(p=>p!==void 0);if(!process.stdin.isTTY||!process.stdout.isTTY||s){await Wi(t,{businessId:n,environment:i},r,{precheckTargetDir:rr,createPlugin:nr,writeStdout:p=>{process.stdout.write(p)},writeStderr:p=>{process.stderr.write(p)},setExitCode:p=>{process.exitCode=p}});return}let{waitUntilExit:a}=Kd(Wd(Vi,{parentDir:r,defaultBusinessId:n,defaultEnvironment:i}),{exitOnCtrlC:!1});await a()})}import{createElement as _s}from"react";import{render as Ps}from"ink";import{useCallback as ot,useEffect as mr,useRef as Ce,useState as ie}from"react";import{Box as Q,Text as j,useInput as Mu}from"ink";import{PluginValidationError as Lu}from"@kizenapps/packager";import{watch as Uu}from"fs";import{createServer as Hu}from"http";import{join as ks}from"path";import{WebSocketServer as Vu}from"ws";import{createReadStream as as,realpathSync as cu}from"fs";import{access as du,readdir as uu,readFile as pu,realpath as fu,stat as ls}from"fs/promises";import{dirname as mu,extname as cs,join as St,resolve as hu,sep as Nn}from"path";import{fileURLToPath as gu}from"url";var Jd=new Set(["set-cookie","strict-transport-security","content-security-policy","content-security-policy-report-only","x-frame-options","content-encoding","content-length"]);function lr(e){let t={};for(let[r,o]of Object.entries(e)){let n=r.toLowerCase();Jd.has(n)||n.startsWith("access-control-")||(t[r]=o)}return t}var kn=10*1024*1024,qd=6e4,Gd=200,wt=class extends Error{bytesRead;limit;constructor(t,r){super(`Upstream response exceeded ${String(r)} bytes (read ${String(t)}).`),this.name="ProxyResponseTooLargeError",this.bytesRead=t,this.limit=r}};async function Cn(e,t){let r=e.body;if(r===null)return Buffer.alloc(0);let o=[],n=0;for await(let i of r){if(n+=i.length,n>t)throw new wt(n,t);o.push(i)}return Buffer.concat(o)}async function Ji(e){let t=lr(Object.fromEntries(e.headers)),r=await Cn(e,kn);return{status:e.status,headers:t,body:r}}function qi(e={}){let{onChange:t,enabled:r=!0}=e;if(!r)return{async get(s,l){return{response:await Ji(await l()),fromCache:!1}},clear(){}};let o=new Map,n=()=>{t?.(o.size)},i=s=>{o.delete(s)&&n()};return{get(s,l){let a=o.get(s);if(a!==void 0){if(Date.now()-a.insertedAt<qd)return a.promise.then(h=>({response:h,fromCache:!0}));i(s)}if(o.size>=Gd){let h=o.keys().next().value;h!==void 0&&i(h)}let p=l().then(Ji).catch(h=>{throw i(s),h});return o.set(s,{insertedAt:Date.now(),promise:p}),n(),p.then(h=>((h.status<200||h.status>=300)&&i(s),{response:h,fromCache:!1}))},clear(){o.clear(),n()}}}var Sn={".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"};var _n={prod:"https://plugin-wizard.kizen.com",dev:"https://plugin-wizard.kizen.dev",localDev:"http://localhost:9823"};function xt(e){let t=process.env.PLUGIN_WIZARD_URL;return t!==void 0&&t!==""?t:e==="prod"?process.env.PLUGIN_WIZARD_URL_PROD||_n.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!==""?_n.localDev:_n.dev}import{spawn as In}from"child_process";import{writeFile as Qi,rm as Tn,mkdtemp as Qd,access as eu}from"fs/promises";import{join as kt}from"path";import{tmpdir as tu}from"os";var Gi=`awslambdaric
917
+ `)}function Ki(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: ${X.join(", ")} (defaults to saved credentials)`).option("--artifacts <list>",`comma-separated artifact types, or "all" / "none" (default: all). Types: ${ne.join(", ")}`).action(async t=>{let r=process.cwd(),o=await te(),n=o?.businessId??"",i=o?.environment??"go",s=Object.values(t).some(p=>p!==void 0);if(!process.stdin.isTTY||!process.stdout.isTTY||s){await Wi(t,{businessId:n,environment:i},r,{precheckTargetDir:rr,createPlugin:nr,writeStdout:p=>{process.stdout.write(p)},writeStderr:p=>{process.stderr.write(p)},setExitCode:p=>{process.exitCode=p}});return}let{waitUntilExit:a}=Kd(Wd(Vi,{parentDir:r,defaultBusinessId:n,defaultEnvironment:i}),{exitOnCtrlC:!1});await a()})}import{createElement as _s}from"react";import{render as Ps}from"ink";import{useCallback as ot,useEffect as mr,useRef as Ce,useState as ie}from"react";import{Box as Q,Text as j,useInput as Mu}from"ink";import{PluginValidationError as Lu}from"@kizenapps/packager";import{watch as Hu}from"fs";import{createServer as Uu}from"http";import{join as ks}from"path";import{WebSocketServer as Vu}from"ws";import{createReadStream as as,realpathSync as cu}from"fs";import{access as du,readdir as uu,readFile as pu,realpath as fu,stat as ls}from"fs/promises";import{dirname as mu,extname as cs,join as St,resolve as hu,sep as Nn}from"path";import{fileURLToPath as gu}from"url";var Jd=new Set(["set-cookie","strict-transport-security","content-security-policy","content-security-policy-report-only","x-frame-options","content-encoding","content-length"]);function lr(e){let t={};for(let[r,o]of Object.entries(e)){let n=r.toLowerCase();Jd.has(n)||n.startsWith("access-control-")||(t[r]=o)}return t}var kn=10*1024*1024,qd=6e4,Gd=200,wt=class extends Error{bytesRead;limit;constructor(t,r){super(`Upstream response exceeded ${String(r)} bytes (read ${String(t)}).`),this.name="ProxyResponseTooLargeError",this.bytesRead=t,this.limit=r}};async function Cn(e,t){let r=e.body;if(r===null)return Buffer.alloc(0);let o=[],n=0;for await(let i of r){if(n+=i.length,n>t)throw new wt(n,t);o.push(i)}return Buffer.concat(o)}async function Ji(e){let t=lr(Object.fromEntries(e.headers)),r=await Cn(e,kn);return{status:e.status,headers:t,body:r}}function qi(e={}){let{onChange:t,enabled:r=!0}=e;if(!r)return{async get(s,l){return{response:await Ji(await l()),fromCache:!1}},clear(){}};let o=new Map,n=()=>{t?.(o.size)},i=s=>{o.delete(s)&&n()};return{get(s,l){let a=o.get(s);if(a!==void 0){if(Date.now()-a.insertedAt<qd)return a.promise.then(h=>({response:h,fromCache:!0}));i(s)}if(o.size>=Gd){let h=o.keys().next().value;h!==void 0&&i(h)}let p=l().then(Ji).catch(h=>{throw i(s),h});return o.set(s,{insertedAt:Date.now(),promise:p}),n(),p.then(h=>((h.status<200||h.status>=300)&&i(s),{response:h,fromCache:!1}))},clear(){o.clear(),n()}}}var Sn={".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"};var _n={prod:"https://plugin-wizard.kizen.com",dev:"https://plugin-wizard.kizen.dev",localDev:"http://localhost:9823"};function xt(e){let t=process.env.PLUGIN_WIZARD_URL;return t!==void 0&&t!==""?t:e==="prod"?process.env.PLUGIN_WIZARD_URL_PROD||_n.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!==""?_n.localDev:_n.dev}import{spawn as In}from"child_process";import{writeFile as Qi,rm as Tn,mkdtemp as Qd,access as eu}from"fs/promises";import{join as kt}from"path";import{tmpdir as tu}from"os";var Gi=`awslambdaric
918
918
  bcrypt
919
919
  boto3
920
920
  fpdf2
@@ -1098,13 +1098,13 @@ sys.stdout.flush()
1098
1098
  `)}}),a.on("end",()=>{if(w.length>0){let x=w.replace(/\r$/,"");h.push(x),r?.(x,p)}}),h},l=s(i.stderr,"stderr");s(i.stdout,"stdout"),i.on("error",n),i.on("close",a=>{if(a===0)o();else{let p=l.slice(-10).join(`
1099
1099
  `).trim(),h=p.length>0?`: ${p}`:"";n(new Error(`${e} exited with code ${String(a)}${h}`))}})})}var En=null;function su(e,t){if(vt)return t&&En?.add(t),vt;let r=new Set;t&&r.add(t),En=r;let o=i=>{for(let s of r)s(i)},n=kt(cr,"bin","python");return vt=(async()=>{try{let i=!1;try{await eu(n);let s=await os(n);i=s!==null&&ns(s)}catch{i=!1}if(!i){await Tn(cr,{recursive:!0,force:!0}).catch(()=>{});let s=await iu(e);await es(s,["-m","venv",cr])}return o({kind:"start"}),await es(n,["-m","pip","install","--disable-pip-version-check",...rs],(s,l)=>{o({kind:"log",line:s,stream:l})}),o({kind:"complete"}),n}catch(i){let s=i instanceof Error?i.message:String(i);throw o({kind:"error",message:s}),vt=null,await Tn(cr,{recursive:!0,force:!0}).catch(()=>{}),i}finally{En=null}})(),vt}function au(e){let t="__KIZEN_RESULT_START__",r="__KIZEN_RESULT_END__",o=e.indexOf(t),n=e.indexOf(r);if(o===-1||n===-1)return{userStdout:e,result:null};let i=e.slice(0,o).trimEnd(),s=e.slice(o+t.length,n).trim();try{let l=JSON.parse(s);return{userStdout:i,result:l}}catch{return{userStdout:e,result:null}}}function lu(e){return{success:!1,outputValues:{},logs:[],stdout:"",stderr:"",error:e,exitCode:1,durationMs:0}}async function is(e){let t=e.timeout??nu;if(!ou(e.scriptRuntime))return lu(`Unsupported runtime "${e.scriptRuntime}". Supported runtimes: ${ts.join(", ")}. Update the step's config.json "runtime" field (e.g. "python 3.13").`);let r=await su(e.scriptRuntime,e.onInstallProgress),o=Date.now(),n;try{n=await Qd(kt(tu(),"kizen-step-"));let i=kt(n,"wrapper.py"),s=kt(n,"script.py");await Promise.all([Qi(i,ru,"utf-8"),Qi(s,e.script,"utf-8")]);let l={...process.env,__KIZEN_INPUTS__:JSON.stringify(e.inputs),__KIZEN_SECRETS__:JSON.stringify(e.secrets),__KIZEN_SCRIPT_PATH__:s},{exitCode:a,stdout:p,stderr:h}=await new Promise(y=>{let v=[],P=[],C=!1,_=In(r,[i],{env:l,cwd:n,stdio:["ignore","pipe","pipe"]}),S=setTimeout(()=>{_.kill("SIGKILL")},t);_.stdout.on("data",f=>{v.push(f)}),_.stderr.on("data",f=>{P.push(f)});let g=f=>{C||(C=!0,clearTimeout(S),y({exitCode:f??1,stdout:Buffer.concat(v).toString("utf-8"),stderr:Buffer.concat(P).toString("utf-8")}))};_.on("close",g),_.on("error",f=>{C||(C=!0,clearTimeout(S),y({exitCode:1,stdout:"",stderr:f.message}))})}),w=Date.now()-o,{userStdout:x,result:d}=au(p);if(d){let y={success:d.success,outputValues:d.outputValues,logs:d.logs,stdout:x,stderr:h,exitCode:a,durationMs:w};return d.error!==null&&(y.error=d.error),d.httpRequests&&(y.httpRequests=d.httpRequests),y}let c={success:!1,outputValues:{},logs:[],stdout:x,stderr:h,exitCode:a,durationMs:w};return a!==0&&(c.error=`Process exited with code ${String(a)}`),c}finally{n&&Tn(n,{recursive:!0,force:!0})}}var ss=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 ds,CRYPTO_VERSION as us,deserializeEnvelope as yu,encrypt as bu,serializeEnvelope as wu}from"@kizenapps/packager";function An(e){if(e.kind==="info")return e.message;let t=e.fromCache?" [cache]":"",r=e.upstreamStatus!==void 0?` (upstream ${String(e.upstreamStatus)})`:"";return`${e.method} ${e.url} \u2192 ${String(e.status)}${r}${t}`}var xu=2*1024*1024,vu=new Set([".DS_Store",".gitignore"]);function ku(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 hs=["kizen.com","kizen.dev"];function Cu(e){let t;try{t=new URL(e)}catch{return!1}let r=t.hostname.toLowerCase();return r==="localhost"||r==="127.0.0.1"||r==="[::1]"?!0:t.protocol!=="https:"?!1:hs.some(o=>r===o||r.endsWith("."+o))}function Su(e){let t;try{t=new URL(e)}catch{return!1}if(t.protocol!=="https:")return!1;let r=t.hostname.toLowerCase();return hs.some(o=>r===o||r.endsWith("."+o))}function _u(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 ps(e,t){if(t.includes("\0"))return null;let r=t.replace(/^\/+/,""),o=hu(e,r);if(o!==e&&!o.startsWith(e+Nn))return null;try{let n=await fu(o);return n!==e&&!n.startsWith(e+Nn)?null:n}catch{return null}}function fs(e,t){let r=t===e?"":t.slice(e.length+1);return r===""?!1:r.split(Nn).some(n=>Bt.has(n))}function gs(){let e=gu(import.meta.url);return St(mu(e),"viewer")}function ms(e,t,r){if(e.includes("/external-integrations/proxy")&&t["content-type"]?.includes("application/json"))try{let o=JSON.parse(r.toString("utf8"));return typeof o.status_code=="number"?o.status_code:void 0}catch{return}}async function Dn(e){try{return await du(e),!0}catch{return!1}}function ys(e,t,r,o,n,i,s,l,a,p,h){let w=qi({onChange:l,enabled:h}),x=cu(p);return(d,c)=>{(async()=>{let y=d.url??"/";try{if(!ku(d.headers.host)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if((d.method==="POST"||d.method==="PATCH"||d.method==="DELETE")&&!_u(d.headers.origin)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if(t(`Received request: ${y}`),y==="/api/credentials"){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({credentials:o.current??null,activeProfile:n.current??null}));return}if(y==="/api/credential-profiles"&&d.method==="GET"){let f=await Ae();c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({profiles:f,active:n.current}));return}if(y==="/api/credentials/switch"&&d.method==="POST"){let f=[];for await(let k of d)f.push(k);let m=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}").profile,b=m===void 0||m===""?await te():await ve(m);if(b!==null){o.current=b,n.current=m??void 0;let k=n.current,I=await he(i);await Ee(i,{...I,credentialMode:"global",...k!==void 0&&{activeCredentialProfile:k}}),s({type:"credentials-updated",credentials:b,activeProfile:n.current??null})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:b!==null}));return}if(y==="/api/bundle"){let f=St(process.cwd(),".kizenapp","bundle.json");try{let u=await pu(f,"utf-8");c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(u)}catch{c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end("{}")}return}if(y==="/api/last-path"&&d.method==="POST"){let f=[];for await(let m of d)f.push(m);let u=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}");if(typeof u.path=="string"){a.current=u.path;let m=await he(i);await Ee(i,{...m,lastPath:u.path})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(y==="/api/encryption-target"&&d.method==="GET"){let u=(await he(i)).encryptionTarget==="dev"?"dev":"prod";c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({target:u}));return}if(y==="/api/encryption-target"&&d.method==="POST"){let f=[];for await(let k of d)f.push(k);let u=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}"),m=u!==null&&typeof u=="object"?u:{};if(m.target!=="dev"&&m.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 b=await he(i);await Ee(i,{...b,encryptionTarget:m.target}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(y==="/api/execute-step"&&d.method==="POST"){let f=[];for await(let k of d)f.push(k);let u=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}");if(typeof u.script!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: script"}));return}let m={script:u.script,scriptRuntime:u.scriptRuntime??"python-3-13",inputs:Zi(u.inputs),secrets:u.secrets??{},onInstallProgress:k=>{k.kind==="start"?s({type:"venv-install-start"}):k.kind==="log"?s({type:"venv-install-log",line:k.line,stream:k.stream}):k.kind==="complete"?s({type:"venv-install-complete"}):s({type:"venv-install-error",message:k.message})}};typeof u.timeout=="number"&&u.timeout>0&&(m.timeout=Math.min(u.timeout,300*1e3));let b=await is(m);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(b));return}if(y==="/api/proxy-cache/clear"){w.clear(),r({kind:"info",message:"Proxy cache cleared"}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(y==="/api/local/encrypt"&&d.method==="POST"){let f=[];for await(let m of d)f.push(m);let u=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}");if(typeof u.publicKeyPem!="string"||typeof u.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 m=bu(u.value,u.publicKeyPem),b=wu(m);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(b))}catch(m){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:m.message}))}return}if(y==="/api/local/validate"&&d.method==="POST"){let f=[];for await(let E of d)f.push(E);let u=JSON.parse(Buffer.concat(f).toString("utf-8")||"{}");if(typeof u.value!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: value"}));return}let m,b;try{m=yu(u.value)}catch(E){b=E.message}if(b!==void 0||m===void 0){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:!1,checks:[],error:b}));return}let k=E=>Buffer.from(E,"base64").length,I=[{label:"Version",expected:String(us),actual:String(m.v),pass:m.v===us},{label:"Algorithm",expected:ds,actual:m.alg,pass:m.alg===ds},{label:"Wrapped key",expected:"384 bytes (RSA-3072)",actual:`${String(k(m.k))} bytes`,pass:k(m.k)===384},{label:"IV",expected:"12 bytes",actual:`${String(k(m.iv))} bytes`,pass:k(m.iv)===12},{label:"Auth tag",expected:"16 bytes",actual:`${String(k(m.tag))} bytes`,pass:k(m.tag)===16},{label:"Ciphertext",expected:"\u2265 1 byte",actual:`${String(k(m.ct))} bytes`,pass:k(m.ct)>=1}];c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:I.every(E=>E.pass),checks:I}));return}if(y.startsWith("/api/wizard")){let f=d.headers["x-encryption-target"],m=(Array.isArray(f)?f[0]:f)==="dev"?"dev":"prod",b=xt(m);if(!Cu(b)){c.writeHead(500,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:`Encryption API host is not allowed: ${b}`}));return}let k=y.slice(11)||"/",I=`${b}${k}`,E=d.method??"GET",R=[];for await(let je of d)R.push(je);let{host:M,"x-encryption-target":W,...ae}=d.headers,ue=R.length>0?Buffer.concat(R):void 0,pe=ue&&ue.length>0?ue:void 0,le;try{le=await fetch(I,{method:E,headers:ae,...pe!==void 0&&{body:pe}})}catch(je){let xr=je.code==="ECONNREFUSED"?`plugin-wizard is not running at ${b}`:`Failed to reach plugin-wizard: ${je.message}`;c.writeHead(503,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:xr}));return}let se=lr(Object.fromEntries(le.headers)),it=await le.arrayBuffer();c.writeHead(le.status,se),c.end(Buffer.from(it));return}if(y.startsWith("/api/proxy")){let f=d.headers["x-proxy-target"];if(typeof f!="string"){c.writeHead(400),c.end("Missing x-proxy-target header");return}if(!Su(f)){c.writeHead(400),c.end("Invalid proxy target");return}let u=y.slice(10)||"/",m=`${f}${u}`,b=d.method??"GET",k=[];for await(let le of d)k.push(le);let{host:I,"x-proxy-target":E,...R}=d.headers;if(b==="GET"){let le=`GET::${m}`,{response:se,fromCache:it}=await w.get(le,()=>fetch(m,{method:"GET",headers:R}));r({kind:"request",method:"GET",status:se.status,upstreamStatus:ms(u,se.headers,se.body),fromCache:it,url:u}),c.writeHead(se.status,se.headers),c.end(se.body);return}let M=k.length>0?Buffer.concat(k):void 0,W=M&&M.length>0?M:void 0,ae=await fetch(m,{method:b,headers:R,...W!==void 0&&{body:W}}),ue=lr(Object.fromEntries(ae.headers)),pe=await Cn(ae,kn);r({kind:"request",method:b,status:ae.status,upstreamStatus:ms(u,ue,pe),fromCache:!1,url:u}),c.writeHead(ae.status,ue),c.end(pe);return}if(y.startsWith("/api/source/tree")&&d.method==="GET"){let u=new URL(y,"http://localhost").searchParams.get("path")??"",m=await ps(x,u);if(m===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(fs(x,m)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let b=await uu(m,{withFileTypes:!0}),k=await Promise.all(b.filter(E=>E.isDirectory()?!Bt.has(E.name):E.isFile()?!vu.has(E.name):!1).map(async E=>{let R=E.isDirectory()?"dir":"file",M={name:E.name,kind:R};if(R==="file")try{let W=await ls(St(m,E.name));M.size=W.size}catch{}return M}));k.sort((E,R)=>E.kind!==R.kind?E.kind==="dir"?-1:1:E.name.localeCompare(R.name));let I=m===x?"":m.slice(x.length+1);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({path:I,entries:k}))}catch(b){let k=b instanceof Error?b.message:String(b);t(`source/tree failed (${u}): ${k}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}if(y.startsWith("/api/source/file")&&d.method==="GET"){let u=new URL(y,"http://localhost").searchParams.get("path")??"";if(u===""){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing path"}));return}let m=await ps(x,u);if(m===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(fs(x,m)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let b=await ls(m);if(!b.isFile()){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not a file"}));return}if(b.size>xu){c.writeHead(413,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"File too large",size:b.size}));return}let k=cs(m).toLowerCase(),I=Sn[k],E=ss.has(k),R=I??(E?"text/plain; charset=utf-8":"application/octet-stream");c.writeHead(200,{"Content-Type":R,"Content-Length":String(b.size)}),as(m).pipe(c)}catch(b){let k=b instanceof Error?b.message:String(b);t(`source/file failed (${u}): ${k}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}let C=St(e,y==="/"?"/index.html":y),_=await Dn(C)?C:St(e,"index.html"),S=cs(_),g=Sn[S]??"application/octet-stream";c.writeHead(200,{"Content-Type":g}),as(_).pipe(c)}catch(v){if(y.startsWith("/api/proxy")){let P=y.slice(10)||"/",C=d.method??"GET";v instanceof wt?r({kind:"info",message:`${C} ${P} \u2192 502 (response exceeded ${String(v.limit)} bytes)`}):r({kind:"request",method:C,status:502,fromCache:!1,url:P})}else r({kind:"info",message:`Error handling ${y}: ${v instanceof Error?v.message:String(v)}`});c.headersSent||(c.writeHead(502),c.end("Bad Gateway"))}})()}}import{launch as Pu}from"chrome-launcher";import{createRequire as Eu}from"module";import{mkdirSync as Tu}from"fs";import{readFile as Iu}from"fs/promises";import{dirname as Au,join as Nu}from"path";import{fileURLToPath as Du}from"url";var bs=Eu(import.meta.url)("chrome-remote-interface"),Ru=new Set(["content-security-policy","content-security-policy-report-only","x-frame-options"]),xs=["kizen.dev","kizen.com"];function ws(e){try{let{hostname:t}=new URL(e);return xs.some(r=>t===r||t.endsWith("."+r))}catch{return!1}}async function Bu(e){try{let t=Nu(Au(Du(import.meta.url)),"viewer","icon.png"),r=await Iu(t);await e.Browser.setDockTile({image:r.toString("base64")})}catch{}}async function vs(e){Tu(e.userDataDir,{recursive:!0});let t=`http://localhost:${String(e.port)}`,r=await Pu({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=r.port,n=null,i=null,s=null,l=null,a=0,p=!1,h=_=>{e.debugLog?.(_)},w=_=>{e.verbose&&e.debugLog?.(_)},x=()=>{i!==null&&(clearInterval(i),i=null)},d=_=>_==="chrome://new-tab-page/"||_==="chrome://newtab/",c=async _=>{x(),s=null,await Bu(_),await _.Fetch.enable({patterns:xs.flatMap(g=>[{urlPattern:`*://${g}/*`,requestStage:"Response"},{urlPattern:`*://*.${g}/*`,requestStage:"Response"}])}),_.on("Fetch.requestPaused",g=>{(async()=>{let f=g,{requestId:u,request:m,responseHeaders:b,responseStatusCode:k}=f,I=m.url;w(`Fetch ${String(k??"?")} ${I}`);let E=[],R=!1;for(let M of b??[])if(!Ru.has(M.name.toLowerCase()))if(M.name.toLowerCase()==="set-cookie"&&ws(I)){let W=M.value.split(`
1100
1100
  `).map(ae=>/SameSite=/i.test(ae)?ae.replace(/SameSite=\w+/i,"SameSite=None"):ae+"; SameSite=None; Secure").join(`
1101
- `);E.push({name:M.name,value:W}),R=!0}else E.push(M);R&&w(` rewrote Set-Cookie SameSite on ${I}`);try{let{body:M,base64Encoded:W}=await _.Fetch.getResponseBody({requestId:u});await _.Fetch.fulfillRequest({requestId:u,responseCode:k??200,responseHeaders:E,body:M,...W&&{base64Encoded:!0}})}catch(M){w(` fulfillRequest failed (${M.message}), falling through`);try{await _.Fetch.continueRequest({requestId:u})}catch(W){w(` continueRequest also failed (${W.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:g}=await _.Network.getAllCookies(),f=0;for(let u of g){if(!ws(`https://${u.domain??""}`)||u.sameSite==="None")continue;let m=u.domain??"",b=m.startsWith(".")?m.slice(1):m;await _.Network.setCookie({url:`https://${b}`,name:u.name,value:u.value,domain:m,path:u.path??"/",secure:!0,...u.httpOnly!==void 0&&{httpOnly:u.httpOnly},...u.expirationDate!==void 0&&{expires:u.expirationDate},sameSite:"None"}),f++}f>0&&w(`cookie-patch cycle: updated ${String(f)} cookie(s) to SameSite=None`)}catch(g){w(`cookie-patch cycle failed: ${g.message}`)}})()},2e3),await _.Target.setDiscoverTargets({discover:!0});let S=g=>{if(g.type==="page"){if(d(g.url)){h(`closed stray new-tab-page target ${g.targetId}`),s!==null&&_.Target.activateTarget({targetId:s}).catch(()=>{}),_.Target.closeTarget({targetId:g.targetId}).catch(()=>{});return}s===null&&(s=g.targetId,h(`captured main target ${g.targetId} (${g.url})`))}};_.on("Target.targetCreated",g=>{let{targetInfo:f}=g;w(`target +${f.type} ${f.targetId} ${f.url}`),S(f)}),_.on("Target.targetInfoChanged",g=>{let{targetInfo:f}=g;w(`target ~${f.type} ${f.targetId} ${f.url}`),S(f)}),_.on("disconnect",()=>{p||n!==_||(h("CDP disconnected"),n=null,x(),y())})},y=()=>{if(p||l!==null)return;let _=Math.min(1e3*2**a,1e4),S=a+1;a++,h(`CDP reconnect scheduled in ${String(_)}ms (attempt #${String(S)})`),l=setTimeout(()=>{l=null,(async()=>{let g;try{g=await bs({port:o})}catch{h(`CDP reconnect attempt #${String(S)} failed`),y();return}if(p){try{await g.close()}catch{}return}n=g;try{await c(g),h(`CDP reconnected after ${String(S)} attempt(s)`),a=0}catch{n===g&&(n=null);try{await g.close()}catch{}h(`CDP reconnect attempt #${String(S)} failed during setup`),y()}})()},_)},v=30,P=300;for(let _=0;_<v;_++){await new Promise(S=>setTimeout(S,P)),h(`CDP connect attempt ${String(_+1)}/${String(v)}`);try{let S=await bs({port:o});n=S,e.path&&S.send("Page.navigate",{url:`${t}${e.path}`});try{await c(S),h("CDP connected")}catch{n===S&&(n=null);try{await S.close()}catch{}h("CDP setup failed after connect")}break}catch{if(_===v-1){let S=`CDP unavailable after ${String(v)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return h(S),e.onWarn?.(S),{kill:()=>{r.kill()}}}}}return n?{kill:()=>{if(h("CDP kill requested \u2014 tearing down"),p=!0,l!==null&&(clearTimeout(l),l=null),x(),n!==null){try{n.close()}catch{}n=null}r.kill()}}:{kill:()=>{r.kill()}}}import{useCallback as $u,useState as ju}from"react";function dr(e){let[t,r]=ju([]),o=$u(n=>{r(i=>[...i,`${new Date().toLocaleTimeString()}: ${n}`].slice(-e))},[e]);return[t,o]}import{useCallback as ur,useEffect as Rn,useState as pr}from"react";import{Box as Y,Text as z,useInput as Fu}from"ink";import{jsx as D,jsxs as Z}from"react/jsx-runtime";var Be=["apiKey","userId","businessId"],Ou={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},_t=({text:e})=>D(z,{dimColor:!0,children:e}),fr=({initialMode:e,showProfileManager:t,onComplete:r,onCancel:o})=>{let[n,i]=pr(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[s,l]=pr(""),[a,p]=pr(null),[h,w]=pr(void 0),x=ur(g=>{if(g==="local"){r({mode:"local",credentials:null});return}i({type:"profile-loading"})},[r]),d=ur(async g=>{if(g===null){i({type:"profile-loading"});let m=await Ae();i({type:"name-entry",nameBuffer:"",existingProfiles:m});return}w(g.isDefault?void 0:g.name),i({type:"loading"});let f=g.isDefault?await te():await ve(g.name),u=f?Math.max(0,X.indexOf(f.environment)):0;i({type:"creds-entry",field:0,values:f??{},envCursor:u})},[]),c=ur(async(g,f)=>{let u=X[f]??"go",m={...at(g),environment:u};i({type:"saving"});try{await lo(h??Te,m),r({mode:"global",credentials:m,...h!==void 0&&{profileName:h}})}catch(b){p(b instanceof Error?b.message:String(b)),i({type:"creds-entry",field:0,values:g,envCursor:f})}},[r,h]);Fu((g,f)=>{if(f.ctrl&&g==="c"&&process.exit(0),f.escape){if((n.type==="creds-entry"||n.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),y();return}o?.();return}if(n.type==="mode-select"){if(f.upArrow)i({type:"mode-select",cursor:0});else if(f.downArrow)i({type:"mode-select",cursor:1});else if(f.return){let u=n.cursor===0?"global":"local";x(u)}return}if(n.type==="profile-select"){let{profiles:u,cursor:m}=n,b=u.length,k=u.length+1;if(f.upArrow)i({...n,cursor:(m-1+k)%k});else if(f.downArrow)i({...n,cursor:(m+1)%k});else if(f.return)if(m===b)i({type:"name-entry",nameBuffer:"",existingProfiles:u});else{let I=u[m]??u[0];I&&d(I)}return}if(n.type==="name-entry"){let{nameBuffer:u,existingProfiles:m}=n;if(f.backspace||f.delete)i({type:"name-entry",nameBuffer:u.slice(0,-1),existingProfiles:m});else if(f.return){let b=u.trim();if(!b){i({...n,nameError:"Name cannot be empty"});return}if(b===Te){i({...n,nameError:`"${Te}" is reserved`});return}if(m.some(k=>k.name===b)){i({...n,nameError:`Profile "${b}" already exists`});return}w(b),i({type:"creds-entry",field:0,values:{},envCursor:0}),l("")}else g&&!f.ctrl&&!f.meta&&i({type:"name-entry",nameBuffer:u+g,existingProfiles:m});return}if(n.type==="creds-entry"){let{field:u,values:m,envCursor:b}=n;if(u===Be.length){f.leftArrow?i({...n,envCursor:(b-1+X.length)%X.length}):f.rightArrow?i({...n,envCursor:(b+1)%X.length}):f.upArrow?(i({...n,field:u-1}),l(m[Be[u-1]]??"")):f.return&&c(m,b);return}let I=Be[u];if(!I)return;if(f.backspace||f.delete)l(E=>E.slice(0,-1));else if(f.upArrow&&u>0){let E={...m,[I]:s},R=u-1;i({...n,field:R,values:E}),l(E[Be[R]]??"")}else if(f.return||f.tab||f.downArrow){let E={...m,[I]:s},R=u+1;i({...n,field:R,values:E}),R<Be.length?l(E[Be[R]]??""):l("")}else g&&!f.ctrl&&!f.meta&&l(E=>E+g)}});let y=ur(async()=>{let g=await Ae();i({type:"profile-select",profiles:g,cursor:0})},[]);if(Rn(()=>{n.type==="profile-loading"&&y()},[n.type,y]),Rn(()=>{e==="global"&&!t&&(async()=>{let g=await te(),f=g?Math.max(0,X.indexOf(g.environment)):0;i({type:"creds-entry",field:0,values:g??{},envCursor:f})})()},[]),Rn(()=>{n.type==="creds-entry"&&n.field===0&&l(n.values.apiKey??"")},[n.type]),n.type==="loading"||n.type==="saving"||n.type==="profile-loading"){let g=n.type==="saving"?"Saving credentials\u2026":n.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return D(Y,{paddingY:1,paddingX:2,children:D(z,{dimColor:!0,children:g})})}if(n.type==="done")return null;if(n.type==="mode-select")return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{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((f,u)=>{let m=n.cursor===u;return Z(Y,{gap:2,children:[D(z,{...m&&{color:"cyan"},children:m?"\u276F":" "}),D(z,{bold:m,...m&&{color:"cyan"},children:f.label}),D(z,{dimColor:!0,children:f.desc})]},f.mode)})]}),D(_t,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(n.type==="profile-select"){let{profiles:g,cursor:f}=n,u=g.length;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{bold:!0,children:"Credential profiles"}),g.map((m,b)=>{let k=f===b;return Z(Y,{gap:2,children:[D(z,{...k&&{color:"cyan"},children:k?"\u276F":" "}),D(z,{bold:k,...k&&{color:"cyan"},children:m.isDefault?"Default":m.name}),D(z,{dimColor:!0,children:m.path})]},m.name)}),Z(Y,{gap:2,children:[D(z,{...f===u&&{color:"cyan"},children:f===u?"\u276F":" "}),D(z,{bold:f===u,...f===u&&{color:"cyan"},children:"+ Add new profile"})]})]}),D(_t,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(n.type==="name-entry"){let{nameBuffer:g,nameError:f}=n;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),D(Y,{flexDirection:"column",gap:0,children:D(z,{bold:!0,children:"New credential profile"})}),f&&Z(z,{color:"red",children:["Error: ",f]}),Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:!0,color:"cyan",children:"Profile name"})}),D(z,{color:"cyan",children:">"}),D(z,{children:g}),D(z,{color:"cyan",children:"\u2588"})]}),D(_t,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:v,values:P,envCursor:C}=n,_=v===Be.length,S=h??Te;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{bold:!0,children:h!==void 0?`Profile: ${h}`:"Global credentials"}),Z(z,{dimColor:!0,children:["Saved to:"," ",h!==void 0?`~/.kizenappbuilder/${h}.json`:xe]})]}),a&&Z(z,{color:"red",children:["Error: ",a]}),Z(Y,{flexDirection:"column",gap:0,children:[Be.map((g,f)=>{let u=v===f,m=u?s:P[g]??"";return Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:u,...u&&{color:"cyan"},children:Ou[g]})}),D(z,{...u&&{color:"cyan"},children:">"}),D(z,{children:m}),u&&D(z,{color:"cyan",children:"\u2588"})]},g)}),Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:_,..._&&{color:"cyan"},children:"Environment"})}),D(z,{..._&&{color:"cyan"},children:">"}),D(Y,{gap:1,children:X.map((g,f)=>{let u=f===C;return _?D(z,{bold:u,...u&&{color:"cyan"},children:u?`[${g}]`:g},g):D(z,{dimColor:!u,bold:u,children:g},g)})})]})]}),_?D(_t,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):D(_t,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),Z(z,{dimColor:!0,children:["Profile: ",S]})]})};import{jsx as F,jsxs as G}from"react/jsx-runtime";var Wu=[".kizenapp",".git"],Cs=({port:e,pluginDir:t,outputDir:r,credentials:o,credentialMode:n,activeCredentialProfile:i,lastPath:s,debug:l=!1,verbose:a=!1,autoViewer:p=!0,cacheEnabled:h=!0})=>{let w=Ce(o),x=Ce(i),d=Ce(s),[c,y]=ie("main"),[v,P]=ie(n),[C,_]=ie("starting"),[S,g]=ie(null),[f,u]=dr(50),[m,b]=dr(50),[k,I]=dr(50),[E,R]=ie([]),[M,W]=ie("pending"),[ae,ue]=ie(null),[pe,le]=ie(null),[se,it]=ie(null),[je,xr]=ie(null),[vr,kr]=ie(0),[Fn,aa]=ie(0),[la,ca]=ie(0),[Cr,da]=ie(0),Sr=Ce(!1),On=Ce(!1),Et=Ce(null),st=Ce(null),Se=Ce(new Set),Tt=Ce([]),ce=ot(T=>{let H=JSON.stringify(T);if(Se.current.size===0){Tt.current=[...Tt.current,H].slice(-50);return}let _e=!1;for(let fe of Se.current)if(fe.readyState===1)try{fe.send(H)}catch{Se.current.delete(fe),_e=!0}_e&&kr(Se.current.size)},[]),It=u,_r=ot(()=>{Et.current?.kill(),Et.current=null,vs({port:e,userDataDir:ks(r,".chrome"),broadcast:ce,onWarn:T=>{u(`\u26A0 ${T}`)},...d.current!==void 0&&{path:d.current},...l&&{debugLog:I},...a&&{verbose:!0}}).then(T=>{Et.current=T})},[e,r,ce,l,a,I,u]);mr(()=>{let T=()=>{Et.current?.kill()};return process.on("exit",T),()=>{process.off("exit",T)}},[]),Mu((T,H)=>{(T==="q"||H.ctrl&&T==="c")&&process.exit(0),T==="c"&&y("editing"),T==="v"&&_r()},{isActive:c==="main"}),mr(()=>{C!=="running"||On.current||!p||(On.current=!0,_r())},[C,p,_r]);let ua=ot(T=>{w.current=T.credentials,x.current=T.profileName,y("main"),P(T.mode);let H=T.profileName;Ee(r,{credentialMode:T.mode,...H!==void 0&&{activeCredentialProfile:H}}),ce({type:"credentials-updated",credentials:T.credentials})},[r,ce]),zn=ot(T=>{R(H=>[...H,`${new Date().toLocaleTimeString()}: ${An(T)}`].slice(-50)),T.kind==="request"&&(T.fromCache?ca(H=>H+1):da(H=>H+1)),ce({type:"proxy-log",entry:T})},[ce]),Fe=ot(T=>{b(T),ce({type:"log",message:T})},[b,ce]),Pr=ot(()=>{Sr.current||(Sr.current=!0,W("building"),ue(null),le(null),Fe("Build started"),jt(t,r).then(({bundleSize:T})=>{Fe(`Build finished \u2014 bundle: ${mt(T)}`),W("done"),it(new Date),xr(T),Fe("Notifying viewers to reload"),ce({type:"rebuild"})}).catch(T=>{T instanceof Lu?(le(T.issues),ue(null)):(ue(T instanceof Error?T.message:String(T)),le(null)),W("error")}).finally(()=>{Sr.current=!1}))},[t,r,Fe,ce]);if(mr(()=>{Pr();let T=Uu(t,{recursive:!0},(H,_e)=>{if(!_e)return;let fe=_e.replace(/\\/g,"/");Wu.some(At=>fe.startsWith(At))||(Fe(`File change detected: ${_e}`),st.current!==null&&clearTimeout(st.current),st.current=setTimeout(Pr,150))});return T.on("error",H=>{Fe(`File watcher error \u2014 rebuilds have stopped: ${H.message}`)}),()=>{T.close(),st.current!==null&&clearTimeout(st.current)}},[t,Pr,Fe]),mr(()=>{let T=gs();Dn(ks(T,"index.html")).then(H=>{if(!H){g("Viewer not built. Run 'pnpm build:viewer' first."),_("error");return}let _e=ys(T,It,zn,w,x,r,ce,aa,d,t,h),fe=Hu(_e),At=new Vu({server:fe});return At.on("connection",Oe=>{for(let fa of Tt.current)Oe.readyState===1&&Oe.send(fa);Tt.current=[],It("Viewer connected for live reload"),Se.current.add(Oe),kr(Se.current.size),Oe.on("close",()=>{Se.current.delete(Oe),kr(Se.current.size)})}),fe.listen(e,"127.0.0.1",()=>{_("running"),It(`Server started on 127.0.0.1:${String(e)}`)}),fe.on("error",Oe=>{g(Oe.message),_("error")}),()=>{At.close(),fe.close()}})},[e,It,zn,ce,r,t,h]),c==="editing")return F(fr,{...v!==void 0&&{initialMode:v},showProfileManager:v==="global",onComplete:ua,onCancel:()=>{y("main")}});let Er=se!==null?Math.round((Date.now()-se.getTime())/1e3):null,pa=Er===null?"":Er<5?" (just now)":` (${String(Er)}s ago)`,Mn=pe?.filter(T=>T.severity==="error").length??0;return G(Q,{flexDirection:"column",paddingY:1,paddingX:2,children:[F(K,{marginBottom:1}),G(Q,{flexDirection:"column",children:[G(Q,{gap:2,marginBottom:0,children:[F(j,{bold:!0,dimColor:!0,children:"App Build"}),M==="pending"&&F(j,{dimColor:!0,children:"waiting\u2026"}),M==="building"&&G(Q,{gap:1,children:[F(ye,{}),F(j,{children:"Building plugin package\u2026"})]}),M==="done"&&G(Q,{gap:1,children:[F(j,{color:"green",children:"\u2713 Built"}),se!==null&&G(j,{dimColor:!0,children:["at ",se.toLocaleTimeString(),pa]}),je!==null&&G(j,{dimColor:!0,children:["\xB7 bundle: ",mt(je)]})]}),M==="error"&&(pe!==null?G(j,{color:"red",children:["\u2717 ",Mn," validation ",Mn===1?"error":"errors"]}):G(j,{color:"red",children:["\u2717 ",ae??"unknown error"]}))]}),pe!==null&&F(Xt,{issues:pe}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:m.slice(-8).map((T,H)=>F(j,{dimColor:!0,wrap:"truncate",children:T},H))})]}),G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"Web Server"}),C==="starting"&&F(j,{dimColor:!0,children:"starting\u2026"}),C==="running"&&G(Q,{gap:2,children:[F(j,{color:"green",children:"\u2713 Running"}),G(j,{dimColor:!0,children:["\u25CF ",vr," viewer",vr!==1?"s":""]})]}),C==="error"&&G(j,{color:"red",children:["\u2717 ",S??"Server error"]})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:f.slice(-8).map((T,H)=>F(j,{dimColor:!0,wrap:"truncate",children:T},H))})]}),G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"Network Proxy"}),F(j,{color:"green",children:"\u2713 Active"}),F(j,{dimColor:!0,children:h?`\u25CF ${String(Fn)} key${Fn!==1?"s":""} in the network cache \xB7 ${String(la)} hit \xB7 ${String(Cr)} miss`:`\u25CF network cache disabled \xB7 ${String(Cr)} request${Cr!==1?"s":""}`})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:E.length===0?F(j,{dimColor:!0,children:" No requests yet."}):E.slice(-8).map((T,H)=>F(j,{dimColor:!0,wrap:"truncate",children:T},H))})]}),l&&G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"CDP Debug"}),G(j,{dimColor:!0,children:["\u25CF ",k.length," event(s)"]})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:k.length===0?F(j,{dimColor:!0,children:" No CDP events yet."}):k.slice(-8).map((T,H)=>F(j,{dimColor:!0,wrap:"truncate",children:T},H))})]}),G(Q,{marginTop:1,gap:1,children:[F(j,{dimColor:!0,children:"["}),F(j,{children:"q"}),F(j,{dimColor:!0,children:"] quit ["}),F(j,{children:"c"}),F(j,{dimColor:!0,children:"] credentials ["}),F(j,{children:"v"}),G(j,{dimColor:!0,children:["] ",vr===0?"open viewer":"relaunch viewer"]})]})]})};async function Ss(e){return new Promise(t=>{let r=null,o=i=>{r?.(),t(i)},{unmount:n}=Ps(_s(fr,{...e!==void 0&&{initialMode:e},onComplete:o}),{exitOnCtrlC:!1});r=n})}function Es(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 r=parseInt(t.port,10),o=process.cwd(),n=`${o}/.kizenapp`;Ne(o);let i=null,s,l,{lastPath:a}=await he(n);if(t.credentials)i=await Ie(t.credentials);else{let c=await he(n);if(c.credentialMode==="local")s="local";else if(c.credentialMode==="global"){if(s="global",l=c.activeCredentialProfile,l?(i=await ve(l),i||(i=await te(),l=void 0)):i=await te(),!i){let y=await Ss("global");i=y.credentials,l=y.profileName}}else{let y=await Ss();i=y.credentials,s=y.mode,l=y.profileName;let v=y.profileName;await Ee(n,{credentialMode:y.mode,...v!==void 0&&{activeCredentialProfile:v}})}}let p=t.verbose===!0,h=p||t.debug===!0,w=t.viewer!==!1,x=t.cache!==!1,{waitUntilExit:d}=Ps(_s(Cs,{port:r,pluginDir:o,outputDir:n,credentials:i,...s!==void 0&&{credentialMode:s},...l!==void 0&&{activeCredentialProfile:l},...a!==void 0&&{lastPath:a},debug:h,verbose:p,autoViewer:w,cacheEnabled:x}),{exitOnCtrlC:!1});await d()})}import{createElement as op}from"react";import{render as ip}from"ink";import{useCallback as gr,useEffect as Ns,useState as yr}from"react";import{Box as be,Text as U,useApp as Zu,useInput as Qu}from"ink";import{encrypt as Ku,serializeEnvelope as Ju}from"@kizenapps/packager";function qu(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function Ts(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 Is(e,t,r){try{return await fetch(`${e}${t}`,r)}catch(o){throw new Error(qu(o)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${o.message}${Dt()==="unavailable"?` ${Nt}`:""}`)}}async function As(e){let t=await e.text();if(t==="")return{};try{let r=JSON.parse(t);return typeof r=="object"&&r!==null?r:{}}catch{return{}}}async function Gu(e,t,r){let o=xt(e.stage),n=await Is(o,"/get-public-key",{method:"POST",headers:Ts(t),body:JSON.stringify({api_name:r})}),i=await As(n);if(!n.ok||typeof i.public_key!="string"){let s=typeof i.error=="string"?i.error:`HTTP ${String(n.status)}`;throw new Error(`Failed to fetch public key: ${s}`)}return i.public_key}function Yu(e,t){let r=Ku(t,e),o=Ju(r);if(typeof o.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return o.value}async function Xu(e,t,r,o){let n=xt(e.stage),i=await Is(n,"/encrypt",{method:"POST",headers:Ts(t),body:JSON.stringify({api_name:r,value:o})}),s=await As(i);if(!i.ok||s.encrypted!==!0||typeof s.value!="string"){let l=typeof s.error=="string"?s.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${l}`)}return s.value}async function hr(e,t,r,o,n){if(e.isRemote)return n?.("encrypting"),Xu(e,t,r,o);n?.("fetching-key");let i=await Gu(e,t,r);return n?.("encrypting"),Yu(i,o)}import{Fragment as br,jsx as O,jsxs as ee}from"react/jsx-runtime";var Bn=({text:e})=>O(U,{dimColor:!0,children:e}),Ds=({ctx:e,stageDefaulted:t,credentialsPath:r,initialApiName:o,defaultApiName:n,initialValue:i,onDone:s})=>{let l=Zu(),[a,p]=yr({type:"loading"}),[h,w]=yr(null),[x,d]=yr(o??""),[c,y]=yr(i??""),v=gr(u=>{process.exitCode=1,p({type:"error",message:u instanceof Error?u.message:String(u)})},[]),P=gr(async(u,m,b)=>{try{let k=await hr(e,u,m,b,R=>{p(R==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),I=JSON.stringify({encrypted:!0,value:k},null,2);s?.(k);let E=await Rt(I);p({type:"done",envelope:I,copied:E})}catch(k){v(k)}},[e,v,s]),C=gr((u,m,b)=>{if(m.trim()===""){p({type:"api-name-entry",buffer:n??""});return}if(b===""){p({type:"value-entry",buffer:""});return}P(u,m.trim(),b)},[n,P]),_=gr(async u=>{try{p({type:"loading"});let m=u.isDefault?await te():await ve(u.name);if(m===null)throw new Error(`Could not load credential profile: ${u.name}`);w(m),C(m,x,c)}catch(m){v(m)}},[x,c,C,v]);Ns(()=>{(async()=>{try{if(r!==void 0){let b;try{b=await Ie(r)}catch(k){throw new Error(`Could not load credentials from ${r}: ${k instanceof Error?k.message:String(k)}`)}w(b),C(b,x,c);return}let u=await Ae();if(u.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[m]=u;if(u.length===1&&m!==void 0){let b=m.isDefault?await te():await ve(m.name);if(b===null)throw new Error(`Could not load credential profile: ${m.name}`);w(b),C(b,x,c);return}p({type:"profile-select",profiles:u,cursor:0})}catch(u){v(u)}})()},[]),Ns(()=>{(a.type==="done"||a.type==="error")&&l.exit()},[a,l]),Qu((u,m)=>{if(m.ctrl&&u==="c"){process.exitCode=130,l.exit();return}if(a.type==="profile-select"){let{profiles:b,cursor:k}=a;if(m.upArrow)p({...a,cursor:(k-1+b.length)%b.length});else if(m.downArrow)p({...a,cursor:(k+1)%b.length});else if(m.return){let I=b[k];I!==void 0&&_(I)}return}if(a.type==="api-name-entry"){let{buffer:b}=a;if(m.backspace||m.delete)p({type:"api-name-entry",buffer:b.slice(0,-1)});else if(m.return){let k=b.trim();if(k===""){p({type:"api-name-entry",buffer:b,error:"api_name cannot be empty"});return}d(k),h?C(h,k,c):v(new Error("Internal error: credentials were not loaded"))}else u&&!m.ctrl&&!m.meta&&p({type:"api-name-entry",buffer:b+u});return}if(a.type==="value-entry"){let{buffer:b}=a;if(m.backspace||m.delete)p({type:"value-entry",buffer:b.slice(0,-1)});else if(m.return){if(b===""){p({type:"value-entry",buffer:b,error:"secret cannot be empty"});return}y(b),h?C(h,x,b):v(new Error("Internal error: credentials were not loaded"))}else u&&!m.ctrl&&!m.meta&&p({type:"value-entry",buffer:b+u});return}});let S=e.isRemote?"remote Kizen API":"on-machine",g=t===!0?`${e.stage} (default)`:e.stage,f=u=>ee(be,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[O(K,{}),ee(U,{dimColor:!0,children:["Mode: ",S," Stage: ",g]}),u]});if(a.type==="loading")return f(ee(be,{gap:1,children:[O(ye,{}),O(U,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(a.type==="profile-select"){let{profiles:u,cursor:m}=a;return f(ee(br,{children:[O(U,{bold:!0,children:"Credential profile"}),O(be,{flexDirection:"column",children:u.map((b,k)=>{let I=m===k;return ee(be,{gap:2,children:[O(U,{...I&&{color:"cyan"},children:I?"\u276F":" "}),O(U,{bold:I,...I&&{color:"cyan"},children:b.isDefault?"Default":b.name}),O(U,{dimColor:!0,children:b.path})]},b.name)})}),O(Bn,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return a.type==="api-name-entry"?f(ee(br,{children:[O(U,{bold:!0,children:"Plugin api_name"}),a.error!==void 0&&ee(U,{color:"red",children:["Error: ",a.error]}),ee(be,{gap:1,children:[O(U,{color:"cyan",children:">"}),O(U,{children:a.buffer}),O(U,{color:"cyan",children:"\u2588"})]}),O(Bn,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):a.type==="value-entry"?f(ee(br,{children:[O(U,{bold:!0,children:"Secret value"}),a.error!==void 0&&ee(U,{color:"red",children:["Error: ",a.error]}),ee(be,{gap:1,children:[O(U,{color:"cyan",children:">"}),O(U,{children:"\u2022".repeat(a.buffer.length)}),O(U,{color:"cyan",children:"\u2588"})]}),O(Bn,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):a.type==="fetching-key"?f(ee(be,{gap:1,children:[O(ye,{}),ee(U,{children:["Fetching ",e.stage," public key for ",O(U,{bold:!0,children:x}),"\u2026"]})]})):a.type==="encrypting"?f(ee(be,{gap:1,children:[O(ye,{}),O(U,{children:"Encrypting\u2026"})]})):a.type==="error"?f(ee(be,{gap:1,children:[O(U,{color:"red",children:"\u2717"}),O(U,{color:"red",children:a.message})]})):f(ee(br,{children:[ee(be,{gap:1,children:[O(U,{color:"green",children:"\u2713"}),O(U,{bold:!0,children:"Encrypted secret ready"})]}),a.copied?O(U,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):O(U,{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):"}),O(U,{children:a.envelope})]}))};import{readFile as ep,writeFile as tp}from"fs/promises";import{join as rp}from"path";function Rs(e){return{encrypted:!0,value:e}}function Bs(e){return JSON.stringify(Rs(e))}async function $n(e,t){await tp(e,`${JSON.stringify(Rs(t),null,2)}
1101
+ `);E.push({name:M.name,value:W}),R=!0}else E.push(M);R&&w(` rewrote Set-Cookie SameSite on ${I}`);try{let{body:M,base64Encoded:W}=await _.Fetch.getResponseBody({requestId:u});await _.Fetch.fulfillRequest({requestId:u,responseCode:k??200,responseHeaders:E,body:M,...W&&{base64Encoded:!0}})}catch(M){w(` fulfillRequest failed (${M.message}), falling through`);try{await _.Fetch.continueRequest({requestId:u})}catch(W){w(` continueRequest also failed (${W.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:g}=await _.Network.getAllCookies(),f=0;for(let u of g){if(!ws(`https://${u.domain??""}`)||u.sameSite==="None")continue;let m=u.domain??"",b=m.startsWith(".")?m.slice(1):m;await _.Network.setCookie({url:`https://${b}`,name:u.name,value:u.value,domain:m,path:u.path??"/",secure:!0,...u.httpOnly!==void 0&&{httpOnly:u.httpOnly},...u.expirationDate!==void 0&&{expires:u.expirationDate},sameSite:"None"}),f++}f>0&&w(`cookie-patch cycle: updated ${String(f)} cookie(s) to SameSite=None`)}catch(g){w(`cookie-patch cycle failed: ${g.message}`)}})()},2e3),await _.Target.setDiscoverTargets({discover:!0});let S=g=>{if(g.type==="page"){if(d(g.url)){h(`closed stray new-tab-page target ${g.targetId}`),s!==null&&_.Target.activateTarget({targetId:s}).catch(()=>{}),_.Target.closeTarget({targetId:g.targetId}).catch(()=>{});return}s===null&&(s=g.targetId,h(`captured main target ${g.targetId} (${g.url})`))}};_.on("Target.targetCreated",g=>{let{targetInfo:f}=g;w(`target +${f.type} ${f.targetId} ${f.url}`),S(f)}),_.on("Target.targetInfoChanged",g=>{let{targetInfo:f}=g;w(`target ~${f.type} ${f.targetId} ${f.url}`),S(f)}),_.on("disconnect",()=>{p||n!==_||(h("CDP disconnected"),n=null,x(),y())})},y=()=>{if(p||l!==null)return;let _=Math.min(1e3*2**a,1e4),S=a+1;a++,h(`CDP reconnect scheduled in ${String(_)}ms (attempt #${String(S)})`),l=setTimeout(()=>{l=null,(async()=>{let g;try{g=await bs({port:o})}catch{h(`CDP reconnect attempt #${String(S)} failed`),y();return}if(p){try{await g.close()}catch{}return}n=g;try{await c(g),h(`CDP reconnected after ${String(S)} attempt(s)`),a=0}catch{n===g&&(n=null);try{await g.close()}catch{}h(`CDP reconnect attempt #${String(S)} failed during setup`),y()}})()},_)},v=30,P=300;for(let _=0;_<v;_++){await new Promise(S=>setTimeout(S,P)),h(`CDP connect attempt ${String(_+1)}/${String(v)}`);try{let S=await bs({port:o});n=S,e.path&&S.send("Page.navigate",{url:`${t}${e.path}`});try{await c(S),h("CDP connected")}catch{n===S&&(n=null);try{await S.close()}catch{}h("CDP setup failed after connect")}break}catch{if(_===v-1){let S=`CDP unavailable after ${String(v)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return h(S),e.onWarn?.(S),{kill:()=>{r.kill()}}}}}return n?{kill:()=>{if(h("CDP kill requested \u2014 tearing down"),p=!0,l!==null&&(clearTimeout(l),l=null),x(),n!==null){try{n.close()}catch{}n=null}r.kill()}}:{kill:()=>{r.kill()}}}import{useCallback as $u,useState as ju}from"react";function dr(e){let[t,r]=ju([]),o=$u(n=>{r(i=>[...i,`${new Date().toLocaleTimeString()}: ${n}`].slice(-e))},[e]);return[t,o]}import{useCallback as ur,useEffect as Rn,useState as pr}from"react";import{Box as Y,Text as z,useInput as Fu}from"ink";import{jsx as D,jsxs as Z}from"react/jsx-runtime";var Be=["apiKey","userId","businessId"],Ou={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},_t=({text:e})=>D(z,{dimColor:!0,children:e}),fr=({initialMode:e,showProfileManager:t,onComplete:r,onCancel:o})=>{let[n,i]=pr(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[s,l]=pr(""),[a,p]=pr(null),[h,w]=pr(void 0),x=ur(g=>{if(g==="local"){r({mode:"local",credentials:null});return}i({type:"profile-loading"})},[r]),d=ur(async g=>{if(g===null){i({type:"profile-loading"});let m=await Ae();i({type:"name-entry",nameBuffer:"",existingProfiles:m});return}w(g.isDefault?void 0:g.name),i({type:"loading"});let f=g.isDefault?await te():await ve(g.name),u=f?Math.max(0,X.indexOf(f.environment)):0;i({type:"creds-entry",field:0,values:f??{},envCursor:u})},[]),c=ur(async(g,f)=>{let u=X[f]??"go",m={...at(g),environment:u};i({type:"saving"});try{await lo(h??Te,m),r({mode:"global",credentials:m,...h!==void 0&&{profileName:h}})}catch(b){p(b instanceof Error?b.message:String(b)),i({type:"creds-entry",field:0,values:g,envCursor:f})}},[r,h]);Fu((g,f)=>{if(f.ctrl&&g==="c"&&process.exit(0),f.escape){if((n.type==="creds-entry"||n.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),y();return}o?.();return}if(n.type==="mode-select"){if(f.upArrow)i({type:"mode-select",cursor:0});else if(f.downArrow)i({type:"mode-select",cursor:1});else if(f.return){let u=n.cursor===0?"global":"local";x(u)}return}if(n.type==="profile-select"){let{profiles:u,cursor:m}=n,b=u.length,k=u.length+1;if(f.upArrow)i({...n,cursor:(m-1+k)%k});else if(f.downArrow)i({...n,cursor:(m+1)%k});else if(f.return)if(m===b)i({type:"name-entry",nameBuffer:"",existingProfiles:u});else{let I=u[m]??u[0];I&&d(I)}return}if(n.type==="name-entry"){let{nameBuffer:u,existingProfiles:m}=n;if(f.backspace||f.delete)i({type:"name-entry",nameBuffer:u.slice(0,-1),existingProfiles:m});else if(f.return){let b=u.trim();if(!b){i({...n,nameError:"Name cannot be empty"});return}if(b===Te){i({...n,nameError:`"${Te}" is reserved`});return}if(m.some(k=>k.name===b)){i({...n,nameError:`Profile "${b}" already exists`});return}w(b),i({type:"creds-entry",field:0,values:{},envCursor:0}),l("")}else g&&!f.ctrl&&!f.meta&&i({type:"name-entry",nameBuffer:u+g,existingProfiles:m});return}if(n.type==="creds-entry"){let{field:u,values:m,envCursor:b}=n;if(u===Be.length){f.leftArrow?i({...n,envCursor:(b-1+X.length)%X.length}):f.rightArrow?i({...n,envCursor:(b+1)%X.length}):f.upArrow?(i({...n,field:u-1}),l(m[Be[u-1]]??"")):f.return&&c(m,b);return}let I=Be[u];if(!I)return;if(f.backspace||f.delete)l(E=>E.slice(0,-1));else if(f.upArrow&&u>0){let E={...m,[I]:s},R=u-1;i({...n,field:R,values:E}),l(E[Be[R]]??"")}else if(f.return||f.tab||f.downArrow){let E={...m,[I]:s},R=u+1;i({...n,field:R,values:E}),R<Be.length?l(E[Be[R]]??""):l("")}else g&&!f.ctrl&&!f.meta&&l(E=>E+g)}});let y=ur(async()=>{let g=await Ae();i({type:"profile-select",profiles:g,cursor:0})},[]);if(Rn(()=>{n.type==="profile-loading"&&y()},[n.type,y]),Rn(()=>{e==="global"&&!t&&(async()=>{let g=await te(),f=g?Math.max(0,X.indexOf(g.environment)):0;i({type:"creds-entry",field:0,values:g??{},envCursor:f})})()},[]),Rn(()=>{n.type==="creds-entry"&&n.field===0&&l(n.values.apiKey??"")},[n.type]),n.type==="loading"||n.type==="saving"||n.type==="profile-loading"){let g=n.type==="saving"?"Saving credentials\u2026":n.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return D(Y,{paddingY:1,paddingX:2,children:D(z,{dimColor:!0,children:g})})}if(n.type==="done")return null;if(n.type==="mode-select")return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{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((f,u)=>{let m=n.cursor===u;return Z(Y,{gap:2,children:[D(z,{...m&&{color:"cyan"},children:m?"\u276F":" "}),D(z,{bold:m,...m&&{color:"cyan"},children:f.label}),D(z,{dimColor:!0,children:f.desc})]},f.mode)})]}),D(_t,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(n.type==="profile-select"){let{profiles:g,cursor:f}=n,u=g.length;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{bold:!0,children:"Credential profiles"}),g.map((m,b)=>{let k=f===b;return Z(Y,{gap:2,children:[D(z,{...k&&{color:"cyan"},children:k?"\u276F":" "}),D(z,{bold:k,...k&&{color:"cyan"},children:m.isDefault?"Default":m.name}),D(z,{dimColor:!0,children:m.path})]},m.name)}),Z(Y,{gap:2,children:[D(z,{...f===u&&{color:"cyan"},children:f===u?"\u276F":" "}),D(z,{bold:f===u,...f===u&&{color:"cyan"},children:"+ Add new profile"})]})]}),D(_t,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(n.type==="name-entry"){let{nameBuffer:g,nameError:f}=n;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),D(Y,{flexDirection:"column",gap:0,children:D(z,{bold:!0,children:"New credential profile"})}),f&&Z(z,{color:"red",children:["Error: ",f]}),Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:!0,color:"cyan",children:"Profile name"})}),D(z,{color:"cyan",children:">"}),D(z,{children:g}),D(z,{color:"cyan",children:"\u2588"})]}),D(_t,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:v,values:P,envCursor:C}=n,_=v===Be.length,S=h??Te;return Z(Y,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[D(K,{}),Z(Y,{flexDirection:"column",gap:0,children:[D(z,{bold:!0,children:h!==void 0?`Profile: ${h}`:"Global credentials"}),Z(z,{dimColor:!0,children:["Saved to:"," ",h!==void 0?`~/.kizenappbuilder/${h}.json`:xe]})]}),a&&Z(z,{color:"red",children:["Error: ",a]}),Z(Y,{flexDirection:"column",gap:0,children:[Be.map((g,f)=>{let u=v===f,m=u?s:P[g]??"";return Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:u,...u&&{color:"cyan"},children:Ou[g]})}),D(z,{...u&&{color:"cyan"},children:">"}),D(z,{children:m}),u&&D(z,{color:"cyan",children:"\u2588"})]},g)}),Z(Y,{gap:2,children:[D(Y,{width:12,children:D(z,{bold:_,..._&&{color:"cyan"},children:"Environment"})}),D(z,{..._&&{color:"cyan"},children:">"}),D(Y,{gap:1,children:X.map((g,f)=>{let u=f===C;return _?D(z,{bold:u,...u&&{color:"cyan"},children:u?`[${g}]`:g},g):D(z,{dimColor:!u,bold:u,children:g},g)})})]})]}),_?D(_t,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):D(_t,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),Z(z,{dimColor:!0,children:["Profile: ",S]})]})};import{jsx as F,jsxs as G}from"react/jsx-runtime";var Wu=[".kizenapp",".git"],Cs=({port:e,pluginDir:t,outputDir:r,credentials:o,credentialMode:n,activeCredentialProfile:i,lastPath:s,debug:l=!1,verbose:a=!1,autoViewer:p=!0,cacheEnabled:h=!0})=>{let w=Ce(o),x=Ce(i),d=Ce(s),[c,y]=ie("main"),[v,P]=ie(n),[C,_]=ie("starting"),[S,g]=ie(null),[f,u]=dr(50),[m,b]=dr(50),[k,I]=dr(50),[E,R]=ie([]),[M,W]=ie("pending"),[ae,ue]=ie(null),[pe,le]=ie(null),[se,it]=ie(null),[je,xr]=ie(null),[vr,kr]=ie(0),[Fn,aa]=ie(0),[la,ca]=ie(0),[Cr,da]=ie(0),Sr=Ce(!1),On=Ce(!1),Et=Ce(null),st=Ce(null),Se=Ce(new Set),Tt=Ce([]),ce=ot(T=>{let U=JSON.stringify(T);if(Se.current.size===0){Tt.current=[...Tt.current,U].slice(-50);return}let _e=!1;for(let fe of Se.current)if(fe.readyState===1)try{fe.send(U)}catch{Se.current.delete(fe),_e=!0}_e&&kr(Se.current.size)},[]),It=u,_r=ot(()=>{Et.current?.kill(),Et.current=null,vs({port:e,userDataDir:ks(r,".chrome"),broadcast:ce,onWarn:T=>{u(`\u26A0 ${T}`)},...d.current!==void 0&&{path:d.current},...l&&{debugLog:I},...a&&{verbose:!0}}).then(T=>{Et.current=T})},[e,r,ce,l,a,I,u]);mr(()=>{let T=()=>{Et.current?.kill()};return process.on("exit",T),()=>{process.off("exit",T)}},[]),Mu((T,U)=>{(T==="q"||U.ctrl&&T==="c")&&process.exit(0),T==="c"&&y("editing"),T==="v"&&_r()},{isActive:c==="main"}),mr(()=>{C!=="running"||On.current||!p||(On.current=!0,_r())},[C,p,_r]);let ua=ot(T=>{w.current=T.credentials,x.current=T.profileName,y("main"),P(T.mode);let U=T.profileName;Ee(r,{credentialMode:T.mode,...U!==void 0&&{activeCredentialProfile:U}}),ce({type:"credentials-updated",credentials:T.credentials})},[r,ce]),zn=ot(T=>{R(U=>[...U,`${new Date().toLocaleTimeString()}: ${An(T)}`].slice(-50)),T.kind==="request"&&(T.fromCache?ca(U=>U+1):da(U=>U+1)),ce({type:"proxy-log",entry:T})},[ce]),Fe=ot(T=>{b(T),ce({type:"log",message:T})},[b,ce]),Pr=ot(()=>{Sr.current||(Sr.current=!0,W("building"),ue(null),le(null),Fe("Build started"),jt(t,r).then(({bundleSize:T})=>{Fe(`Build finished \u2014 bundle: ${mt(T)}`),W("done"),it(new Date),xr(T),Fe("Notifying viewers to reload"),ce({type:"rebuild"})}).catch(T=>{T instanceof Lu?(le(T.issues),ue(null)):(ue(T instanceof Error?T.message:String(T)),le(null)),W("error")}).finally(()=>{Sr.current=!1}))},[t,r,Fe,ce]);if(mr(()=>{Pr();let T=Hu(t,{recursive:!0},(U,_e)=>{if(!_e)return;let fe=_e.replace(/\\/g,"/");Wu.some(At=>fe.startsWith(At))||(Fe(`File change detected: ${_e}`),st.current!==null&&clearTimeout(st.current),st.current=setTimeout(Pr,150))});return T.on("error",U=>{Fe(`File watcher error \u2014 rebuilds have stopped: ${U.message}`)}),()=>{T.close(),st.current!==null&&clearTimeout(st.current)}},[t,Pr,Fe]),mr(()=>{let T=gs();Dn(ks(T,"index.html")).then(U=>{if(!U){g("Viewer not built. Run 'pnpm build:viewer' first."),_("error");return}let _e=ys(T,It,zn,w,x,r,ce,aa,d,t,h),fe=Uu(_e),At=new Vu({server:fe});return At.on("connection",Oe=>{for(let fa of Tt.current)Oe.readyState===1&&Oe.send(fa);Tt.current=[],It("Viewer connected for live reload"),Se.current.add(Oe),kr(Se.current.size),Oe.on("close",()=>{Se.current.delete(Oe),kr(Se.current.size)})}),fe.listen(e,"127.0.0.1",()=>{_("running"),It(`Server started on 127.0.0.1:${String(e)}`)}),fe.on("error",Oe=>{g(Oe.message),_("error")}),()=>{At.close(),fe.close()}})},[e,It,zn,ce,r,t,h]),c==="editing")return F(fr,{...v!==void 0&&{initialMode:v},showProfileManager:v==="global",onComplete:ua,onCancel:()=>{y("main")}});let Er=se!==null?Math.round((Date.now()-se.getTime())/1e3):null,pa=Er===null?"":Er<5?" (just now)":` (${String(Er)}s ago)`,Mn=pe?.filter(T=>T.severity==="error").length??0;return G(Q,{flexDirection:"column",paddingY:1,paddingX:2,children:[F(K,{marginBottom:1}),G(Q,{flexDirection:"column",children:[G(Q,{gap:2,marginBottom:0,children:[F(j,{bold:!0,dimColor:!0,children:"App Build"}),M==="pending"&&F(j,{dimColor:!0,children:"waiting\u2026"}),M==="building"&&G(Q,{gap:1,children:[F(ye,{}),F(j,{children:"Building plugin package\u2026"})]}),M==="done"&&G(Q,{gap:1,children:[F(j,{color:"green",children:"\u2713 Built"}),se!==null&&G(j,{dimColor:!0,children:["at ",se.toLocaleTimeString(),pa]}),je!==null&&G(j,{dimColor:!0,children:["\xB7 bundle: ",mt(je)]})]}),M==="error"&&(pe!==null?G(j,{color:"red",children:["\u2717 ",Mn," validation ",Mn===1?"error":"errors"]}):G(j,{color:"red",children:["\u2717 ",ae??"unknown error"]}))]}),pe!==null&&F(Xt,{issues:pe}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:m.slice(-8).map((T,U)=>F(j,{dimColor:!0,wrap:"truncate",children:T},U))})]}),G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"Web Server"}),C==="starting"&&F(j,{dimColor:!0,children:"starting\u2026"}),C==="running"&&G(Q,{gap:2,children:[F(j,{color:"green",children:"\u2713 Running"}),G(j,{dimColor:!0,children:["\u25CF ",vr," viewer",vr!==1?"s":""]})]}),C==="error"&&G(j,{color:"red",children:["\u2717 ",S??"Server error"]})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:f.slice(-8).map((T,U)=>F(j,{dimColor:!0,wrap:"truncate",children:T},U))})]}),G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"Network Proxy"}),F(j,{color:"green",children:"\u2713 Active"}),F(j,{dimColor:!0,children:h?`\u25CF ${String(Fn)} key${Fn!==1?"s":""} in the network cache \xB7 ${String(la)} hit \xB7 ${String(Cr)} miss`:`\u25CF network cache disabled \xB7 ${String(Cr)} request${Cr!==1?"s":""}`})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:E.length===0?F(j,{dimColor:!0,children:" No requests yet."}):E.slice(-8).map((T,U)=>F(j,{dimColor:!0,wrap:"truncate",children:T},U))})]}),l&&G(Q,{marginTop:1,flexDirection:"column",children:[G(Q,{gap:2,children:[F(j,{bold:!0,dimColor:!0,children:"CDP Debug"}),G(j,{dimColor:!0,children:["\u25CF ",k.length," event(s)"]})]}),F(Q,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:k.length===0?F(j,{dimColor:!0,children:" No CDP events yet."}):k.slice(-8).map((T,U)=>F(j,{dimColor:!0,wrap:"truncate",children:T},U))})]}),G(Q,{marginTop:1,gap:1,children:[F(j,{dimColor:!0,children:"["}),F(j,{children:"q"}),F(j,{dimColor:!0,children:"] quit ["}),F(j,{children:"c"}),F(j,{dimColor:!0,children:"] credentials ["}),F(j,{children:"v"}),G(j,{dimColor:!0,children:["] ",vr===0?"open viewer":"relaunch viewer"]})]})]})};async function Ss(e){return new Promise(t=>{let r=null,o=i=>{r?.(),t(i)},{unmount:n}=Ps(_s(fr,{...e!==void 0&&{initialMode:e},onComplete:o}),{exitOnCtrlC:!1});r=n})}function Es(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 r=parseInt(t.port,10),o=process.cwd(),n=`${o}/.kizenapp`;Ne(o);let i=null,s,l,{lastPath:a}=await he(n);if(t.credentials)i=await Ie(t.credentials);else{let c=await he(n);if(c.credentialMode==="local")s="local";else if(c.credentialMode==="global"){if(s="global",l=c.activeCredentialProfile,l?(i=await ve(l),i||(i=await te(),l=void 0)):i=await te(),!i){let y=await Ss("global");i=y.credentials,l=y.profileName}}else{let y=await Ss();i=y.credentials,s=y.mode,l=y.profileName;let v=y.profileName;await Ee(n,{credentialMode:y.mode,...v!==void 0&&{activeCredentialProfile:v}})}}let p=t.verbose===!0,h=p||t.debug===!0,w=t.viewer!==!1,x=t.cache!==!1,{waitUntilExit:d}=Ps(_s(Cs,{port:r,pluginDir:o,outputDir:n,credentials:i,...s!==void 0&&{credentialMode:s},...l!==void 0&&{activeCredentialProfile:l},...a!==void 0&&{lastPath:a},debug:h,verbose:p,autoViewer:w,cacheEnabled:x}),{exitOnCtrlC:!1});await d()})}import{createElement as op}from"react";import{render as ip}from"ink";import{useCallback as gr,useEffect as Ns,useState as yr}from"react";import{Box as be,Text as H,useApp as Zu,useInput as Qu}from"ink";import{encrypt as Ku,serializeEnvelope as Ju}from"@kizenapps/packager";function qu(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function Ts(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 Is(e,t,r){try{return await fetch(`${e}${t}`,r)}catch(o){throw new Error(qu(o)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${o.message}${Dt()==="unavailable"?` ${Nt}`:""}`)}}async function As(e){let t=await e.text();if(t==="")return{};try{let r=JSON.parse(t);return typeof r=="object"&&r!==null?r:{}}catch{return{}}}async function Gu(e,t,r){let o=xt(e.stage),n=await Is(o,"/get-public-key",{method:"POST",headers:Ts(t),body:JSON.stringify({api_name:r})}),i=await As(n);if(!n.ok||typeof i.public_key!="string"){let s=typeof i.error=="string"?i.error:`HTTP ${String(n.status)}`;throw new Error(`Failed to fetch public key: ${s}`)}return i.public_key}function Yu(e,t){let r=Ku(t,e),o=Ju(r);if(typeof o.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return o.value}async function Xu(e,t,r,o){let n=xt(e.stage),i=await Is(n,"/encrypt",{method:"POST",headers:Ts(t),body:JSON.stringify({api_name:r,value:o})}),s=await As(i);if(!i.ok||s.encrypted!==!0||typeof s.value!="string"){let l=typeof s.error=="string"?s.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${l}`)}return s.value}async function hr(e,t,r,o,n){if(e.isRemote)return n?.("encrypting"),Xu(e,t,r,o);n?.("fetching-key");let i=await Gu(e,t,r);return n?.("encrypting"),Yu(i,o)}import{Fragment as br,jsx as O,jsxs as ee}from"react/jsx-runtime";var Bn=({text:e})=>O(H,{dimColor:!0,children:e}),Ds=({ctx:e,stageDefaulted:t,credentialsPath:r,initialApiName:o,defaultApiName:n,initialValue:i,onDone:s})=>{let l=Zu(),[a,p]=yr({type:"loading"}),[h,w]=yr(null),[x,d]=yr(o??""),[c,y]=yr(i??""),v=gr(u=>{process.exitCode=1,p({type:"error",message:u instanceof Error?u.message:String(u)})},[]),P=gr(async(u,m,b)=>{try{let k=await hr(e,u,m,b,R=>{p(R==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),I=JSON.stringify({encrypted:!0,value:k},null,2);s?.(k);let E=await Rt(I);p({type:"done",envelope:I,copied:E})}catch(k){v(k)}},[e,v,s]),C=gr((u,m,b)=>{if(m.trim()===""){p({type:"api-name-entry",buffer:n??""});return}if(b===""){p({type:"value-entry",buffer:""});return}P(u,m.trim(),b)},[n,P]),_=gr(async u=>{try{p({type:"loading"});let m=u.isDefault?await te():await ve(u.name);if(m===null)throw new Error(`Could not load credential profile: ${u.name}`);w(m),C(m,x,c)}catch(m){v(m)}},[x,c,C,v]);Ns(()=>{(async()=>{try{if(r!==void 0){let b;try{b=await Ie(r)}catch(k){throw new Error(`Could not load credentials from ${r}: ${k instanceof Error?k.message:String(k)}`)}w(b),C(b,x,c);return}let u=await Ae();if(u.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[m]=u;if(u.length===1&&m!==void 0){let b=m.isDefault?await te():await ve(m.name);if(b===null)throw new Error(`Could not load credential profile: ${m.name}`);w(b),C(b,x,c);return}p({type:"profile-select",profiles:u,cursor:0})}catch(u){v(u)}})()},[]),Ns(()=>{(a.type==="done"||a.type==="error")&&l.exit()},[a,l]),Qu((u,m)=>{if(m.ctrl&&u==="c"){process.exitCode=130,l.exit();return}if(a.type==="profile-select"){let{profiles:b,cursor:k}=a;if(m.upArrow)p({...a,cursor:(k-1+b.length)%b.length});else if(m.downArrow)p({...a,cursor:(k+1)%b.length});else if(m.return){let I=b[k];I!==void 0&&_(I)}return}if(a.type==="api-name-entry"){let{buffer:b}=a;if(m.backspace||m.delete)p({type:"api-name-entry",buffer:b.slice(0,-1)});else if(m.return){let k=b.trim();if(k===""){p({type:"api-name-entry",buffer:b,error:"api_name cannot be empty"});return}d(k),h?C(h,k,c):v(new Error("Internal error: credentials were not loaded"))}else u&&!m.ctrl&&!m.meta&&p({type:"api-name-entry",buffer:b+u});return}if(a.type==="value-entry"){let{buffer:b}=a;if(m.backspace||m.delete)p({type:"value-entry",buffer:b.slice(0,-1)});else if(m.return){if(b===""){p({type:"value-entry",buffer:b,error:"secret cannot be empty"});return}y(b),h?C(h,x,b):v(new Error("Internal error: credentials were not loaded"))}else u&&!m.ctrl&&!m.meta&&p({type:"value-entry",buffer:b+u});return}});let S=e.isRemote?"remote Kizen API":"on-machine",g=t===!0?`${e.stage} (default)`:e.stage,f=u=>ee(be,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[O(K,{}),ee(H,{dimColor:!0,children:["Mode: ",S," Stage: ",g]}),u]});if(a.type==="loading")return f(ee(be,{gap:1,children:[O(ye,{}),O(H,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(a.type==="profile-select"){let{profiles:u,cursor:m}=a;return f(ee(br,{children:[O(H,{bold:!0,children:"Credential profile"}),O(be,{flexDirection:"column",children:u.map((b,k)=>{let I=m===k;return ee(be,{gap:2,children:[O(H,{...I&&{color:"cyan"},children:I?"\u276F":" "}),O(H,{bold:I,...I&&{color:"cyan"},children:b.isDefault?"Default":b.name}),O(H,{dimColor:!0,children:b.path})]},b.name)})}),O(Bn,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return a.type==="api-name-entry"?f(ee(br,{children:[O(H,{bold:!0,children:"Plugin api_name"}),a.error!==void 0&&ee(H,{color:"red",children:["Error: ",a.error]}),ee(be,{gap:1,children:[O(H,{color:"cyan",children:">"}),O(H,{children:a.buffer}),O(H,{color:"cyan",children:"\u2588"})]}),O(Bn,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):a.type==="value-entry"?f(ee(br,{children:[O(H,{bold:!0,children:"Secret value"}),a.error!==void 0&&ee(H,{color:"red",children:["Error: ",a.error]}),ee(be,{gap:1,children:[O(H,{color:"cyan",children:">"}),O(H,{children:"\u2022".repeat(a.buffer.length)}),O(H,{color:"cyan",children:"\u2588"})]}),O(Bn,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):a.type==="fetching-key"?f(ee(be,{gap:1,children:[O(ye,{}),ee(H,{children:["Fetching ",e.stage," public key for ",O(H,{bold:!0,children:x}),"\u2026"]})]})):a.type==="encrypting"?f(ee(be,{gap:1,children:[O(ye,{}),O(H,{children:"Encrypting\u2026"})]})):a.type==="error"?f(ee(be,{gap:1,children:[O(H,{color:"red",children:"\u2717"}),O(H,{color:"red",children:a.message})]})):f(ee(br,{children:[ee(be,{gap:1,children:[O(H,{color:"green",children:"\u2713"}),O(H,{bold:!0,children:"Encrypted secret ready"})]}),a.copied?O(H,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):O(H,{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):"}),O(H,{children:a.envelope})]}))};import{readFile as ep,writeFile as tp}from"fs/promises";import{join as rp}from"path";function Rs(e){return{encrypted:!0,value:e}}function Bs(e){return JSON.stringify(Rs(e))}async function $n(e,t){await tp(e,`${JSON.stringify(Rs(t),null,2)}
1102
1102
  `,"utf-8")}var np="prod";function $s(e){return e==="dev"||e==="prod"}function js(e){return`Error: --stage must be "dev" or "prod" (got: "${e}")`}function Fs(e){return{stage:e==="dev"||e==="prod"?e:np,wasDefaulted:e===void 0}}function Os(e){return`No --stage given; defaulting to ${e} encryption keys (pass --stage dev to override)
1103
- `}async function zs(e=process.cwd()){try{let t=await ep(rp(e,"kizen.json"),"utf-8"),r=JSON.parse(t),o=Array.isArray(r)?r[0]:r,n=typeof o.api_name=="string"&&o.api_name!==""?o.api_name:void 0;return{...n!==void 0&&{apiName:n}}}catch{}return{}}function Ms(e){return e.replace(/[\r\n]+$/,"")}async function Ls(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function Us(e,t,r,o,n){let i=t.credentials!==void 0?await n.loadCredentialsFromFile(t.credentials):await n.loadGlobalCredentials();if(i===null)throw new Error("No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.");let s=t.apiName??r.apiName;if(s===void 0||s.trim()==="")throw new Error("api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.");o&&n.writeStderr(Os(e.stage));let l=t.value;if(l===void 0){if(n.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`).');n.writeStderr(`Reading secret from stdin (pass --value to skip)\u2026
1103
+ `}async function zs(e=process.cwd()){try{let t=await ep(rp(e,"kizen.json"),"utf-8"),r=JSON.parse(t),o=Array.isArray(r)?r[0]:r,n=typeof o.api_name=="string"&&o.api_name!==""?o.api_name:void 0;return{...n!==void 0&&{apiName:n}}}catch{}return{}}function Ms(e){return e.replace(/[\r\n]+$/,"")}async function Ls(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function Hs(e,t,r,o,n){let i=t.credentials!==void 0?await n.loadCredentialsFromFile(t.credentials):await n.loadGlobalCredentials();if(i===null)throw new Error("No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.");let s=t.apiName??r.apiName;if(s===void 0||s.trim()==="")throw new Error("api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.");o&&n.writeStderr(Os(e.stage));let l=t.value;if(l===void 0){if(n.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`).');n.writeStderr(`Reading secret from stdin (pass --value to skip)\u2026
1104
1104
  `),l=Ms(await n.readStdin())}if(l==="")throw new Error("A secret value is required. Pass --value or pipe it via stdin.");let a=await n.encryptSecret(e,i,s.trim(),l);if(n.writeStdout(`${Bs(a)}
1105
1105
  `),t.out!==void 0)try{await n.writeEnvelopeFile(t.out,a),n.writeStderr(`Wrote encrypted envelope to ${t.out}
1106
1106
  `)}catch(p){n.writeStderr(`Error writing ${t.out}: ${p instanceof Error?p.message:String(p)}
1107
- `),n.setExitCode(1)}}function Hs(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&&!$s(t.stage)&&(console.error(js(t.stage)),process.exit(1));let o=t.apiName===void 0?await zs():{},{stage:n,wasDefaulted:i}=Fs(t.stage),s={isRemote:t.remote===!0,stage:n};if(!process.stdin.isTTY||!process.stdout.isTTY){try{await Us(s,t,o,i,{loadCredentialsFromFile:Ie,loadGlobalCredentials:te,encryptSecret:hr,readStdin:Ls,stdinIsTTY:()=>process.stdin.isTTY,writeStdout:p=>{process.stdout.write(p)},writeStderr:p=>{process.stderr.write(p)},writeEnvelopeFile:$n,setExitCode:p=>{process.exitCode=p}})}catch(p){console.error(`Error: ${p instanceof Error?p.message:String(p)}`),process.exit(1)}return}let l,{waitUntilExit:a}=ip(op(Ds,{ctx:s,stageDefaulted:i,onDone:p=>{l=p},...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 a(),l!==void 0&&t.out!==void 0)try{await $n(t.out,l),process.stderr.write(`Wrote encrypted envelope to ${t.out}
1107
+ `),n.setExitCode(1)}}function Us(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&&!$s(t.stage)&&(console.error(js(t.stage)),process.exit(1));let o=t.apiName===void 0?await zs():{},{stage:n,wasDefaulted:i}=Fs(t.stage),s={isRemote:t.remote===!0,stage:n};if(!process.stdin.isTTY||!process.stdout.isTTY){try{await Hs(s,t,o,i,{loadCredentialsFromFile:Ie,loadGlobalCredentials:te,encryptSecret:hr,readStdin:Ls,stdinIsTTY:()=>process.stdin.isTTY,writeStdout:p=>{process.stdout.write(p)},writeStderr:p=>{process.stderr.write(p)},writeEnvelopeFile:$n,setExitCode:p=>{process.exitCode=p}})}catch(p){console.error(`Error: ${p instanceof Error?p.message:String(p)}`),process.exit(1)}return}let l,{waitUntilExit:a}=ip(op(Ds,{ctx:s,stageDefaulted:i,onDone:p=>{l=p},...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 a(),l!==void 0&&t.out!==void 0)try{await $n(t.out,l),process.stderr.write(`Wrote encrypted envelope to ${t.out}
1108
1108
  `)}catch(p){console.error(`Error writing ${t.out}: ${p instanceof Error?p.message:String(p)}`),process.exitCode=1}})}var sp=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"]),ap=[...sp].sort(),lp=new Set(["kizen-k","form-entity"]),Vs=[...ap,...[...lp].sort()];function Ws(e){e.command("icons").description("List all valid icon names accepted by toolbar items, pages, and adornments").action(()=>{for(let t of Vs)console.log(t)})}import{mkdir as gp,writeFile as ra,readFile as yp}from"fs/promises";import{join as wr}from"path";var cp=new Set(["developer_business_id"]);function dp(e){return Array.isArray(e)?e.map(t=>{if(typeof t!="object"||t===null)return t;let r=t;if(typeof r.auth_credentials!="object"||r.auth_credentials===null)return r;let o=Object.fromEntries(Object.keys(r.auth_credentials).map(n=>[n,"*****"]));return{...r,auth_credentials:o}}):e}function Js(e){let t={name:"",children:new Map,isFile:!1,filePath:""};for(let r of e){let o=r.path.split("/"),n=t;o.forEach((i,s)=>{n.children.has(i)||n.children.set(i,{name:i,children:new Map,isFile:s===o.length-1,filePath:o.slice(0,s+1).join("/")});let l=n.children.get(i);l&&(n=l)})}return t}function qs(e){return[...e.children.values()].sort((t,r)=>t.isFile!==r.isFile?t.isFile?1:-1:t.name.localeCompare(r.name))}function jn(e){return"file-"+e.replace(/[^a-zA-Z0-9]/g,"-")}function we(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function Gs(e){let t=e.lastIndexOf(".");return t>=0?e.slice(t).toLowerCase():""}var up={".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 pp(e){return up[Gs(e)]??""}function Ks(e){let t=[...e.matchAll(/`+/g)].reduce((r,o)=>Math.max(r,o[0].length),0);return"`".repeat(Math.max(3,t+1))}function Ys(e,t=""){let r=qs(e);return r.map((o,n)=>{let i=n===r.length-1,s=i?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",l=i?" ":"\u2502 ";return o.isFile?`${t}${s}${o.name}`:`${t}${s}${o.name}/
1109
1109
  ${Ys(o,t+l)}`}).join(`
1110
1110
  `)}var fp=/(^|\/)licen[cs]e(\.md|\.txt)?$/i;function Xs(e){return e.filter(t=>t.path!=="kizen.json"&&t.path!=="plugin-report.html"&&!fp.test(t.path))}function Zs(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!cp.has(t)).map(([t,r])=>[t,t==="services"?dp(r):r]))}var mp={".png":"image/png",".svg":"image/svg+xml",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp"};function Qs(e){return`<ul>${qs(e).map(o=>o.isFile?`<li class="tf"><a href="#${jn(o.filePath)}" data-id="${jn(o.filePath)}">${we(o.name)}</a></li>`:`<li class="td"><span class="dn">${we(o.name)}/</span>${Qs(o)}</li>`).join("")}</ul>`}function hp(e){let t;return e.base64Image!==void 0?t=`<img src="data:${mp[Gs(e.path)]??"image/png"};base64,${e.base64Image}" alt="${we(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>${we(e.content)}</code></pre>`,`<section id="${jn(e.path)}"><h2 class="fp">${we(e.path)}</h2><div class="fb">${t}</div></section>`}function ea(e,t){let r=Zs(e),o=typeof e.name=="string"?e.name:"Plugin",n=typeof e.version=="string"?e.version:"",i=typeof e.description=="string"?e.description:"",s=Xs(t),l=[];l.push(`# ${o}${n?` v${n}`:""}`),i&&l.push("",i);let a=JSON.stringify(r,null,2),p=Ks(a);l.push("","## Configuration (`kizen.json`)","",`${p}json`,a,p),l.push("","## File Tree","","```",Ys(Js(s)),"```"),l.push("","## Files");for(let h of s)if(l.push("",`### \`${h.path}\``,""),h.base64Image!==void 0)l.push(`[Image file: ${h.path}]`);else if(h.binaryData!==void 0)l.push(`[Binary file: ${String(h.binaryData.length)} bytes]`);else{let w=Ks(h.content);l.push(`${w}${pp(h.path)}`,h.content,w)}return l.join(`
@@ -1177,5 +1177,5 @@ ${a}
1177
1177
  </body>
1178
1178
  </html>`}var na=wr(ze,"examples");function oa(e){e.command("report").description("Generate a self-contained HTML report of the plugin").option("-o, --output <path>",`output file path (default: ${na}/<api_name>.html)`).action(async t=>{let r=process.cwd(),o;try{let a=await yp(wr(r,"kizen.json"),"utf-8"),p=JSON.parse(a);o=Array.isArray(p)?p[0]:p}catch{console.error("Error: kizen.json not found. Run this command from a plugin directory."),process.exit(1)}let n=typeof o.api_name=="string"?o.api_name:"plugin",i=t.output??wr(na,`${n}.html`),s=i.replace(/\.html$/,".md"),l=await $t(r,{detectBinaryByContent:!0});await gp(wr(i,".."),{recursive:!0}),await Promise.all([ra(i,ta(o,l),"utf-8"),ra(s,ea(o,l),"utf-8")]),console.log(`Plugin report written to:
1179
1179
  ${i}
1180
- ${s}`)})}function ia(e){e.command("setup-claude").description("Install or refresh the Claude Code skill for building custom blocks").option("--dry-run","report what would change without writing files").action(async t=>{await Jo(process.cwd(),t)})}function Cp(){let e=xp(wp(vp(import.meta.url)),"..","package.json");return JSON.parse(bp(e,"utf-8")).version}function sa(){let e=new kp;return e.name("appbuilder").description("Kizen plugin app builder").version(Cp()),Ki(e),ia(e),yi(e),Es(e),Hs(e),oa(e),Ws(e),pi(e),e}Un({env:process.env,http:Sp});sa().parse();
1180
+ ${s}`)})}function ia(e){e.command("setup-claude").description("Install or refresh the Claude Code skill for building custom blocks").option("--dry-run","report what would change without writing files").action(async t=>{await Jo(process.cwd(),t)})}function Cp(){let e=xp(wp(vp(import.meta.url)),"..","package.json");return JSON.parse(bp(e,"utf-8")).version}function sa(){let e=new kp;return e.name("appbuilder").description("Kizen plugin app builder").version(Cp()),Ki(e),ia(e),yi(e),Es(e),Us(e),oa(e),Ws(e),pi(e),e}Hn({env:process.env,http:Sp});sa().parse();
1181
1181
  //# sourceMappingURL=index.js.map