@kizenapps/cli 1.12.0-a2af6ac → 1.13.0-1bb4c57
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/README.md +18 -2
- package/dist/THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/index.js +145 -175
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/{AppDetailPage-D9xr-bY8.js → AppDetailPage-CGrukEIj.js} +1 -1
- package/dist/viewer/assets/{CodeStepsPage-D_kTMpRO.js → CodeStepsPage-Cu9UiRy9.js} +1 -1
- package/dist/viewer/assets/ConfigurationPage-CI0pRNJ0.js +1 -0
- package/dist/viewer/assets/{DevSidebar-zX-4CWYv.js → DevSidebar-BFsoIbMt.js} +1 -1
- package/dist/viewer/assets/{SandboxPage-DuCHX1FY.js → SandboxPage-Dyb8i7vf.js} +1 -1
- package/dist/viewer/assets/{SecretsPage-Da55-e_S.js → SecretsPage-g2FF7d-B.js} +1 -1
- package/dist/viewer/assets/{WhenBadge-B7s7fns2.js → WhenBadge-DKz8ukwo.js} +1 -1
- package/dist/viewer/assets/api--pW2v3sH.js +11 -0
- package/dist/viewer/assets/{bootstrapQuery-CyYWFe68.js → bootstrapQuery-DTAPKOf-.js} +1 -1
- package/dist/viewer/assets/{calendarSource.worker-CTgMuhqr.js → calendarSource.worker-DjLHW14n.js} +1 -1
- package/dist/viewer/assets/{floatingFrame.worker-zn66fKUA.js → floatingFrame.worker-Cy3ysIc7.js} +1 -1
- package/dist/viewer/assets/{generic.worker-gJPrf_ED.js → generic.worker-DKCeuXG7.js} +1 -1
- package/dist/viewer/assets/{index-BF1Fk_v0.js → index-GvAPdgKb.js} +3 -3
- package/dist/viewer/assets/{recordDetail.worker-CGLG0Evq.js → recordDetail.worker-DrTKYLJc.js} +1 -1
- package/dist/viewer/assets/storageKeys-BDp-0diL.js +1 -0
- package/dist/viewer/assets/useCompleteSetup-QS3W9RRO.js +40 -0
- package/dist/viewer/assets/usePluginConfig--4sAyik4.js +1 -0
- package/dist/viewer/index.html +4 -4
- package/package.json +3 -3
- package/dist/viewer/assets/ConfigurationPage-5qOX-sx0.js +0 -1
- package/dist/viewer/assets/api--Ax6VWLq.js +0 -11
- package/dist/viewer/assets/storageKeys-DPq6kaaE.js +0 -1
- package/dist/viewer/assets/useCompleteSetup-DUHoBgca.js +0 -40
- package/dist/viewer/assets/usePluginConfig-C8d13THZ.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as
|
|
3
|
-
`).map(
|
|
4
|
-
`)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import{readFileSync as ul}from"fs";import{dirname as fl,join as ml}from"path";import{fileURLToPath as gl}from"url";import{Command as hl}from"commander";import{createElement as hi}from"react";import{render as yi}from"ink";import{useEffect as wr,useState as Me}from"react";import{Box as He,Text as Be,useApp as ui}from"ink";import{PluginValidationError as fi}from"@kizenapps/packager";import{mkdir as Vo,writeFile as qo}from"fs/promises";import{join as Jo}from"path";import{PluginValidationError as Wo,packagePlugin as Go,parseManifestFromFiles as Ko,transformDeployablePlugin as Yo,transformFiles as Xo,validatePluginApp as Zo}from"@kizenapps/packager";import{readdir as jo,readFile as mr}from"fs/promises";import{join as gr,relative as Lo}from"path";var Oo=new Set([".png",".svg"]),zo=new Set([".kzn"]),Mo=new Set([".DS_Store"]),rt=new Set(["node_modules",".git",".kizenapp",".copilot-docs",".github",".claude","__pycache__"]),Ho=8e3;function Uo(e){return e.subarray(0,Ho).includes(0)}async function hr(e,t){let n=await jo(e,{withFileTypes:!0}),o=[];for(let r of n)if(r.isDirectory()){if(rt.has(r.name))continue;o.push(...await hr(gr(e,r.name),t))}else r.isFile()&&(Mo.has(r.name)||o.push(gr(e,r.name)));return o}async function nt(e,{detectBinaryByContent:t=!1}={}){let n=await hr(e,e);return Promise.all(n.map(async o=>{let r=Lo(e,o).split("\\").join("/"),i=r.lastIndexOf("."),p=i>=0?r.slice(i).toLowerCase():"";if(Oo.has(p)){let g=await mr(o);return{path:r,content:"",base64Image:g.toString("base64")}}let f=await mr(o);return zo.has(p)||t&&Uo(f)?{path:r,content:"",binaryData:f}:{path:r,content:f.toString("utf-8")}}))}var Qo=(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 ot(e,t,n){await Vo(t,{recursive:!0}),n?.("reading-files");let o=await nt(e);n?.("validating");let r=Zo(o);if(r.some(x=>x.severity==="error"))throw new Wo(r);n?.("minifying");let i=await Xo(o);n?.("packaging");let p=Ko(i),f=Go(i,p),g=Object.values(f).map(Yo);n?.("writing-bundle");let m=g.map(x=>{let c=x.release_notes_directory?.replace(/\/$/,""),b=c?o.filter(w=>w.path.startsWith(c+"/")&&w.path.endsWith(".md")&&w.content).map(w=>({version:w.path.slice(w.path.lastIndexOf("/")+1,-3),notes:w.content})).sort((w,H)=>H.version.localeCompare(w.version,void 0,{numeric:!0})):[];return Qo(x,b)}),y=JSON.stringify(m,null,2),T=(x,c)=>x==="allReleaseNotes"?void 0:c,P=Buffer.byteLength(JSON.stringify(m,T,2),"utf-8");return await qo(Jo(t,"bundle.json"),y,"utf-8"),{bundleSize:P}}function Oe(e){return e<1024?`${String(e)} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}import{Box as ni,Text as oi}from"ink";import{Box as ei,Text as ti}from"ink";import{jsx as yr}from"react/jsx-runtime";var ri=[" :::::::: "," :::::: ::::::::::: "," :::::: :::::::::: "," :::::: :::::: ::::::: "," ::::: :::::: ::::::::::::::::: "," ::::: ::::: ::::::::::::::::::: "," ::::: ::::: :::::: ::::: ",":::: ::::: ::: ::::: :: ","::::: :::::: :::::::::: ","::::: :::::: ::::::::::: "," ::::: ::: ::::::: "," ::::::: ::: ::::: "," ::::::::::: :::::: :::::"," :::::::::: :::::: :::::"," :: ::::: ::: ::::: ::::"," ::::: :::::: ::::: ::::: ::: "," ::::::::::::::::::: ::::: ::::: "," ::::::::::::::::: ::::: ::::: "," ::::::::: :::::: :::::: "," :::::::::: :::::: "," ::::::::::: :::::: "," :::::::: "],br=()=>yr(ei,{flexDirection:"column",children:ri.map((e,t)=>yr(ti,{color:"cyan",children:e},t))});import{Fragment as ii,jsx as Lt,jsxs as si}from"react/jsx-runtime";var q=({marginBottom:e=0})=>si(ii,{children:[Lt(br,{}),Lt(ni,{flexDirection:"column",marginTop:1,marginBottom:e,children:Lt(oi,{bold:!0,color:"cyan",children:"Kizen App Development Toolkit"})})]});import{useEffect as ai,useState as li}from"react";import{Text as ci}from"ink";import{jsx as di}from"react/jsx-runtime";var xr=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],me=()=>{let[e,t]=li(0);return ai(()=>{let n=setInterval(()=>{t(o=>(o+1)%xr.length)},80);return()=>{clearInterval(n)}},[]),di(ci,{color:"cyan",children:xr[e]??"\u280B"})};import{Box as Ot,Text as it}from"ink";import{jsx as vr,jsxs as ze}from"react/jsx-runtime";var pi=e=>{let t=new Map;for(let n of e){let o=n.path??n.pluginApiName??"general",r=t.get(o)??[];r.push(n),t.set(o,r)}return t},st=({issues:e})=>{let t=e.filter(n=>n.severity==="error").length;return ze(Ot,{flexDirection:"column",marginTop:1,children:[ze(it,{color:"red",children:["\u2717 ",t," validation ",t===1?"error":"errors"]}),[...pi(e)].map(([n,o])=>ze(Ot,{flexDirection:"column",marginTop:1,children:[vr(it,{bold:!0,children:n}),o.map((r,i)=>vr(Ot,{paddingLeft:2,children:ze(it,{color:r.severity==="error"?"red":"yellow",children:[r.severity==="error"?"\u2717":"\u26A0"," ",r.message," ",ze(it,{dimColor:!0,children:["(",r.rule,")"]})]})},`${r.rule}-${String(i)}`))]},n))]})};import{Fragment as mi,jsx as ge,jsxs as Pe}from"react/jsx-runtime";var Cr=["creating-dir","reading-files","validating","minifying","packaging","writing-bundle"],at={"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"},Sr=({outputDir:e,pluginDir:t})=>{let n=ui(),[o,r]=Me("creating-dir"),[i,p]=Me(!1),[f,g]=Me(null),[m,y]=Me(null),[T,P]=Me(null);wr(()=>{ot(t,e,r).then(({bundleSize:b})=>{P(b),r("done")}).catch(b=>{b instanceof fi?g(b.issues):y(b instanceof Error?b.message:String(b)),p(!0),process.exitCode=1})},[e,t]),wr(()=>{(o==="done"||i)&&n.exit()},[o,i,n]);let x=Cr.indexOf(o),c=o==="done";return Pe(He,{flexDirection:"column",paddingY:1,paddingX:2,children:[ge(q,{marginBottom:1}),Pe(He,{flexDirection:"column",gap:0,children:[Cr.map((b,w)=>{let H=o===b,j=c||x>w;return ge(He,{gap:1,children:i&&w===x?Pe(Be,{color:"red",children:["\u2717 ",at[b]]}):j?Pe(Be,{color:"green",children:["\u2713 ",at[b]]}):H?Pe(mi,{children:[ge(me,{}),ge(Be,{children:at[b]})]}):Pe(Be,{dimColor:!0,children:[" ",at[b]]})},b)}),c&&T!==null&&ge(He,{marginTop:1,gap:1,children:Pe(Be,{color:"green",children:["\u2713 bundle \u2014 ",Oe(T)]})}),f!==null&&ge(st,{issues:f}),m!==null&&ge(He,{marginTop:1,borderStyle:"single",borderColor:"red",paddingX:1,children:ge(Be,{color:"red",children:m})})]})]})};import*as Ae from"fs";import*as Tr from"path";var gi=[".kizenapp/",".copilot-docs/"];function he(e){let t=Tr.join(e,".gitignore"),n="";Ae.existsSync(t)&&(n=Ae.readFileSync(t,"utf8"));let o=new Set(n.split(`
|
|
3
|
+
`).map(f=>f.trim())),r=gi.filter(f=>!o.has(f)&&!o.has(f.replace(/\/$/,"")));if(r.length===0)return;let i=r.join(`
|
|
4
|
+
`)+`
|
|
5
|
+
`,p=n===""||n.endsWith(`
|
|
6
|
+
`)?i:`
|
|
7
|
+
`+i;Ae.writeFileSync(t,n+p)}function Er(e){e.command("build").description("Bundle the plugin app into .kizenapp directory").action(async()=>{let t=process.cwd(),n=`${t}/.kizenapp`;he(t);let{waitUntilExit:o}=yi(hi(Sr,{outputDir:n,pluginDir:t}));await o()})}import{createElement as ws}from"react";import{render as Cs}from"ink";import{useCallback as gt,useState as De}from"react";import{Box as M,Text as I,useApp as as,useInput as ls}from"ink";import{join as ht}from"path";import{access as ns,mkdir as dt,writeFile as Vt}from"fs/promises";import{dirname as os,join as ce}from"path";var _r=`{
|
|
8
8
|
"name": "Hello Frame",
|
|
9
9
|
"api_name": "hello_frame",
|
|
10
10
|
"title": "Hello Frame",
|
|
@@ -13,13 +13,13 @@ import{readFileSync as Ya}from"fs";import{dirname as Xa,join as Za}from"path";im
|
|
|
13
13
|
"height": 320,
|
|
14
14
|
"width": 280
|
|
15
15
|
}
|
|
16
|
-
`;var
|
|
16
|
+
`;var kr=`this.outputUI(\`
|
|
17
17
|
<div class="hello-frame">
|
|
18
18
|
<h2 class="hello-frame__title">Hello from a floating frame</h2>
|
|
19
19
|
<p class="hello-frame__body">Edit src/floatingFrames/helloFrame/script.js to change this.</p>
|
|
20
20
|
</div>
|
|
21
21
|
\`);
|
|
22
|
-
`;var
|
|
22
|
+
`;var Pr=`.hello-frame {
|
|
23
23
|
padding: 16px;
|
|
24
24
|
font-family: system-ui, sans-serif;
|
|
25
25
|
}
|
|
@@ -33,12 +33,12 @@ import{readFileSync as Ya}from"fs";import{dirname as Xa,join as Za}from"path";im
|
|
|
33
33
|
margin: 0;
|
|
34
34
|
color: #555;
|
|
35
35
|
}
|
|
36
|
-
`;var
|
|
36
|
+
`;var Ir=`{
|
|
37
37
|
"name": "Hello Block",
|
|
38
38
|
"api_name": "hello_block",
|
|
39
39
|
"types": ["dashboards"]
|
|
40
40
|
}
|
|
41
|
-
`;var
|
|
41
|
+
`;var Nr=`this.outputUI(\`
|
|
42
42
|
<div class="hello-block">
|
|
43
43
|
<h2 class="hello-block__title">Hello from a block</h2>
|
|
44
44
|
<p class="hello-block__body">Edit src/blocks/helloBlock/script.js to change this.</p>
|
|
@@ -60,25 +60,25 @@ import{readFileSync as Ya}from"fs";import{dirname as Xa,join as Za}from"path";im
|
|
|
60
60
|
margin: 0;
|
|
61
61
|
color: #555;
|
|
62
62
|
}
|
|
63
|
-
`;var
|
|
63
|
+
`;var Br=`{
|
|
64
64
|
"icon": "phone",
|
|
65
65
|
"color": "#0ea5e9",
|
|
66
66
|
"tooltip": "Hello adornment",
|
|
67
67
|
"field_type": "phonenumber"
|
|
68
68
|
}
|
|
69
|
-
`;var
|
|
70
|
-
`;var
|
|
69
|
+
`;var Ar=`this.showToast('Hello from a data adornment.', { variant: 'success' });
|
|
70
|
+
`;var Dr=`{
|
|
71
71
|
"name": "Hello Page",
|
|
72
72
|
"api_name": "hello_page"
|
|
73
73
|
}
|
|
74
|
-
`;var
|
|
74
|
+
`;var Fr=`this.outputUI(\`
|
|
75
75
|
<div class="hello-page">
|
|
76
76
|
<p class="hello-page__loading">Loading\u2026</p>
|
|
77
77
|
</div>
|
|
78
78
|
\`);
|
|
79
79
|
|
|
80
80
|
this.runEventScript('greet');
|
|
81
|
-
`;var
|
|
81
|
+
`;var $r=`.hello-page {
|
|
82
82
|
padding: 24px;
|
|
83
83
|
font-family: system-ui, sans-serif;
|
|
84
84
|
}
|
|
@@ -116,7 +116,7 @@ this.runEventScript('greet');
|
|
|
116
116
|
.hello-page__button:hover {
|
|
117
117
|
background: #cbd5e1;
|
|
118
118
|
}
|
|
119
|
-
`;var
|
|
119
|
+
`;var jr=`const tone = this.args?.formData?.tone?.[0] ?? 'plain';
|
|
120
120
|
|
|
121
121
|
const greeting = tone === 'cheer' ? 'Hello, and good to see you!' : 'Hello from a routable page.';
|
|
122
122
|
|
|
@@ -139,170 +139,138 @@ this.outputUI(\`
|
|
|
139
139
|
</div>
|
|
140
140
|
</div>
|
|
141
141
|
\`);
|
|
142
|
-
`;var
|
|
142
|
+
`;var Lr=`{
|
|
143
143
|
"api_name": "hello_toolbar_item",
|
|
144
144
|
"label": "Hello Toolbar Item",
|
|
145
145
|
"icon": "star",
|
|
146
146
|
"color": "#0ea5e9"
|
|
147
147
|
}
|
|
148
|
-
`;var
|
|
149
|
-
`;var
|
|
148
|
+
`;var Or=`this.showToast('Hello from a toolbar item.', { variant: 'success' });
|
|
149
|
+
`;var zr=`{
|
|
150
150
|
"api_name": "hello_object_settings_item",
|
|
151
151
|
"label": "Hello Object Settings"
|
|
152
152
|
}
|
|
153
153
|
`;var Mr=`this.showToast('Hello from an object settings item.', { variant: 'success' });
|
|
154
|
-
`;var
|
|
154
|
+
`;var Hr=`{
|
|
155
155
|
"name": "Hello Action",
|
|
156
156
|
"api_name": "hello_action",
|
|
157
157
|
"hint_object_name": "client_client"
|
|
158
158
|
}
|
|
159
|
-
`;var
|
|
160
|
-
`;var X=["floatingFrame","block","dataAdornment","page","toolbarItem","objectSettingsItem","jsAction"],
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
unexpected endpoint, or otherwise exfiltrated. Review for this by hand: look
|
|
215
|
-
for credentials or decrypted secret values flowing into \`console.log\`, error
|
|
216
|
-
messages, analytics calls, or outbound requests to anything other than the
|
|
217
|
-
service they belong to.
|
|
218
|
-
|
|
219
|
-
## Handling secrets in this repo
|
|
220
|
-
|
|
221
|
-
Encrypt secrets locally with \`appbuilder encrypt\` before committing them. Do
|
|
222
|
-
not commit a plaintext secret value in any form; a comment, a script fixture,
|
|
223
|
-
and a commit you intend to rewrite later all count.
|
|
224
|
-
`;var Jr=`---
|
|
159
|
+
`;var Ur=`this.showToast('Hello from a JS action.', { variant: 'success' });
|
|
160
|
+
`;var X=["floatingFrame","block","dataAdornment","page","toolbarItem","objectSettingsItem","jsAction"],zt={floatingFrame:"Floating frame",block:"Block",dataAdornment:"Data adornment",page:"Routable page",toolbarItem:"Toolbar item",objectSettingsItem:"Object settings item",jsAction:"JS action"},$i={floatingFrame:{directory:"floatingFrames",component:"helloFrame",files:{"config.json":_r,"script.js":kr,"styles.css":Pr}},block:{directory:"blocks",component:"helloBlock",files:{"config.json":Ir,"script.js":Nr,"styles.css":Rr}},dataAdornment:{directory:"dataAdornments",component:"helloAdornment",files:{"config.json":Br,"script.js":Ar}},page:{directory:"pages",component:"helloPage",files:{"config.json":Dr,"script.js":Fr,"styles.css":$r,"eventScripts/greet.js":jr}},toolbarItem:{directory:"toolbarItems",component:"helloToolbarItem",files:{"config.json":Lr,"script.js":Or}},objectSettingsItem:{directory:"objectSettingsItems",component:"helloObjectSettingsItem",files:{"config.json":zr,"script.js":Mr}},jsAction:{directory:"actions",component:"helloAction",files:{"config.json":Hr,"script.js":Ur}}};function ji(e,t="src"){let{directory:n,component:o,files:r}=$i[e];return Object.entries(r).map(([i,p])=>({path:`${t}/${n}/${o}/${i}`,content:p}))}function Vr(e,t="src"){return[...new Set(e)].flatMap(n=>ji(n,t))}var qr=`# Copilot review instructions for this Kizen plugin
|
|
161
|
+
|
|
162
|
+
This repo is a Kizen plugin app: a \`kizen.json\` manifest plus the artifacts
|
|
163
|
+
that \`@kizenapps/packager\` finds by walking the directory tree under the
|
|
164
|
+
manifest's \`entry\` (default \`src/\`). No manifest key lists artifacts. The
|
|
165
|
+
directory layout decides what gets packaged.
|
|
166
|
+
|
|
167
|
+
## The full Kizen plugin documentation is available at \`.copilot-docs/\`
|
|
168
|
+
|
|
169
|
+
Before this review started, the complete Kizen plugin developer documentation
|
|
170
|
+
was fetched into \`.copilot-docs/\` by \`.github/workflows/copilot-code-review.yml\`.
|
|
171
|
+
It is not committed to this repo \u2014 it is cloned from \`kizen/app-engine\` at review
|
|
172
|
+
time, so it is always current. It is the authoritative reference for every plugin
|
|
173
|
+
API, manifest field and runtime contract. Deliberately, no plugin rules are
|
|
174
|
+
copied into this repo: read them from \`.copilot-docs/\` instead.
|
|
175
|
+
|
|
176
|
+
Use it. Start from:
|
|
177
|
+
|
|
178
|
+
- \`.copilot-docs/17-gotchas.md\` \u2014 the consolidated list of traps and silent
|
|
179
|
+
failure modes, grouped by topic. Scan the sections relevant to the changed
|
|
180
|
+
files.
|
|
181
|
+
- \`.copilot-docs/method-index.md\` \u2014 A\u2013Z lookup from any method, manifest field,
|
|
182
|
+
endpoint or identifier to the doc that owns it.
|
|
183
|
+
- \`.copilot-docs/03-manifest-reference.md\` \u2014 every \`kizen.json\` and \`config.json\`
|
|
184
|
+
field, the component directory names, \`api_name\` rules, and the build/publish
|
|
185
|
+
validation rules.
|
|
186
|
+
- The other numbered docs (\`.copilot-docs/04-worker-runtime-api.md\`,
|
|
187
|
+
\`.copilot-docs/07-automation-steps.md\`, \`.copilot-docs/08-actions.md\`, and so
|
|
188
|
+
on) for complete contracts.
|
|
189
|
+
|
|
190
|
+
**Many Kizen plugin APIs fail silently when misused** \u2014 the call succeeds,
|
|
191
|
+
nothing throws, and the behavior is quietly wrong. These defects are not
|
|
192
|
+
detectable from the calling code alone, and they are the single most valuable
|
|
193
|
+
thing to catch in review. When a changed file calls a \`this.*\` worker method,
|
|
194
|
+
look that method up in \`method-index.md\` and read its contract before concluding
|
|
195
|
+
the call is correct.
|
|
196
|
+
|
|
197
|
+
The same applies to artifact config: check each \`config.json\` against
|
|
198
|
+
\`03-manifest-reference.md\`, and each automation step against
|
|
199
|
+
\`07-automation-steps.md\`.
|
|
200
|
+
|
|
201
|
+
When a review comment is based on the documentation, name the file it came from.
|
|
202
|
+
|
|
203
|
+
If \`.copilot-docs/\` is not present, the setup workflow did not run \u2014 it only
|
|
204
|
+
takes effect once it is on the repository's default branch \u2014 so say that in
|
|
205
|
+
the review instead of guessing at the rules from memory.
|
|
206
|
+
|
|
207
|
+
## Scope
|
|
208
|
+
|
|
209
|
+
This file covers repo structure and general review. Two path-scoped files cover
|
|
210
|
+
the rest: \`.github/instructions/security.instructions.md\` for security-sensitive
|
|
211
|
+
patterns and \`.github/instructions/version-discipline.instructions.md\` for
|
|
212
|
+
manifest version bumps.
|
|
213
|
+
`;var Jr='---\napplyTo: "src/**/*.js,kizen.json"\n---\n\n# Security review rules for plugin scripts\n\nThe rules themselves live in the docs corpus that\n`.github/workflows/copilot-code-review.yml` fetches into `.copilot-docs/`, so\nthey cannot drift out of date here. Read them there rather than reviewing from\nmemory.\n\nWhen a change touches a service, `auth_credentials`, a `{{secret.KEY}}`\nreference, `base_config.secrets`, or dynamic code (`eval`, `new Function`, or a\nstring argument to `setTimeout` or `setInterval`), read\n`.copilot-docs/06-auth-secrets-services.md` together with the "Services, auth &\nsecrets" and "Release & publish" sections of `.copilot-docs/17-gotchas.md`, and\nreview the change against what they say.\n\nWhen a change uses `__dangerouslySkipProxy`, also read\n`.copilot-docs/11-output-ui-iframes-frames.md`.\n';var Wr=`---
|
|
225
214
|
applyTo: "kizen.json"
|
|
226
215
|
---
|
|
227
216
|
|
|
228
217
|
# Version-bump discipline for \`kizen.json\`
|
|
229
218
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
| Automation step | add optional input | MINOR |
|
|
278
|
-
| Automation step | change python runtime | PATCH |
|
|
279
|
-
| Automation step | edit script body only | PATCH |
|
|
280
|
-
| Artifact (frame, block, adornment, page, route script, toolbar/object-settings item, calendar source) | add | MINOR |
|
|
281
|
-
| Artifact | remove | MINOR |
|
|
282
|
-
| Artifact | rename \`api_name\` | MINOR |
|
|
283
|
-
| Artifact | edit script or behavior | PATCH |
|
|
284
|
-
| JS action | add | MINOR |
|
|
285
|
-
| JS action | remove | MAJOR |
|
|
286
|
-
| JS action | rename \`api_name\` | MAJOR |
|
|
287
|
-
| JS action | change \`hint_object_name\` or script | PATCH |
|
|
288
|
-
| Config field | add optional (with default) | MINOR |
|
|
289
|
-
| Config field | add required (no default) | MAJOR |
|
|
290
|
-
| Config field | remove | MINOR |
|
|
291
|
-
| Config field | rename | MAJOR |
|
|
292
|
-
| Config field | change type | MAJOR |
|
|
293
|
-
| Config field | change default or label | PATCH |
|
|
294
|
-
| \`required_entitlement\` | add gating | MINOR |
|
|
295
|
-
| \`required_entitlement\` | change or remove | PATCH |
|
|
296
|
-
| Manifest metadata (\`name\`, \`description\`, \`entry\`, \`release_branches\`, \`release_environments\`, \`published\`, \`developer_business_id\`) | any change | PATCH |
|
|
297
|
-
`;function Wr(){return[{path:".github/copilot-instructions.md",content:Vr},{path:".github/instructions/security.instructions.md",content:qr},{path:".github/instructions/version-discipline.instructions.md",content:Jr}]}import{deflateSync as ji}from"zlib";var zt=512,$i=150,Li=26,Ht=46,Kr=.6,Mi=Ht*.55,zi=.55,Hi=.47;function Ui(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=t+((t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24))>>>0;return t}function Vi(e){let t=Ui(e);return{hue:t%360,quarterTurns:(t>>>16)%4}}function qi(e,t,n){let o=(1-Math.abs(2*n-1))*t,r=e/60,i=o*(1-Math.abs(r%2-1)),d=n-o/2,[f,g,m]=r<1?[o,i,0]:r<2?[i,o,0]:r<3?[0,o,i]:r<4?[0,i,o]:r<5?[i,0,o]:[o,0,i];return[Math.round((f+d)*255),Math.round((g+d)*255),Math.round((m+d)*255)]}function He(e,t,n,o,r){let i=Math.abs(e)-n+r,d=Math.abs(t)-o+r;return Math.hypot(Math.max(i,0),Math.max(d,0))+Math.min(Math.max(i,d),0)-r}function at(e,t,n,o,r){return Math.hypot(e-n,t-o)-r}function Ji(e,t){let n=$i,o=Ht,r=o*Kr,i=Mi,d=He(e,t,n,n,Li),f=Math.min(at(e,t,0,-n-r,o),He(e,t+n+r/2,i,r/2+1,0)),g=Math.min(at(e,t,n+r,0,o),He(e-n-r/2,t,r/2+1,i,0));d=Math.min(d,f,g);let m=Math.min(at(e,t,0,n-r,o),He(e,t-n+r/2,i,r/2+1,0)),b=Math.min(at(e,t,-n+r,0,o),He(e+n-r/2,t,r/2+1,i,0));return Math.max(d,-m,-b)}function Wi(e){let t=zt,n=new Uint8Array(t*t*4),[o,r,i]=qi(e.hue,zi,Hi),d=Ht*(1+Kr),f=(t-1)/2,g=d/2;for(let m=0;m<t;m+=1)for(let b=0;b<t;b+=1){let T=b-f,P=m-f;for(let S=0;S<e.quarterTurns;S+=1)[T,P]=[-P,T];let x=Ji(T+g,P-g),p=Math.min(1,Math.max(0,.5-x));if(p<=0)continue;let y=(m*t+b)*4;n[y]=o,n[y+1]=r,n[y+2]=i,n[y+3]=Math.round(p*255)}return n}var Ki=new Uint32Array(256).map((e,t)=>{let n=t;for(let o=0;o<8;o+=1)n=n&1?3988292384^n>>>1:n>>>1;return n>>>0});function Gi(e){let t=4294967295;for(let n of e)t=(Ki[(t^n)&255]??0)^t>>>8;return(t^4294967295)>>>0}function Mt(e,t){let n=Buffer.from(e,"latin1"),o=Buffer.alloc(4);o.writeUInt32BE(t.length);let r=Buffer.alloc(4);return r.writeUInt32BE(Gi(Buffer.concat([n,t]))),Buffer.concat([o,n,t,r])}var Yi=Buffer.from([137,80,78,71,13,10,26,10]);function Xi(e,t,n){if(n.length!==e*t*4)throw new Error(`encodePng: expected ${String(e*t*4)} bytes of RGBA for ${String(e)}x${String(t)}, got ${String(n.length)}`);let o=Buffer.alloc(13);o.writeUInt32BE(e,0),o.writeUInt32BE(t,4),o[8]=8,o[9]=6;let r=e*4,i=Buffer.alloc((r+1)*t);for(let d=0;d<t;d+=1)i.set(n.subarray(d*r,(d+1)*r),d*(r+1)+1);return Buffer.concat([Yi,Mt("IHDR",o),Mt("IDAT",ji(i,{level:9})),Mt("IEND",new Uint8Array(0))])}function Gr(e){return Xi(zt,zt,Wi(Vi(e)))}var es="src/thumbnail.png",ts=["go","fmo"];async function ct(e){try{return await Zi(e),!0}catch{return!1}}async function dt(e){return await ct(ce(e,"kizen.json"))?"has-manifest":await ct(ce(e,".kizenapp"))?"has-kizenapp":"ok"}async function Xr(e,t){let n=ce(e,t);if(!await ct(n))return n;for(let o=1;o<1e3;o++){let r=ce(e,`${t}-${String(o)}`);if(!await ct(r))return r}throw new Error(`Could not find an available directory name for "${t}"`)}function Vt(e){let t=e.developerBusinessId.trim(),n=t!==""&&!ts.includes(e.developerEnvironment)?[e.developerEnvironment]:["prod"];return{name:e.name,version:"1.0.0",published:!0,api_name:e.apiName,external_link:e.externalLink,description:e.description,entry:"src/",engine:"1.0.0",release_notes_directory:"releaseNotes/",release_environments:n,config_template:{},base_config:{},...t?{developer_business_id:{[e.developerEnvironment]:t}}:{}}}async function Yr(e,t){let n=t.map(r=>({fullPath:ce(e,...r.path.split("/")),content:r.content})),o=new Set(n.map(r=>Qi(r.fullPath)));await Promise.all([...o].map(r=>lt(r,{recursive:!0}))),await Promise.all(n.map(r=>Ut(r.fullPath,r.content,"utf-8")))}async function pt(e){await lt(e.targetDir,{recursive:!0});let t=Vt(e);await Ut(ce(e.targetDir,"kizen.json"),JSON.stringify(t,null,2)+`
|
|
298
|
-
`,"utf-8"),await lt(ce(e.targetDir,"src"),{recursive:!0}),await lt(ce(e.targetDir,"releaseNotes"),{recursive:!0}),await Promise.all([Yr(e.targetDir,Ur(e.artifacts??[])),Yr(e.targetDir,Wr()),Ut(ce(e.targetDir,...es.split("/")),Gr(e.apiName))]),Ne(e.targetDir)}var he=["name","apiName","externalLink","description","developerBusinessId"],ut={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},qt=["name","apiName","description"],Jt=/^[a-z_][a-z0-9_]+$/,Wt="must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)";function ft(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Zr(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function Qr(e,t){let n=t.trim();if(qt.includes(e)&&!n)return`${ut[e]} is required`;if(e==="apiName"&&!Jt.test(n))return`${ut[e]} ${Wt}`}function en(e,t){return e==="description"?t:t.trim()}function tn(e,t){let n=new Set(e);return n.has(t)?n.delete(t):n.add(t),X.filter(o=>n.has(o))}import{jsx as E,jsxs as N}from"react/jsx-runtime";var ke=({text:e})=>E(I,{dimColor:!0,children:e}),rn=({parentDir:e,defaultBusinessId:t,defaultEnvironment:n})=>{let o=rs(),[r,i]=Be({type:"target-select",cursor:0}),[d,f]=Be("in-place"),[g,m]=Be(()=>Zr(t)),[b,T]=Be(()=>[...X]),[P,x]=Be(""),[p,y]=Be(e),S=mt((v,c)=>{f(v),x(c.name),i({type:"field-entry",field:0,values:c})},[]),H=mt(async v=>{let c=await dt(v);if(c!=="ok"){i({type:"precheck-error",targetDir:v,reason:c});return}y(v),S("in-place",g)},[g,S]),O=mt(async(v,c)=>{try{let a=await Xr(e,v.apiName);y(a),i({type:"confirm",values:v,artifacts:c})}catch(a){i({type:"error",message:a instanceof Error?a.message:String(a)})}},[e]),w=mt(async(v,c,a)=>{try{await pt({targetDir:c,name:v.name,apiName:v.apiName,externalLink:v.externalLink,description:v.description,developerBusinessId:v.developerBusinessId,developerEnvironment:n,artifacts:a}),i({type:"done",targetDir:c})}catch(s){i({type:"error",message:s instanceof Error?s.message:String(s)})}},[n]);if(ns((v,c)=>{if(c.ctrl&&v==="c"){o.exit();return}if(r.type==="target-select"){c.upArrow?i({type:"target-select",cursor:0}):c.downArrow?i({type:"target-select",cursor:1}):c.return?r.cursor===0?H(e):S("sub-dir",g):c.escape&&o.exit();return}if(r.type==="precheck-error"){(c.return||c.escape)&&o.exit();return}if(r.type==="field-entry"){let{field:a,values:s}=r,l=he[a];if(!l)return;if(c.escape){o.exit();return}if(c.backspace||c.delete){x(u=>u.slice(0,-1));return}if(c.upArrow&&a>0){let u={...s,[l]:P},h=a-1,k=he[h];i({type:"field-entry",field:h,values:u}),m(u),x(k?u[k]:"");return}if(c.return||c.tab||c.downArrow){let u=Qr(l,P);if(u!==void 0){i({type:"field-entry",field:a,values:s,fieldError:u});return}let h=en(l,P),k={...s,[l]:h};m(k);let _=a+1;if(_>=he.length)x(""),i({type:"artifact-select",values:k,cursor:0,selected:b});else{let A=he[_],M=A?k[A]:"",W=A==="apiName"&&!M?ft(k.name):M;i({type:"field-entry",field:_,values:k}),x(W)}return}v&&!c.ctrl&&!c.meta&&x(u=>u+v);return}if(r.type==="artifact-select"){let{cursor:a,selected:s,values:l}=r;if(c.escape){let u=he.length-1,h=he[u];i({type:"field-entry",field:u,values:l}),x(h?l[h]:"");return}if(c.upArrow){i({...r,cursor:Math.max(0,a-1)});return}if(c.downArrow){i({...r,cursor:Math.min(X.length-1,a+1)});return}if(v===" "){let u=X[a];if(u){let h=tn(s,u);T(h),i({...r,selected:h})}return}if(v==="a"){T([...X]),i({...r,selected:[...X]});return}if(v==="n"){T([]),i({...r,selected:[]});return}c.return&&(d==="sub-dir"?(i({type:"resolving-target"}),O(l,s)):i({type:"confirm",values:l,artifacts:s}));return}if(r.type==="confirm"){if(c.escape){i({type:"artifact-select",values:r.values,cursor:0,selected:r.artifacts});return}c.return&&(i({type:"writing"}),w(r.values,p,r.artifacts));return}(r.type==="done"||r.type==="error")&&(c.return||c.escape)&&o.exit()}),r.type==="target-select"){let v=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Where should the new plugin live?"}),v.map((c,a)=>{let s=r.cursor===a;return N(z,{gap:2,children:[E(I,{...s&&{color:"cyan"},children:s?"\u276F":" "}),E(I,{bold:s,...s&&{color:"cyan"},children:c.label}),E(I,{dimColor:!0,children:c.desc})]},c.label)})]}),E(ke,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="precheck-error"){let{targetDir:v,reason:c}=r;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),E(I,{color:"red",bold:!0,children:"Cannot create plugin"}),N(z,{flexDirection:"column",gap:0,children:[N(I,{children:[v," already contains ",E(I,{bold:!0,children:c==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),E(I,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),E(ke,{text:"Enter or Esc to exit"})]})}if(r.type==="field-entry"){let{field:v,fieldError:c}=r,a=d==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${p}`;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Plugin details"}),E(I,{dimColor:!0,children:a})]}),c!==void 0&&N(I,{color:"red",children:["Error: ",c]}),E(z,{flexDirection:"column",gap:0,children:he.map((s,l)=>{let u=v===l,h=u?P:g[s],k=qt.includes(s),_=`${ut[s]}${k?"":" (optional)"}`;return N(z,{gap:2,children:[E(z,{width:24,children:E(I,{bold:u,...u&&{color:"cyan"},children:_})}),E(I,{...u&&{color:"cyan"},children:">"}),E(I,{children:h}),u&&E(I,{color:"cyan",children:"\u2588"})]},s)})}),E(ke,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(r.type==="artifact-select"){let{cursor:v,selected:c}=r;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Which artifacts should we scaffold?"}),E(I,{dimColor:!0,children:"Each one gets a directory with a config.json and a script that runs."})]}),E(z,{flexDirection:"column",gap:0,children:X.map((a,s)=>{let l=v===s,u=c.includes(a);return N(z,{gap:1,children:[E(I,{...l&&{color:"cyan"},children:l?"\u276F":" "}),E(I,{...u&&{color:"green"},children:u?"\u25C9":"\u25EF"}),E(I,{bold:l,...l&&{color:"cyan"},children:Lt[a]})]},a)})}),E(ke,{text:"\u2191\u2193 move \xB7 Space toggle \xB7 a all \xB7 n none \xB7 Enter continue \xB7 Esc back"})]})}if(r.type==="confirm"){let v=Vt({targetDir:p,name:r.values.name,apiName:r.values.apiName,externalLink:r.values.externalLink,description:r.values.description,developerBusinessId:r.values.developerBusinessId,developerEnvironment:n});return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Ready to create"}),N(I,{dimColor:!0,children:["Target: ",p]})]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"kizen.json preview"}),E(I,{children:JSON.stringify(v,null,2)})]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Artifacts"}),r.artifacts.length===0?N(I,{dimColor:!0,children:[" ","none (src/ will hold only thumbnail.png)"]}):r.artifacts.map(c=>N(I,{dimColor:!0,children:[" ",Lt[c]]},c))]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{dimColor:!0,children:"Also creates:"}),N(I,{dimColor:!0,children:[" ",gt(p,"src/")]}),N(I,{dimColor:!0,children:[" ",gt(p,"src/thumbnail.png")," (generated placeholder)"]}),N(I,{dimColor:!0,children:[" ",gt(p,"releaseNotes/")]}),N(I,{dimColor:!0,children:[" ",gt(p,".gitignore")," (adds .kizenapp/)"]})]}),E(ke,{text:"Enter to create \xB7 Esc to go back"})]})}return r.type==="resolving-target"?E(z,{paddingY:1,paddingX:2,children:E(I,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):r.type==="writing"?E(z,{paddingY:1,paddingX:2,children:E(I,{dimColor:!0,children:"Creating plugin\u2026"})}):r.type==="done"?N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(I,{color:"green",bold:!0,children:["Plugin created at ",r.targetDir]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{dimColor:!0,children:"Next steps:"}),N(I,{children:[" ","cd ",r.targetDir]}),N(I,{children:[" ","npx --yes @kizenapps/cli dev"]}),N(I,{dimColor:!0,children:[" ","Replace src/thumbnail.png with real artwork before publishing."]})]}),E(ke,{text:"Enter or Esc to exit"})]}):N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),E(I,{color:"red",bold:!0,children:"Failed to create plugin"}),E(I,{children:r.message}),E(ke,{text:"Enter or Esc to exit"})]})};import{mkdir as nn,readFile as os,readdir as is,writeFile as on}from"fs/promises";import{homedir as ss}from"os";import{dirname as as,join as ht}from"path";var Y=["go","fmo","staging","integration","test1"];var Pe=ht(ss(),".kizenappbuilder"),De=ht(Pe,"credentials.json"),ye="credentials";function ls(e){return Y.includes(e)}function cs(e){if(typeof e!="object"||e===null)throw new Error("Credentials must be a JSON object");let t=e,n=t.environment;return{apiKey:typeof t.apiKey=="string"?t.apiKey:"",userId:typeof t.userId=="string"?t.userId:"",businessId:typeof t.businessId=="string"?t.businessId:"",environment:ls(n)?n:"go"}}async function be(e){let t=await os(e,"utf-8");return cs(JSON.parse(t))}async function Z(){try{return await be(De)}catch{return null}}async function ds(e){await nn(as(De),{recursive:!0,mode:448}),await on(De,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384})}function sn(e){return ht(Pe,`${e}.json`)}async function Ie(){let e=[{name:ye,path:De,isDefault:!0}];try{let t=await is(Pe);for(let n of t){if(!n.endsWith(".json"))continue;let o=n.slice(0,-5);o!==ye&&e.push({name:o,path:ht(Pe,n),isDefault:!1})}}catch{}return e}async function an(e,t){if(e===ye){await ds(t);return}await nn(Pe,{recursive:!0,mode:448}),await on(sn(e),JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}async function de(e){try{return await be(sn(e))}catch{return null}}var ps="A hello-world Kizen plugin.";function us(e){if(e===void 0||e.trim()===""||e.trim()==="all")return[...X];if(e.trim()==="none")return[];let t=e.split(",").map(o=>o.trim()).filter(o=>o!==""),n=t.filter(o=>!X.includes(o));if(n.length>0)throw new Error(`Unknown artifact type(s): ${n.join(", ")}. Valid types: ${X.join(", ")}, or "all" / "none".`);return[...new Set(t)]}function fs(e,t,n){let o=e.name?.trim()??"";if(o==="")throw new Error("--name is required for a non-interactive run.");let r=(e.apiName?.trim()??"")||ft(o);if(!Jt.test(r))throw new Error(`api_name "${r}" is invalid: ${Wt}. Pass --api-name.`);let i=e.description?.trim(),d=e.businessId?.trim()??t.businessId,f=gs(e,t);return{targetDir:n,name:o,apiName:r,externalLink:e.externalLink?.trim()??"",description:i===void 0||i===""?ps:i,developerBusinessId:d,developerEnvironment:f,artifacts:us(e.artifacts)}}function ms(e){return Y.includes(e)}function gs(e,t){let n=e.environment?.trim();if(n!==void 0&&n!==""){if(!ms(n))throw new Error(`Unknown environment "${n}". Valid environments: ${Y.join(", ")}.`);return n}if(e.businessId!==void 0&&t.businessId==="")throw new Error("--environment is required alongside --business-id when no credentials are saved, so the id is keyed to the environment that issued it.");return t.environment}async function ln(e,t,n,o){let r;try{r=fs(e,t,n)}catch(f){o.writeStderr(`Error: ${f instanceof Error?f.message:String(f)}
|
|
219
|
+
The bump matrix lives in the docs corpus that
|
|
220
|
+
\`.github/workflows/copilot-code-review.yml\` fetches into \`.copilot-docs/\`, so it
|
|
221
|
+
cannot drift out of date here.
|
|
222
|
+
|
|
223
|
+
Check every \`kizen.json\` diff against the "How big a bump?" matrix in
|
|
224
|
+
\`.copilot-docs/16-release-and-publish.md\` and the "Release & publish" section of
|
|
225
|
+
\`.copilot-docs/17-gotchas.md\`, and name the change that sets the required level.
|
|
226
|
+
`;var Gr=`# Copilot only reads this file from the default branch, and only if the job is named copilot-setup-steps.
|
|
227
|
+
name: Copilot code review setup
|
|
228
|
+
|
|
229
|
+
on:
|
|
230
|
+
workflow_dispatch:
|
|
231
|
+
|
|
232
|
+
jobs:
|
|
233
|
+
copilot-setup-steps:
|
|
234
|
+
runs-on: ubuntu-latest
|
|
235
|
+
timeout-minutes: 10
|
|
236
|
+
permissions:
|
|
237
|
+
contents: read
|
|
238
|
+
steps:
|
|
239
|
+
- name: Check out this plugin repo
|
|
240
|
+
uses: actions/checkout@v4
|
|
241
|
+
|
|
242
|
+
- name: Fetch the Kizen plugin docs corpus into .copilot-docs/
|
|
243
|
+
run: |
|
|
244
|
+
set -euo pipefail
|
|
245
|
+
git clone --depth 1 --filter=blob:none --sparse \\
|
|
246
|
+
https://github.com/kizen/app-engine.git .docs-src
|
|
247
|
+
git -C .docs-src sparse-checkout set --no-cone '/docs/**/*.md' '!/docs/site/**'
|
|
248
|
+
mv .docs-src/docs .copilot-docs
|
|
249
|
+
rm -rf .docs-src
|
|
250
|
+
|
|
251
|
+
- name: Verify the corpus landed
|
|
252
|
+
run: |
|
|
253
|
+
set -euo pipefail
|
|
254
|
+
test -f .copilot-docs/17-gotchas.md
|
|
255
|
+
test -f .copilot-docs/method-index.md
|
|
256
|
+
|
|
257
|
+
numbered=$(find .copilot-docs -maxdepth 1 -name '[0-9][0-9]-*.md' | wc -l | tr -d ' ')
|
|
258
|
+
test "$numbered" -ge 18
|
|
259
|
+
test -f .copilot-docs/examples/kitchen_sink.md
|
|
260
|
+
|
|
261
|
+
count=$(find .copilot-docs -name '*.md' | wc -l | tr -d ' ')
|
|
262
|
+
echo "Fetched $count markdown files into .copilot-docs/ ($numbered numbered docs)"
|
|
263
|
+
test "$count" -ge 24
|
|
264
|
+
du -sh .copilot-docs
|
|
265
|
+
`;function lt(){return[{path:".github/copilot-instructions.md",content:qr},{path:".github/instructions/security.instructions.md",content:Jr},{path:".github/instructions/version-discipline.instructions.md",content:Wr},{path:".github/workflows/copilot-code-review.yml",content:Gr}]}import{deflateSync as Hi}from"zlib";var Ht=512,Ui=150,Vi=26,Ut=46,Kr=.6,qi=Ut*.55,Ji=.55,Wi=.47;function Gi(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=t+((t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24))>>>0;return t}function Ki(e){let t=Gi(e);return{hue:t%360,quarterTurns:(t>>>16)%4}}function Yi(e,t,n){let o=(1-Math.abs(2*n-1))*t,r=e/60,i=o*(1-Math.abs(r%2-1)),p=n-o/2,[f,g,m]=r<1?[o,i,0]:r<2?[i,o,0]:r<3?[0,o,i]:r<4?[0,i,o]:r<5?[i,0,o]:[o,0,i];return[Math.round((f+p)*255),Math.round((g+p)*255),Math.round((m+p)*255)]}function Ue(e,t,n,o,r){let i=Math.abs(e)-n+r,p=Math.abs(t)-o+r;return Math.hypot(Math.max(i,0),Math.max(p,0))+Math.min(Math.max(i,p),0)-r}function ct(e,t,n,o,r){return Math.hypot(e-n,t-o)-r}function Xi(e,t){let n=Ui,o=Ut,r=o*Kr,i=qi,p=Ue(e,t,n,n,Vi),f=Math.min(ct(e,t,0,-n-r,o),Ue(e,t+n+r/2,i,r/2+1,0)),g=Math.min(ct(e,t,n+r,0,o),Ue(e-n-r/2,t,r/2+1,i,0));p=Math.min(p,f,g);let m=Math.min(ct(e,t,0,n-r,o),Ue(e,t-n+r/2,i,r/2+1,0)),y=Math.min(ct(e,t,-n+r,0,o),Ue(e+n-r/2,t,r/2+1,i,0));return Math.max(p,-m,-y)}function Zi(e){let t=Ht,n=new Uint8Array(t*t*4),[o,r,i]=Yi(e.hue,Ji,Wi),p=Ut*(1+Kr),f=(t-1)/2,g=p/2;for(let m=0;m<t;m+=1)for(let y=0;y<t;y+=1){let T=y-f,P=m-f;for(let w=0;w<e.quarterTurns;w+=1)[T,P]=[-P,T];let x=Xi(T+g,P-g),c=Math.min(1,Math.max(0,.5-x));if(c<=0)continue;let b=(m*t+y)*4;n[b]=o,n[b+1]=r,n[b+2]=i,n[b+3]=Math.round(c*255)}return n}var Qi=new Uint32Array(256).map((e,t)=>{let n=t;for(let o=0;o<8;o+=1)n=n&1?3988292384^n>>>1:n>>>1;return n>>>0});function es(e){let t=4294967295;for(let n of e)t=(Qi[(t^n)&255]??0)^t>>>8;return(t^4294967295)>>>0}function Mt(e,t){let n=Buffer.from(e,"latin1"),o=Buffer.alloc(4);o.writeUInt32BE(t.length);let r=Buffer.alloc(4);return r.writeUInt32BE(es(Buffer.concat([n,t]))),Buffer.concat([o,n,t,r])}var ts=Buffer.from([137,80,78,71,13,10,26,10]);function rs(e,t,n){if(n.length!==e*t*4)throw new Error(`encodePng: expected ${String(e*t*4)} bytes of RGBA for ${String(e)}x${String(t)}, got ${String(n.length)}`);let o=Buffer.alloc(13);o.writeUInt32BE(e,0),o.writeUInt32BE(t,4),o[8]=8,o[9]=6;let r=e*4,i=Buffer.alloc((r+1)*t);for(let p=0;p<t;p+=1)i.set(n.subarray(p*r,(p+1)*r),p*(r+1)+1);return Buffer.concat([ts,Mt("IHDR",o),Mt("IDAT",Hi(i,{level:9})),Mt("IEND",new Uint8Array(0))])}function Yr(e){return rs(Ht,Ht,Zi(Ki(e)))}var is="src/thumbnail.png",ss=["go","fmo"];async function pt(e){try{return await ns(e),!0}catch{return!1}}async function ye(e){return await pt(ce(e,"kizen.json"))?"has-manifest":await pt(ce(e,".kizenapp"))?"has-kizenapp":"ok"}async function Zr(e,t){let n=ce(e,t);if(!await pt(n))return n;for(let o=1;o<1e3;o++){let r=ce(e,`${t}-${String(o)}`);if(!await pt(r))return r}throw new Error(`Could not find an available directory name for "${t}"`)}function qt(e){let t=e.developerBusinessId.trim(),n=t!==""&&!ss.includes(e.developerEnvironment)?[e.developerEnvironment]:["prod"];return{name:e.name,version:"1.0.0",published:!0,api_name:e.apiName,external_link:e.externalLink,description:e.description,entry:"src/",engine:"1.0.0",release_notes_directory:"releaseNotes/",release_environments:n,config_template:{},base_config:{},...t?{developer_business_id:{[e.developerEnvironment]:t}}:{}}}async function Xr(e,t){let n=t.map(r=>({fullPath:ce(e,...r.path.split("/")),content:r.content})),o=new Set(n.map(r=>os(r.fullPath)));await Promise.all([...o].map(r=>dt(r,{recursive:!0}))),await Promise.all(n.map(r=>Vt(r.fullPath,r.content,"utf-8")))}async function ut(e){await dt(e.targetDir,{recursive:!0});let t=qt(e);await Vt(ce(e.targetDir,"kizen.json"),JSON.stringify(t,null,2)+`
|
|
266
|
+
`,"utf-8"),await dt(ce(e.targetDir,"src"),{recursive:!0}),await dt(ce(e.targetDir,"releaseNotes"),{recursive:!0}),await Promise.all([Xr(e.targetDir,Vr(e.artifacts??[])),Xr(e.targetDir,lt()),Vt(ce(e.targetDir,...is.split("/")),Yr(e.apiName))]),he(e.targetDir)}var be=["name","apiName","externalLink","description","developerBusinessId"],ft={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},Jt=["name","apiName","description"],Wt=/^[a-z_][a-z0-9_]+$/,Gt="must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)";function mt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Qr(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function en(e,t){let n=t.trim();if(Jt.includes(e)&&!n)return`${ft[e]} is required`;if(e==="apiName"&&!Wt.test(n))return`${ft[e]} ${Gt}`}function tn(e,t){return e==="description"?t:t.trim()}function rn(e,t){let n=new Set(e);return n.has(t)?n.delete(t):n.add(t),X.filter(o=>n.has(o))}import{jsx as _,jsxs as B}from"react/jsx-runtime";var Ie=({text:e})=>_(I,{dimColor:!0,children:e}),nn=({parentDir:e,defaultBusinessId:t,defaultEnvironment:n})=>{let o=as(),[r,i]=De({type:"target-select",cursor:0}),[p,f]=De("in-place"),[g,m]=De(()=>Qr(t)),[y,T]=De(()=>[...X]),[P,x]=De(""),[c,b]=De(e),w=gt((v,d)=>{f(v),x(d.name),i({type:"field-entry",field:0,values:d})},[]),H=gt(async v=>{let d=await ye(v);if(d!=="ok"){i({type:"precheck-error",targetDir:v,reason:d});return}b(v),w("in-place",g)},[g,w]),j=gt(async(v,d)=>{try{let l=await Zr(e,v.apiName);b(l),i({type:"confirm",values:v,artifacts:d})}catch(l){i({type:"error",message:l instanceof Error?l.message:String(l)})}},[e]),C=gt(async(v,d,l)=>{try{await ut({targetDir:d,name:v.name,apiName:v.apiName,externalLink:v.externalLink,description:v.description,developerBusinessId:v.developerBusinessId,developerEnvironment:n,artifacts:l}),i({type:"done",targetDir:d})}catch(s){i({type:"error",message:s instanceof Error?s.message:String(s)})}},[n]);if(ls((v,d)=>{if(d.ctrl&&v==="c"){o.exit();return}if(r.type==="target-select"){d.upArrow?i({type:"target-select",cursor:0}):d.downArrow?i({type:"target-select",cursor:1}):d.return?r.cursor===0?H(e):w("sub-dir",g):d.escape&&o.exit();return}if(r.type==="precheck-error"){(d.return||d.escape)&&o.exit();return}if(r.type==="field-entry"){let{field:l,values:s}=r,a=be[l];if(!a)return;if(d.escape){o.exit();return}if(d.backspace||d.delete){x(u=>u.slice(0,-1));return}if(d.upArrow&&l>0){let u={...s,[a]:P},h=l-1,k=be[h];i({type:"field-entry",field:h,values:u}),m(u),x(k?u[k]:"");return}if(d.return||d.tab||d.downArrow){let u=en(a,P);if(u!==void 0){i({type:"field-entry",field:l,values:s,fieldError:u});return}let h=tn(a,P),k={...s,[a]:h};m(k);let E=l+1;if(E>=be.length)x(""),i({type:"artifact-select",values:k,cursor:0,selected:y});else{let R=be[E],z=R?k[R]:"",W=R==="apiName"&&!z?mt(k.name):z;i({type:"field-entry",field:E,values:k}),x(W)}return}v&&!d.ctrl&&!d.meta&&x(u=>u+v);return}if(r.type==="artifact-select"){let{cursor:l,selected:s,values:a}=r;if(d.escape){let u=be.length-1,h=be[u];i({type:"field-entry",field:u,values:a}),x(h?a[h]:"");return}if(d.upArrow){i({...r,cursor:Math.max(0,l-1)});return}if(d.downArrow){i({...r,cursor:Math.min(X.length-1,l+1)});return}if(v===" "){let u=X[l];if(u){let h=rn(s,u);T(h),i({...r,selected:h})}return}if(v==="a"){T([...X]),i({...r,selected:[...X]});return}if(v==="n"){T([]),i({...r,selected:[]});return}d.return&&(p==="sub-dir"?(i({type:"resolving-target"}),j(a,s)):i({type:"confirm",values:a,artifacts:s}));return}if(r.type==="confirm"){if(d.escape){i({type:"artifact-select",values:r.values,cursor:0,selected:r.artifacts});return}d.return&&(i({type:"writing"}),C(r.values,c,r.artifacts));return}(r.type==="done"||r.type==="error")&&(d.return||d.escape)&&o.exit()}),r.type==="target-select"){let v=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"Where should the new plugin live?"}),v.map((d,l)=>{let s=r.cursor===l;return B(M,{gap:2,children:[_(I,{...s&&{color:"cyan"},children:s?"\u276F":" "}),_(I,{bold:s,...s&&{color:"cyan"},children:d.label}),_(I,{dimColor:!0,children:d.desc})]},d.label)})]}),_(Ie,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="precheck-error"){let{targetDir:v,reason:d}=r;return B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),_(I,{color:"red",bold:!0,children:"Cannot create plugin"}),B(M,{flexDirection:"column",gap:0,children:[B(I,{children:[v," already contains ",_(I,{bold:!0,children:d==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),_(I,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),_(Ie,{text:"Enter or Esc to exit"})]})}if(r.type==="field-entry"){let{field:v,fieldError:d}=r,l=p==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${c}`;return B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"Plugin details"}),_(I,{dimColor:!0,children:l})]}),d!==void 0&&B(I,{color:"red",children:["Error: ",d]}),_(M,{flexDirection:"column",gap:0,children:be.map((s,a)=>{let u=v===a,h=u?P:g[s],k=Jt.includes(s),E=`${ft[s]}${k?"":" (optional)"}`;return B(M,{gap:2,children:[_(M,{width:24,children:_(I,{bold:u,...u&&{color:"cyan"},children:E})}),_(I,{...u&&{color:"cyan"},children:">"}),_(I,{children:h}),u&&_(I,{color:"cyan",children:"\u2588"})]},s)})}),_(Ie,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(r.type==="artifact-select"){let{cursor:v,selected:d}=r;return B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"Which artifacts should we scaffold?"}),_(I,{dimColor:!0,children:"Each one gets a directory with a config.json and a script that runs."})]}),_(M,{flexDirection:"column",gap:0,children:X.map((l,s)=>{let a=v===s,u=d.includes(l);return B(M,{gap:1,children:[_(I,{...a&&{color:"cyan"},children:a?"\u276F":" "}),_(I,{...u&&{color:"green"},children:u?"\u25C9":"\u25EF"}),_(I,{bold:a,...a&&{color:"cyan"},children:zt[l]})]},l)})}),_(Ie,{text:"\u2191\u2193 move \xB7 Space toggle \xB7 a all \xB7 n none \xB7 Enter continue \xB7 Esc back"})]})}if(r.type==="confirm"){let v=qt({targetDir:c,name:r.values.name,apiName:r.values.apiName,externalLink:r.values.externalLink,description:r.values.description,developerBusinessId:r.values.developerBusinessId,developerEnvironment:n});return B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"Ready to create"}),B(I,{dimColor:!0,children:["Target: ",c]})]}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"kizen.json preview"}),_(I,{children:JSON.stringify(v,null,2)})]}),B(M,{flexDirection:"column",gap:0,children:[_(I,{bold:!0,children:"Artifacts"}),r.artifacts.length===0?B(I,{dimColor:!0,children:[" ","none (src/ will hold only thumbnail.png)"]}):r.artifacts.map(d=>B(I,{dimColor:!0,children:[" ",zt[d]]},d))]}),B(M,{flexDirection:"column",gap:0,children:[_(I,{dimColor:!0,children:"Also creates:"}),B(I,{dimColor:!0,children:[" ",ht(c,"src/")]}),B(I,{dimColor:!0,children:[" ",ht(c,"src/thumbnail.png")," (generated placeholder)"]}),B(I,{dimColor:!0,children:[" ",ht(c,"releaseNotes/")]}),B(I,{dimColor:!0,children:[" ",ht(c,".gitignore")," (adds .kizenapp/)"]})]}),_(Ie,{text:"Enter to create \xB7 Esc to go back"})]})}return r.type==="resolving-target"?_(M,{paddingY:1,paddingX:2,children:_(I,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):r.type==="writing"?_(M,{paddingY:1,paddingX:2,children:_(I,{dimColor:!0,children:"Creating plugin\u2026"})}):r.type==="done"?B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),B(I,{color:"green",bold:!0,children:["Plugin created at ",r.targetDir]}),B(M,{flexDirection:"column",gap:0,children:[_(I,{dimColor:!0,children:"Next steps:"}),B(I,{children:[" ","cd ",r.targetDir]}),B(I,{children:[" ","npx --yes @kizenapps/cli dev"]}),B(I,{dimColor:!0,children:[" ","Replace src/thumbnail.png with real artwork before publishing."]})]}),_(Ie,{text:"Enter or Esc to exit"})]}):B(M,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),_(I,{color:"red",bold:!0,children:"Failed to create plugin"}),_(I,{children:r.message}),_(Ie,{text:"Enter or Esc to exit"})]})};import{mkdir as on,readFile as cs,readdir as ds,writeFile as sn}from"fs/promises";import{homedir as ps}from"os";import{dirname as us,join as yt}from"path";var Y=["go","fmo","staging","integration","test1"];var Ne=yt(ps(),".kizenappbuilder"),Fe=yt(Ne,"credentials.json"),xe="credentials";function fs(e){return Y.includes(e)}function ms(e){if(typeof e!="object"||e===null)throw new Error("Credentials must be a JSON object");let t=e,n=t.environment;return{apiKey:typeof t.apiKey=="string"?t.apiKey:"",userId:typeof t.userId=="string"?t.userId:"",businessId:typeof t.businessId=="string"?t.businessId:"",environment:fs(n)?n:"go"}}async function ve(e){let t=await cs(e,"utf-8");return ms(JSON.parse(t))}async function Z(){try{return await ve(Fe)}catch{return null}}async function gs(e){await on(us(Fe),{recursive:!0,mode:448}),await sn(Fe,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384})}function an(e){return yt(Ne,`${e}.json`)}async function Re(){let e=[{name:xe,path:Fe,isDefault:!0}];try{let t=await ds(Ne);for(let n of t){if(!n.endsWith(".json"))continue;let o=n.slice(0,-5);o!==xe&&e.push({name:o,path:yt(Ne,n),isDefault:!1})}}catch{}return e}async function ln(e,t){if(e===xe){await gs(t);return}await on(Ne,{recursive:!0,mode:448}),await sn(an(e),JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}async function de(e){try{return await ve(an(e))}catch{return null}}var hs="A hello-world Kizen plugin.";function ys(e){if(e===void 0||e.trim()===""||e.trim()==="all")return[...X];if(e.trim()==="none")return[];let t=e.split(",").map(o=>o.trim()).filter(o=>o!==""),n=t.filter(o=>!X.includes(o));if(n.length>0)throw new Error(`Unknown artifact type(s): ${n.join(", ")}. Valid types: ${X.join(", ")}, or "all" / "none".`);return[...new Set(t)]}function bs(e,t,n){let o=e.name?.trim()??"";if(o==="")throw new Error("--name is required for a non-interactive run.");let r=(e.apiName?.trim()??"")||mt(o);if(!Wt.test(r))throw new Error(`api_name "${r}" is invalid: ${Gt}. Pass --api-name.`);let i=e.description?.trim(),p=e.businessId?.trim()??t.businessId,f=vs(e,t);return{targetDir:n,name:o,apiName:r,externalLink:e.externalLink?.trim()??"",description:i===void 0||i===""?hs:i,developerBusinessId:p,developerEnvironment:f,artifacts:ys(e.artifacts)}}function xs(e){return Y.includes(e)}function vs(e,t){let n=e.environment?.trim();if(n!==void 0&&n!==""){if(!xs(n))throw new Error(`Unknown environment "${n}". Valid environments: ${Y.join(", ")}.`);return n}if(e.businessId!==void 0&&t.businessId==="")throw new Error("--environment is required alongside --business-id when no credentials are saved, so the id is keyed to the environment that issued it.");return t.environment}async function cn(e,t,n,o){let r;try{r=bs(e,t,n)}catch(f){o.writeStderr(`Error: ${f instanceof Error?f.message:String(f)}
|
|
299
267
|
`),o.setExitCode(1);return}let i=await o.precheckTargetDir(n);if(i!=="ok"){let f=i==="has-manifest"?"kizen.json":".kizenapp/";o.writeStderr(`Error: ${n} already contains ${f}. Refusing to overwrite an existing plugin.
|
|
300
268
|
`),o.setExitCode(1);return}try{await o.createPlugin(r)}catch(f){o.writeStderr(`Error: ${f instanceof Error?f.message:String(f)}
|
|
301
|
-
`),o.setExitCode(1);return}let
|
|
302
|
-
`),o.writeStdout(`Artifacts: ${
|
|
269
|
+
`),o.setExitCode(1);return}let p=r.artifacts&&r.artifacts.length>0?r.artifacts.join(", "):"none";o.writeStdout(`Created plugin ${r.apiName} at ${n}
|
|
270
|
+
`),o.writeStdout(`Artifacts: ${p}
|
|
303
271
|
`),o.writeStdout(`Thumbnail: src/thumbnail.png (generated placeholder; replace it before publishing)
|
|
304
272
|
`),r.developerBusinessId.trim()===""&&o.writeStderr(`Warning: no developer_business_id configured, so this plugin cannot be preview-published yet.
|
|
305
|
-
`)}function
|
|
273
|
+
`)}function dn(e){e.command("create").description("Scaffold a new Kizen plugin project").option("-n, --name <name>","plugin display name (implies a non-interactive run)").option("-a, --api-name <name>","plugin api_name (inferred from --name when omitted)").option("-d, --description <text>","plugin description").option("-l, --external-link <url>","external link shown on the plugin listing").option("-b, --business-id <id>","developer business id (defaults to saved credentials)").option("-e, --environment <env>",`environment the business id belongs to: ${Y.join(", ")} (defaults to saved credentials)`).option("--artifacts <list>",`comma-separated artifact types, or "all" / "none" (default: all). Types: ${X.join(", ")}`).action(async t=>{let n=process.cwd(),o=await Z(),r=o?.businessId??"",i=o?.environment??"go",p=Object.values(t).some(m=>m!==void 0);if(!process.stdin.isTTY||!process.stdout.isTTY||p){await cn(t,{businessId:r,environment:i},n,{precheckTargetDir:ye,createPlugin:ut,writeStdout:m=>{process.stdout.write(m)},writeStderr:m=>{process.stderr.write(m)},setExitCode:m=>{process.exitCode=m}});return}let{waitUntilExit:g}=Cs(ws(nn,{parentDir:n,defaultBusinessId:r,defaultEnvironment:i}),{exitOnCtrlC:!1});await g()})}import{createElement as Vn}from"react";import{render as qn}from"ink";import{useCallback as $e,useEffect as Tt,useRef as pe,useState as Q}from"react";import{Box as G,Text as A,useInput as Sa}from"ink";import{PluginValidationError as Ta}from"@kizenapps/packager";import{watch as Ea}from"fs";import{createServer as _a}from"http";import{join as Mn}from"path";import{WebSocketServer as ka}from"ws";import{createReadStream as _n,realpathSync as Vs}from"fs";import{access as qs,readdir as Js,readFile as Ws,realpath as Gs,stat as kn}from"fs/promises";import{dirname as Ks,extname as Pn,join as Ke,resolve as Ys,sep as or}from"path";import{fileURLToPath as Xs}from"url";var Ss=new Set(["set-cookie","strict-transport-security","content-security-policy","content-security-policy-report-only","x-frame-options","content-encoding","content-length"]);function bt(e){let t={};for(let[n,o]of Object.entries(e)){let r=n.toLowerCase();Ss.has(r)||r.startsWith("access-control-")||(t[n]=o)}return t}var Kt=10*1024*1024,Ts=6e4,Es=200,Ve=class extends Error{bytesRead;limit;constructor(t,n){super(`Upstream response exceeded ${String(n)} bytes (read ${String(t)}).`),this.name="ProxyResponseTooLargeError",this.bytesRead=t,this.limit=n}};async function Yt(e,t){let n=e.body;if(n===null)return Buffer.alloc(0);let o=[],r=0;for await(let i of n){if(r+=i.length,r>t)throw new Ve(r,t);o.push(i)}return Buffer.concat(o)}async function pn(e){let t=bt(Object.fromEntries(e.headers)),n=await Yt(e,Kt);return{status:e.status,headers:t,body:n}}function un(e={}){let{onChange:t,enabled:n=!0}=e;if(!n)return{async get(p,f){return{response:await pn(await f()),fromCache:!1}},clear(){}};let o=new Map,r=()=>{t?.(o.size)},i=p=>{o.delete(p)&&r()};return{get(p,f){let g=o.get(p);if(g!==void 0){if(Date.now()-g.insertedAt<Ts)return g.promise.then(y=>({response:y,fromCache:!0}));i(p)}if(o.size>=Es){let y=o.keys().next().value;y!==void 0&&i(y)}let m=f().then(pn).catch(y=>{throw i(p),y});return o.set(p,{insertedAt:Date.now(),promise:m}),r(),m.then(y=>((y.status<200||y.status>=300)&&i(p),{response:y,fromCache:!1}))},clear(){o.clear(),r()}}}var Xt={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".json":"application/json; charset=utf-8",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".map":"application/json"};import{mkdir as _s,readFile as ks,writeFile as Ps}from"fs/promises";import{join as fn}from"path";async function we(e){try{let t=await ks(fn(e,"config.json"),"utf-8");return JSON.parse(t)}catch{return{}}}async function Ce(e,t){await _s(e,{recursive:!0}),await Ps(fn(e,"config.json"),JSON.stringify(t,null,2),"utf-8")}var Zt={prod:"https://plugin-wizard.kizen.com",dev:"https://plugin-wizard.kizen.dev",localDev:"http://localhost:9823"};function qe(e){let t=process.env.PLUGIN_WIZARD_URL;return t!==void 0&&t!==""?t:e==="prod"?process.env.PLUGIN_WIZARD_URL_PROD||Zt.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!==""?Zt.localDev:Zt.dev}import{spawn as rr}from"child_process";import{writeFile as bn,rm as tr,mkdtemp as Bs,access as As}from"fs/promises";import{join as We}from"path";import{tmpdir as Ds}from"os";var mn=`awslambdaric
|
|
306
274
|
bcrypt
|
|
307
275
|
boto3
|
|
308
276
|
fpdf2
|
|
@@ -320,8 +288,8 @@ pytz
|
|
|
320
288
|
requests
|
|
321
289
|
sqlalchemy>=2.0,<2.1
|
|
322
290
|
tzdata
|
|
323
|
-
`;function
|
|
324
|
-
`).map(t=>t.trim().replace(/\s+#.*$/,"")).filter(t=>t.length>0&&!t.startsWith("#"))}function
|
|
291
|
+
`;import{AUTOMATION_SCRIPT_RUNTIMES as Fs,isSupportedScriptRuntime as $s,scriptRuntimeToApiName as vn}from"@kizenapps/packager";function gn(e){return e.split(`
|
|
292
|
+
`).map(t=>t.trim().replace(/\s+#.*$/,"")).filter(t=>t.length>0&&!t.startsWith("#"))}function hn(e){let t=/^python-(\d+)[.-](\d+)$/.exec(e),n=t?.[1],o=t?.[2];return n!==void 0&&o!==void 0?`python${n}.${o}`:"python3"}function Ns(e){return e==null||e.trim()===""?null:e}function Rs(e){return e==null?null:typeof e=="string"?Ns(e):typeof e=="number"||typeof e=="boolean"||typeof e=="bigint"?String(e):typeof e=="function"||typeof e=="symbol"?null:JSON.stringify(e)}function yn(e){return e?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Rs(n)])):{}}var js=`
|
|
325
293
|
import sys, json, os, traceback
|
|
326
294
|
|
|
327
295
|
# --- Inputs proxy (attribute access) ---
|
|
@@ -481,23 +449,23 @@ sys.stdout.write('\\n__KIZEN_RESULT_START__\\n')
|
|
|
481
449
|
sys.stdout.write(json.dumps(result, ensure_ascii=False))
|
|
482
450
|
sys.stdout.write('\\n__KIZEN_RESULT_END__\\n')
|
|
483
451
|
sys.stdout.flush()
|
|
484
|
-
`.trim(),
|
|
485
|
-
`);for(;x>=0;){let
|
|
486
|
-
`)}}),g.on("end",()=>{if(T.length>0){let P=T.replace(/\r$/,"");
|
|
487
|
-
`).trim(),b=m.length>0?`: ${m}`:"";r(new Error(`${e} exited with code ${String(g)}${b}`))}})})}var Qt=null;function Ds(e,t){if(qe)return t&&Qt?.add(t),qe;let n=new Set;t&&n.add(t),Qt=n;let o=i=>{for(let d of n)d(i)},r=Je(bt,"bin","python");return qe=(async()=>{try{let i=!1;try{await Ps(r);let d=await Cn(r);i=d!==null&&wn(d)}catch{i=!1}if(!i){await er(bt,{recursive:!0,force:!0}).catch(()=>{});let d=await Bs(e);await bn(d,["-m","venv",bt])}return o({kind:"start"}),await bn(r,["-m","pip","install","--disable-pip-version-check",...vn],(d,f)=>{o({kind:"log",line:d,stream:f})}),o({kind:"complete"}),r}catch(i){let d=i instanceof Error?i.message:String(i);throw o({kind:"error",message:d}),qe=null,await er(bt,{recursive:!0,force:!0}).catch(()=>{}),i}finally{Qt=null}})(),qe}function Fs(e){let t="__KIZEN_RESULT_START__",n="__KIZEN_RESULT_END__",o=e.indexOf(t),r=e.indexOf(n);if(o===-1||r===-1)return{userStdout:e,result:null};let i=e.slice(0,o).trimEnd(),d=e.slice(o+t.length,r).trim();try{let f=JSON.parse(d);return{userStdout:i,result:f}}catch{return{userStdout:e,result:null}}}function Os(e){return{success:!1,outputValues:{},logs:[],stdout:"",stderr:"",error:e,exitCode:1,durationMs:0}}async function Sn(e){let t=e.timeout??As;if(!Ns(e.scriptRuntime))return Os(`Unsupported runtime "${e.scriptRuntime}". Supported runtimes: ${xn.join(", ")}. Update the step's config.json "runtime" field (e.g. "python 3.13").`);let n=await Ds(e.scriptRuntime,e.onInstallProgress),o=Date.now(),r;try{r=await ks(Je(Is(),"kizen-step-"));let i=Je(r,"wrapper.py"),d=Je(r,"script.py");await Promise.all([yn(i,Rs,"utf-8"),yn(d,e.script,"utf-8")]);let f={...process.env,__KIZEN_INPUTS__:JSON.stringify(e.inputs),__KIZEN_SECRETS__:JSON.stringify(e.secrets),__KIZEN_SCRIPT_PATH__:d},{exitCode:g,stdout:m,stderr:b}=await new Promise(y=>{let S=[],H=[],O=!1,w=tr(n,[i],{env:f,cwd:r,stdio:["ignore","pipe","pipe"]}),v=setTimeout(()=>{w.kill("SIGKILL")},t);w.stdout.on("data",a=>{S.push(a)}),w.stderr.on("data",a=>{H.push(a)});let c=a=>{O||(O=!0,clearTimeout(v),y({exitCode:a??1,stdout:Buffer.concat(S).toString("utf-8"),stderr:Buffer.concat(H).toString("utf-8")}))};w.on("close",c),w.on("error",a=>{O||(O=!0,clearTimeout(v),y({exitCode:1,stdout:"",stderr:a.message}))})}),T=Date.now()-o,{userStdout:P,result:x}=Fs(m);if(x){let y={success:x.success,outputValues:x.outputValues,logs:x.logs,stdout:P,stderr:b,exitCode:g,durationMs:T};return x.error!==null&&(y.error=x.error),x.httpRequests&&(y.httpRequests=x.httpRequests),y}let p={success:!1,outputValues:{},logs:[],stdout:P,stderr:b,exitCode:g,durationMs:T};return g!==0&&(p.error=`Process exited with code ${String(g)}`),p}finally{r&&er(r,{recursive:!0,force:!0})}}var Tn=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".md",".mdx",".yml",".yaml",".toml",".css",".scss",".html",".htm",".xml",".svg",".txt",".sh",".py",".env",".gitignore",".prettierrc",".eslintrc"]);import{CRYPTO_ALG as Pn,CRYPTO_VERSION as In,deserializeEnvelope as qs,encrypt as Js,serializeEnvelope as Ws}from"@kizenapps/packager";function rr(e){if(e.kind==="info")return e.message;let t=e.fromCache?" [cache]":"",n=e.upstreamStatus!==void 0?` (upstream ${String(e.upstreamStatus)})`:"";return`${e.method} ${e.url} \u2192 ${String(e.status)}${n}${t}`}var Ks=2*1024*1024,Gs=new Set([".DS_Store",".gitignore"]);function Ys(e){if(e===void 0||e==="")return!1;let t=e.startsWith("[")?e.slice(0,e.indexOf("]")+1):e.split(":")[0]??"";return t==="localhost"||t==="127.0.0.1"||t==="[::1]"}var Bn=["kizen.com","kizen.dev"];function Xs(e){let t;try{t=new URL(e)}catch{return!1}let n=t.hostname.toLowerCase();return n==="localhost"||n==="127.0.0.1"||n==="[::1]"?!0:t.protocol!=="https:"?!1:Bn.some(o=>n===o||n.endsWith("."+o))}function Zs(e){let t;try{t=new URL(e)}catch{return!1}if(t.protocol!=="https:")return!1;let n=t.hostname.toLowerCase();return Bn.some(o=>n===o||n.endsWith("."+o))}function Qs(e){if(e===void 0||e==="")return!1;try{let{hostname:t}=new URL(e);return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}async function Rn(e,t){if(t.includes("\0"))return null;let n=t.replace(/^\/+/,""),o=Us(e,n);if(o!==e&&!o.startsWith(e+nr))return null;try{let r=await zs(o);return r!==e&&!r.startsWith(e+nr)?null:r}catch{return null}}function An(e,t){let n=t===e?"":t.slice(e.length+1);return n===""?!1:n.split(nr).some(r=>tt.has(r))}function Dn(){let e=Vs(import.meta.url);return Ke(Hs(e),"viewer")}function Nn(e,t,n){if(e.includes("/external-integrations/proxy")&&t["content-type"]?.includes("application/json"))try{let o=JSON.parse(n.toString("utf8"));return typeof o.status_code=="number"?o.status_code:void 0}catch{return}}async function or(e){try{return await $s(e),!0}catch{return!1}}function Fn(e,t,n,o,r,i,d,f,g,m,b){let T=pn({onChange:f,enabled:b}),P=js(m);return(x,p)=>{(async()=>{let y=x.url??"/";try{if(!Ys(x.headers.host)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Forbidden"}));return}if((x.method==="POST"||x.method==="PATCH"||x.method==="DELETE")&&!Qs(x.headers.origin)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Forbidden"}));return}if(t(`Received request: ${y}`),y==="/api/credentials"){p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({credentials:o.current??null,activeProfile:r.current??null}));return}if(y==="/api/credential-profiles"&&x.method==="GET"){let a=await Ie();p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({profiles:a,active:r.current}));return}if(y==="/api/credentials/switch"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let l=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}").profile,u=l===void 0||l===""?await Z():await de(l);if(u!==null){o.current=u,r.current=l??void 0;let h=r.current,k=await xe(i);await ve(i,{...k,credentialMode:"global",...h!==void 0&&{activeCredentialProfile:h}}),d({type:"credentials-updated",credentials:u,activeProfile:r.current??null})}p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({ok:u!==null}));return}if(y==="/api/bundle"){let a=Ke(process.cwd(),".kizenapp","bundle.json");try{let s=await Ms(a,"utf-8");p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(s)}catch{p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end("{}")}return}if(y==="/api/last-path"&&x.method==="POST"){let a=[];for await(let l of x)a.push(l);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.path=="string"){g.current=s.path;let l=await xe(i);await ve(i,{...l,lastPath:s.path})}p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/encryption-target"&&x.method==="GET"){let s=(await xe(i)).encryptionTarget==="dev"?"dev":"prod";p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({target:s}));return}if(y==="/api/encryption-target"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}"),l=s!==null&&typeof s=="object"?s:{};if(l.target!=="dev"&&l.target!=="prod"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"target must be one of: 'dev', 'prod'"}));return}let u=await xe(i);await ve(i,{...u,encryptionTarget:l.target}),p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/execute-step"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.script!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required field: script"}));return}let l={script:s.script,scriptRuntime:s.scriptRuntime??"python-3-13",inputs:hn(s.inputs),secrets:s.secrets??{},onInstallProgress:h=>{h.kind==="start"?d({type:"venv-install-start"}):h.kind==="log"?d({type:"venv-install-log",line:h.line,stream:h.stream}):h.kind==="complete"?d({type:"venv-install-complete"}):d({type:"venv-install-error",message:h.message})}};typeof s.timeout=="number"&&s.timeout>0&&(l.timeout=Math.min(s.timeout,300*1e3));let u=await Sn(l);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify(u));return}if(y==="/api/proxy-cache/clear"){T.clear(),n({kind:"info",message:"Proxy cache cleared"}),p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/local/encrypt"&&x.method==="POST"){let a=[];for await(let l of x)a.push(l);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.publicKeyPem!="string"||typeof s.value!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required fields: publicKeyPem, value"}));return}try{let l=Js(s.value,s.publicKeyPem),u=Ws(l);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify(u))}catch(l){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:l.message}))}return}if(y==="/api/local/validate"&&x.method==="POST"){let a=[];for await(let _ of x)a.push(_);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.value!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required field: value"}));return}let l,u;try{l=qs(s.value)}catch(_){u=_.message}if(u!==void 0||l===void 0){p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({valid:!1,checks:[],error:u}));return}let h=_=>Buffer.from(_,"base64").length,k=[{label:"Version",expected:String(In),actual:String(l.v),pass:l.v===In},{label:"Algorithm",expected:Pn,actual:l.alg,pass:l.alg===Pn},{label:"Wrapped key",expected:"384 bytes (RSA-3072)",actual:`${String(h(l.k))} bytes`,pass:h(l.k)===384},{label:"IV",expected:"12 bytes",actual:`${String(h(l.iv))} bytes`,pass:h(l.iv)===12},{label:"Auth tag",expected:"16 bytes",actual:`${String(h(l.tag))} bytes`,pass:h(l.tag)===16},{label:"Ciphertext",expected:"\u2265 1 byte",actual:`${String(h(l.ct))} bytes`,pass:h(l.ct)>=1}];p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({valid:k.every(_=>_.pass),checks:k}));return}if(y.startsWith("/api/wizard")){let a=x.headers["x-encryption-target"],l=(Array.isArray(a)?a[0]:a)==="dev"?"dev":"prod",u=Ve(l);if(!Xs(u)){p.writeHead(500,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:`Encryption API host is not allowed: ${u}`}));return}let h=y.slice(11)||"/",k=`${u}${h}`,_=x.method??"GET",A=[];for await(let Se of x)A.push(Se);let{host:M,"x-encryption-target":W,...te}=x.headers,oe=A.length>0?Buffer.concat(A):void 0,ie=oe&&oe.length>0?oe:void 0,re;try{re=await fetch(k,{method:_,headers:te,...ie!==void 0&&{body:ie}})}catch(Se){let It=Se.code==="ECONNREFUSED"?`plugin-wizard is not running at ${u}`:`Failed to reach plugin-wizard: ${Se.message}`;p.writeHead(503,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:It}));return}let ee=yt(Object.fromEntries(re.headers)),Oe=await re.arrayBuffer();p.writeHead(re.status,ee),p.end(Buffer.from(Oe));return}if(y.startsWith("/api/proxy")){let a=x.headers["x-proxy-target"];if(typeof a!="string"){p.writeHead(400),p.end("Missing x-proxy-target header");return}if(!Zs(a)){p.writeHead(400),p.end("Invalid proxy target");return}let s=y.slice(10)||"/",l=`${a}${s}`,u=x.method??"GET",h=[];for await(let re of x)h.push(re);let{host:k,"x-proxy-target":_,...A}=x.headers;if(u==="GET"){let re=`GET::${l}`,{response:ee,fromCache:Oe}=await T.get(re,()=>fetch(l,{method:"GET",headers:A}));n({kind:"request",method:"GET",status:ee.status,upstreamStatus:Nn(s,ee.headers,ee.body),fromCache:Oe,url:s}),p.writeHead(ee.status,ee.headers),p.end(ee.body);return}let M=h.length>0?Buffer.concat(h):void 0,W=M&&M.length>0?M:void 0,te=await fetch(l,{method:u,headers:A,...W!==void 0&&{body:W}}),oe=yt(Object.fromEntries(te.headers)),ie=await Gt(te,Kt);n({kind:"request",method:u,status:te.status,upstreamStatus:Nn(s,oe,ie),fromCache:!1,url:s}),p.writeHead(te.status,oe),p.end(ie);return}if(y.startsWith("/api/source/tree")&&x.method==="GET"){let s=new URL(y,"http://localhost").searchParams.get("path")??"",l=await Rn(P,s);if(l===null){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Invalid path"}));return}if(An(P,l)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await Ls(l,{withFileTypes:!0}),h=await Promise.all(u.filter(_=>_.isDirectory()?!tt.has(_.name):_.isFile()?!Gs.has(_.name):!1).map(async _=>{let A=_.isDirectory()?"dir":"file",M={name:_.name,kind:A};if(A==="file")try{let W=await En(Ke(l,_.name));M.size=W.size}catch{}return M}));h.sort((_,A)=>_.kind!==A.kind?_.kind==="dir"?-1:1:_.name.localeCompare(A.name));let k=l===P?"":l.slice(P.length+1);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({path:k,entries:h}))}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/tree failed (${s}): ${h}`),p.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not found"}))}return}if(y.startsWith("/api/source/file")&&x.method==="GET"){let s=new URL(y,"http://localhost").searchParams.get("path")??"";if(s===""){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing path"}));return}let l=await Rn(P,s);if(l===null){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Invalid path"}));return}if(An(P,l)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await En(l);if(!u.isFile()){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not a file"}));return}if(u.size>Ks){p.writeHead(413,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"File too large",size:u.size}));return}let h=kn(l).toLowerCase(),k=Yt[h],_=Tn.has(h),A=k??(_?"text/plain; charset=utf-8":"application/octet-stream");p.writeHead(200,{"Content-Type":A,"Content-Length":String(u.size)}),_n(l).pipe(p)}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/file failed (${s}): ${h}`),p.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not found"}))}return}let O=Ke(e,y==="/"?"/index.html":y),w=await or(O)?O:Ke(e,"index.html"),v=kn(w),c=Yt[v]??"application/octet-stream";p.writeHead(200,{"Content-Type":c}),_n(w).pipe(p)}catch(S){if(y.startsWith("/api/proxy")){let H=y.slice(10)||"/",O=x.method??"GET";S instanceof Ue?n({kind:"info",message:`${O} ${H} \u2192 502 (response exceeded ${String(S.limit)} bytes)`}):n({kind:"request",method:O,status:502,fromCache:!1,url:H})}else n({kind:"info",message:`Error handling ${y}: ${S instanceof Error?S.message:String(S)}`});p.headersSent||(p.writeHead(502),p.end("Bad Gateway"))}})()}}import{launch as ea}from"chrome-launcher";import{createRequire as ta}from"module";import{mkdirSync as ra}from"fs";import{readFile as na}from"fs/promises";import{dirname as oa,join as ia}from"path";import{fileURLToPath as sa}from"url";var On=ta(import.meta.url)("chrome-remote-interface"),aa=new Set(["content-security-policy","content-security-policy-report-only","x-frame-options"]),$n=["kizen.dev","kizen.com"];function jn(e){try{let{hostname:t}=new URL(e);return $n.some(n=>t===n||t.endsWith("."+n))}catch{return!1}}async function la(e){try{let t=ia(oa(sa(import.meta.url)),"viewer","icon.png"),n=await na(t);await e.Browser.setDockTile({image:n.toString("base64")})}catch{}}async function Ln(e){ra(e.userDataDir,{recursive:!0});let t=`http://localhost:${String(e.port)}`,n=await ea({startingUrl:t,chromeFlags:[`--app=${t}`,"--no-first-run","--no-default-browser-check","--disable-extensions","--disable-features=DeviceBoundSessions"],userDataDir:e.userDataDir,handleSIGINT:!1,logLevel:"silent"}),o=n.port,r=null,i=null,d=null,f=null,g=0,m=!1,b=w=>{e.debugLog?.(w)},T=w=>{e.verbose&&e.debugLog?.(w)},P=()=>{i!==null&&(clearInterval(i),i=null)},x=w=>w==="chrome://new-tab-page/"||w==="chrome://newtab/",p=async w=>{P(),d=null,await la(w),await w.Fetch.enable({patterns:$n.flatMap(c=>[{urlPattern:`*://${c}/*`,requestStage:"Response"},{urlPattern:`*://*.${c}/*`,requestStage:"Response"}])}),w.on("Fetch.requestPaused",c=>{(async()=>{let a=c,{requestId:s,request:l,responseHeaders:u,responseStatusCode:h}=a,k=l.url;T(`Fetch ${String(h??"?")} ${k}`);let _=[],A=!1;for(let M of u??[])if(!aa.has(M.name.toLowerCase()))if(M.name.toLowerCase()==="set-cookie"&&jn(k)){let W=M.value.split(`
|
|
452
|
+
`.trim(),Ls=3e4,xt=We(process.cwd(),".kizenapp","venv"),Os=Fs.map(vn),wn=gn(mn);if(wn.length===0)throw new Error("python-requirements.txt bundled no packages \u2014 check the build output");var Je=null,Ge=[3,10];function Cn([e,t]){return e>Ge[0]||e===Ge[0]&&t>=Ge[1]}function Qt(e){return`${String(e[0])}.${String(e[1])}`}function Sn(e){return new Promise(t=>{let n=rr(e,["-c","import sys; print('%d.%d' % sys.version_info[:2])"],{stdio:["ignore","pipe","ignore"]}),o="";n.stdout.on("data",r=>{o+=r.toString("utf-8")}),n.on("error",()=>{t(null)}),n.on("close",r=>{let i=/(\d+)\.(\d+)/.exec(o);if(r!==0||!i){t(null);return}t([Number(i[1]),Number(i[2])])})})}async function zs(e){let t=hn(e),n=t==="python3"?["python3"]:[t,"python3"],o=[];for(let r of n){let i=await Sn(r);if(!i){o.push(`${r}: not found`);continue}if(Cn(i))return r;o.push(`${r}: ${Qt(i)} (too old)`)}throw new Error(`No Python >= ${Qt(Ge)} found for runtime "${e}". The local runner needs Python ${Qt(Ge)}+ to install the bundled packages (e.g. psycopg 3.3), matching the remote code-runner (3.12 / 3.13). Tried ${o.join(", ")}. Install Python 3.12 or 3.13 and retry.`)}function xn(e,t,n){return new Promise((o,r)=>{let i=rr(e,t,{stdio:["ignore","pipe","pipe"]}),p=(g,m)=>{let y=[],T="";return g.on("data",P=>{T+=P.toString("utf-8");let x=T.indexOf(`
|
|
453
|
+
`);for(;x>=0;){let c=T.slice(0,x).replace(/\r$/,"");T=T.slice(x+1),y.push(c),n?.(c,m),x=T.indexOf(`
|
|
454
|
+
`)}}),g.on("end",()=>{if(T.length>0){let P=T.replace(/\r$/,"");y.push(P),n?.(P,m)}}),y},f=p(i.stderr,"stderr");p(i.stdout,"stdout"),i.on("error",r),i.on("close",g=>{if(g===0)o();else{let m=f.slice(-10).join(`
|
|
455
|
+
`).trim(),y=m.length>0?`: ${m}`:"";r(new Error(`${e} exited with code ${String(g)}${y}`))}})})}var er=null;function Ms(e,t){if(Je)return t&&er?.add(t),Je;let n=new Set;t&&n.add(t),er=n;let o=i=>{for(let p of n)p(i)},r=We(xt,"bin","python");return Je=(async()=>{try{let i=!1;try{await As(r);let p=await Sn(r);i=p!==null&&Cn(p)}catch{i=!1}if(!i){await tr(xt,{recursive:!0,force:!0}).catch(()=>{});let p=await zs(e);await xn(p,["-m","venv",xt])}return o({kind:"start"}),await xn(r,["-m","pip","install","--disable-pip-version-check",...wn],(p,f)=>{o({kind:"log",line:p,stream:f})}),o({kind:"complete"}),r}catch(i){let p=i instanceof Error?i.message:String(i);throw o({kind:"error",message:p}),Je=null,await tr(xt,{recursive:!0,force:!0}).catch(()=>{}),i}finally{er=null}})(),Je}function Hs(e){let t="__KIZEN_RESULT_START__",n="__KIZEN_RESULT_END__",o=e.indexOf(t),r=e.indexOf(n);if(o===-1||r===-1)return{userStdout:e,result:null};let i=e.slice(0,o).trimEnd(),p=e.slice(o+t.length,r).trim();try{let f=JSON.parse(p);return{userStdout:i,result:f}}catch{return{userStdout:e,result:null}}}function Us(e){return{success:!1,outputValues:{},logs:[],stdout:"",stderr:"",error:e,exitCode:1,durationMs:0}}async function Tn(e){let t=e.timeout??Ls;if(!$s(e.scriptRuntime))return Us(`Unsupported runtime "${e.scriptRuntime}". Supported runtimes: ${Os.join(", ")}. Update the step's config.json "runtime" field (e.g. "python 3.13").`);let o=await Ms(vn(e.scriptRuntime),e.onInstallProgress),r=Date.now(),i;try{i=await Bs(We(Ds(),"kizen-step-"));let p=We(i,"wrapper.py"),f=We(i,"script.py");await Promise.all([bn(p,js,"utf-8"),bn(f,e.script,"utf-8")]);let g={...process.env,__KIZEN_INPUTS__:JSON.stringify(e.inputs),__KIZEN_SECRETS__:JSON.stringify(e.secrets),__KIZEN_SCRIPT_PATH__:f},{exitCode:m,stdout:y,stderr:T}=await new Promise(w=>{let H=[],j=[],C=!1,v=rr(o,[p],{env:g,cwd:i,stdio:["ignore","pipe","pipe"]}),d=setTimeout(()=>{v.kill("SIGKILL")},t);v.stdout.on("data",s=>{H.push(s)}),v.stderr.on("data",s=>{j.push(s)});let l=s=>{C||(C=!0,clearTimeout(d),w({exitCode:s??1,stdout:Buffer.concat(H).toString("utf-8"),stderr:Buffer.concat(j).toString("utf-8")}))};v.on("close",l),v.on("error",s=>{C||(C=!0,clearTimeout(d),w({exitCode:1,stdout:"",stderr:s.message}))})}),P=Date.now()-r,{userStdout:x,result:c}=Hs(y);if(c){let w={success:c.success,outputValues:c.outputValues,logs:c.logs,stdout:x,stderr:T,exitCode:m,durationMs:P};return c.error!==null&&(w.error=c.error),c.httpRequests&&(w.httpRequests=c.httpRequests),w}let b={success:!1,outputValues:{},logs:[],stdout:x,stderr:T,exitCode:m,durationMs:P};return m!==0&&(b.error=`Process exited with code ${String(m)}`),b}finally{i&&tr(i,{recursive:!0,force:!0})}}var En=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 In,CRYPTO_VERSION as Nn,DEFAULT_AUTOMATION_RUNTIME as Zs,deserializeEnvelope as Qs,encrypt as ea,scriptRuntimeToApiName as ta,serializeEnvelope as ra}from"@kizenapps/packager";function nr(e){if(e.kind==="info")return e.message;let t=e.fromCache?" [cache]":"",n=e.upstreamStatus!==void 0?` (upstream ${String(e.upstreamStatus)})`:"";return`${e.method} ${e.url} \u2192 ${String(e.status)}${n}${t}`}var na=2*1024*1024,oa=new Set([".DS_Store",".gitignore"]);function ia(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 Dn=["kizen.com","kizen.dev"];function sa(e){let t;try{t=new URL(e)}catch{return!1}let n=t.hostname.toLowerCase();return n==="localhost"||n==="127.0.0.1"||n==="[::1]"?!0:t.protocol!=="https:"?!1:Dn.some(o=>n===o||n.endsWith("."+o))}function aa(e){let t;try{t=new URL(e)}catch{return!1}if(t.protocol!=="https:")return!1;let n=t.hostname.toLowerCase();return Dn.some(o=>n===o||n.endsWith("."+o))}function la(e){if(e===void 0||e==="")return!1;try{let{hostname:t}=new URL(e);return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}async function Rn(e,t){if(t.includes("\0"))return null;let n=t.replace(/^\/+/,""),o=Ys(e,n);if(o!==e&&!o.startsWith(e+or))return null;try{let r=await Gs(o);return r!==e&&!r.startsWith(e+or)?null:r}catch{return null}}function Bn(e,t){let n=t===e?"":t.slice(e.length+1);return n===""?!1:n.split(or).some(r=>rt.has(r))}function Fn(){let e=Xs(import.meta.url);return Ke(Ks(e),"viewer")}function An(e,t,n){if(e.includes("/external-integrations/proxy")&&t["content-type"]?.includes("application/json"))try{let o=JSON.parse(n.toString("utf8"));return typeof o.status_code=="number"?o.status_code:void 0}catch{return}}async function ir(e){try{return await qs(e),!0}catch{return!1}}function $n(e,t,n,o,r,i,p,f,g,m,y){let T=un({onChange:f,enabled:y}),P=Vs(m);return(x,c)=>{(async()=>{let b=x.url??"/";try{if(!ia(x.headers.host)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if((x.method==="POST"||x.method==="PATCH"||x.method==="DELETE")&&!la(x.headers.origin)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if(t(`Received request: ${b}`),b==="/api/credentials"){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({credentials:o.current??null,activeProfile:r.current??null}));return}if(b==="/api/credential-profiles"&&x.method==="GET"){let l=await Re();c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({profiles:l,active:r.current}));return}if(b==="/api/credentials/switch"&&x.method==="POST"){let l=[];for await(let h of x)l.push(h);let a=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}").profile,u=a===void 0||a===""?await Z():await de(a);if(u!==null){o.current=u,r.current=a??void 0;let h=r.current,k=await we(i);await Ce(i,{...k,credentialMode:"global",...h!==void 0&&{activeCredentialProfile:h}}),p({type:"credentials-updated",credentials:u,activeProfile:r.current??null})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:u!==null}));return}if(b==="/api/bundle"){let l=Ke(process.cwd(),".kizenapp","bundle.json");try{let s=await Ws(l,"utf-8");c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(s)}catch{c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end("{}")}return}if(b==="/api/last-path"&&x.method==="POST"){let l=[];for await(let a of x)l.push(a);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.path=="string"){g.current=s.path;let a=await we(i);await Ce(i,{...a,lastPath:s.path})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(b==="/api/encryption-target"&&x.method==="GET"){let s=(await we(i)).encryptionTarget==="dev"?"dev":"prod";c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({target:s}));return}if(b==="/api/encryption-target"&&x.method==="POST"){let l=[];for await(let h of x)l.push(h);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}"),a=s!==null&&typeof s=="object"?s:{};if(a.target!=="dev"&&a.target!=="prod"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"target must be one of: 'dev', 'prod'"}));return}let u=await we(i);await Ce(i,{...u,encryptionTarget:a.target}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(b==="/api/execute-step"&&x.method==="POST"){let l=[];for await(let h of x)l.push(h);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.script!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: script"}));return}let a={script:s.script,scriptRuntime:s.scriptRuntime??ta(Zs),inputs:yn(s.inputs),secrets:s.secrets??{},onInstallProgress:h=>{h.kind==="start"?p({type:"venv-install-start"}):h.kind==="log"?p({type:"venv-install-log",line:h.line,stream:h.stream}):h.kind==="complete"?p({type:"venv-install-complete"}):p({type:"venv-install-error",message:h.message})}};typeof s.timeout=="number"&&s.timeout>0&&(a.timeout=Math.min(s.timeout,300*1e3));let u=await Tn(a);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(u));return}if(b==="/api/proxy-cache/clear"){T.clear(),n({kind:"info",message:"Proxy cache cleared"}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(b==="/api/local/encrypt"&&x.method==="POST"){let l=[];for await(let a of x)l.push(a);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.publicKeyPem!="string"||typeof s.value!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required fields: publicKeyPem, value"}));return}try{let a=ea(s.value,s.publicKeyPem),u=ra(a);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(u))}catch(a){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:a.message}))}return}if(b==="/api/local/validate"&&x.method==="POST"){let l=[];for await(let E of x)l.push(E);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.value!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: value"}));return}let a,u;try{a=Qs(s.value)}catch(E){u=E.message}if(u!==void 0||a===void 0){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:!1,checks:[],error:u}));return}let h=E=>Buffer.from(E,"base64").length,k=[{label:"Version",expected:String(Nn),actual:String(a.v),pass:a.v===Nn},{label:"Algorithm",expected:In,actual:a.alg,pass:a.alg===In},{label:"Wrapped key",expected:"384 bytes (RSA-3072)",actual:`${String(h(a.k))} bytes`,pass:h(a.k)===384},{label:"IV",expected:"12 bytes",actual:`${String(h(a.iv))} bytes`,pass:h(a.iv)===12},{label:"Auth tag",expected:"16 bytes",actual:`${String(h(a.tag))} bytes`,pass:h(a.tag)===16},{label:"Ciphertext",expected:"\u2265 1 byte",actual:`${String(h(a.ct))} bytes`,pass:h(a.ct)>=1}];c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:k.every(E=>E.pass),checks:k}));return}if(b.startsWith("/api/wizard")){let l=x.headers["x-encryption-target"],a=(Array.isArray(l)?l[0]:l)==="dev"?"dev":"prod",u=qe(a);if(!sa(u)){c.writeHead(500,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:`Encryption API host is not allowed: ${u}`}));return}let h=b.slice(11)||"/",k=`${u}${h}`,E=x.method??"GET",R=[];for await(let Ee of x)R.push(Ee);let{host:z,"x-encryption-target":W,...te}=x.headers,oe=R.length>0?Buffer.concat(R):void 0,ie=oe&&oe.length>0?oe:void 0,re;try{re=await fetch(k,{method:E,headers:te,...ie!==void 0&&{body:ie}})}catch(Ee){let Nt=Ee.code==="ECONNREFUSED"?`plugin-wizard is not running at ${u}`:`Failed to reach plugin-wizard: ${Ee.message}`;c.writeHead(503,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:Nt}));return}let ee=bt(Object.fromEntries(re.headers)),je=await re.arrayBuffer();c.writeHead(re.status,ee),c.end(Buffer.from(je));return}if(b.startsWith("/api/proxy")){let l=x.headers["x-proxy-target"];if(typeof l!="string"){c.writeHead(400),c.end("Missing x-proxy-target header");return}if(!aa(l)){c.writeHead(400),c.end("Invalid proxy target");return}let s=b.slice(10)||"/",a=`${l}${s}`,u=x.method??"GET",h=[];for await(let re of x)h.push(re);let{host:k,"x-proxy-target":E,...R}=x.headers;if(u==="GET"){let re=`GET::${a}`,{response:ee,fromCache:je}=await T.get(re,()=>fetch(a,{method:"GET",headers:R}));n({kind:"request",method:"GET",status:ee.status,upstreamStatus:An(s,ee.headers,ee.body),fromCache:je,url:s}),c.writeHead(ee.status,ee.headers),c.end(ee.body);return}let z=h.length>0?Buffer.concat(h):void 0,W=z&&z.length>0?z:void 0,te=await fetch(a,{method:u,headers:R,...W!==void 0&&{body:W}}),oe=bt(Object.fromEntries(te.headers)),ie=await Yt(te,Kt);n({kind:"request",method:u,status:te.status,upstreamStatus:An(s,oe,ie),fromCache:!1,url:s}),c.writeHead(te.status,oe),c.end(ie);return}if(b.startsWith("/api/source/tree")&&x.method==="GET"){let s=new URL(b,"http://localhost").searchParams.get("path")??"",a=await Rn(P,s);if(a===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(Bn(P,a)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await Js(a,{withFileTypes:!0}),h=await Promise.all(u.filter(E=>E.isDirectory()?!rt.has(E.name):E.isFile()?!oa.has(E.name):!1).map(async E=>{let R=E.isDirectory()?"dir":"file",z={name:E.name,kind:R};if(R==="file")try{let W=await kn(Ke(a,E.name));z.size=W.size}catch{}return z}));h.sort((E,R)=>E.kind!==R.kind?E.kind==="dir"?-1:1:E.name.localeCompare(R.name));let k=a===P?"":a.slice(P.length+1);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({path:k,entries:h}))}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/tree failed (${s}): ${h}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}if(b.startsWith("/api/source/file")&&x.method==="GET"){let s=new URL(b,"http://localhost").searchParams.get("path")??"";if(s===""){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing path"}));return}let a=await Rn(P,s);if(a===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(Bn(P,a)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await kn(a);if(!u.isFile()){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not a file"}));return}if(u.size>na){c.writeHead(413,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"File too large",size:u.size}));return}let h=Pn(a).toLowerCase(),k=Xt[h],E=En.has(h),R=k??(E?"text/plain; charset=utf-8":"application/octet-stream");c.writeHead(200,{"Content-Type":R,"Content-Length":String(u.size)}),_n(a).pipe(c)}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/file failed (${s}): ${h}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}let j=Ke(e,b==="/"?"/index.html":b),C=await ir(j)?j:Ke(e,"index.html"),v=Pn(C),d=Xt[v]??"application/octet-stream";c.writeHead(200,{"Content-Type":d}),_n(C).pipe(c)}catch(w){if(b.startsWith("/api/proxy")){let H=b.slice(10)||"/",j=x.method??"GET";w instanceof Ve?n({kind:"info",message:`${j} ${H} \u2192 502 (response exceeded ${String(w.limit)} bytes)`}):n({kind:"request",method:j,status:502,fromCache:!1,url:H})}else n({kind:"info",message:`Error handling ${b}: ${w instanceof Error?w.message:String(w)}`});c.headersSent||(c.writeHead(502),c.end("Bad Gateway"))}})()}}import{launch as ca}from"chrome-launcher";import{createRequire as da}from"module";import{mkdirSync as pa}from"fs";import{readFile as ua}from"fs/promises";import{dirname as fa,join as ma}from"path";import{fileURLToPath as ga}from"url";var jn=da(import.meta.url)("chrome-remote-interface"),ha=new Set(["content-security-policy","content-security-policy-report-only","x-frame-options"]),On=["kizen.dev","kizen.com"];function Ln(e){try{let{hostname:t}=new URL(e);return On.some(n=>t===n||t.endsWith("."+n))}catch{return!1}}async function ya(e){try{let t=ma(fa(ga(import.meta.url)),"viewer","icon.png"),n=await ua(t);await e.Browser.setDockTile({image:n.toString("base64")})}catch{}}async function zn(e){pa(e.userDataDir,{recursive:!0});let t=`http://localhost:${String(e.port)}`,n=await ca({startingUrl:t,chromeFlags:[`--app=${t}`,"--no-first-run","--no-default-browser-check","--disable-extensions","--disable-features=DeviceBoundSessions"],userDataDir:e.userDataDir,handleSIGINT:!1,logLevel:"silent"}),o=n.port,r=null,i=null,p=null,f=null,g=0,m=!1,y=C=>{e.debugLog?.(C)},T=C=>{e.verbose&&e.debugLog?.(C)},P=()=>{i!==null&&(clearInterval(i),i=null)},x=C=>C==="chrome://new-tab-page/"||C==="chrome://newtab/",c=async C=>{P(),p=null,await ya(C),await C.Fetch.enable({patterns:On.flatMap(d=>[{urlPattern:`*://${d}/*`,requestStage:"Response"},{urlPattern:`*://*.${d}/*`,requestStage:"Response"}])}),C.on("Fetch.requestPaused",d=>{(async()=>{let l=d,{requestId:s,request:a,responseHeaders:u,responseStatusCode:h}=l,k=a.url;T(`Fetch ${String(h??"?")} ${k}`);let E=[],R=!1;for(let z of u??[])if(!ha.has(z.name.toLowerCase()))if(z.name.toLowerCase()==="set-cookie"&&Ln(k)){let W=z.value.split(`
|
|
488
456
|
`).map(te=>/SameSite=/i.test(te)?te.replace(/SameSite=\w+/i,"SameSite=None"):te+"; SameSite=None; Secure").join(`
|
|
489
|
-
`);_.push({name:M.name,value:W}),A=!0}else _.push(M);A&&T(` rewrote Set-Cookie SameSite on ${k}`);try{let{body:M,base64Encoded:W}=await w.Fetch.getResponseBody({requestId:s});await w.Fetch.fulfillRequest({requestId:s,responseCode:h??200,responseHeaders:_,body:M,...W&&{base64Encoded:!0}})}catch(M){T(` fulfillRequest failed (${M.message}), falling through`);try{await w.Fetch.continueRequest({requestId:s})}catch(W){T(` continueRequest also failed (${W.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:c}=await w.Network.getAllCookies(),a=0;for(let s of c){if(!jn(`https://${s.domain??""}`)||s.sameSite==="None")continue;let l=s.domain??"",u=l.startsWith(".")?l.slice(1):l;await w.Network.setCookie({url:`https://${u}`,name:s.name,value:s.value,domain:l,path:s.path??"/",secure:!0,...s.httpOnly!==void 0&&{httpOnly:s.httpOnly},...s.expirationDate!==void 0&&{expires:s.expirationDate},sameSite:"None"}),a++}a>0&&T(`cookie-patch cycle: updated ${String(a)} cookie(s) to SameSite=None`)}catch(c){T(`cookie-patch cycle failed: ${c.message}`)}})()},2e3),await w.Target.setDiscoverTargets({discover:!0});let v=c=>{if(c.type==="page"){if(x(c.url)){b(`closed stray new-tab-page target ${c.targetId}`),d!==null&&w.Target.activateTarget({targetId:d}).catch(()=>{}),w.Target.closeTarget({targetId:c.targetId}).catch(()=>{});return}d===null&&(d=c.targetId,b(`captured main target ${c.targetId} (${c.url})`))}};w.on("Target.targetCreated",c=>{let{targetInfo:a}=c;T(`target +${a.type} ${a.targetId} ${a.url}`),v(a)}),w.on("Target.targetInfoChanged",c=>{let{targetInfo:a}=c;T(`target ~${a.type} ${a.targetId} ${a.url}`),v(a)}),w.on("disconnect",()=>{m||r!==w||(b("CDP disconnected"),r=null,P(),y())})},y=()=>{if(m||f!==null)return;let w=Math.min(1e3*2**g,1e4),v=g+1;g++,b(`CDP reconnect scheduled in ${String(w)}ms (attempt #${String(v)})`),f=setTimeout(()=>{f=null,(async()=>{let c;try{c=await On({port:o})}catch{b(`CDP reconnect attempt #${String(v)} failed`),y();return}if(m){try{await c.close()}catch{}return}r=c;try{await p(c),b(`CDP reconnected after ${String(v)} attempt(s)`),g=0}catch{r===c&&(r=null);try{await c.close()}catch{}b(`CDP reconnect attempt #${String(v)} failed during setup`),y()}})()},w)},S=30,H=300;for(let w=0;w<S;w++){await new Promise(v=>setTimeout(v,H)),b(`CDP connect attempt ${String(w+1)}/${String(S)}`);try{let v=await On({port:o});r=v,e.path&&v.send("Page.navigate",{url:`${t}${e.path}`});try{await p(v),b("CDP connected")}catch{r===v&&(r=null);try{await v.close()}catch{}b("CDP setup failed after connect")}break}catch{if(w===S-1){let v=`CDP unavailable after ${String(S)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return b(v),e.onWarn?.(v),{kill:()=>{n.kill()}}}}}return r?{kill:()=>{if(b("CDP kill requested \u2014 tearing down"),m=!0,f!==null&&(clearTimeout(f),f=null),P(),r!==null){try{r.close()}catch{}r=null}n.kill()}}:{kill:()=>{n.kill()}}}import{useCallback as ca,useState as da}from"react";function xt(e){let[t,n]=da([]),o=ca(r=>{n(i=>[...i,`${new Date().toLocaleTimeString()}: ${r}`].slice(-e))},[e]);return[t,o]}import{useCallback as vt,useEffect as ir,useState as wt}from"react";import{Box as V,Text as j,useInput as pa}from"ink";import{jsx as R,jsxs as J}from"react/jsx-runtime";var we=["apiKey","userId","businessId"],ua={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},Ge=({text:e})=>R(j,{dimColor:!0,children:e}),Ct=({initialMode:e,showProfileManager:t,onComplete:n,onCancel:o})=>{let[r,i]=wt(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[d,f]=wt(""),[g,m]=wt(null),[b,T]=wt(void 0),P=vt(c=>{if(c==="local"){n({mode:"local",credentials:null});return}i({type:"profile-loading"})},[n]),x=vt(async c=>{if(c===null){i({type:"profile-loading"});let l=await Ie();i({type:"name-entry",nameBuffer:"",existingProfiles:l});return}T(c.isDefault?void 0:c.name),i({type:"loading"});let a=c.isDefault?await Z():await de(c.name),s=a?Math.max(0,Y.indexOf(a.environment)):0;i({type:"creds-entry",field:0,values:a??{},envCursor:s})},[]),p=vt(async(c,a)=>{let s=Y[a]??"go",l={apiKey:c.apiKey??"",userId:c.userId??"",businessId:c.businessId??"",environment:s};i({type:"saving"});try{await an(b??ye,l),n({mode:"global",credentials:l,...b!==void 0&&{profileName:b}})}catch(u){m(u instanceof Error?u.message:String(u)),i({type:"creds-entry",field:0,values:c,envCursor:a})}},[n,b]);pa((c,a)=>{if(a.ctrl&&c==="c"&&process.exit(0),a.escape){if((r.type==="creds-entry"||r.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),y();return}o?.();return}if(r.type==="mode-select"){if(a.upArrow)i({type:"mode-select",cursor:0});else if(a.downArrow)i({type:"mode-select",cursor:1});else if(a.return){let s=r.cursor===0?"global":"local";P(s)}return}if(r.type==="profile-select"){let{profiles:s,cursor:l}=r,u=s.length,h=s.length+1;if(a.upArrow)i({...r,cursor:(l-1+h)%h});else if(a.downArrow)i({...r,cursor:(l+1)%h});else if(a.return)if(l===u)i({type:"name-entry",nameBuffer:"",existingProfiles:s});else{let k=s[l]??s[0];k&&x(k)}return}if(r.type==="name-entry"){let{nameBuffer:s,existingProfiles:l}=r;if(a.backspace||a.delete)i({type:"name-entry",nameBuffer:s.slice(0,-1),existingProfiles:l});else if(a.return){let u=s.trim();if(!u){i({...r,nameError:"Name cannot be empty"});return}if(u===ye){i({...r,nameError:`"${ye}" is reserved`});return}if(l.some(h=>h.name===u)){i({...r,nameError:`Profile "${u}" already exists`});return}T(u),i({type:"creds-entry",field:0,values:{},envCursor:0}),f("")}else c&&!a.ctrl&&!a.meta&&i({type:"name-entry",nameBuffer:s+c,existingProfiles:l});return}if(r.type==="creds-entry"){let{field:s,values:l,envCursor:u}=r;if(s===we.length){a.leftArrow?i({...r,envCursor:(u-1+Y.length)%Y.length}):a.rightArrow?i({...r,envCursor:(u+1)%Y.length}):a.upArrow?(i({...r,field:s-1}),f(l[we[s-1]]??"")):a.return&&p(l,u);return}let k=we[s];if(!k)return;if(a.backspace||a.delete)f(_=>_.slice(0,-1));else if(a.upArrow&&s>0){let _={...l,[k]:d},A=s-1;i({...r,field:A,values:_}),f(_[we[A]]??"")}else if(a.return||a.tab||a.downArrow){let _={...l,[k]:d},A=s+1;i({...r,field:A,values:_}),A<we.length?f(_[we[A]]??""):f("")}else c&&!a.ctrl&&!a.meta&&f(_=>_+c)}});let y=vt(async()=>{let c=await Ie();i({type:"profile-select",profiles:c,cursor:0})},[]);if(ir(()=>{r.type==="profile-loading"&&y()},[r.type,y]),ir(()=>{e==="global"&&!t&&(async()=>{let c=await Z(),a=c?Math.max(0,Y.indexOf(c.environment)):0;i({type:"creds-entry",field:0,values:c??{},envCursor:a})})()},[]),ir(()=>{r.type==="creds-entry"&&r.field===0&&f(r.values.apiKey??"")},[r.type]),r.type==="loading"||r.type==="saving"||r.type==="profile-loading"){let c=r.type==="saving"?"Saving credentials\u2026":r.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return R(V,{paddingY:1,paddingX:2,children:R(j,{dimColor:!0,children:c})})}if(r.type==="done")return null;if(r.type==="mode-select")return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:"Credential mode"}),[{label:"Global",desc:"~/.kizenappbuilder/credentials.json",mode:"global"},{label:"Local",desc:"Enter credentials in the browser dev tools",mode:"local"}].map((a,s)=>{let l=r.cursor===s;return J(V,{gap:2,children:[R(j,{...l&&{color:"cyan"},children:l?"\u276F":" "}),R(j,{bold:l,...l&&{color:"cyan"},children:a.label}),R(j,{dimColor:!0,children:a.desc})]},a.mode)})]}),R(Ge,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(r.type==="profile-select"){let{profiles:c,cursor:a}=r,s=c.length;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:"Credential profiles"}),c.map((l,u)=>{let h=a===u;return J(V,{gap:2,children:[R(j,{...h&&{color:"cyan"},children:h?"\u276F":" "}),R(j,{bold:h,...h&&{color:"cyan"},children:l.isDefault?"Default":l.name}),R(j,{dimColor:!0,children:l.path})]},l.name)}),J(V,{gap:2,children:[R(j,{...a===s&&{color:"cyan"},children:a===s?"\u276F":" "}),R(j,{bold:a===s,...a===s&&{color:"cyan"},children:"+ Add new profile"})]})]}),R(Ge,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="name-entry"){let{nameBuffer:c,nameError:a}=r;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),R(V,{flexDirection:"column",gap:0,children:R(j,{bold:!0,children:"New credential profile"})}),a&&J(j,{color:"red",children:["Error: ",a]}),J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:!0,color:"cyan",children:"Profile name"})}),R(j,{color:"cyan",children:">"}),R(j,{children:c}),R(j,{color:"cyan",children:"\u2588"})]}),R(Ge,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:S,values:H,envCursor:O}=r,w=S===we.length,v=b??ye;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:b!==void 0?`Profile: ${b}`:"Global credentials"}),J(j,{dimColor:!0,children:["Saved to:"," ",b!==void 0?`~/.kizenappbuilder/${b}.json`:De]})]}),g&&J(j,{color:"red",children:["Error: ",g]}),J(V,{flexDirection:"column",gap:0,children:[we.map((c,a)=>{let s=S===a,l=s?d:H[c]??"";return J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:s,...s&&{color:"cyan"},children:ua[c]})}),R(j,{...s&&{color:"cyan"},children:">"}),R(j,{children:l}),s&&R(j,{color:"cyan",children:"\u2588"})]},c)}),J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:w,...w&&{color:"cyan"},children:"Environment"})}),R(j,{...w&&{color:"cyan"},children:">"}),R(V,{gap:1,children:Y.map((c,a)=>{let s=a===O;return w?R(j,{bold:s,...s&&{color:"cyan"},children:s?`[${c}]`:c},c):R(j,{dimColor:!s,bold:s,children:c},c)})})]})]}),w?R(Ge,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):R(Ge,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),J(j,{dimColor:!0,children:["Profile: ",v]})]})};import{jsx as D,jsxs as U}from"react/jsx-runtime";var xa=[".kizenapp",".git"],zn=({port:e,pluginDir:t,outputDir:n,credentials:o,credentialMode:r,activeCredentialProfile:i,lastPath:d,debug:f=!1,verbose:g=!1,autoViewer:m=!0,cacheEnabled:b=!0})=>{let T=pe(o),P=pe(i),x=pe(d),[p,y]=Q("main"),[S,H]=Q(r),[O,w]=Q("starting"),[v,c]=Q(null),[a,s]=xt(50),[l,u]=xt(50),[h,k]=xt(50),[_,A]=Q([]),[M,W]=Q("pending"),[te,oe]=Q(null),[ie,re]=Q(null),[ee,Oe]=Q(null),[Se,It]=Q(null),[Rt,At]=Q(0),[cr,ko]=Q(0),[Po,Io]=Q(0),[Nt,Ro]=Q(0),Bt=pe(!1),dr=pe(!1),Xe=pe(null),je=pe(null),ue=pe(new Set),Ze=pe([]),ne=Fe(C=>{let L=JSON.stringify(C);if(ue.current.size===0){Ze.current=[...Ze.current,L].slice(-50);return}let fe=!1;for(let se of ue.current)if(se.readyState===1)try{se.send(L)}catch{ue.current.delete(se),fe=!0}fe&&At(ue.current.size)},[]),Qe=s,Dt=Fe(()=>{Xe.current?.kill(),Xe.current=null,Ln({port:e,userDataDir:Mn(n,".chrome"),broadcast:ne,onWarn:C=>{s(`\u26A0 ${C}`)},...x.current!==void 0&&{path:x.current},...f&&{debugLog:k},...g&&{verbose:!0}}).then(C=>{Xe.current=C})},[e,n,ne,f,g,k,s]);St(()=>{let C=()=>{Xe.current?.kill()};return process.on("exit",C),()=>{process.off("exit",C)}},[]),ma((C,L)=>{(C==="q"||L.ctrl&&C==="c")&&process.exit(0),C==="c"&&y("editing"),C==="v"&&Dt()},{isActive:p==="main"}),St(()=>{O!=="running"||dr.current||!m||(dr.current=!0,Dt())},[O,m,Dt]);let Ao=Fe(C=>{T.current=C.credentials,P.current=C.profileName,y("main"),H(C.mode);let L=C.profileName;ve(n,{credentialMode:C.mode,...L!==void 0&&{activeCredentialProfile:L}}),ne({type:"credentials-updated",credentials:C.credentials})},[n,ne]),pr=Fe(C=>{A(L=>[...L,`${new Date().toLocaleTimeString()}: ${rr(C)}`].slice(-50)),C.kind==="request"&&(C.fromCache?Io(L=>L+1):Ro(L=>L+1)),ne({type:"proxy-log",entry:C})},[ne]),Te=Fe(C=>{u(C),ne({type:"log",message:C})},[u,ne]),Ft=Fe(()=>{Bt.current||(Bt.current=!0,W("building"),oe(null),re(null),Te("Build started"),nt(t,n).then(({bundleSize:C})=>{Te(`Build finished \u2014 bundle: ${$e(C)}`),W("done"),Oe(new Date),It(C),Te("Notifying viewers to reload"),ne({type:"rebuild"})}).catch(C=>{C instanceof ga?(re(C.issues),oe(null)):(oe(C instanceof Error?C.message:String(C)),re(null)),W("error")}).finally(()=>{Bt.current=!1}))},[t,n,Te,ne]);if(St(()=>{Ft();let C=ha(t,{recursive:!0},(L,fe)=>{if(!fe)return;let se=fe.replace(/\\/g,"/");xa.some(et=>se.startsWith(et))||(Te(`File change detected: ${fe}`),je.current!==null&&clearTimeout(je.current),je.current=setTimeout(Ft,150))});return C.on("error",L=>{Te(`File watcher error \u2014 rebuilds have stopped: ${L.message}`)}),()=>{C.close(),je.current!==null&&clearTimeout(je.current)}},[t,Ft,Te]),St(()=>{let C=Dn();or(Mn(C,"index.html")).then(L=>{if(!L){c("Viewer not built. Run 'pnpm build:viewer' first."),w("error");return}let fe=Fn(C,Qe,pr,T,P,n,ne,ko,x,t,b),se=ya(fe),et=new ba({server:se});return et.on("connection",_e=>{for(let Bo of Ze.current)_e.readyState===1&&_e.send(Bo);Ze.current=[],Qe("Viewer connected for live reload"),ue.current.add(_e),At(ue.current.size),_e.on("close",()=>{ue.current.delete(_e),At(ue.current.size)})}),se.listen(e,"127.0.0.1",()=>{w("running"),Qe(`Server started on 127.0.0.1:${String(e)}`)}),se.on("error",_e=>{c(_e.message),w("error")}),()=>{et.close(),se.close()}})},[e,Qe,pr,ne,n,t,b]),p==="editing")return D(Ct,{...S!==void 0&&{initialMode:S},showProfileManager:S==="global",onComplete:Ao,onCancel:()=>{y("main")}});let Ot=ee!==null?Math.round((Date.now()-ee.getTime())/1e3):null,No=Ot===null?"":Ot<5?" (just now)":` (${String(Ot)}s ago)`,ur=ie?.filter(C=>C.severity==="error").length??0;return U(K,{flexDirection:"column",paddingY:1,paddingX:2,children:[D(q,{marginBottom:1}),U(K,{flexDirection:"column",children:[U(K,{gap:2,marginBottom:0,children:[D(B,{bold:!0,dimColor:!0,children:"App Build"}),M==="pending"&&D(B,{dimColor:!0,children:"waiting\u2026"}),M==="building"&&U(K,{gap:1,children:[D(me,{}),D(B,{children:"Building plugin package\u2026"})]}),M==="done"&&U(K,{gap:1,children:[D(B,{color:"green",children:"\u2713 Built"}),ee!==null&&U(B,{dimColor:!0,children:["at ",ee.toLocaleTimeString(),No]}),Se!==null&&U(B,{dimColor:!0,children:["\xB7 bundle: ",$e(Se)]})]}),M==="error"&&(ie!==null?U(B,{color:"red",children:["\u2717 ",ur," validation ",ur===1?"error":"errors"]}):U(B,{color:"red",children:["\u2717 ",te??"unknown error"]}))]}),ie!==null&&D(it,{issues:ie}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:l.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"Web Server"}),O==="starting"&&D(B,{dimColor:!0,children:"starting\u2026"}),O==="running"&&U(K,{gap:2,children:[D(B,{color:"green",children:"\u2713 Running"}),U(B,{dimColor:!0,children:["\u25CF ",Rt," viewer",Rt!==1?"s":""]})]}),O==="error"&&U(B,{color:"red",children:["\u2717 ",v??"Server error"]})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:a.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"Network Proxy"}),D(B,{color:"green",children:"\u2713 Active"}),D(B,{dimColor:!0,children:b?`\u25CF ${String(cr)} key${cr!==1?"s":""} in the network cache \xB7 ${String(Po)} hit \xB7 ${String(Nt)} miss`:`\u25CF network cache disabled \xB7 ${String(Nt)} request${Nt!==1?"s":""}`})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:_.length===0?D(B,{dimColor:!0,children:" No requests yet."}):_.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),f&&U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"CDP Debug"}),U(B,{dimColor:!0,children:["\u25CF ",h.length," event(s)"]})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:h.length===0?D(B,{dimColor:!0,children:" No CDP events yet."}):h.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,gap:1,children:[D(B,{dimColor:!0,children:"["}),D(B,{children:"q"}),D(B,{dimColor:!0,children:"] quit ["}),D(B,{children:"c"}),D(B,{dimColor:!0,children:"] credentials ["}),D(B,{children:"v"}),U(B,{dimColor:!0,children:["] ",Rt===0?"open viewer":"relaunch viewer"]})]})]})};async function Hn(e){return new Promise(t=>{let n=null,o=i=>{n?.(),t(i)},{unmount:r}=Vn(Un(Ct,{...e!==void 0&&{initialMode:e},onComplete:o}),{exitOnCtrlC:!1});n=r})}function qn(e){e.command("dev").description("Start the plugin viewer dev server").option("-p, --port <port>","port to listen on","3121").option("-c, --credentials <path>","path to a credentials JSON file").option("-d, --debug","Enable CDP lifecycle logs in the TUI").option("-v, --verbose","Log every CDP event and handled error (implies --debug)").option("--no-viewer","Don't auto-launch the viewer on startup (press [v] to launch manually)").option("--no-cache","Disable the network proxy cache (always fetch upstream)").action(async t=>{let n=parseInt(t.port,10),o=process.cwd(),r=`${o}/.kizenapp`;Ne(o);let i=null,d,f,{lastPath:g}=await xe(r);if(t.credentials)i=await be(t.credentials);else{let p=await xe(r);if(p.credentialMode==="local")d="local";else if(p.credentialMode==="global"){if(d="global",f=p.activeCredentialProfile,f?(i=await de(f),i||(i=await Z(),f=void 0)):i=await Z(),!i){let y=await Hn("global");i=y.credentials,f=y.profileName}}else{let y=await Hn();i=y.credentials,d=y.mode,f=y.profileName;let S=y.profileName;await ve(r,{credentialMode:y.mode,...S!==void 0&&{activeCredentialProfile:S}})}}let m=t.verbose===!0,b=m||t.debug===!0,T=t.viewer!==!1,P=t.cache!==!1,{waitUntilExit:x}=Vn(Un(zn,{port:n,pluginDir:o,outputDir:r,credentials:i,...d!==void 0&&{credentialMode:d},...f!==void 0&&{activeCredentialProfile:f},...g!==void 0&&{lastPath:g},debug:b,verbose:m,autoViewer:T,cacheEnabled:P}),{exitOnCtrlC:!1});await x()})}import{createElement as Oa}from"react";import{render as ja}from"ink";import{useCallback as _t,useEffect as Xn,useState as Et}from"react";import{Box as ae,Text as $,useApp as Ra,useInput as Aa}from"ink";import{encrypt as va,serializeEnvelope as wa}from"@kizenapps/packager";function Ca(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function Jn(e){return{"Content-Type":"application/json","x-api-key":e.apiKey,"x-user-id":e.userId,"x-business-id":e.businessId,"x-auth-environment":e.environment}}async function Wn(e,t,n){try{return await fetch(`${e}${t}`,n)}catch(o){throw new Error(Ca(o)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${o.message}`)}}async function Kn(e){let t=await e.text();if(t==="")return{};try{let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:{}}catch{return{}}}async function Sa(e,t,n){let o=Ve(e.stage),r=await Wn(o,"/get-public-key",{method:"POST",headers:Jn(t),body:JSON.stringify({api_name:n})}),i=await Kn(r);if(!r.ok||typeof i.public_key!="string"){let d=typeof i.error=="string"?i.error:`HTTP ${String(r.status)}`;throw new Error(`Failed to fetch public key: ${d}`)}return i.public_key}function Ta(e,t){let n=va(t,e),o=wa(n);if(typeof o.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return o.value}async function _a(e,t,n,o){let r=Ve(e.stage),i=await Wn(r,"/encrypt",{method:"POST",headers:Jn(t),body:JSON.stringify({api_name:n,value:o})}),d=await Kn(i);if(!i.ok||d.encrypted!==!0||typeof d.value!="string"){let f=typeof d.error=="string"?d.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${f}`)}return d.value}async function Tt(e,t,n,o,r){if(e.isRemote)return r?.("encrypting"),_a(e,t,n,o);r?.("fetching-key");let i=await Sa(e,t,n);return r?.("encrypting"),Ta(i,o)}import{spawn as Ea}from"child_process";import{platform as Gn}from"process";function ka(){return Gn==="darwin"?[{cmd:"pbcopy",args:[]}]:Gn==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var Pa=2e3;function Ia(e,{cmd:t,args:n}){return new Promise(o=>{let r;try{r=Ea(t,n,{stdio:["pipe","ignore","ignore"]})}catch{o(!1);return}let i=r,d=!1;function f(m){d||(d=!0,clearTimeout(g),o(m))}let g=setTimeout(()=>{i.kill(),f(!1)},Pa);g.unref(),i.on("error",()=>{f(!1)}),i.on("close",m=>{f(m===0)}),i.stdin.on("error",()=>{f(!1)});try{i.stdin.end(e)}catch{f(!1)}})}async function Yn(e){for(let t of ka())if(await Ia(e,t))return!0;return!1}import{Fragment as kt,jsx as F,jsxs as G}from"react/jsx-runtime";var sr=({text:e})=>F($,{dimColor:!0,children:e}),Zn=({ctx:e,stageDefaulted:t,credentialsPath:n,initialApiName:o,defaultApiName:r,initialValue:i,onDone:d})=>{let f=Ra(),[g,m]=Et({type:"loading"}),[b,T]=Et(null),[P,x]=Et(o??""),[p,y]=Et(i??""),S=_t(s=>{process.exitCode=1,m({type:"error",message:s instanceof Error?s.message:String(s)})},[]),H=_t(async(s,l,u)=>{try{let h=await Tt(e,s,l,u,A=>{m(A==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),k=JSON.stringify({encrypted:!0,value:h},null,2);d?.(h);let _=await Yn(k);m({type:"done",envelope:k,copied:_})}catch(h){S(h)}},[e,S,d]),O=_t((s,l,u)=>{if(l.trim()===""){m({type:"api-name-entry",buffer:r??""});return}if(u===""){m({type:"value-entry",buffer:""});return}H(s,l.trim(),u)},[r,H]),w=_t(async s=>{try{m({type:"loading"});let l=s.isDefault?await Z():await de(s.name);if(l===null)throw new Error(`Could not load credential profile: ${s.name}`);T(l),O(l,P,p)}catch(l){S(l)}},[P,p,O,S]);Xn(()=>{(async()=>{try{if(n!==void 0){let u;try{u=await be(n)}catch(h){throw new Error(`Could not load credentials from ${n}: ${h instanceof Error?h.message:String(h)}`)}T(u),O(u,P,p);return}let s=await Ie();if(s.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[l]=s;if(s.length===1&&l!==void 0){let u=l.isDefault?await Z():await de(l.name);if(u===null)throw new Error(`Could not load credential profile: ${l.name}`);T(u),O(u,P,p);return}m({type:"profile-select",profiles:s,cursor:0})}catch(s){S(s)}})()},[]),Xn(()=>{(g.type==="done"||g.type==="error")&&f.exit()},[g,f]),Aa((s,l)=>{if(l.ctrl&&s==="c"){process.exitCode=130,f.exit();return}if(g.type==="profile-select"){let{profiles:u,cursor:h}=g;if(l.upArrow)m({...g,cursor:(h-1+u.length)%u.length});else if(l.downArrow)m({...g,cursor:(h+1)%u.length});else if(l.return){let k=u[h];k!==void 0&&w(k)}return}if(g.type==="api-name-entry"){let{buffer:u}=g;if(l.backspace||l.delete)m({type:"api-name-entry",buffer:u.slice(0,-1)});else if(l.return){let h=u.trim();if(h===""){m({type:"api-name-entry",buffer:u,error:"api_name cannot be empty"});return}x(h),b?O(b,h,p):S(new Error("Internal error: credentials were not loaded"))}else s&&!l.ctrl&&!l.meta&&m({type:"api-name-entry",buffer:u+s});return}if(g.type==="value-entry"){let{buffer:u}=g;if(l.backspace||l.delete)m({type:"value-entry",buffer:u.slice(0,-1)});else if(l.return){if(u===""){m({type:"value-entry",buffer:u,error:"secret cannot be empty"});return}y(u),b?O(b,P,u):S(new Error("Internal error: credentials were not loaded"))}else s&&!l.ctrl&&!l.meta&&m({type:"value-entry",buffer:u+s});return}});let v=e.isRemote?"remote Kizen API":"on-machine",c=t===!0?`${e.stage} (default)`:e.stage,a=s=>G(ae,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[F(q,{}),G($,{dimColor:!0,children:["Mode: ",v," Stage: ",c]}),s]});if(g.type==="loading")return a(G(ae,{gap:1,children:[F(me,{}),F($,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(g.type==="profile-select"){let{profiles:s,cursor:l}=g;return a(G(kt,{children:[F($,{bold:!0,children:"Credential profile"}),F(ae,{flexDirection:"column",children:s.map((u,h)=>{let k=l===h;return G(ae,{gap:2,children:[F($,{...k&&{color:"cyan"},children:k?"\u276F":" "}),F($,{bold:k,...k&&{color:"cyan"},children:u.isDefault?"Default":u.name}),F($,{dimColor:!0,children:u.path})]},u.name)})}),F(sr,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return g.type==="api-name-entry"?a(G(kt,{children:[F($,{bold:!0,children:"Plugin api_name"}),g.error!==void 0&&G($,{color:"red",children:["Error: ",g.error]}),G(ae,{gap:1,children:[F($,{color:"cyan",children:">"}),F($,{children:g.buffer}),F($,{color:"cyan",children:"\u2588"})]}),F(sr,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):g.type==="value-entry"?a(G(kt,{children:[F($,{bold:!0,children:"Secret value"}),g.error!==void 0&&G($,{color:"red",children:["Error: ",g.error]}),G(ae,{gap:1,children:[F($,{color:"cyan",children:">"}),F($,{children:"\u2022".repeat(g.buffer.length)}),F($,{color:"cyan",children:"\u2588"})]}),F(sr,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):g.type==="fetching-key"?a(G(ae,{gap:1,children:[F(me,{}),G($,{children:["Fetching ",e.stage," public key for ",F($,{bold:!0,children:P}),"\u2026"]})]})):g.type==="encrypting"?a(G(ae,{gap:1,children:[F(me,{}),F($,{children:"Encrypting\u2026"})]})):g.type==="error"?a(G(ae,{gap:1,children:[F($,{color:"red",children:"\u2717"}),F($,{color:"red",children:g.message})]})):a(G(kt,{children:[G(ae,{gap:1,children:[F($,{color:"green",children:"\u2713"}),F($,{bold:!0,children:"Encrypted secret ready"})]}),g.copied?F($,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):F($,{dimColor:!0,children:"Paste this into the secret value in your kizen.json (re-run with --out <path> to save it to a file; selecting it here may capture line wraps):"}),F($,{children:g.envelope})]}))};import{readFile as Na,writeFile as Ba}from"fs/promises";import{join as Da}from"path";function Qn(e){return{encrypted:!0,value:e}}function eo(e){return JSON.stringify(Qn(e))}async function ar(e,t){await Ba(e,`${JSON.stringify(Qn(t),null,2)}
|
|
490
|
-
`,"utf-8")}var
|
|
491
|
-
`}async function
|
|
492
|
-
`),f=
|
|
457
|
+
`);E.push({name:z.name,value:W}),R=!0}else E.push(z);R&&T(` rewrote Set-Cookie SameSite on ${k}`);try{let{body:z,base64Encoded:W}=await C.Fetch.getResponseBody({requestId:s});await C.Fetch.fulfillRequest({requestId:s,responseCode:h??200,responseHeaders:E,body:z,...W&&{base64Encoded:!0}})}catch(z){T(` fulfillRequest failed (${z.message}), falling through`);try{await C.Fetch.continueRequest({requestId:s})}catch(W){T(` continueRequest also failed (${W.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:d}=await C.Network.getAllCookies(),l=0;for(let s of d){if(!Ln(`https://${s.domain??""}`)||s.sameSite==="None")continue;let a=s.domain??"",u=a.startsWith(".")?a.slice(1):a;await C.Network.setCookie({url:`https://${u}`,name:s.name,value:s.value,domain:a,path:s.path??"/",secure:!0,...s.httpOnly!==void 0&&{httpOnly:s.httpOnly},...s.expirationDate!==void 0&&{expires:s.expirationDate},sameSite:"None"}),l++}l>0&&T(`cookie-patch cycle: updated ${String(l)} cookie(s) to SameSite=None`)}catch(d){T(`cookie-patch cycle failed: ${d.message}`)}})()},2e3),await C.Target.setDiscoverTargets({discover:!0});let v=d=>{if(d.type==="page"){if(x(d.url)){y(`closed stray new-tab-page target ${d.targetId}`),p!==null&&C.Target.activateTarget({targetId:p}).catch(()=>{}),C.Target.closeTarget({targetId:d.targetId}).catch(()=>{});return}p===null&&(p=d.targetId,y(`captured main target ${d.targetId} (${d.url})`))}};C.on("Target.targetCreated",d=>{let{targetInfo:l}=d;T(`target +${l.type} ${l.targetId} ${l.url}`),v(l)}),C.on("Target.targetInfoChanged",d=>{let{targetInfo:l}=d;T(`target ~${l.type} ${l.targetId} ${l.url}`),v(l)}),C.on("disconnect",()=>{m||r!==C||(y("CDP disconnected"),r=null,P(),b())})},b=()=>{if(m||f!==null)return;let C=Math.min(1e3*2**g,1e4),v=g+1;g++,y(`CDP reconnect scheduled in ${String(C)}ms (attempt #${String(v)})`),f=setTimeout(()=>{f=null,(async()=>{let d;try{d=await jn({port:o})}catch{y(`CDP reconnect attempt #${String(v)} failed`),b();return}if(m){try{await d.close()}catch{}return}r=d;try{await c(d),y(`CDP reconnected after ${String(v)} attempt(s)`),g=0}catch{r===d&&(r=null);try{await d.close()}catch{}y(`CDP reconnect attempt #${String(v)} failed during setup`),b()}})()},C)},w=30,H=300;for(let C=0;C<w;C++){await new Promise(v=>setTimeout(v,H)),y(`CDP connect attempt ${String(C+1)}/${String(w)}`);try{let v=await jn({port:o});r=v,e.path&&v.send("Page.navigate",{url:`${t}${e.path}`});try{await c(v),y("CDP connected")}catch{r===v&&(r=null);try{await v.close()}catch{}y("CDP setup failed after connect")}break}catch{if(C===w-1){let v=`CDP unavailable after ${String(w)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return y(v),e.onWarn?.(v),{kill:()=>{n.kill()}}}}}return r?{kill:()=>{if(y("CDP kill requested \u2014 tearing down"),m=!0,f!==null&&(clearTimeout(f),f=null),P(),r!==null){try{r.close()}catch{}r=null}n.kill()}}:{kill:()=>{n.kill()}}}import{useCallback as ba,useState as xa}from"react";function vt(e){let[t,n]=xa([]),o=ba(r=>{n(i=>[...i,`${new Date().toLocaleTimeString()}: ${r}`].slice(-e))},[e]);return[t,o]}import{useCallback as wt,useEffect as sr,useState as Ct}from"react";import{Box as V,Text as $,useInput as va}from"ink";import{jsx as N,jsxs as J}from"react/jsx-runtime";var Se=["apiKey","userId","businessId"],wa={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},Ye=({text:e})=>N($,{dimColor:!0,children:e}),St=({initialMode:e,showProfileManager:t,onComplete:n,onCancel:o})=>{let[r,i]=Ct(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[p,f]=Ct(""),[g,m]=Ct(null),[y,T]=Ct(void 0),P=wt(d=>{if(d==="local"){n({mode:"local",credentials:null});return}i({type:"profile-loading"})},[n]),x=wt(async d=>{if(d===null){i({type:"profile-loading"});let a=await Re();i({type:"name-entry",nameBuffer:"",existingProfiles:a});return}T(d.isDefault?void 0:d.name),i({type:"loading"});let l=d.isDefault?await Z():await de(d.name),s=l?Math.max(0,Y.indexOf(l.environment)):0;i({type:"creds-entry",field:0,values:l??{},envCursor:s})},[]),c=wt(async(d,l)=>{let s=Y[l]??"go",a={apiKey:d.apiKey??"",userId:d.userId??"",businessId:d.businessId??"",environment:s};i({type:"saving"});try{await ln(y??xe,a),n({mode:"global",credentials:a,...y!==void 0&&{profileName:y}})}catch(u){m(u instanceof Error?u.message:String(u)),i({type:"creds-entry",field:0,values:d,envCursor:l})}},[n,y]);va((d,l)=>{if(l.ctrl&&d==="c"&&process.exit(0),l.escape){if((r.type==="creds-entry"||r.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),b();return}o?.();return}if(r.type==="mode-select"){if(l.upArrow)i({type:"mode-select",cursor:0});else if(l.downArrow)i({type:"mode-select",cursor:1});else if(l.return){let s=r.cursor===0?"global":"local";P(s)}return}if(r.type==="profile-select"){let{profiles:s,cursor:a}=r,u=s.length,h=s.length+1;if(l.upArrow)i({...r,cursor:(a-1+h)%h});else if(l.downArrow)i({...r,cursor:(a+1)%h});else if(l.return)if(a===u)i({type:"name-entry",nameBuffer:"",existingProfiles:s});else{let k=s[a]??s[0];k&&x(k)}return}if(r.type==="name-entry"){let{nameBuffer:s,existingProfiles:a}=r;if(l.backspace||l.delete)i({type:"name-entry",nameBuffer:s.slice(0,-1),existingProfiles:a});else if(l.return){let u=s.trim();if(!u){i({...r,nameError:"Name cannot be empty"});return}if(u===xe){i({...r,nameError:`"${xe}" is reserved`});return}if(a.some(h=>h.name===u)){i({...r,nameError:`Profile "${u}" already exists`});return}T(u),i({type:"creds-entry",field:0,values:{},envCursor:0}),f("")}else d&&!l.ctrl&&!l.meta&&i({type:"name-entry",nameBuffer:s+d,existingProfiles:a});return}if(r.type==="creds-entry"){let{field:s,values:a,envCursor:u}=r;if(s===Se.length){l.leftArrow?i({...r,envCursor:(u-1+Y.length)%Y.length}):l.rightArrow?i({...r,envCursor:(u+1)%Y.length}):l.upArrow?(i({...r,field:s-1}),f(a[Se[s-1]]??"")):l.return&&c(a,u);return}let k=Se[s];if(!k)return;if(l.backspace||l.delete)f(E=>E.slice(0,-1));else if(l.upArrow&&s>0){let E={...a,[k]:p},R=s-1;i({...r,field:R,values:E}),f(E[Se[R]]??"")}else if(l.return||l.tab||l.downArrow){let E={...a,[k]:p},R=s+1;i({...r,field:R,values:E}),R<Se.length?f(E[Se[R]]??""):f("")}else d&&!l.ctrl&&!l.meta&&f(E=>E+d)}});let b=wt(async()=>{let d=await Re();i({type:"profile-select",profiles:d,cursor:0})},[]);if(sr(()=>{r.type==="profile-loading"&&b()},[r.type,b]),sr(()=>{e==="global"&&!t&&(async()=>{let d=await Z(),l=d?Math.max(0,Y.indexOf(d.environment)):0;i({type:"creds-entry",field:0,values:d??{},envCursor:l})})()},[]),sr(()=>{r.type==="creds-entry"&&r.field===0&&f(r.values.apiKey??"")},[r.type]),r.type==="loading"||r.type==="saving"||r.type==="profile-loading"){let d=r.type==="saving"?"Saving credentials\u2026":r.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return N(V,{paddingY:1,paddingX:2,children:N($,{dimColor:!0,children:d})})}if(r.type==="done")return null;if(r.type==="mode-select")return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[N(q,{}),J(V,{flexDirection:"column",gap:0,children:[N($,{bold:!0,children:"Credential mode"}),[{label:"Global",desc:"~/.kizenappbuilder/credentials.json",mode:"global"},{label:"Local",desc:"Enter credentials in the browser dev tools",mode:"local"}].map((l,s)=>{let a=r.cursor===s;return J(V,{gap:2,children:[N($,{...a&&{color:"cyan"},children:a?"\u276F":" "}),N($,{bold:a,...a&&{color:"cyan"},children:l.label}),N($,{dimColor:!0,children:l.desc})]},l.mode)})]}),N(Ye,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(r.type==="profile-select"){let{profiles:d,cursor:l}=r,s=d.length;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[N(q,{}),J(V,{flexDirection:"column",gap:0,children:[N($,{bold:!0,children:"Credential profiles"}),d.map((a,u)=>{let h=l===u;return J(V,{gap:2,children:[N($,{...h&&{color:"cyan"},children:h?"\u276F":" "}),N($,{bold:h,...h&&{color:"cyan"},children:a.isDefault?"Default":a.name}),N($,{dimColor:!0,children:a.path})]},a.name)}),J(V,{gap:2,children:[N($,{...l===s&&{color:"cyan"},children:l===s?"\u276F":" "}),N($,{bold:l===s,...l===s&&{color:"cyan"},children:"+ Add new profile"})]})]}),N(Ye,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="name-entry"){let{nameBuffer:d,nameError:l}=r;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[N(q,{}),N(V,{flexDirection:"column",gap:0,children:N($,{bold:!0,children:"New credential profile"})}),l&&J($,{color:"red",children:["Error: ",l]}),J(V,{gap:2,children:[N(V,{width:12,children:N($,{bold:!0,color:"cyan",children:"Profile name"})}),N($,{color:"cyan",children:">"}),N($,{children:d}),N($,{color:"cyan",children:"\u2588"})]}),N(Ye,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:w,values:H,envCursor:j}=r,C=w===Se.length,v=y??xe;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[N(q,{}),J(V,{flexDirection:"column",gap:0,children:[N($,{bold:!0,children:y!==void 0?`Profile: ${y}`:"Global credentials"}),J($,{dimColor:!0,children:["Saved to:"," ",y!==void 0?`~/.kizenappbuilder/${y}.json`:Fe]})]}),g&&J($,{color:"red",children:["Error: ",g]}),J(V,{flexDirection:"column",gap:0,children:[Se.map((d,l)=>{let s=w===l,a=s?p:H[d]??"";return J(V,{gap:2,children:[N(V,{width:12,children:N($,{bold:s,...s&&{color:"cyan"},children:wa[d]})}),N($,{...s&&{color:"cyan"},children:">"}),N($,{children:a}),s&&N($,{color:"cyan",children:"\u2588"})]},d)}),J(V,{gap:2,children:[N(V,{width:12,children:N($,{bold:C,...C&&{color:"cyan"},children:"Environment"})}),N($,{...C&&{color:"cyan"},children:">"}),N(V,{gap:1,children:Y.map((d,l)=>{let s=l===j;return C?N($,{bold:s,...s&&{color:"cyan"},children:s?`[${d}]`:d},d):N($,{dimColor:!s,bold:s,children:d},d)})})]})]}),C?N(Ye,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):N(Ye,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),J($,{dimColor:!0,children:["Profile: ",v]})]})};import{jsx as D,jsxs as U}from"react/jsx-runtime";var Pa=[".kizenapp",".git"],Hn=({port:e,pluginDir:t,outputDir:n,credentials:o,credentialMode:r,activeCredentialProfile:i,lastPath:p,debug:f=!1,verbose:g=!1,autoViewer:m=!0,cacheEnabled:y=!0})=>{let T=pe(o),P=pe(i),x=pe(p),[c,b]=Q("main"),[w,H]=Q(r),[j,C]=Q("starting"),[v,d]=Q(null),[l,s]=vt(50),[a,u]=vt(50),[h,k]=vt(50),[E,R]=Q([]),[z,W]=Q("pending"),[te,oe]=Q(null),[ie,re]=Q(null),[ee,je]=Q(null),[Ee,Nt]=Q(null),[Rt,Bt]=Q(0),[dr,No]=Q(0),[Ro,Bo]=Q(0),[At,Ao]=Q(0),Dt=pe(!1),pr=pe(!1),Ze=pe(null),Le=pe(null),ue=pe(new Set),Qe=pe([]),ne=$e(S=>{let O=JSON.stringify(S);if(ue.current.size===0){Qe.current=[...Qe.current,O].slice(-50);return}let fe=!1;for(let se of ue.current)if(se.readyState===1)try{se.send(O)}catch{ue.current.delete(se),fe=!0}fe&&Bt(ue.current.size)},[]),et=s,Ft=$e(()=>{Ze.current?.kill(),Ze.current=null,zn({port:e,userDataDir:Mn(n,".chrome"),broadcast:ne,onWarn:S=>{s(`\u26A0 ${S}`)},...x.current!==void 0&&{path:x.current},...f&&{debugLog:k},...g&&{verbose:!0}}).then(S=>{Ze.current=S})},[e,n,ne,f,g,k,s]);Tt(()=>{let S=()=>{Ze.current?.kill()};return process.on("exit",S),()=>{process.off("exit",S)}},[]),Sa((S,O)=>{(S==="q"||O.ctrl&&S==="c")&&process.exit(0),S==="c"&&b("editing"),S==="v"&&Ft()},{isActive:c==="main"}),Tt(()=>{j!=="running"||pr.current||!m||(pr.current=!0,Ft())},[j,m,Ft]);let Do=$e(S=>{T.current=S.credentials,P.current=S.profileName,b("main"),H(S.mode);let O=S.profileName;Ce(n,{credentialMode:S.mode,...O!==void 0&&{activeCredentialProfile:O}}),ne({type:"credentials-updated",credentials:S.credentials})},[n,ne]),ur=$e(S=>{R(O=>[...O,`${new Date().toLocaleTimeString()}: ${nr(S)}`].slice(-50)),S.kind==="request"&&(S.fromCache?Bo(O=>O+1):Ao(O=>O+1)),ne({type:"proxy-log",entry:S})},[ne]),_e=$e(S=>{u(S),ne({type:"log",message:S})},[u,ne]),$t=$e(()=>{Dt.current||(Dt.current=!0,W("building"),oe(null),re(null),_e("Build started"),ot(t,n).then(({bundleSize:S})=>{_e(`Build finished \u2014 bundle: ${Oe(S)}`),W("done"),je(new Date),Nt(S),_e("Notifying viewers to reload"),ne({type:"rebuild"})}).catch(S=>{S instanceof Ta?(re(S.issues),oe(null)):(oe(S instanceof Error?S.message:String(S)),re(null)),W("error")}).finally(()=>{Dt.current=!1}))},[t,n,_e,ne]);if(Tt(()=>{$t();let S=Ea(t,{recursive:!0},(O,fe)=>{if(!fe)return;let se=fe.replace(/\\/g,"/");Pa.some(tt=>se.startsWith(tt))||(_e(`File change detected: ${fe}`),Le.current!==null&&clearTimeout(Le.current),Le.current=setTimeout($t,150))});return S.on("error",O=>{_e(`File watcher error \u2014 rebuilds have stopped: ${O.message}`)}),()=>{S.close(),Le.current!==null&&clearTimeout(Le.current)}},[t,$t,_e]),Tt(()=>{let S=Fn();ir(Mn(S,"index.html")).then(O=>{if(!O){d("Viewer not built. Run 'pnpm build:viewer' first."),C("error");return}let fe=$n(S,et,ur,T,P,n,ne,No,x,t,y),se=_a(fe),tt=new ka({server:se});return tt.on("connection",ke=>{for(let $o of Qe.current)ke.readyState===1&&ke.send($o);Qe.current=[],et("Viewer connected for live reload"),ue.current.add(ke),Bt(ue.current.size),ke.on("close",()=>{ue.current.delete(ke),Bt(ue.current.size)})}),se.listen(e,"127.0.0.1",()=>{C("running"),et(`Server started on 127.0.0.1:${String(e)}`)}),se.on("error",ke=>{d(ke.message),C("error")}),()=>{tt.close(),se.close()}})},[e,et,ur,ne,n,t,y]),c==="editing")return D(St,{...w!==void 0&&{initialMode:w},showProfileManager:w==="global",onComplete:Do,onCancel:()=>{b("main")}});let jt=ee!==null?Math.round((Date.now()-ee.getTime())/1e3):null,Fo=jt===null?"":jt<5?" (just now)":` (${String(jt)}s ago)`,fr=ie?.filter(S=>S.severity==="error").length??0;return U(G,{flexDirection:"column",paddingY:1,paddingX:2,children:[D(q,{marginBottom:1}),U(G,{flexDirection:"column",children:[U(G,{gap:2,marginBottom:0,children:[D(A,{bold:!0,dimColor:!0,children:"App Build"}),z==="pending"&&D(A,{dimColor:!0,children:"waiting\u2026"}),z==="building"&&U(G,{gap:1,children:[D(me,{}),D(A,{children:"Building plugin package\u2026"})]}),z==="done"&&U(G,{gap:1,children:[D(A,{color:"green",children:"\u2713 Built"}),ee!==null&&U(A,{dimColor:!0,children:["at ",ee.toLocaleTimeString(),Fo]}),Ee!==null&&U(A,{dimColor:!0,children:["\xB7 bundle: ",Oe(Ee)]})]}),z==="error"&&(ie!==null?U(A,{color:"red",children:["\u2717 ",fr," validation ",fr===1?"error":"errors"]}):U(A,{color:"red",children:["\u2717 ",te??"unknown error"]}))]}),ie!==null&&D(st,{issues:ie}),D(G,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:a.slice(-8).map((S,O)=>D(A,{dimColor:!0,wrap:"truncate",children:S},O))})]}),U(G,{marginTop:1,flexDirection:"column",children:[U(G,{gap:2,children:[D(A,{bold:!0,dimColor:!0,children:"Web Server"}),j==="starting"&&D(A,{dimColor:!0,children:"starting\u2026"}),j==="running"&&U(G,{gap:2,children:[D(A,{color:"green",children:"\u2713 Running"}),U(A,{dimColor:!0,children:["\u25CF ",Rt," viewer",Rt!==1?"s":""]})]}),j==="error"&&U(A,{color:"red",children:["\u2717 ",v??"Server error"]})]}),D(G,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:l.slice(-8).map((S,O)=>D(A,{dimColor:!0,wrap:"truncate",children:S},O))})]}),U(G,{marginTop:1,flexDirection:"column",children:[U(G,{gap:2,children:[D(A,{bold:!0,dimColor:!0,children:"Network Proxy"}),D(A,{color:"green",children:"\u2713 Active"}),D(A,{dimColor:!0,children:y?`\u25CF ${String(dr)} key${dr!==1?"s":""} in the network cache \xB7 ${String(Ro)} hit \xB7 ${String(At)} miss`:`\u25CF network cache disabled \xB7 ${String(At)} request${At!==1?"s":""}`})]}),D(G,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:E.length===0?D(A,{dimColor:!0,children:" No requests yet."}):E.slice(-8).map((S,O)=>D(A,{dimColor:!0,wrap:"truncate",children:S},O))})]}),f&&U(G,{marginTop:1,flexDirection:"column",children:[U(G,{gap:2,children:[D(A,{bold:!0,dimColor:!0,children:"CDP Debug"}),U(A,{dimColor:!0,children:["\u25CF ",h.length," event(s)"]})]}),D(G,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:h.length===0?D(A,{dimColor:!0,children:" No CDP events yet."}):h.slice(-8).map((S,O)=>D(A,{dimColor:!0,wrap:"truncate",children:S},O))})]}),U(G,{marginTop:1,gap:1,children:[D(A,{dimColor:!0,children:"["}),D(A,{children:"q"}),D(A,{dimColor:!0,children:"] quit ["}),D(A,{children:"c"}),D(A,{dimColor:!0,children:"] credentials ["}),D(A,{children:"v"}),U(A,{dimColor:!0,children:["] ",Rt===0?"open viewer":"relaunch viewer"]})]})]})};async function Un(e){return new Promise(t=>{let n=null,o=i=>{n?.(),t(i)},{unmount:r}=qn(Vn(St,{...e!==void 0&&{initialMode:e},onComplete:o}),{exitOnCtrlC:!1});n=r})}function Jn(e){e.command("dev").description("Start the plugin viewer dev server").option("-p, --port <port>","port to listen on","3121").option("-c, --credentials <path>","path to a credentials JSON file").option("-d, --debug","Enable CDP lifecycle logs in the TUI").option("-v, --verbose","Log every CDP event and handled error (implies --debug)").option("--no-viewer","Don't auto-launch the viewer on startup (press [v] to launch manually)").option("--no-cache","Disable the network proxy cache (always fetch upstream)").action(async t=>{let n=parseInt(t.port,10),o=process.cwd(),r=`${o}/.kizenapp`;he(o);let i=null,p,f,{lastPath:g}=await we(r);if(t.credentials)i=await ve(t.credentials);else{let c=await we(r);if(c.credentialMode==="local")p="local";else if(c.credentialMode==="global"){if(p="global",f=c.activeCredentialProfile,f?(i=await de(f),i||(i=await Z(),f=void 0)):i=await Z(),!i){let b=await Un("global");i=b.credentials,f=b.profileName}}else{let b=await Un();i=b.credentials,p=b.mode,f=b.profileName;let w=b.profileName;await Ce(r,{credentialMode:b.mode,...w!==void 0&&{activeCredentialProfile:w}})}}let m=t.verbose===!0,y=m||t.debug===!0,T=t.viewer!==!1,P=t.cache!==!1,{waitUntilExit:x}=qn(Vn(Hn,{port:n,pluginDir:o,outputDir:r,credentials:i,...p!==void 0&&{credentialMode:p},...f!==void 0&&{activeCredentialProfile:f},...g!==void 0&&{lastPath:g},debug:y,verbose:m,autoViewer:T,cacheEnabled:P}),{exitOnCtrlC:!1});await x()})}import{createElement as qa}from"react";import{render as Ja}from"ink";import{useCallback as _t,useEffect as Zn,useState as kt}from"react";import{Box as ae,Text as L,useApp as Oa,useInput as za}from"ink";import{encrypt as Ia,serializeEnvelope as Na}from"@kizenapps/packager";function Ra(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function Wn(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 Gn(e,t,n){try{return await fetch(`${e}${t}`,n)}catch(o){throw new Error(Ra(o)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${o.message}`)}}async function Kn(e){let t=await e.text();if(t==="")return{};try{let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:{}}catch{return{}}}async function Ba(e,t,n){let o=qe(e.stage),r=await Gn(o,"/get-public-key",{method:"POST",headers:Wn(t),body:JSON.stringify({api_name:n})}),i=await Kn(r);if(!r.ok||typeof i.public_key!="string"){let p=typeof i.error=="string"?i.error:`HTTP ${String(r.status)}`;throw new Error(`Failed to fetch public key: ${p}`)}return i.public_key}function Aa(e,t){let n=Ia(t,e),o=Na(n);if(typeof o.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return o.value}async function Da(e,t,n,o){let r=qe(e.stage),i=await Gn(r,"/encrypt",{method:"POST",headers:Wn(t),body:JSON.stringify({api_name:n,value:o})}),p=await Kn(i);if(!i.ok||p.encrypted!==!0||typeof p.value!="string"){let f=typeof p.error=="string"?p.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${f}`)}return p.value}async function Et(e,t,n,o,r){if(e.isRemote)return r?.("encrypting"),Da(e,t,n,o);r?.("fetching-key");let i=await Ba(e,t,n);return r?.("encrypting"),Aa(i,o)}import{spawn as Fa}from"child_process";import{platform as Yn}from"process";function $a(){return Yn==="darwin"?[{cmd:"pbcopy",args:[]}]:Yn==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var ja=2e3;function La(e,{cmd:t,args:n}){return new Promise(o=>{let r;try{r=Fa(t,n,{stdio:["pipe","ignore","ignore"]})}catch{o(!1);return}let i=r,p=!1;function f(m){p||(p=!0,clearTimeout(g),o(m))}let g=setTimeout(()=>{i.kill(),f(!1)},ja);g.unref(),i.on("error",()=>{f(!1)}),i.on("close",m=>{f(m===0)}),i.stdin.on("error",()=>{f(!1)});try{i.stdin.end(e)}catch{f(!1)}})}async function Xn(e){for(let t of $a())if(await La(e,t))return!0;return!1}import{Fragment as Pt,jsx as F,jsxs as K}from"react/jsx-runtime";var ar=({text:e})=>F(L,{dimColor:!0,children:e}),Qn=({ctx:e,stageDefaulted:t,credentialsPath:n,initialApiName:o,defaultApiName:r,initialValue:i,onDone:p})=>{let f=Oa(),[g,m]=kt({type:"loading"}),[y,T]=kt(null),[P,x]=kt(o??""),[c,b]=kt(i??""),w=_t(s=>{process.exitCode=1,m({type:"error",message:s instanceof Error?s.message:String(s)})},[]),H=_t(async(s,a,u)=>{try{let h=await Et(e,s,a,u,R=>{m(R==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),k=JSON.stringify({encrypted:!0,value:h},null,2);p?.(h);let E=await Xn(k);m({type:"done",envelope:k,copied:E})}catch(h){w(h)}},[e,w,p]),j=_t((s,a,u)=>{if(a.trim()===""){m({type:"api-name-entry",buffer:r??""});return}if(u===""){m({type:"value-entry",buffer:""});return}H(s,a.trim(),u)},[r,H]),C=_t(async s=>{try{m({type:"loading"});let a=s.isDefault?await Z():await de(s.name);if(a===null)throw new Error(`Could not load credential profile: ${s.name}`);T(a),j(a,P,c)}catch(a){w(a)}},[P,c,j,w]);Zn(()=>{(async()=>{try{if(n!==void 0){let u;try{u=await ve(n)}catch(h){throw new Error(`Could not load credentials from ${n}: ${h instanceof Error?h.message:String(h)}`)}T(u),j(u,P,c);return}let s=await Re();if(s.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[a]=s;if(s.length===1&&a!==void 0){let u=a.isDefault?await Z():await de(a.name);if(u===null)throw new Error(`Could not load credential profile: ${a.name}`);T(u),j(u,P,c);return}m({type:"profile-select",profiles:s,cursor:0})}catch(s){w(s)}})()},[]),Zn(()=>{(g.type==="done"||g.type==="error")&&f.exit()},[g,f]),za((s,a)=>{if(a.ctrl&&s==="c"){process.exitCode=130,f.exit();return}if(g.type==="profile-select"){let{profiles:u,cursor:h}=g;if(a.upArrow)m({...g,cursor:(h-1+u.length)%u.length});else if(a.downArrow)m({...g,cursor:(h+1)%u.length});else if(a.return){let k=u[h];k!==void 0&&C(k)}return}if(g.type==="api-name-entry"){let{buffer:u}=g;if(a.backspace||a.delete)m({type:"api-name-entry",buffer:u.slice(0,-1)});else if(a.return){let h=u.trim();if(h===""){m({type:"api-name-entry",buffer:u,error:"api_name cannot be empty"});return}x(h),y?j(y,h,c):w(new Error("Internal error: credentials were not loaded"))}else s&&!a.ctrl&&!a.meta&&m({type:"api-name-entry",buffer:u+s});return}if(g.type==="value-entry"){let{buffer:u}=g;if(a.backspace||a.delete)m({type:"value-entry",buffer:u.slice(0,-1)});else if(a.return){if(u===""){m({type:"value-entry",buffer:u,error:"secret cannot be empty"});return}b(u),y?j(y,P,u):w(new Error("Internal error: credentials were not loaded"))}else s&&!a.ctrl&&!a.meta&&m({type:"value-entry",buffer:u+s});return}});let v=e.isRemote?"remote Kizen API":"on-machine",d=t===!0?`${e.stage} (default)`:e.stage,l=s=>K(ae,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[F(q,{}),K(L,{dimColor:!0,children:["Mode: ",v," Stage: ",d]}),s]});if(g.type==="loading")return l(K(ae,{gap:1,children:[F(me,{}),F(L,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(g.type==="profile-select"){let{profiles:s,cursor:a}=g;return l(K(Pt,{children:[F(L,{bold:!0,children:"Credential profile"}),F(ae,{flexDirection:"column",children:s.map((u,h)=>{let k=a===h;return K(ae,{gap:2,children:[F(L,{...k&&{color:"cyan"},children:k?"\u276F":" "}),F(L,{bold:k,...k&&{color:"cyan"},children:u.isDefault?"Default":u.name}),F(L,{dimColor:!0,children:u.path})]},u.name)})}),F(ar,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return g.type==="api-name-entry"?l(K(Pt,{children:[F(L,{bold:!0,children:"Plugin api_name"}),g.error!==void 0&&K(L,{color:"red",children:["Error: ",g.error]}),K(ae,{gap:1,children:[F(L,{color:"cyan",children:">"}),F(L,{children:g.buffer}),F(L,{color:"cyan",children:"\u2588"})]}),F(ar,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):g.type==="value-entry"?l(K(Pt,{children:[F(L,{bold:!0,children:"Secret value"}),g.error!==void 0&&K(L,{color:"red",children:["Error: ",g.error]}),K(ae,{gap:1,children:[F(L,{color:"cyan",children:">"}),F(L,{children:"\u2022".repeat(g.buffer.length)}),F(L,{color:"cyan",children:"\u2588"})]}),F(ar,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):g.type==="fetching-key"?l(K(ae,{gap:1,children:[F(me,{}),K(L,{children:["Fetching ",e.stage," public key for ",F(L,{bold:!0,children:P}),"\u2026"]})]})):g.type==="encrypting"?l(K(ae,{gap:1,children:[F(me,{}),F(L,{children:"Encrypting\u2026"})]})):g.type==="error"?l(K(ae,{gap:1,children:[F(L,{color:"red",children:"\u2717"}),F(L,{color:"red",children:g.message})]})):l(K(Pt,{children:[K(ae,{gap:1,children:[F(L,{color:"green",children:"\u2713"}),F(L,{bold:!0,children:"Encrypted secret ready"})]}),g.copied?F(L,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):F(L,{dimColor:!0,children:"Paste this into the secret value in your kizen.json (re-run with --out <path> to save it to a file; selecting it here may capture line wraps):"}),F(L,{children:g.envelope})]}))};import{readFile as Ma,writeFile as Ha}from"fs/promises";import{join as Ua}from"path";function eo(e){return{encrypted:!0,value:e}}function to(e){return JSON.stringify(eo(e))}async function lr(e,t){await Ha(e,`${JSON.stringify(eo(t),null,2)}
|
|
458
|
+
`,"utf-8")}var Va="prod";function ro(e){return e==="dev"||e==="prod"}function no(e){return`Error: --stage must be "dev" or "prod" (got: "${e}")`}function oo(e){return{stage:e==="dev"||e==="prod"?e:Va,wasDefaulted:e===void 0}}function io(e){return`No --stage given; defaulting to ${e} encryption keys (pass --stage dev to override)
|
|
459
|
+
`}async function so(e=process.cwd()){try{let t=await Ma(Ua(e,"kizen.json"),"utf-8"),n=JSON.parse(t),o=Array.isArray(n)?n[0]:n,r=typeof o.api_name=="string"&&o.api_name!==""?o.api_name:void 0;return{...r!==void 0&&{apiName:r}}}catch{}return{}}function ao(e){return e.replace(/[\r\n]+$/,"")}async function lo(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function co(e,t,n,o,r){let i=t.credentials!==void 0?await r.loadCredentialsFromFile(t.credentials):await r.loadGlobalCredentials();if(i===null)throw new Error("No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.");let p=t.apiName??n.apiName;if(p===void 0||p.trim()==="")throw new Error("api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.");o&&r.writeStderr(io(e.stage));let f=t.value;if(f===void 0){if(r.stdinIsTTY())throw new Error('No secret provided and stdin is a terminal. Pass --value, or pipe the secret in (e.g. `printf %s "$SECRET" | npx --yes @kizenapps/cli encrypt \u2026`).');r.writeStderr(`Reading secret from stdin (pass --value to skip)\u2026
|
|
460
|
+
`),f=ao(await r.readStdin())}if(f==="")throw new Error("A secret value is required. Pass --value or pipe it via stdin.");let g=await r.encryptSecret(e,i,p.trim(),f);if(r.writeStdout(`${to(g)}
|
|
493
461
|
`),t.out!==void 0)try{await r.writeEnvelopeFile(t.out,g),r.writeStderr(`Wrote encrypted envelope to ${t.out}
|
|
494
462
|
`)}catch(m){r.writeStderr(`Error writing ${t.out}: ${m instanceof Error?m.message:String(m)}
|
|
495
|
-
`),r.setExitCode(1)}}function
|
|
496
|
-
`)}catch(m){console.error(`Error writing ${t.out}: ${m instanceof Error?m.message:String(m)}`),process.exitCode=1}})}var
|
|
497
|
-
${
|
|
498
|
-
`)}var
|
|
463
|
+
`),r.setExitCode(1)}}function po(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&&!ro(t.stage)&&(console.error(no(t.stage)),process.exit(1));let o=t.apiName===void 0?await so():{},{stage:r,wasDefaulted:i}=oo(t.stage),p={isRemote:t.remote===!0,stage:r};if(!process.stdin.isTTY||!process.stdout.isTTY){try{await co(p,t,o,i,{loadCredentialsFromFile:ve,loadGlobalCredentials:Z,encryptSecret:Et,readStdin:lo,stdinIsTTY:()=>process.stdin.isTTY,writeStdout:m=>{process.stdout.write(m)},writeStderr:m=>{process.stderr.write(m)},writeEnvelopeFile:lr,setExitCode:m=>{process.exitCode=m}})}catch(m){console.error(`Error: ${m instanceof Error?m.message:String(m)}`),process.exit(1)}return}let f,{waitUntilExit:g}=Ja(qa(Qn,{ctx:p,stageDefaulted:i,onDone:m=>{f=m},...t.credentials!==void 0&&{credentialsPath:t.credentials},...t.apiName!==void 0&&{initialApiName:t.apiName},...o.apiName!==void 0&&{defaultApiName:o.apiName},...t.value!==void 0&&{initialValue:t.value}}),{exitOnCtrlC:!1});if(await g(),f!==void 0&&t.out!==void 0)try{await lr(t.out,f),process.stderr.write(`Wrote encrypted envelope to ${t.out}
|
|
464
|
+
`)}catch(m){console.error(`Error writing ${t.out}: ${m instanceof Error?m.message:String(m)}`),process.exitCode=1}})}var Wa=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"]),Ga=[...Wa].sort(),Ka=new Set(["kizen-k","form-entity"]),uo=[...Ga,...[...Ka].sort()];function fo(e){e.command("icons").description("List all valid icon names accepted by toolbar items, pages, and adornments").action(()=>{for(let t of uo)console.log(t)})}import{mkdir as nl,writeFile as To,readFile as ol}from"fs/promises";import{join as It}from"path";var Ya=new Set(["developer_business_id"]);function Xa(e){return Array.isArray(e)?e.map(t=>{if(typeof t!="object"||t===null)return t;let n=t;if(typeof n.auth_credentials!="object"||n.auth_credentials===null)return n;let o=Object.fromEntries(Object.keys(n.auth_credentials).map(r=>[r,"*****"]));return{...n,auth_credentials:o}}):e}function go(e){let t={name:"",children:new Map,isFile:!1,filePath:""};for(let n of e){let o=n.path.split("/"),r=t;o.forEach((i,p)=>{r.children.has(i)||r.children.set(i,{name:i,children:new Map,isFile:p===o.length-1,filePath:o.slice(0,p+1).join("/")});let f=r.children.get(i);f&&(r=f)})}return t}function ho(e){return[...e.children.values()].sort((t,n)=>t.isFile!==n.isFile?t.isFile?1:-1:t.name.localeCompare(n.name))}function cr(e){return"file-"+e.replace(/[^a-zA-Z0-9]/g,"-")}function le(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function yo(e){let t=e.lastIndexOf(".");return t>=0?e.slice(t).toLowerCase():""}var Za={".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 Qa(e){return Za[yo(e)]??""}function mo(e){let t=[...e.matchAll(/`+/g)].reduce((n,o)=>Math.max(n,o[0].length),0);return"`".repeat(Math.max(3,t+1))}function bo(e,t=""){let n=ho(e);return n.map((o,r)=>{let i=r===n.length-1,p=i?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",f=i?" ":"\u2502 ";return o.isFile?`${t}${p}${o.name}`:`${t}${p}${o.name}/
|
|
465
|
+
${bo(o,t+f)}`}).join(`
|
|
466
|
+
`)}var el=/(^|\/)licen[cs]e(\.md|\.txt)?$/i;function xo(e){return e.filter(t=>t.path!=="kizen.json"&&t.path!=="plugin-report.html"&&!el.test(t.path))}function vo(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!Ya.has(t)).map(([t,n])=>[t,t==="services"?Xa(n):n]))}var tl={".png":"image/png",".svg":"image/svg+xml",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp"};function wo(e){return`<ul>${ho(e).map(o=>o.isFile?`<li class="tf"><a href="#${cr(o.filePath)}" data-id="${cr(o.filePath)}">${le(o.name)}</a></li>`:`<li class="td"><span class="dn">${le(o.name)}/</span>${wo(o)}</li>`).join("")}</ul>`}function rl(e){let t;return e.base64Image!==void 0?t=`<img src="data:${tl[yo(e.path)]??"image/png"};base64,${e.base64Image}" alt="${le(e.path)}" style="max-width:100%">`:e.binaryData!==void 0?t=`<p class="bin">[Binary file: ${String(e.binaryData.length)} bytes]</p>`:t=`<pre><code>${le(e.content)}</code></pre>`,`<section id="${cr(e.path)}"><h2 class="fp">${le(e.path)}</h2><div class="fb">${t}</div></section>`}function Co(e,t){let n=vo(e),o=typeof e.name=="string"?e.name:"Plugin",r=typeof e.version=="string"?e.version:"",i=typeof e.description=="string"?e.description:"",p=xo(t),f=[];f.push(`# ${o}${r?` v${r}`:""}`),i&&f.push("",i);let g=JSON.stringify(n,null,2),m=mo(g);f.push("","## Configuration (`kizen.json`)","",`${m}json`,g,m),f.push("","## File Tree","","```",bo(go(p)),"```"),f.push("","## Files");for(let y of p)if(f.push("",`### \`${y.path}\``,""),y.base64Image!==void 0)f.push(`[Image file: ${y.path}]`);else if(y.binaryData!==void 0)f.push(`[Binary file: ${String(y.binaryData.length)} bytes]`);else{let T=mo(y.content);f.push(`${T}${Qa(y.path)}`,y.content,T)}return f.join(`
|
|
499
467
|
`)+`
|
|
500
|
-
`}function
|
|
468
|
+
`}function So(e,t){let n=vo(e),o=typeof e.name=="string"?e.name:"Plugin",r=typeof e.version=="string"?e.version:"",i=typeof e.description=="string"?e.description:"",p=xo(t),f=wo(go(p)),g=p.map(rl).join(`
|
|
501
469
|
`);return`<!DOCTYPE html>
|
|
502
470
|
<html lang="en">
|
|
503
471
|
<head>
|
|
@@ -563,7 +531,9 @@ ${g}
|
|
|
563
531
|
})();
|
|
564
532
|
</script>
|
|
565
533
|
</body>
|
|
566
|
-
</html>`}var
|
|
534
|
+
</html>`}var Eo=It(Ne,"examples");function _o(e){e.command("report").description("Generate a self-contained HTML report of the plugin").option("-o, --output <path>",`output file path (default: ${Eo}/<api_name>.html)`).action(async t=>{let n=process.cwd(),o;try{let g=await ol(It(n,"kizen.json"),"utf-8"),m=JSON.parse(g);o=Array.isArray(m)?m[0]:m}catch{console.error("Error: kizen.json not found. Run this command from a plugin directory."),process.exit(1)}let r=typeof o.api_name=="string"?o.api_name:"plugin",i=t.output??It(Eo,`${r}.html`),p=i.replace(/\.html$/,".md"),f=await nt(n,{detectBinaryByContent:!0});await nl(It(i,".."),{recursive:!0}),await Promise.all([To(i,So(o,f),"utf-8"),To(p,Co(o,f),"utf-8")]),console.log(`Plugin report written to:
|
|
567
535
|
${i}
|
|
568
|
-
${
|
|
536
|
+
${p}`)})}import{mkdir as il,readFile as sl,writeFile as al}from"fs/promises";import{dirname as ll,join as cl}from"path";async function dl(e){try{return await sl(e,"utf-8")}catch(t){if(t.code==="ENOENT")return;throw t}}async function pl(e,t,n){let o=cl(e,...t.path.split("/")),r=await dl(o);if(r===t.content)return{path:t.path,status:"unchanged"};let i=r===void 0?"created":"updated";return n||(await il(ll(o),{recursive:!0}),await al(o,t.content,"utf-8")),{path:t.path,status:i}}async function ko(e,t={}){if(await ye(e)!=="has-manifest")throw new Error(`No kizen.json found in ${e}`);let n=t.dryRun===!0,o=await Promise.all(lt().map(r=>pl(e,r,n)));return n||he(e),{files:o}}function Po(e){e.command("setup-copilot").description("Add or refresh the Copilot code-review setup in an existing plugin repo").option("--dry-run","report what would change without writing anything").action(async t=>{let n=process.cwd();if(await ye(n)!=="has-manifest"){console.error(`No kizen.json found in ${n} \u2014 run "appbuilder setup-copilot" from the root of a plugin repo.`),process.exitCode=1;return}let o=t.dryRun===!0;try{let r=await ko(n,{dryRun:o});for(let i of r.files)console.log(`${i.status.padEnd(9)} ${i.path}`);if(o){console.log(`
|
|
537
|
+
Dry run \u2014 no files and no .gitignore entries were written.`);return}console.log(`
|
|
538
|
+
Ensured .gitignore ignores .kizenapp/ and .copilot-docs/.`),console.log("The code review workflow only takes effect once it is on the repository default branch \u2014 merge it before expecting reviews to cite .copilot-docs/.")}catch(r){console.error(`Error: ${r instanceof Error?r.message:String(r)}`),process.exitCode=1}})}function yl(){let e=ml(fl(gl(import.meta.url)),"..","package.json");return JSON.parse(ul(e,"utf-8")).version}function Io(){let e=new hl;return e.name("appbuilder").description("Kizen plugin app builder").version(yl()),dn(e),Po(e),Er(e),Jn(e),po(e),_o(e),fo(e),e}Io().parse();
|
|
569
539
|
//# sourceMappingURL=index.js.map
|