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