@kizenapps/cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4OYGMEFM.js +3675 -0
- package/dist/chunk-4OYGMEFM.js.map +1 -0
- package/dist/chunk-4Z6S6LWP.js +6134 -0
- package/dist/chunk-4Z6S6LWP.js.map +1 -0
- package/dist/chunk-5WPGAZLP.js +6136 -0
- package/dist/chunk-5WPGAZLP.js.map +1 -0
- package/dist/chunk-6XGFZ4W5.js +3673 -0
- package/dist/chunk-6XGFZ4W5.js.map +1 -0
- package/dist/chunk-KMKDY2I6.js +46 -0
- package/dist/chunk-KMKDY2I6.js.map +1 -0
- package/dist/chunk-LSHHXCC6.js +3639 -0
- package/dist/chunk-LSHHXCC6.js.map +1 -0
- package/dist/chunk-NNDSADQG.js +3641 -0
- package/dist/chunk-NNDSADQG.js.map +1 -0
- package/dist/chunk-SEGVTWSK.js +44 -0
- package/dist/chunk-SEGVTWSK.js.map +1 -0
- package/dist/devtools-HNR7DD7Q.js +68 -0
- package/dist/devtools-HNR7DD7Q.js.map +1 -0
- package/dist/devtools-HW3UQAHH.js +69 -0
- package/dist/devtools-HW3UQAHH.js.map +1 -0
- package/dist/devtools-KXIXZGBY.js +64 -0
- package/dist/devtools-KXIXZGBY.js.map +1 -0
- package/dist/devtools-PDXM3L35.js +67 -0
- package/dist/devtools-PDXM3L35.js.map +1 -0
- package/dist/devtools-SDEASRYI.js +66 -0
- package/dist/devtools-SDEASRYI.js.map +1 -0
- package/dist/devtools-XBEEGBQ4.js +66 -0
- package/dist/devtools-XBEEGBQ4.js.map +1 -0
- package/dist/dist-4P5P64FK.js +8474 -0
- package/dist/dist-4P5P64FK.js.map +1 -0
- package/dist/dist-AVHDSU4X.js +137 -0
- package/dist/dist-AVHDSU4X.js.map +1 -0
- package/dist/dist-NUJOSN7W.js +8472 -0
- package/dist/dist-NUJOSN7W.js.map +1 -0
- package/dist/dist-QHDMIBVE.js +135 -0
- package/dist/dist-QHDMIBVE.js.map +1 -0
- package/dist/electron/icon.png +0 -0
- package/dist/electron/main.js +65 -3
- package/dist/electron/main.js.map +1 -1
- package/dist/electron/preload.cjs +5 -0
- package/dist/gzip-size-K37OQCQ2.js +137 -0
- package/dist/gzip-size-K37OQCQ2.js.map +1 -0
- package/dist/gzip-size-SHZBT5GU.js +139 -0
- package/dist/gzip-size-SHZBT5GU.js.map +1 -0
- package/dist/index.js +588 -171
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/calendarSource.worker-C9iglnKD.js +24 -0
- package/dist/viewer/assets/expression.worker-Cin-WNVB.js +5 -0
- package/dist/viewer/assets/floatingFrame.worker-CWLtchq3.js +23 -0
- package/dist/viewer/assets/generic.worker-DRXu0-5B.js +23 -0
- package/dist/viewer/assets/index-B0d3If0o.js +582 -0
- package/dist/viewer/assets/index-B1mMv9H8.css +2 -0
- package/dist/viewer/assets/index-BTLnOfRu.css +2 -0
- package/dist/viewer/assets/index-B_uo-pdA.js +582 -0
- package/dist/viewer/assets/index-Bp6umXGR.js +582 -0
- package/dist/viewer/assets/index-Bsja5bOD.js +582 -0
- package/dist/viewer/assets/index-CAej9s9R.js +582 -0
- package/dist/viewer/assets/index-CCMFzDS-.css +2 -0
- package/dist/viewer/assets/index-Ci4aelpQ.js +582 -0
- package/dist/viewer/assets/index-CuVHD6vO.css +2 -0
- package/dist/viewer/assets/index-DQZ1fN2j.js +582 -0
- package/dist/viewer/assets/index-DSeA5UDI.js +582 -0
- package/dist/viewer/assets/index-w7OW3o4t.js +582 -0
- package/dist/viewer/assets/recordDetail.worker-BIHPFt8Y.js +23 -0
- package/dist/viewer/icon.png +0 -0
- package/dist/viewer/index.html +2 -2
- package/package.json +17 -13
- package/dist/viewer/assets/calendarSource.worker-DF0wAwJR.js +0 -24
- package/dist/viewer/assets/expression.worker-_W4VR2xe.js +0 -5
- package/dist/viewer/assets/floatingFrame.worker-DXcDBfqJ.js +0 -23
- package/dist/viewer/assets/generic.worker-CsqlYndL.js +0 -23
- package/dist/viewer/assets/index-CW_UqFf3.css +0 -1
- package/dist/viewer/assets/index-DaB01Qok.js +0 -637
- package/dist/viewer/assets/recordDetail.worker-Ccm59Np6.js +0 -23
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { render } from "ink";
|
|
|
9
9
|
|
|
10
10
|
// src/ui/BuildUI.tsx
|
|
11
11
|
import { useEffect, useState } from "react";
|
|
12
|
-
import { Box, Text, useApp } from "ink";
|
|
12
|
+
import { Box as Box2, Text as Text2, useApp } from "ink";
|
|
13
13
|
|
|
14
14
|
// src/lib/runBuild.ts
|
|
15
15
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -59,10 +59,11 @@ async function readLocalFiles(rootDir) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// src/lib/runBuild.ts
|
|
62
|
-
var serializePlugin = (plugin) => ({
|
|
62
|
+
var serializePlugin = (plugin, allReleaseNotes) => ({
|
|
63
63
|
...plugin,
|
|
64
64
|
thumbnail: plugin.thumbnail ? Buffer.from(plugin.thumbnail).toString("base64") : null,
|
|
65
|
-
kznFile: plugin.kznFile ? Buffer.from(plugin.kznFile).toString("base64") : null
|
|
65
|
+
kznFile: plugin.kznFile ? Buffer.from(plugin.kznFile).toString("base64") : null,
|
|
66
|
+
allReleaseNotes
|
|
66
67
|
});
|
|
67
68
|
async function runBuild(pluginDir, outputDir, onStep) {
|
|
68
69
|
await mkdir(outputDir, { recursive: true });
|
|
@@ -79,12 +80,44 @@ async function runBuild(pluginDir, outputDir, onStep) {
|
|
|
79
80
|
const packaged = packagePlugin(minified, manifests);
|
|
80
81
|
const deployable = Object.values(packaged).map(transformDeployablePlugin);
|
|
81
82
|
onStep?.("writing-bundle");
|
|
82
|
-
const bundle = deployable.map(
|
|
83
|
+
const bundle = deployable.map((plugin) => {
|
|
84
|
+
const notesDir = plugin.release_notes_directory?.replace(/\/$/, "");
|
|
85
|
+
const allReleaseNotes = notesDir ? files.filter((f) => f.path.startsWith(notesDir + "/") && f.path.endsWith(".md") && f.content).map((f) => ({
|
|
86
|
+
version: f.path.slice(f.path.lastIndexOf("/") + 1, -3),
|
|
87
|
+
notes: f.content
|
|
88
|
+
})).sort((a, b) => b.version.localeCompare(a.version, void 0, { numeric: true })) : [];
|
|
89
|
+
return serializePlugin(plugin, allReleaseNotes);
|
|
90
|
+
});
|
|
83
91
|
await writeFile(join2(outputDir, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8");
|
|
84
92
|
}
|
|
85
93
|
|
|
94
|
+
// src/ui/Logo.tsx
|
|
95
|
+
import { Box, Text } from "ink";
|
|
96
|
+
import { jsx } from "react/jsx-runtime";
|
|
97
|
+
var LOGO_LINES = [
|
|
98
|
+
" @@@ ",
|
|
99
|
+
" @@@@@ @@@@@@@ ",
|
|
100
|
+
" @@@@ @@@@@@@@@@ ",
|
|
101
|
+
" @@@@ @@@@@ ",
|
|
102
|
+
" @@@ @@@@ @@@@@ @@@@@@@ ",
|
|
103
|
+
" @@@@ @@@@ @@@@ @@@@@@@@@@@@@",
|
|
104
|
+
" @@@@ @@@@ @@@@@",
|
|
105
|
+
" @@@@ @@@ @@@@ @@@",
|
|
106
|
+
" @@@@ @@@@@@ ",
|
|
107
|
+
" @@@@@@ @@@@ ",
|
|
108
|
+
" @@@ @@@@@ @@@ @@@@ ",
|
|
109
|
+
" @@@@@ @@@@ @@@@ ",
|
|
110
|
+
" @@@@@@@@@@@@@ @@@ @@@ @@@ ",
|
|
111
|
+
" @@@@@@@@ @@@@ @@@ @@@@ ",
|
|
112
|
+
" @@@@@ @@@@ ",
|
|
113
|
+
" @@@@@@@@@@@ @@@@ ",
|
|
114
|
+
" @@@@@@@ @@@@@ ",
|
|
115
|
+
" @@@@ "
|
|
116
|
+
];
|
|
117
|
+
var Logo = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: LOGO_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "cyan", children: line }, i)) });
|
|
118
|
+
|
|
86
119
|
// src/ui/BuildUI.tsx
|
|
87
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
120
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
88
121
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
89
122
|
var Spinner = () => {
|
|
90
123
|
const [frame, setFrame] = useState(0);
|
|
@@ -96,7 +129,7 @@ var Spinner = () => {
|
|
|
96
129
|
clearInterval(id);
|
|
97
130
|
};
|
|
98
131
|
}, []);
|
|
99
|
-
return /* @__PURE__ */
|
|
132
|
+
return /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: SPINNER_FRAMES[frame] ?? "\u280B" });
|
|
100
133
|
};
|
|
101
134
|
var STEPS = [
|
|
102
135
|
"creating-dir",
|
|
@@ -113,57 +146,77 @@ var STEP_LABELS = {
|
|
|
113
146
|
"writing-bundle": "Writing bundle.json"
|
|
114
147
|
};
|
|
115
148
|
var BuildUI = ({ outputDir, pluginDir }) => {
|
|
116
|
-
const
|
|
149
|
+
const app = useApp();
|
|
117
150
|
const [step, setStep] = useState("creating-dir");
|
|
118
151
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
119
152
|
useEffect(() => {
|
|
120
153
|
void runBuild(pluginDir, outputDir, setStep).then(() => {
|
|
121
154
|
setStep("done");
|
|
122
|
-
exit();
|
|
155
|
+
app.exit();
|
|
123
156
|
}).catch((err) => {
|
|
124
157
|
const message = err instanceof Error ? err.message : String(err);
|
|
125
158
|
setErrorMessage(message);
|
|
126
159
|
setStep("error");
|
|
127
|
-
exit(
|
|
160
|
+
app.exit();
|
|
128
161
|
});
|
|
129
|
-
}, [outputDir, pluginDir,
|
|
162
|
+
}, [outputDir, pluginDir, app]);
|
|
130
163
|
const currentIndex = STEPS.indexOf(step);
|
|
131
164
|
const isError = step === "error";
|
|
132
165
|
const isDone = step === "done";
|
|
133
|
-
return /* @__PURE__ */ jsxs(
|
|
134
|
-
/* @__PURE__ */
|
|
135
|
-
|
|
136
|
-
/* @__PURE__ */
|
|
166
|
+
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
167
|
+
/* @__PURE__ */ jsx2(Logo, {}),
|
|
168
|
+
/* @__PURE__ */ jsxs(Box2, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [
|
|
169
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
170
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(24) })
|
|
137
171
|
] }),
|
|
138
|
-
/* @__PURE__ */ jsxs(
|
|
172
|
+
/* @__PURE__ */ jsxs(Box2, { flexDirection: "column", gap: 0, children: [
|
|
139
173
|
STEPS.map((s, i) => {
|
|
140
174
|
const isActive = step === s;
|
|
141
175
|
const isStepDone = isDone || currentIndex > i;
|
|
142
176
|
const isFailed = isError && i === currentIndex;
|
|
143
|
-
return /* @__PURE__ */
|
|
177
|
+
return /* @__PURE__ */ jsx2(Box2, { gap: 1, children: isFailed ? /* @__PURE__ */ jsxs(Text2, { color: "red", children: [
|
|
144
178
|
"\u2717 ",
|
|
145
179
|
STEP_LABELS[s]
|
|
146
|
-
] }) : isStepDone ? /* @__PURE__ */ jsxs(
|
|
180
|
+
] }) : isStepDone ? /* @__PURE__ */ jsxs(Text2, { color: "green", children: [
|
|
147
181
|
"\u2713 ",
|
|
148
182
|
STEP_LABELS[s]
|
|
149
183
|
] }) : isActive ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
150
|
-
/* @__PURE__ */
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
153
|
-
"
|
|
184
|
+
/* @__PURE__ */ jsx2(Spinner, {}),
|
|
185
|
+
/* @__PURE__ */ jsx2(Text2, { children: STEP_LABELS[s] })
|
|
186
|
+
] }) : /* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
187
|
+
" ",
|
|
154
188
|
STEP_LABELS[s]
|
|
155
189
|
] }) }, s);
|
|
156
190
|
}),
|
|
157
|
-
errorMessage !== null && /* @__PURE__ */
|
|
191
|
+
errorMessage !== null && /* @__PURE__ */ jsx2(Box2, { marginTop: 1, borderStyle: "single", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx2(Text2, { color: "red", children: errorMessage }) })
|
|
158
192
|
] })
|
|
159
193
|
] });
|
|
160
194
|
};
|
|
161
195
|
|
|
196
|
+
// src/lib/gitignore.ts
|
|
197
|
+
import * as fs from "fs";
|
|
198
|
+
import * as path from "path";
|
|
199
|
+
function ensureGitignore(projectDir) {
|
|
200
|
+
const gitignorePath = path.join(projectDir, ".gitignore");
|
|
201
|
+
const entry = ".kizenapp/";
|
|
202
|
+
let contents = "";
|
|
203
|
+
if (fs.existsSync(gitignorePath)) {
|
|
204
|
+
contents = fs.readFileSync(gitignorePath, "utf8");
|
|
205
|
+
const lines = contents.split("\n").map((l) => l.trim());
|
|
206
|
+
if (lines.includes(entry) || lines.includes(".kizenapp")) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const addition = contents.endsWith("\n") ? entry + "\n" : "\n" + entry + "\n";
|
|
211
|
+
fs.writeFileSync(gitignorePath, contents + addition);
|
|
212
|
+
}
|
|
213
|
+
|
|
162
214
|
// src/commands/build.ts
|
|
163
215
|
function buildCommand(program2) {
|
|
164
216
|
program2.command("build").description("Bundle the plugin app into .kizenapp directory").action(async () => {
|
|
165
|
-
const outputDir = `${process.cwd()}/.kizenapp`;
|
|
166
217
|
const pluginDir = process.cwd();
|
|
218
|
+
const outputDir = `${pluginDir}/.kizenapp`;
|
|
219
|
+
ensureGitignore(pluginDir);
|
|
167
220
|
const { waitUntilExit } = render(createElement(BuildUI, { outputDir, pluginDir }));
|
|
168
221
|
await waitUntilExit();
|
|
169
222
|
});
|
|
@@ -174,24 +227,285 @@ import { createElement as createElement2 } from "react";
|
|
|
174
227
|
import { render as render2 } from "ink";
|
|
175
228
|
|
|
176
229
|
// src/ui/DevUI.tsx
|
|
177
|
-
import { useCallback, useEffect as
|
|
178
|
-
import { Box as
|
|
230
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef, useState as useState3 } from "react";
|
|
231
|
+
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
179
232
|
import { spawn } from "child_process";
|
|
180
|
-
import {
|
|
181
|
-
|
|
182
|
-
readFileSync,
|
|
183
|
-
statSync,
|
|
184
|
-
unlinkSync,
|
|
185
|
-
watch,
|
|
186
|
-
writeFileSync
|
|
187
|
-
} from "fs";
|
|
188
|
-
import { access, readFile as readFile2 } from "fs/promises";
|
|
233
|
+
import { createReadStream, watch } from "fs";
|
|
234
|
+
import { access, readFile as readFile4 } from "fs/promises";
|
|
189
235
|
import { createServer } from "http";
|
|
190
236
|
import { createRequire } from "module";
|
|
191
|
-
import { dirname, extname, join as
|
|
237
|
+
import { dirname as dirname2, extname, join as join6 } from "path";
|
|
192
238
|
import { fileURLToPath } from "url";
|
|
193
239
|
import { WebSocketServer } from "ws";
|
|
194
|
-
|
|
240
|
+
|
|
241
|
+
// src/lib/config.ts
|
|
242
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
243
|
+
import { join as join4 } from "path";
|
|
244
|
+
async function loadConfig(outputDir) {
|
|
245
|
+
try {
|
|
246
|
+
const content = await readFile2(join4(outputDir, "config.json"), "utf-8");
|
|
247
|
+
return JSON.parse(content);
|
|
248
|
+
} catch {
|
|
249
|
+
return {};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function saveConfig(outputDir, config) {
|
|
253
|
+
await mkdir2(outputDir, { recursive: true });
|
|
254
|
+
await writeFile2(join4(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/ui/CredentialSetupUI.tsx
|
|
258
|
+
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
259
|
+
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
260
|
+
|
|
261
|
+
// src/lib/credentials.ts
|
|
262
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
263
|
+
import { homedir } from "os";
|
|
264
|
+
import { dirname, join as join5 } from "path";
|
|
265
|
+
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
266
|
+
var GLOBAL_CREDENTIALS_DIR = join5(homedir(), ".kizenappbuilder");
|
|
267
|
+
var GLOBAL_CREDENTIALS_PATH = join5(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
268
|
+
function isValidEnvironment(value) {
|
|
269
|
+
return ENVIRONMENTS.includes(value);
|
|
270
|
+
}
|
|
271
|
+
function parseCredentials(raw) {
|
|
272
|
+
if (typeof raw !== "object" || raw === null) {
|
|
273
|
+
throw new Error("Credentials must be a JSON object");
|
|
274
|
+
}
|
|
275
|
+
const obj = raw;
|
|
276
|
+
const env = obj.environment;
|
|
277
|
+
return {
|
|
278
|
+
apiKey: typeof obj.apiKey === "string" ? obj.apiKey : "",
|
|
279
|
+
userId: typeof obj.userId === "string" ? obj.userId : "",
|
|
280
|
+
businessId: typeof obj.businessId === "string" ? obj.businessId : "",
|
|
281
|
+
environment: isValidEnvironment(env) ? env : "go"
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async function loadCredentialsFromFile(filePath) {
|
|
285
|
+
const content = await readFile3(filePath, "utf-8");
|
|
286
|
+
return parseCredentials(JSON.parse(content));
|
|
287
|
+
}
|
|
288
|
+
async function loadGlobalCredentials() {
|
|
289
|
+
try {
|
|
290
|
+
return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);
|
|
291
|
+
} catch {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async function saveGlobalCredentials(credentials) {
|
|
296
|
+
await mkdir3(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
297
|
+
await writeFile3(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/ui/CredentialSetupUI.tsx
|
|
301
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
302
|
+
var FIELDS = ["apiKey", "userId", "businessId"];
|
|
303
|
+
var FIELD_LABELS = {
|
|
304
|
+
apiKey: "API Key",
|
|
305
|
+
userId: "User ID",
|
|
306
|
+
businessId: "Business ID"
|
|
307
|
+
};
|
|
308
|
+
var Hint = ({ text }) => /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: text });
|
|
309
|
+
var CredentialSetupUI = ({
|
|
310
|
+
initialMode,
|
|
311
|
+
onComplete,
|
|
312
|
+
onCancel
|
|
313
|
+
}) => {
|
|
314
|
+
const [phase, setPhase] = useState2(
|
|
315
|
+
initialMode === "global" ? { type: "loading" } : { type: "mode-select", cursor: 0 }
|
|
316
|
+
);
|
|
317
|
+
const [inputBuffer, setInputBuffer] = useState2("");
|
|
318
|
+
const [error, setError] = useState2(null);
|
|
319
|
+
const handleModeChosen = useCallback(
|
|
320
|
+
async (mode) => {
|
|
321
|
+
if (mode === "local") {
|
|
322
|
+
onComplete({ mode: "local", credentials: null });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
setPhase({ type: "loading" });
|
|
326
|
+
const existing = await loadGlobalCredentials();
|
|
327
|
+
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
328
|
+
setPhase({
|
|
329
|
+
type: "creds-entry",
|
|
330
|
+
field: 0,
|
|
331
|
+
values: existing ?? {},
|
|
332
|
+
envCursor: envCursor2
|
|
333
|
+
});
|
|
334
|
+
},
|
|
335
|
+
[onComplete]
|
|
336
|
+
);
|
|
337
|
+
const handleSave = useCallback(
|
|
338
|
+
async (values2, envCursor2) => {
|
|
339
|
+
const environment = ENVIRONMENTS[envCursor2] ?? "go";
|
|
340
|
+
const credentials = {
|
|
341
|
+
apiKey: values2.apiKey ?? "",
|
|
342
|
+
userId: values2.userId ?? "",
|
|
343
|
+
businessId: values2.businessId ?? "",
|
|
344
|
+
environment
|
|
345
|
+
};
|
|
346
|
+
setPhase({ type: "saving" });
|
|
347
|
+
try {
|
|
348
|
+
await saveGlobalCredentials(credentials);
|
|
349
|
+
onComplete({ mode: "global", credentials });
|
|
350
|
+
} catch (err) {
|
|
351
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
352
|
+
setPhase({ type: "creds-entry", field: 0, values: values2, envCursor: envCursor2 });
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
[onComplete]
|
|
356
|
+
);
|
|
357
|
+
useInput((input, key) => {
|
|
358
|
+
if (key.ctrl && input === "c") {
|
|
359
|
+
process.exit(0);
|
|
360
|
+
}
|
|
361
|
+
if (key.escape) {
|
|
362
|
+
onCancel?.();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (phase.type === "mode-select") {
|
|
366
|
+
if (key.upArrow) {
|
|
367
|
+
setPhase({ type: "mode-select", cursor: 0 });
|
|
368
|
+
} else if (key.downArrow) {
|
|
369
|
+
setPhase({ type: "mode-select", cursor: 1 });
|
|
370
|
+
} else if (key.return) {
|
|
371
|
+
const mode = phase.cursor === 0 ? "global" : "local";
|
|
372
|
+
void handleModeChosen(mode);
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (phase.type === "creds-entry") {
|
|
377
|
+
const { field, values: values2, envCursor: envCursor2 } = phase;
|
|
378
|
+
const isEnvField2 = field === FIELDS.length;
|
|
379
|
+
if (isEnvField2) {
|
|
380
|
+
if (key.leftArrow) {
|
|
381
|
+
setPhase({
|
|
382
|
+
...phase,
|
|
383
|
+
envCursor: (envCursor2 - 1 + ENVIRONMENTS.length) % ENVIRONMENTS.length
|
|
384
|
+
});
|
|
385
|
+
} else if (key.rightArrow) {
|
|
386
|
+
setPhase({ ...phase, envCursor: (envCursor2 + 1) % ENVIRONMENTS.length });
|
|
387
|
+
} else if (key.upArrow) {
|
|
388
|
+
setPhase({ ...phase, field: field - 1 });
|
|
389
|
+
setInputBuffer(values2[FIELDS[field - 1]] ?? "");
|
|
390
|
+
} else if (key.return) {
|
|
391
|
+
void handleSave(values2, envCursor2);
|
|
392
|
+
}
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const fieldName = FIELDS[field];
|
|
396
|
+
if (!fieldName) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (key.backspace || key.delete) {
|
|
400
|
+
setInputBuffer((prev) => prev.slice(0, -1));
|
|
401
|
+
} else if (key.upArrow && field > 0) {
|
|
402
|
+
const updatedValues = { ...values2, [fieldName]: inputBuffer };
|
|
403
|
+
const prevField = field - 1;
|
|
404
|
+
setPhase({ ...phase, field: prevField, values: updatedValues });
|
|
405
|
+
setInputBuffer(updatedValues[FIELDS[prevField]] ?? "");
|
|
406
|
+
} else if (key.return || key.tab || key.downArrow) {
|
|
407
|
+
const updatedValues = { ...values2, [fieldName]: inputBuffer };
|
|
408
|
+
const nextField = field + 1;
|
|
409
|
+
setPhase({ ...phase, field: nextField, values: updatedValues });
|
|
410
|
+
if (nextField < FIELDS.length) {
|
|
411
|
+
setInputBuffer(updatedValues[FIELDS[nextField]] ?? "");
|
|
412
|
+
} else {
|
|
413
|
+
setInputBuffer("");
|
|
414
|
+
}
|
|
415
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
416
|
+
setInputBuffer((prev) => prev + input);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
useEffect2(() => {
|
|
421
|
+
if (initialMode === "global") {
|
|
422
|
+
void handleModeChosen("global");
|
|
423
|
+
}
|
|
424
|
+
}, []);
|
|
425
|
+
useEffect2(() => {
|
|
426
|
+
if (phase.type === "creds-entry" && phase.field === 0) {
|
|
427
|
+
setInputBuffer(phase.values.apiKey ?? "");
|
|
428
|
+
}
|
|
429
|
+
}, [phase.type]);
|
|
430
|
+
if (phase.type === "loading" || phase.type === "saving") {
|
|
431
|
+
return /* @__PURE__ */ jsx3(Box3, { paddingY: 1, paddingX: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: phase.type === "loading" ? "Loading credentials\u2026" : "Saving credentials\u2026" }) });
|
|
432
|
+
}
|
|
433
|
+
if (phase.type === "done") {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
if (phase.type === "mode-select") {
|
|
437
|
+
const options = [
|
|
438
|
+
{ label: "Global", desc: `~/.kizenappbuilder/credentials.json`, mode: "global" },
|
|
439
|
+
{ label: "Local", desc: "Enter credentials in the browser dev tools", mode: "local" }
|
|
440
|
+
];
|
|
441
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
442
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
443
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
444
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
445
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
446
|
+
] }),
|
|
447
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
448
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential mode" }),
|
|
449
|
+
options.map((opt, i) => {
|
|
450
|
+
const selected = phase.cursor === i;
|
|
451
|
+
return /* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
452
|
+
/* @__PURE__ */ jsx3(Text3, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
453
|
+
/* @__PURE__ */ jsx3(Text3, { bold: selected, ...selected && { color: "cyan" }, children: opt.label }),
|
|
454
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: opt.desc })
|
|
455
|
+
] }, opt.mode);
|
|
456
|
+
})
|
|
457
|
+
] }),
|
|
458
|
+
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit" })
|
|
459
|
+
] });
|
|
460
|
+
}
|
|
461
|
+
const { field: activeField, values, envCursor } = phase;
|
|
462
|
+
const isEnvField = activeField === FIELDS.length;
|
|
463
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
464
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
465
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
466
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
467
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
468
|
+
] }),
|
|
469
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
470
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Global credentials" }),
|
|
471
|
+
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
472
|
+
"Saved to: ",
|
|
473
|
+
GLOBAL_CREDENTIALS_PATH
|
|
474
|
+
] })
|
|
475
|
+
] }),
|
|
476
|
+
error && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
477
|
+
"Error: ",
|
|
478
|
+
error
|
|
479
|
+
] }),
|
|
480
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
481
|
+
FIELDS.map((name, i) => {
|
|
482
|
+
const isActive = activeField === i;
|
|
483
|
+
const displayValue = isActive ? inputBuffer : values[name] ?? "";
|
|
484
|
+
return /* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
485
|
+
/* @__PURE__ */ jsx3(Box3, { width: 12, children: /* @__PURE__ */ jsx3(Text3, { bold: isActive, ...isActive && { color: "cyan" }, children: FIELD_LABELS[name] }) }),
|
|
486
|
+
/* @__PURE__ */ jsx3(Text3, { ...isActive && { color: "cyan" }, children: ">" }),
|
|
487
|
+
/* @__PURE__ */ jsx3(Text3, { children: displayValue }),
|
|
488
|
+
isActive && /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u2588" })
|
|
489
|
+
] }, name);
|
|
490
|
+
}),
|
|
491
|
+
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
492
|
+
/* @__PURE__ */ jsx3(Box3, { width: 12, children: /* @__PURE__ */ jsx3(Text3, { bold: isEnvField, ...isEnvField && { color: "cyan" }, children: "Environment" }) }),
|
|
493
|
+
/* @__PURE__ */ jsx3(Text3, { ...isEnvField && { color: "cyan" }, children: ">" }),
|
|
494
|
+
/* @__PURE__ */ jsx3(Box3, { gap: 1, children: ENVIRONMENTS.map((env, i) => {
|
|
495
|
+
const isSelected = i === envCursor;
|
|
496
|
+
if (isEnvField) {
|
|
497
|
+
return /* @__PURE__ */ jsx3(Text3, { bold: isSelected, ...isSelected && { color: "cyan" }, children: isSelected ? `[${env}]` : env }, env);
|
|
498
|
+
}
|
|
499
|
+
return /* @__PURE__ */ jsx3(Text3, { dimColor: !isSelected, bold: isSelected, children: env }, env);
|
|
500
|
+
}) })
|
|
501
|
+
] })
|
|
502
|
+
] }),
|
|
503
|
+
isEnvField ? /* @__PURE__ */ jsx3(Hint, { text: "\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel" }) : /* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel" })
|
|
504
|
+
] });
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// src/ui/DevUI.tsx
|
|
508
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
195
509
|
var SKIP_WATCH_PREFIXES = [".kizenapp", ".git"];
|
|
196
510
|
var LOG_LIMIT = 50;
|
|
197
511
|
var LOG_DISPLAY = 8;
|
|
@@ -212,8 +526,8 @@ var MIME_TYPES = {
|
|
|
212
526
|
};
|
|
213
527
|
var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
214
528
|
var Spinner2 = () => {
|
|
215
|
-
const [frame, setFrame] =
|
|
216
|
-
|
|
529
|
+
const [frame, setFrame] = useState3(0);
|
|
530
|
+
useEffect3(() => {
|
|
217
531
|
const id = setInterval(() => {
|
|
218
532
|
setFrame((prev) => (prev + 1) % SPINNER_FRAMES2.length);
|
|
219
533
|
}, 80);
|
|
@@ -221,15 +535,15 @@ var Spinner2 = () => {
|
|
|
221
535
|
clearInterval(id);
|
|
222
536
|
};
|
|
223
537
|
}, []);
|
|
224
|
-
return /* @__PURE__ */
|
|
538
|
+
return /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: SPINNER_FRAMES2[frame] ?? "\u280B" });
|
|
225
539
|
};
|
|
226
540
|
function getViewerPath() {
|
|
227
541
|
const filename = fileURLToPath(import.meta.url);
|
|
228
|
-
return
|
|
542
|
+
return join6(dirname2(filename), "viewer");
|
|
229
543
|
}
|
|
230
544
|
function getElectronMainPath() {
|
|
231
545
|
const filename = fileURLToPath(import.meta.url);
|
|
232
|
-
return
|
|
546
|
+
return join6(dirname2(filename), "electron", "main.js");
|
|
233
547
|
}
|
|
234
548
|
async function fileExists(filePath) {
|
|
235
549
|
try {
|
|
@@ -239,83 +553,114 @@ async function fileExists(filePath) {
|
|
|
239
553
|
return false;
|
|
240
554
|
}
|
|
241
555
|
}
|
|
242
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog) {
|
|
556
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef) {
|
|
243
557
|
return (req, res) => {
|
|
244
558
|
void (async () => {
|
|
245
559
|
const url = req.url ?? "/";
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const content = await readFile2(bundlePath, "utf-8");
|
|
251
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
252
|
-
res.end(content);
|
|
253
|
-
} catch {
|
|
560
|
+
try {
|
|
561
|
+
createServerLog(`Received request: ${url}`);
|
|
562
|
+
if (url === "/api/credentials") {
|
|
254
563
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
255
|
-
res.end("{}");
|
|
564
|
+
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
565
|
+
return;
|
|
256
566
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
567
|
+
if (url === "/api/bundle") {
|
|
568
|
+
const bundlePath = join6(process.cwd(), ".kizenapp", "bundle.json");
|
|
569
|
+
try {
|
|
570
|
+
const content = await readFile4(bundlePath, "utf-8");
|
|
571
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
572
|
+
res.end(content);
|
|
573
|
+
} catch {
|
|
574
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
575
|
+
res.end("{}");
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (url.startsWith("/api/proxy")) {
|
|
580
|
+
const proxyTarget = req.headers["x-proxy-target"];
|
|
581
|
+
if (typeof proxyTarget !== "string") {
|
|
582
|
+
res.writeHead(400);
|
|
583
|
+
res.end("Missing x-proxy-target header");
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
587
|
+
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
588
|
+
const chunks = [];
|
|
589
|
+
for await (const chunk of req) {
|
|
590
|
+
chunks.push(chunk);
|
|
591
|
+
}
|
|
592
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
593
|
+
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
594
|
+
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
595
|
+
const upstream = await fetch(upstreamUrl, {
|
|
596
|
+
...req.method !== void 0 && { method: req.method },
|
|
597
|
+
headers: forwardHeaders,
|
|
598
|
+
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
599
|
+
});
|
|
600
|
+
createProxyLog(`${req.method ?? "GET"} ${upstreamPath} \u2192 ${String(upstream.status)}`);
|
|
601
|
+
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
602
|
+
delete responseHeaders["content-encoding"];
|
|
603
|
+
delete responseHeaders["content-length"];
|
|
604
|
+
res.writeHead(upstream.status, responseHeaders);
|
|
605
|
+
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
264
606
|
return;
|
|
265
607
|
}
|
|
266
|
-
const
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
608
|
+
const rawPath = url === "/" ? "/index.html" : url;
|
|
609
|
+
const filePath = join6(viewerPath, rawPath);
|
|
610
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join6(viewerPath, "index.html");
|
|
611
|
+
const ext = extname(resolvedPath);
|
|
612
|
+
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
613
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
614
|
+
createReadStream(resolvedPath).pipe(res);
|
|
615
|
+
} catch (err) {
|
|
616
|
+
createProxyLog(
|
|
617
|
+
`Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
618
|
+
);
|
|
619
|
+
if (!res.headersSent) {
|
|
620
|
+
res.writeHead(502);
|
|
621
|
+
res.end("Bad Gateway");
|
|
271
622
|
}
|
|
272
|
-
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
273
|
-
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
274
|
-
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
275
|
-
const upstream = await fetch(upstreamUrl, {
|
|
276
|
-
...req.method !== void 0 && { method: req.method },
|
|
277
|
-
headers: forwardHeaders,
|
|
278
|
-
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
279
|
-
});
|
|
280
|
-
createProxyLog(`${req.method ?? "GET"} ${upstreamPath} \u2192 ${String(upstream.status)}`);
|
|
281
|
-
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
282
|
-
delete responseHeaders["content-encoding"];
|
|
283
|
-
delete responseHeaders["content-length"];
|
|
284
|
-
res.writeHead(upstream.status, responseHeaders);
|
|
285
|
-
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
286
|
-
return;
|
|
287
623
|
}
|
|
288
|
-
const rawPath = url === "/" ? "/index.html" : url;
|
|
289
|
-
const filePath = join3(viewerPath, rawPath);
|
|
290
|
-
const resolvedPath = await fileExists(filePath) ? filePath : join3(viewerPath, "index.html");
|
|
291
|
-
const ext = extname(resolvedPath);
|
|
292
|
-
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
293
|
-
res.writeHead(200, { "Content-Type": mimeType });
|
|
294
|
-
createReadStream(resolvedPath).pipe(res);
|
|
295
624
|
})();
|
|
296
625
|
};
|
|
297
626
|
}
|
|
298
|
-
var DevUI = ({
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
const [
|
|
306
|
-
const [
|
|
307
|
-
const [
|
|
627
|
+
var DevUI = ({
|
|
628
|
+
port,
|
|
629
|
+
pluginDir,
|
|
630
|
+
outputDir,
|
|
631
|
+
credentials: initialCredentials
|
|
632
|
+
}) => {
|
|
633
|
+
const credentialsRef = useRef(initialCredentials);
|
|
634
|
+
const [credMode, setCredMode] = useState3("main");
|
|
635
|
+
const [status, setStatus] = useState3("starting");
|
|
636
|
+
const [errorMessage, setErrorMessage] = useState3(null);
|
|
637
|
+
const [serverLogHistory, setServerLogHistory] = useState3([]);
|
|
638
|
+
const [buildLogHistory, setBuildLogHistory] = useState3([]);
|
|
639
|
+
const [proxyLogHistory, setProxyLogHistory] = useState3([]);
|
|
640
|
+
const [buildStatus, setBuildStatus] = useState3("pending");
|
|
641
|
+
const [buildError, setBuildError] = useState3(null);
|
|
642
|
+
const [lastBuilt, setLastBuilt] = useState3(null);
|
|
643
|
+
const [wsClientCount, setWsClientCount] = useState3(0);
|
|
308
644
|
const buildingRef = useRef(false);
|
|
309
645
|
const electronLaunchedRef = useRef(false);
|
|
310
646
|
const debounceTimerRef = useRef(null);
|
|
311
647
|
const wsClientsRef = useRef(/* @__PURE__ */ new Set());
|
|
312
648
|
const pendingMessagesRef = useRef([]);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
649
|
+
useInput2(
|
|
650
|
+
(input, key) => {
|
|
651
|
+
if (input === "q" || key.ctrl && input === "c") {
|
|
652
|
+
process.exit(0);
|
|
653
|
+
}
|
|
654
|
+
if (input === "c") {
|
|
655
|
+
setCredMode("editing");
|
|
656
|
+
}
|
|
657
|
+
if (input === "d") {
|
|
658
|
+
broadcast({ type: "open-devtools" });
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{ isActive: credMode === "main" }
|
|
662
|
+
);
|
|
663
|
+
useEffect3(() => {
|
|
319
664
|
if (status !== "running" || electronLaunchedRef.current) {
|
|
320
665
|
return;
|
|
321
666
|
}
|
|
@@ -323,27 +668,7 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
323
668
|
const _require = createRequire(import.meta.url);
|
|
324
669
|
const electronBin = _require("electron");
|
|
325
670
|
const electronMain = getElectronMainPath();
|
|
326
|
-
const userDataDir =
|
|
327
|
-
if (process.platform === "darwin") {
|
|
328
|
-
try {
|
|
329
|
-
const plistPath = join3(dirname(dirname(electronBin)), "Info.plist");
|
|
330
|
-
const plist = readFileSync(plistPath, "utf-8");
|
|
331
|
-
if (!plist.includes(">Kizen Dev<")) {
|
|
332
|
-
if (statSync(plistPath).nlink > 1) {
|
|
333
|
-
unlinkSync(plistPath);
|
|
334
|
-
writeFileSync(plistPath, plist);
|
|
335
|
-
}
|
|
336
|
-
writeFileSync(
|
|
337
|
-
plistPath,
|
|
338
|
-
plist.replace(/(<key>CFBundleName<\/key>\s*<string>)[^<]*(<\/string>)/, "$1Kizen Dev$2").replace(
|
|
339
|
-
/(<key>CFBundleDisplayName<\/key>\s*<string>)[^<]*(<\/string>)/,
|
|
340
|
-
"$1Kizen Dev$2"
|
|
341
|
-
)
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
} catch {
|
|
345
|
-
}
|
|
346
|
-
}
|
|
671
|
+
const userDataDir = join6(outputDir, ".electron");
|
|
347
672
|
const proc = spawn(
|
|
348
673
|
electronBin,
|
|
349
674
|
[electronMain, `--port=${String(port)}`, `--user-data-dir=${userDataDir}`],
|
|
@@ -356,12 +681,12 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
356
681
|
proc.kill();
|
|
357
682
|
});
|
|
358
683
|
}, [status, port, outputDir]);
|
|
359
|
-
const createServerLog =
|
|
684
|
+
const createServerLog = useCallback2((message) => {
|
|
360
685
|
setServerLogHistory(
|
|
361
686
|
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
362
687
|
);
|
|
363
688
|
}, []);
|
|
364
|
-
const broadcast =
|
|
689
|
+
const broadcast = useCallback2((msg) => {
|
|
365
690
|
const json = JSON.stringify(msg);
|
|
366
691
|
if (wsClientsRef.current.size === 0) {
|
|
367
692
|
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
@@ -373,7 +698,16 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
373
698
|
}
|
|
374
699
|
}
|
|
375
700
|
}, []);
|
|
376
|
-
const
|
|
701
|
+
const handleCredentialsDone = useCallback2(
|
|
702
|
+
(result) => {
|
|
703
|
+
credentialsRef.current = result.credentials;
|
|
704
|
+
setCredMode("main");
|
|
705
|
+
void saveConfig(outputDir, { credentialMode: result.mode });
|
|
706
|
+
broadcast({ type: "credentials-updated", credentials: result.credentials });
|
|
707
|
+
},
|
|
708
|
+
[outputDir, broadcast]
|
|
709
|
+
);
|
|
710
|
+
const createProxyLog = useCallback2(
|
|
377
711
|
(message) => {
|
|
378
712
|
setProxyLogHistory(
|
|
379
713
|
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
@@ -382,7 +716,7 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
382
716
|
},
|
|
383
717
|
[broadcast]
|
|
384
718
|
);
|
|
385
|
-
const createBuildLog =
|
|
719
|
+
const createBuildLog = useCallback2(
|
|
386
720
|
(message) => {
|
|
387
721
|
setBuildLogHistory(
|
|
388
722
|
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
@@ -391,7 +725,7 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
391
725
|
},
|
|
392
726
|
[broadcast]
|
|
393
727
|
);
|
|
394
|
-
const triggerBuild =
|
|
728
|
+
const triggerBuild = useCallback2(() => {
|
|
395
729
|
if (buildingRef.current) {
|
|
396
730
|
return;
|
|
397
731
|
}
|
|
@@ -417,7 +751,7 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
417
751
|
buildingRef.current = false;
|
|
418
752
|
});
|
|
419
753
|
}, [pluginDir, outputDir, createBuildLog]);
|
|
420
|
-
|
|
754
|
+
useEffect3(() => {
|
|
421
755
|
triggerBuild();
|
|
422
756
|
const watcher = watch(pluginDir, { recursive: true }, (_, filename) => {
|
|
423
757
|
if (!filename) {
|
|
@@ -440,15 +774,20 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
440
774
|
}
|
|
441
775
|
};
|
|
442
776
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
443
|
-
|
|
777
|
+
useEffect3(() => {
|
|
444
778
|
const viewerPath = getViewerPath();
|
|
445
|
-
void fileExists(
|
|
779
|
+
void fileExists(join6(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
446
780
|
if (!viewerBuilt) {
|
|
447
781
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
448
782
|
setStatus("error");
|
|
449
783
|
return;
|
|
450
784
|
}
|
|
451
|
-
const handler = createRequestHandler(
|
|
785
|
+
const handler = createRequestHandler(
|
|
786
|
+
viewerPath,
|
|
787
|
+
createServerLog,
|
|
788
|
+
createProxyLog,
|
|
789
|
+
credentialsRef
|
|
790
|
+
);
|
|
452
791
|
const server = createServer(handler);
|
|
453
792
|
const wss = new WebSocketServer({ server });
|
|
454
793
|
wss.on("connection", (ws) => {
|
|
@@ -480,95 +819,173 @@ var DevUI = ({ port, pluginDir, outputDir }) => {
|
|
|
480
819
|
};
|
|
481
820
|
});
|
|
482
821
|
}, [port, createServerLog, createProxyLog]);
|
|
822
|
+
if (credMode === "editing") {
|
|
823
|
+
return /* @__PURE__ */ jsx4(
|
|
824
|
+
CredentialSetupUI,
|
|
825
|
+
{
|
|
826
|
+
onComplete: handleCredentialsDone,
|
|
827
|
+
onCancel: () => {
|
|
828
|
+
setCredMode("main");
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
);
|
|
832
|
+
}
|
|
483
833
|
const elapsedSeconds = lastBuilt !== null ? Math.round((Date.now() - lastBuilt.getTime()) / 1e3) : null;
|
|
484
834
|
const elapsedLabel = elapsedSeconds === null ? "" : elapsedSeconds < 5 ? " (just now)" : ` (${String(elapsedSeconds)}s ago)`;
|
|
485
|
-
return /* @__PURE__ */
|
|
486
|
-
/* @__PURE__ */
|
|
487
|
-
/* @__PURE__ */
|
|
488
|
-
/* @__PURE__ */
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
835
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
836
|
+
/* @__PURE__ */ jsx4(Logo, {}),
|
|
837
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [
|
|
838
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
839
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "\u2500".repeat(24) })
|
|
840
|
+
] }),
|
|
841
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
|
|
842
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, marginBottom: 0, children: [
|
|
843
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Build" }),
|
|
844
|
+
buildStatus === "pending" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "waiting\u2026" }),
|
|
845
|
+
buildStatus === "building" && /* @__PURE__ */ jsxs3(Box4, { gap: 1, children: [
|
|
846
|
+
/* @__PURE__ */ jsx4(Spinner2, {}),
|
|
847
|
+
/* @__PURE__ */ jsx4(Text4, { children: "Building plugin package\u2026" })
|
|
493
848
|
] }),
|
|
494
|
-
buildStatus === "done" && /* @__PURE__ */
|
|
495
|
-
"\u2713 Built
|
|
496
|
-
lastBuilt !== null
|
|
497
|
-
|
|
849
|
+
buildStatus === "done" && /* @__PURE__ */ jsxs3(Box4, { gap: 1, children: [
|
|
850
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Built" }),
|
|
851
|
+
lastBuilt !== null && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
852
|
+
"at ",
|
|
853
|
+
lastBuilt.toLocaleTimeString(),
|
|
854
|
+
elapsedLabel
|
|
855
|
+
] })
|
|
498
856
|
] }),
|
|
499
|
-
buildStatus === "error" && /* @__PURE__ */
|
|
500
|
-
"\u2717
|
|
857
|
+
buildStatus === "error" && /* @__PURE__ */ jsxs3(Text4, { color: "red", children: [
|
|
858
|
+
"\u2717 ",
|
|
501
859
|
buildError ?? "unknown error"
|
|
502
860
|
] })
|
|
503
861
|
] }),
|
|
504
|
-
/* @__PURE__ */
|
|
505
|
-
|
|
862
|
+
/* @__PURE__ */ jsx4(
|
|
863
|
+
Box4,
|
|
506
864
|
{
|
|
507
865
|
flexDirection: "column",
|
|
508
866
|
height: LOG_DISPLAY,
|
|
509
|
-
borderStyle: "
|
|
867
|
+
borderStyle: "single",
|
|
510
868
|
borderColor: "gray",
|
|
511
869
|
overflow: "hidden",
|
|
512
|
-
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
870
|
+
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx4(Text4, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
513
871
|
}
|
|
514
872
|
)
|
|
515
873
|
] }),
|
|
516
|
-
/* @__PURE__ */
|
|
517
|
-
/* @__PURE__ */
|
|
518
|
-
|
|
519
|
-
status === "
|
|
520
|
-
|
|
521
|
-
/* @__PURE__ */
|
|
874
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
875
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
876
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Server" }),
|
|
877
|
+
status === "starting" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "starting\u2026" }),
|
|
878
|
+
status === "running" && /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
879
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Running" }),
|
|
880
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
522
881
|
"\u25CF ",
|
|
523
882
|
wsClientCount,
|
|
524
883
|
" viewer",
|
|
525
884
|
wsClientCount !== 1 ? "s" : ""
|
|
526
885
|
] })
|
|
527
886
|
] }),
|
|
528
|
-
status === "error" && /* @__PURE__ */
|
|
887
|
+
status === "error" && /* @__PURE__ */ jsxs3(Text4, { color: "red", children: [
|
|
529
888
|
"\u2717 ",
|
|
530
889
|
errorMessage ?? "Server error"
|
|
531
890
|
] })
|
|
532
891
|
] }),
|
|
533
|
-
/* @__PURE__ */
|
|
534
|
-
|
|
892
|
+
/* @__PURE__ */ jsx4(
|
|
893
|
+
Box4,
|
|
535
894
|
{
|
|
536
895
|
flexDirection: "column",
|
|
537
896
|
height: LOG_DISPLAY,
|
|
538
|
-
borderStyle: "
|
|
897
|
+
borderStyle: "single",
|
|
539
898
|
borderColor: "gray",
|
|
540
899
|
overflow: "hidden",
|
|
541
|
-
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
900
|
+
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx4(Text4, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
542
901
|
}
|
|
543
902
|
)
|
|
544
903
|
] }),
|
|
545
|
-
/* @__PURE__ */
|
|
546
|
-
/* @__PURE__ */
|
|
547
|
-
|
|
548
|
-
|
|
904
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
905
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
906
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Proxy" }),
|
|
907
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Active" })
|
|
908
|
+
] }),
|
|
909
|
+
/* @__PURE__ */ jsx4(
|
|
910
|
+
Box4,
|
|
549
911
|
{
|
|
550
912
|
flexDirection: "column",
|
|
551
913
|
height: LOG_DISPLAY,
|
|
552
|
-
borderStyle: "
|
|
914
|
+
borderStyle: "single",
|
|
553
915
|
borderColor: "gray",
|
|
554
916
|
overflow: "hidden",
|
|
555
|
-
children: proxyLogHistory.length === 0 ? /* @__PURE__ */
|
|
917
|
+
children: proxyLogHistory.length === 0 ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " No requests yet." }) : proxyLogHistory.slice(-LOG_DISPLAY).map((log, i) => /* @__PURE__ */ jsx4(Text4, { dimColor: true, wrap: "truncate", children: log }, i))
|
|
556
918
|
}
|
|
557
919
|
)
|
|
558
920
|
] }),
|
|
559
|
-
/* @__PURE__ */
|
|
921
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, gap: 1, children: [
|
|
922
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "[" }),
|
|
923
|
+
/* @__PURE__ */ jsx4(Text4, { children: "q" }),
|
|
924
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] quit [" }),
|
|
925
|
+
/* @__PURE__ */ jsx4(Text4, { children: "c" }),
|
|
926
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] credentials [" }),
|
|
927
|
+
/* @__PURE__ */ jsx4(Text4, { children: "d" }),
|
|
928
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] devtools" })
|
|
929
|
+
] })
|
|
560
930
|
] });
|
|
561
931
|
};
|
|
562
932
|
|
|
563
933
|
// src/commands/dev.ts
|
|
934
|
+
async function runSetupUI(initialMode) {
|
|
935
|
+
return new Promise((resolve) => {
|
|
936
|
+
let unmountFn = null;
|
|
937
|
+
const handleComplete = (result) => {
|
|
938
|
+
unmountFn?.();
|
|
939
|
+
resolve(result);
|
|
940
|
+
};
|
|
941
|
+
const { unmount } = render2(
|
|
942
|
+
createElement2(CredentialSetupUI, {
|
|
943
|
+
...initialMode !== void 0 && { initialMode },
|
|
944
|
+
onComplete: handleComplete
|
|
945
|
+
}),
|
|
946
|
+
{ exitOnCtrlC: false }
|
|
947
|
+
);
|
|
948
|
+
unmountFn = unmount;
|
|
949
|
+
});
|
|
950
|
+
}
|
|
564
951
|
function devCommand(program2) {
|
|
565
|
-
program2.command("dev").description("Start the plugin viewer dev server").option("-p, --port <port>", "port to listen on", "3121").action(async (options) => {
|
|
952
|
+
program2.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").action(async (options) => {
|
|
566
953
|
const port = parseInt(options.port, 10);
|
|
567
954
|
const pluginDir = process.cwd();
|
|
568
955
|
const outputDir = `${pluginDir}/.kizenapp`;
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
956
|
+
ensureGitignore(pluginDir);
|
|
957
|
+
let credentials = null;
|
|
958
|
+
let credentialMode;
|
|
959
|
+
if (options.credentials) {
|
|
960
|
+
credentials = await loadCredentialsFromFile(options.credentials);
|
|
961
|
+
} else {
|
|
962
|
+
const config = await loadConfig(outputDir);
|
|
963
|
+
if (config.credentialMode === "local") {
|
|
964
|
+
credentialMode = "local";
|
|
965
|
+
} else if (config.credentialMode === "global") {
|
|
966
|
+
credentialMode = "global";
|
|
967
|
+
credentials = await loadGlobalCredentials();
|
|
968
|
+
if (!credentials) {
|
|
969
|
+
const result = await runSetupUI("global");
|
|
970
|
+
credentials = result.credentials;
|
|
971
|
+
}
|
|
972
|
+
} else {
|
|
973
|
+
const result = await runSetupUI();
|
|
974
|
+
credentials = result.credentials;
|
|
975
|
+
credentialMode = result.mode;
|
|
976
|
+
await saveConfig(outputDir, { credentialMode: result.mode });
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const { waitUntilExit } = render2(
|
|
980
|
+
createElement2(DevUI, {
|
|
981
|
+
port,
|
|
982
|
+
pluginDir,
|
|
983
|
+
outputDir,
|
|
984
|
+
credentials,
|
|
985
|
+
...credentialMode !== void 0 && { credentialMode }
|
|
986
|
+
}),
|
|
987
|
+
{ exitOnCtrlC: false }
|
|
988
|
+
);
|
|
572
989
|
await waitUntilExit();
|
|
573
990
|
});
|
|
574
991
|
}
|