@kizenapps/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +482 -41
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/AppDetailPage-BPvWscWJ.js +1 -0
- package/dist/viewer/assets/AppDetailPage-DIuYKCTQ.js +1 -0
- package/dist/viewer/assets/AppDetailPage-r3jzO9Kf.js +1 -0
- package/dist/viewer/assets/BootstrapContext-CExPp3R2.js +1 -0
- package/dist/viewer/assets/BootstrapContext-CTQMWXf-.js +1 -0
- package/dist/viewer/assets/BootstrapContext-DbnbWmQT.js +1 -0
- package/dist/viewer/assets/Card-Bmn1HMWl.js +1 -0
- package/dist/viewer/assets/Card-DMz6T3VL.js +1 -0
- package/dist/viewer/assets/Card-DsqKctyM.js +1 -0
- package/dist/viewer/assets/CodeStepsPage-BHqLfCdV.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-BymhEfzO.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-CD_MhDwY.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-CgI-LqEx.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-Dak3saZE.js +5 -0
- package/dist/viewer/assets/CodeStepsPage-DdKuH37F.css +1 -0
- package/dist/viewer/assets/CodeStepsPage-Zj6DscGd.js +4 -0
- package/dist/viewer/assets/ConfigurationPage-Cjy9TH3N.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-DmX-6MM-.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-J56kCD_e.js +1 -0
- package/dist/viewer/assets/CredentialsContext-Xbse1T0q.js +1 -0
- package/dist/viewer/assets/CredentialsContext-zl2e9kpM.js +1 -0
- package/dist/viewer/assets/DevSidebar-B30mgxSn.js +1 -0
- package/dist/viewer/assets/{DevSidebar-BiROAoKF.js → DevSidebar-BhTD2bBO.js} +1 -1
- package/dist/viewer/assets/DevSidebar-CsEdCTej.js +1 -0
- package/dist/viewer/assets/IconReferencePage-B6j9wlte.js +1 -0
- package/dist/viewer/assets/IconReferencePage-CJa9yg9Z.js +1 -0
- package/dist/viewer/assets/IconReferencePage-Q5I-lMFQ.js +1 -0
- package/dist/viewer/assets/SandboxPage-C0h7GUkw.js +1 -0
- package/dist/viewer/assets/SandboxPage-GDcydJnJ.js +1 -0
- package/dist/viewer/assets/SandboxPage-JREBQ4id.js +1 -0
- package/dist/viewer/assets/SidebarContext-BPkYyxET.js +1 -0
- package/dist/viewer/assets/SidebarContext-DVDXFWJI.js +1 -0
- package/dist/viewer/assets/SidebarContext-HucmR353.js +1 -0
- package/dist/viewer/assets/VersionsPage-B76eugMm.js +1 -0
- package/dist/viewer/assets/VersionsPage-BIpB0iBz.js +1 -0
- package/dist/viewer/assets/VersionsPage-D0qenxK5.js +1 -0
- package/dist/viewer/assets/api-BOqcXygX.js +1 -0
- package/dist/viewer/assets/api-DqAiw0w9.js +1 -0
- package/dist/viewer/assets/bundleQuery-206rQR6g.js +1 -0
- package/dist/viewer/assets/{Card-CPMAuqAb.js → bundleQuery-L4H4wq5q.js} +1 -1
- package/dist/viewer/assets/{fa-core-mHW_3JUd.js → fa-core-DaD7O-yO.js} +1 -1
- package/dist/viewer/assets/fa-core-wsCxaNB7.js +558 -0
- package/dist/viewer/assets/fa-pro-icons-Dzkwxnip.js +1 -0
- package/dist/viewer/assets/index-BPiwld5D.js +5 -0
- package/dist/viewer/assets/index-BiyeMU_r.css +2 -0
- package/dist/viewer/assets/index-BlJv_543.js +5 -0
- package/dist/viewer/assets/index-CAYNux5J.js +5 -0
- package/dist/viewer/assets/index-D4AnoAXz.js +5 -0
- package/dist/viewer/assets/index-D8Koqlb-.js +5 -0
- package/dist/viewer/assets/index-DKrC0qkC.js +5 -0
- package/dist/viewer/assets/{react-D_K8ni3_.js → react-CkuOm_dq.js} +1 -1
- package/dist/viewer/assets/react-CyWK9rg5.js +9 -0
- package/dist/viewer/assets/useLocalStorage-BWwvt0nG.js +1 -0
- package/dist/viewer/assets/useLocalStorage-BlZWItfY.js +1 -0
- package/dist/viewer/assets/useLocalStorage-CQO0VGQ6.js +1 -0
- package/dist/viewer/assets/useNavigate-9J1ZzN1J.js +1 -0
- package/dist/viewer/assets/useNavigate-V8wjv5GQ.js +1 -0
- package/dist/viewer/assets/useObjectLookups-BAqe9wvu.js +14 -0
- package/dist/viewer/assets/useObjectLookups-C65zm-bM.js +14 -0
- package/dist/viewer/assets/{useObjectLookups-Cx6A7PGj.js → useObjectLookups-CslM2vSA.js} +3 -3
- package/dist/viewer/assets/{validIcons-TcFXfn-E.js → validIcons-Dqgxgpv-.js} +1 -1
- package/dist/viewer/assets/validIcons-UmfwFGTT.js +1 -0
- package/dist/viewer/index.html +10 -8
- package/dist/viewer/mark.svg +17 -0
- package/package.json +8 -7
- package/dist/viewer/assets/AppDetailPage-BJrg5Wsz.js +0 -1
- package/dist/viewer/assets/BootstrapContext-D3lhzWap.js +0 -1
- package/dist/viewer/assets/ConfigurationPage-D8I8rWjF.js +0 -1
- package/dist/viewer/assets/CredentialsContext-BLZX6RwF.js +0 -1
- package/dist/viewer/assets/SandboxPage-ByixszHi.js +0 -1
- package/dist/viewer/assets/SidebarContext-Byo6PYOF.js +0 -1
- package/dist/viewer/assets/VersionsPage-BKul6bXI.js +0 -1
- package/dist/viewer/assets/index-BoSQQwMQ.css +0 -2
- package/dist/viewer/assets/index-Bomh3C3X.js +0 -5
- /package/dist/viewer/assets/{fa-pro-icons-CIQGXozY.js → fa-pro-icons-CiTC899m.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -112,24 +112,28 @@ import { Box as Box2, Text as Text2 } from "ink";
|
|
|
112
112
|
import { Box, Text } from "ink";
|
|
113
113
|
import { jsx } from "react/jsx-runtime";
|
|
114
114
|
var LOGO_LINES = [
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
115
|
+
" :::::::: ",
|
|
116
|
+
" :::::: ::::::::::: ",
|
|
117
|
+
" :::::: :::::::::: ",
|
|
118
|
+
" :::::: :::::: ::::::: ",
|
|
119
|
+
" ::::: :::::: ::::::::::::::::: ",
|
|
120
|
+
" ::::: ::::: ::::::::::::::::::: ",
|
|
121
|
+
" ::::: ::::: :::::: ::::: ",
|
|
122
|
+
":::: ::::: ::: ::::: :: ",
|
|
123
|
+
"::::: :::::: :::::::::: ",
|
|
124
|
+
"::::: :::::: ::::::::::: ",
|
|
125
|
+
" ::::: ::: ::::::: ",
|
|
126
|
+
" ::::::: ::: ::::: ",
|
|
127
|
+
" ::::::::::: :::::: :::::",
|
|
128
|
+
" :::::::::: :::::: :::::",
|
|
129
|
+
" :: ::::: ::: ::::: ::::",
|
|
130
|
+
" ::::: :::::: ::::: ::::: ::: ",
|
|
131
|
+
" ::::::::::::::::::: ::::: ::::: ",
|
|
132
|
+
" ::::::::::::::::: ::::: ::::: ",
|
|
133
|
+
" ::::::::: :::::: :::::: ",
|
|
134
|
+
" :::::::::: :::::: ",
|
|
135
|
+
" ::::::::::: :::::: ",
|
|
136
|
+
" :::::::: "
|
|
133
137
|
];
|
|
134
138
|
var Logo = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: LOGO_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "cyan", children: line }, i)) });
|
|
135
139
|
|
|
@@ -137,10 +141,7 @@ var Logo = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: L
|
|
|
137
141
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
138
142
|
var AppHeader = ({ marginBottom = 0 }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
139
143
|
/* @__PURE__ */ jsx2(Logo, {}),
|
|
140
|
-
/* @__PURE__ */
|
|
141
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
142
|
-
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(24) })
|
|
143
|
-
] })
|
|
144
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, marginBottom, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Development Toolkit" }) })
|
|
144
145
|
] });
|
|
145
146
|
|
|
146
147
|
// src/ui/Spinner.tsx
|
|
@@ -265,13 +266,13 @@ import { useCallback as useCallback3, useEffect as useEffect4, useRef, useState
|
|
|
265
266
|
import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
|
|
266
267
|
import { watch } from "fs";
|
|
267
268
|
import { createServer } from "http";
|
|
268
|
-
import { join as
|
|
269
|
+
import { join as join9 } from "path";
|
|
269
270
|
import { WebSocketServer } from "ws";
|
|
270
271
|
|
|
271
272
|
// src/server/requestHandler.ts
|
|
272
273
|
import { createReadStream } from "fs";
|
|
273
|
-
import { access, readFile as readFile4 } from "fs/promises";
|
|
274
|
-
import { dirname as dirname2, extname, join as
|
|
274
|
+
import { access as access2, readFile as readFile4 } from "fs/promises";
|
|
275
|
+
import { dirname as dirname2, extname, join as join7 } from "path";
|
|
275
276
|
import { fileURLToPath } from "url";
|
|
276
277
|
|
|
277
278
|
// src/lib/proxyCache.ts
|
|
@@ -432,6 +433,376 @@ async function saveConfig(outputDir, config) {
|
|
|
432
433
|
await writeFile3(join5(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
433
434
|
}
|
|
434
435
|
|
|
436
|
+
// src/server/pythonExecutor.ts
|
|
437
|
+
import { spawn, execFileSync } from "child_process";
|
|
438
|
+
import { writeFile as writeFile4, rm, mkdtemp, access } from "fs/promises";
|
|
439
|
+
import { join as join6 } from "path";
|
|
440
|
+
import { tmpdir } from "os";
|
|
441
|
+
var WRAPPER_SCRIPT = `
|
|
442
|
+
import sys, json, os, traceback
|
|
443
|
+
|
|
444
|
+
# --- Inputs proxy (attribute access) ---
|
|
445
|
+
class _InputsProxy:
|
|
446
|
+
def __init__(self, data):
|
|
447
|
+
object.__setattr__(self, '_data', data)
|
|
448
|
+
|
|
449
|
+
def __getattr__(self, name):
|
|
450
|
+
if name.startswith('_'):
|
|
451
|
+
raise AttributeError(name)
|
|
452
|
+
return self._data.get(name)
|
|
453
|
+
|
|
454
|
+
def __repr__(self):
|
|
455
|
+
return repr(self._data)
|
|
456
|
+
|
|
457
|
+
def __str__(self):
|
|
458
|
+
return str(self._data)
|
|
459
|
+
|
|
460
|
+
def __bool__(self):
|
|
461
|
+
return bool(self._data)
|
|
462
|
+
|
|
463
|
+
inputs = _InputsProxy(json.loads(os.environ.get('__KIZEN_INPUTS__', '{}')))
|
|
464
|
+
|
|
465
|
+
# --- Secrets ---
|
|
466
|
+
secrets = json.loads(os.environ.get('__KIZEN_SECRETS__', '{}'))
|
|
467
|
+
|
|
468
|
+
# --- Outputs proxy ---
|
|
469
|
+
class _OutputsProxy:
|
|
470
|
+
def __init__(self):
|
|
471
|
+
object.__setattr__(self, '_values', {})
|
|
472
|
+
object.__setattr__(self, '_logs', [])
|
|
473
|
+
|
|
474
|
+
def __setattr__(self, name, value):
|
|
475
|
+
if name.startswith('_'):
|
|
476
|
+
object.__setattr__(self, name, value)
|
|
477
|
+
else:
|
|
478
|
+
self._values[name] = value
|
|
479
|
+
|
|
480
|
+
def __getattr__(self, name):
|
|
481
|
+
if name.startswith('_'):
|
|
482
|
+
raise AttributeError(name)
|
|
483
|
+
return self._values.get(name)
|
|
484
|
+
|
|
485
|
+
def log(self, message):
|
|
486
|
+
self._logs.append(str(message))
|
|
487
|
+
|
|
488
|
+
outputs = _OutputsProxy()
|
|
489
|
+
|
|
490
|
+
# --- Execute user script ---
|
|
491
|
+
try:
|
|
492
|
+
exec(open(os.environ['__KIZEN_SCRIPT_PATH__'], encoding='utf-8').read())
|
|
493
|
+
result = {
|
|
494
|
+
'success': True,
|
|
495
|
+
'outputValues': outputs._values,
|
|
496
|
+
'logs': outputs._logs,
|
|
497
|
+
'error': None,
|
|
498
|
+
}
|
|
499
|
+
except Exception:
|
|
500
|
+
# Build a clean traceback that hides the wrapper internals.
|
|
501
|
+
# Keep only frames from the user script (shown as File "<string>")
|
|
502
|
+
# and re-label them with "script.py" for clarity.
|
|
503
|
+
exc_type, exc_value, exc_tb = sys.exc_info()
|
|
504
|
+
entries = traceback.extract_tb(exc_tb)
|
|
505
|
+
user_entries = [e for e in entries if e.filename != __file__]
|
|
506
|
+
for e in user_entries:
|
|
507
|
+
if e.filename == '<string>':
|
|
508
|
+
e.filename = 'script.py'
|
|
509
|
+
lines = ['Traceback (most recent call last):\\n']
|
|
510
|
+
lines += traceback.format_list(user_entries)
|
|
511
|
+
lines += traceback.format_exception_only(exc_type, exc_value)
|
|
512
|
+
result = {
|
|
513
|
+
'success': False,
|
|
514
|
+
'outputValues': outputs._values,
|
|
515
|
+
'logs': outputs._logs,
|
|
516
|
+
'error': ''.join(lines),
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# Write results between markers so we can extract them reliably
|
|
520
|
+
# even if the user script wrote to stdout
|
|
521
|
+
sys.stdout.write('\\n__KIZEN_RESULT_START__\\n')
|
|
522
|
+
sys.stdout.write(json.dumps(result, ensure_ascii=False))
|
|
523
|
+
sys.stdout.write('\\n__KIZEN_RESULT_END__\\n')
|
|
524
|
+
sys.stdout.flush()
|
|
525
|
+
`.trim();
|
|
526
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
527
|
+
var VENV_DIR = join6(process.cwd(), ".kizenapp", "venv");
|
|
528
|
+
var VENV_PACKAGES = ["requests"];
|
|
529
|
+
var venvReady = null;
|
|
530
|
+
function resolvePythonBinary(runtime) {
|
|
531
|
+
const match = /^python-(\d+\.\d+)$/.exec(runtime);
|
|
532
|
+
if (match?.[1]) {
|
|
533
|
+
return `python${match[1]}`;
|
|
534
|
+
}
|
|
535
|
+
return "python3";
|
|
536
|
+
}
|
|
537
|
+
function ensureVenv(runtime) {
|
|
538
|
+
if (!venvReady) {
|
|
539
|
+
venvReady = (async () => {
|
|
540
|
+
const venvPython = join6(VENV_DIR, "bin", "python");
|
|
541
|
+
try {
|
|
542
|
+
await access(venvPython);
|
|
543
|
+
} catch {
|
|
544
|
+
const systemPython = resolvePythonBinary(runtime);
|
|
545
|
+
execFileSync(systemPython, ["-m", "venv", VENV_DIR], { stdio: "ignore" });
|
|
546
|
+
}
|
|
547
|
+
execFileSync(venvPython, ["-m", "pip", "install", "-q", ...VENV_PACKAGES], {
|
|
548
|
+
stdio: "ignore"
|
|
549
|
+
});
|
|
550
|
+
return venvPython;
|
|
551
|
+
})();
|
|
552
|
+
}
|
|
553
|
+
return venvReady;
|
|
554
|
+
}
|
|
555
|
+
function parseResult(stdout) {
|
|
556
|
+
const startMarker = "__KIZEN_RESULT_START__";
|
|
557
|
+
const endMarker = "__KIZEN_RESULT_END__";
|
|
558
|
+
const startIdx = stdout.indexOf(startMarker);
|
|
559
|
+
const endIdx = stdout.indexOf(endMarker);
|
|
560
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
561
|
+
return { userStdout: stdout, result: null };
|
|
562
|
+
}
|
|
563
|
+
const userStdout = stdout.slice(0, startIdx).trimEnd();
|
|
564
|
+
const jsonStr = stdout.slice(startIdx + startMarker.length, endIdx).trim();
|
|
565
|
+
try {
|
|
566
|
+
const result = JSON.parse(jsonStr);
|
|
567
|
+
return { userStdout, result };
|
|
568
|
+
} catch {
|
|
569
|
+
return { userStdout: stdout, result: null };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
async function executePythonStep(params) {
|
|
573
|
+
const timeout = params.timeout ?? DEFAULT_TIMEOUT;
|
|
574
|
+
const pythonBin = await ensureVenv(params.scriptRuntime);
|
|
575
|
+
const start = Date.now();
|
|
576
|
+
let tmpDir;
|
|
577
|
+
try {
|
|
578
|
+
tmpDir = await mkdtemp(join6(tmpdir(), "kizen-step-"));
|
|
579
|
+
const wrapperPath = join6(tmpDir, "wrapper.py");
|
|
580
|
+
const scriptPath = join6(tmpDir, "script.py");
|
|
581
|
+
await Promise.all([
|
|
582
|
+
writeFile4(wrapperPath, WRAPPER_SCRIPT, "utf-8"),
|
|
583
|
+
writeFile4(scriptPath, params.script, "utf-8")
|
|
584
|
+
]);
|
|
585
|
+
const env = {
|
|
586
|
+
...process.env,
|
|
587
|
+
__KIZEN_INPUTS__: JSON.stringify(params.inputs),
|
|
588
|
+
__KIZEN_SECRETS__: JSON.stringify(params.secrets),
|
|
589
|
+
__KIZEN_SCRIPT_PATH__: scriptPath
|
|
590
|
+
};
|
|
591
|
+
const { exitCode, stdout, stderr } = await new Promise((resolve) => {
|
|
592
|
+
const stdoutChunks = [];
|
|
593
|
+
const stderrChunks = [];
|
|
594
|
+
let settled = false;
|
|
595
|
+
const proc = spawn(pythonBin, [wrapperPath], {
|
|
596
|
+
env,
|
|
597
|
+
cwd: tmpDir,
|
|
598
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
599
|
+
});
|
|
600
|
+
const timer = setTimeout(() => {
|
|
601
|
+
proc.kill("SIGKILL");
|
|
602
|
+
}, timeout);
|
|
603
|
+
proc.stdout.on("data", (chunk) => {
|
|
604
|
+
stdoutChunks.push(chunk);
|
|
605
|
+
});
|
|
606
|
+
proc.stderr.on("data", (chunk) => {
|
|
607
|
+
stderrChunks.push(chunk);
|
|
608
|
+
});
|
|
609
|
+
const finish = (code) => {
|
|
610
|
+
if (settled) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
settled = true;
|
|
614
|
+
clearTimeout(timer);
|
|
615
|
+
resolve({
|
|
616
|
+
exitCode: code ?? 1,
|
|
617
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
618
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8")
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
proc.on("close", finish);
|
|
622
|
+
proc.on("error", (err) => {
|
|
623
|
+
if (settled) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
settled = true;
|
|
627
|
+
clearTimeout(timer);
|
|
628
|
+
resolve({
|
|
629
|
+
exitCode: 1,
|
|
630
|
+
stdout: "",
|
|
631
|
+
stderr: err.message
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
const durationMs = Date.now() - start;
|
|
636
|
+
const { userStdout, result } = parseResult(stdout);
|
|
637
|
+
if (result) {
|
|
638
|
+
const base2 = {
|
|
639
|
+
success: result.success,
|
|
640
|
+
outputValues: result.outputValues,
|
|
641
|
+
logs: result.logs,
|
|
642
|
+
stdout: userStdout,
|
|
643
|
+
stderr,
|
|
644
|
+
exitCode,
|
|
645
|
+
durationMs
|
|
646
|
+
};
|
|
647
|
+
if (result.error !== null) {
|
|
648
|
+
base2.error = result.error;
|
|
649
|
+
}
|
|
650
|
+
return base2;
|
|
651
|
+
}
|
|
652
|
+
const base = {
|
|
653
|
+
success: false,
|
|
654
|
+
outputValues: {},
|
|
655
|
+
logs: [],
|
|
656
|
+
stdout: userStdout,
|
|
657
|
+
stderr,
|
|
658
|
+
exitCode,
|
|
659
|
+
durationMs
|
|
660
|
+
};
|
|
661
|
+
if (exitCode !== 0) {
|
|
662
|
+
base.error = `Process exited with code ${String(exitCode)}`;
|
|
663
|
+
}
|
|
664
|
+
return base;
|
|
665
|
+
} finally {
|
|
666
|
+
if (tmpDir) {
|
|
667
|
+
void rm(tmpDir, { recursive: true, force: true });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/server/remoteCodeRunner.ts
|
|
673
|
+
var BASE_URLS = {
|
|
674
|
+
go: "https://app.go.kizen.com/api",
|
|
675
|
+
fmo: "https://app.fmo.kizen.com/api",
|
|
676
|
+
staging: "https://staging.kizen.dev/api",
|
|
677
|
+
integration: "https://integration.kizen.dev/api",
|
|
678
|
+
test1: "https://test1.kizen.dev/api"
|
|
679
|
+
};
|
|
680
|
+
var SUPPORTED_RUNTIMES = ["python-3-13", "python-3-12"];
|
|
681
|
+
var DEFAULT_RUNTIME = "python-3-12";
|
|
682
|
+
var DATA_TYPE_TO_KIZEN = {
|
|
683
|
+
text: "s",
|
|
684
|
+
string: "s",
|
|
685
|
+
number: "n",
|
|
686
|
+
integer: "n",
|
|
687
|
+
boolean: "b",
|
|
688
|
+
date: "d",
|
|
689
|
+
datetime: "dt",
|
|
690
|
+
phone: "p",
|
|
691
|
+
phonenumber: "p",
|
|
692
|
+
uuid: "u",
|
|
693
|
+
file: "f",
|
|
694
|
+
list: "l"
|
|
695
|
+
};
|
|
696
|
+
function toKizenType(dataType) {
|
|
697
|
+
return DATA_TYPE_TO_KIZEN[dataType.toLowerCase()] ?? "s";
|
|
698
|
+
}
|
|
699
|
+
function resolveRuntime(runtime) {
|
|
700
|
+
if (SUPPORTED_RUNTIMES.includes(runtime)) {
|
|
701
|
+
return runtime;
|
|
702
|
+
}
|
|
703
|
+
return DEFAULT_RUNTIME;
|
|
704
|
+
}
|
|
705
|
+
function encodeInputs(inputs, inputTypes) {
|
|
706
|
+
const keys = Object.keys(inputs);
|
|
707
|
+
if (keys.length === 0) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
const encoded = {};
|
|
711
|
+
for (const key of keys) {
|
|
712
|
+
encoded[key] = {
|
|
713
|
+
t: toKizenType(inputTypes[key] ?? "string"),
|
|
714
|
+
v: inputs[key]
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
return encoded;
|
|
718
|
+
}
|
|
719
|
+
function encodeOutputTypes(outputTypes) {
|
|
720
|
+
const keys = Object.keys(outputTypes);
|
|
721
|
+
if (keys.length === 0) {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
const encoded = {};
|
|
725
|
+
for (const key of keys) {
|
|
726
|
+
encoded[key] = toKizenType(outputTypes[key] ?? "string");
|
|
727
|
+
}
|
|
728
|
+
return encoded;
|
|
729
|
+
}
|
|
730
|
+
function decodeOutputValues(values) {
|
|
731
|
+
if (!values) {
|
|
732
|
+
return {};
|
|
733
|
+
}
|
|
734
|
+
const decoded = {};
|
|
735
|
+
for (const [key, encoded] of Object.entries(values)) {
|
|
736
|
+
decoded[key] = encoded.v;
|
|
737
|
+
}
|
|
738
|
+
return decoded;
|
|
739
|
+
}
|
|
740
|
+
async function executeRemoteStep(params, credentials) {
|
|
741
|
+
const baseUrl = BASE_URLS[credentials.environment];
|
|
742
|
+
const url = `${baseUrl}/coderunner/run`;
|
|
743
|
+
const start = Date.now();
|
|
744
|
+
const body = {
|
|
745
|
+
user_script: params.script,
|
|
746
|
+
runtime: resolveRuntime(params.scriptRuntime),
|
|
747
|
+
secrets: params.secretNames.length > 0 ? params.secretNames : void 0,
|
|
748
|
+
inputs: encodeInputs(params.inputs, params.inputTypes),
|
|
749
|
+
output_types: encodeOutputTypes(params.outputTypes)
|
|
750
|
+
};
|
|
751
|
+
try {
|
|
752
|
+
const response = await fetch(url, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: {
|
|
755
|
+
"Content-Type": "application/json",
|
|
756
|
+
"X-API-KEY": credentials.apiKey,
|
|
757
|
+
"X-USER-ID": credentials.userId,
|
|
758
|
+
"X-BUSINESS-ID": credentials.businessId
|
|
759
|
+
},
|
|
760
|
+
body: JSON.stringify(body)
|
|
761
|
+
});
|
|
762
|
+
const durationMs = Date.now() - start;
|
|
763
|
+
if (!response.ok) {
|
|
764
|
+
const text = await response.text();
|
|
765
|
+
return {
|
|
766
|
+
success: false,
|
|
767
|
+
outputValues: {},
|
|
768
|
+
logs: [],
|
|
769
|
+
stdout: "",
|
|
770
|
+
stderr: "",
|
|
771
|
+
error: `Remote runner returned ${String(response.status)}: ${text}`,
|
|
772
|
+
exitCode: 1,
|
|
773
|
+
durationMs
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
const data = await response.json();
|
|
777
|
+
const hasError = data.error !== null;
|
|
778
|
+
const result = {
|
|
779
|
+
success: !hasError,
|
|
780
|
+
outputValues: decodeOutputValues(data.values),
|
|
781
|
+
logs: data.logs ?? [],
|
|
782
|
+
stdout: "",
|
|
783
|
+
stderr: "",
|
|
784
|
+
exitCode: hasError ? 1 : 0,
|
|
785
|
+
durationMs: data.duration_ms ?? durationMs
|
|
786
|
+
};
|
|
787
|
+
if (hasError && data.error) {
|
|
788
|
+
result.error = data.error.detail ? `${data.error.error}
|
|
789
|
+
${data.error.detail}` : data.error.error;
|
|
790
|
+
}
|
|
791
|
+
return result;
|
|
792
|
+
} catch (err) {
|
|
793
|
+
return {
|
|
794
|
+
success: false,
|
|
795
|
+
outputValues: {},
|
|
796
|
+
logs: [],
|
|
797
|
+
stdout: "",
|
|
798
|
+
stderr: "",
|
|
799
|
+
error: `Remote execution failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
800
|
+
exitCode: 1,
|
|
801
|
+
durationMs: Date.now() - start
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
435
806
|
// src/server/requestHandler.ts
|
|
436
807
|
function proxyLogEntryToString(entry) {
|
|
437
808
|
if (entry.kind === "info") {
|
|
@@ -442,17 +813,17 @@ function proxyLogEntryToString(entry) {
|
|
|
442
813
|
}
|
|
443
814
|
function getViewerPath() {
|
|
444
815
|
const filename = fileURLToPath(import.meta.url);
|
|
445
|
-
return
|
|
816
|
+
return join7(dirname2(filename), "viewer");
|
|
446
817
|
}
|
|
447
818
|
async function fileExists(filePath) {
|
|
448
819
|
try {
|
|
449
|
-
await
|
|
820
|
+
await access2(filePath);
|
|
450
821
|
return true;
|
|
451
822
|
} catch {
|
|
452
823
|
return false;
|
|
453
824
|
}
|
|
454
825
|
}
|
|
455
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange) {
|
|
826
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange, lastPathRef) {
|
|
456
827
|
const proxyCache = createProxyCache({ onChange: onProxyCacheChange });
|
|
457
828
|
return (req, res) => {
|
|
458
829
|
void (async () => {
|
|
@@ -493,7 +864,7 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
493
864
|
return;
|
|
494
865
|
}
|
|
495
866
|
if (url === "/api/bundle") {
|
|
496
|
-
const bundlePath =
|
|
867
|
+
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
497
868
|
try {
|
|
498
869
|
const content = await readFile4(bundlePath, "utf-8");
|
|
499
870
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
@@ -504,6 +875,66 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
504
875
|
}
|
|
505
876
|
return;
|
|
506
877
|
}
|
|
878
|
+
if (url === "/api/last-path" && req.method === "POST") {
|
|
879
|
+
const chunks = [];
|
|
880
|
+
for await (const chunk of req) {
|
|
881
|
+
chunks.push(chunk);
|
|
882
|
+
}
|
|
883
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
884
|
+
if (typeof body.path === "string") {
|
|
885
|
+
lastPathRef.current = body.path;
|
|
886
|
+
const currentConfig = await loadConfig(outputDir);
|
|
887
|
+
await saveConfig(outputDir, { ...currentConfig, lastPath: body.path });
|
|
888
|
+
}
|
|
889
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
890
|
+
res.end('{"ok":true}');
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (url === "/api/execute-step" && req.method === "POST") {
|
|
894
|
+
const chunks = [];
|
|
895
|
+
for await (const chunk of req) {
|
|
896
|
+
chunks.push(chunk);
|
|
897
|
+
}
|
|
898
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
899
|
+
if (typeof body.script !== "string") {
|
|
900
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
901
|
+
res.end(JSON.stringify({ error: "Missing required field: script" }));
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
let result;
|
|
905
|
+
if (body.mode === "remote") {
|
|
906
|
+
if (!credentialsRef.current) {
|
|
907
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
908
|
+
res.end(JSON.stringify({ error: "Credentials are required for remote execution" }));
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
result = await executeRemoteStep(
|
|
912
|
+
{
|
|
913
|
+
script: body.script,
|
|
914
|
+
scriptRuntime: body.scriptRuntime ?? "python-3-12",
|
|
915
|
+
inputs: body.inputs ?? {},
|
|
916
|
+
inputTypes: body.inputTypes ?? {},
|
|
917
|
+
outputTypes: body.outputTypes ?? {},
|
|
918
|
+
secretNames: body.secretNames ?? []
|
|
919
|
+
},
|
|
920
|
+
credentialsRef.current
|
|
921
|
+
);
|
|
922
|
+
} else {
|
|
923
|
+
const stepParams = {
|
|
924
|
+
script: body.script,
|
|
925
|
+
scriptRuntime: body.scriptRuntime ?? "python-3.9",
|
|
926
|
+
inputs: body.inputs ?? {},
|
|
927
|
+
secrets: body.secrets ?? {}
|
|
928
|
+
};
|
|
929
|
+
if (typeof body.timeout === "number") {
|
|
930
|
+
stepParams.timeout = body.timeout;
|
|
931
|
+
}
|
|
932
|
+
result = await executePythonStep(stepParams);
|
|
933
|
+
}
|
|
934
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
935
|
+
res.end(JSON.stringify(result));
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
507
938
|
if (url === "/api/proxy-cache/clear") {
|
|
508
939
|
proxyCache.clear();
|
|
509
940
|
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
@@ -568,8 +999,8 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
568
999
|
return;
|
|
569
1000
|
}
|
|
570
1001
|
const rawPath = url === "/" ? "/index.html" : url;
|
|
571
|
-
const filePath =
|
|
572
|
-
const resolvedPath = await fileExists(filePath) ? filePath :
|
|
1002
|
+
const filePath = join7(viewerPath, rawPath);
|
|
1003
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
573
1004
|
const ext = extname(resolvedPath);
|
|
574
1005
|
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
575
1006
|
res.writeHead(200, { "Content-Type": mimeType });
|
|
@@ -603,7 +1034,7 @@ import { launch } from "chrome-launcher";
|
|
|
603
1034
|
import { createRequire } from "module";
|
|
604
1035
|
import { mkdirSync } from "fs";
|
|
605
1036
|
import { readFile as readFile5 } from "fs/promises";
|
|
606
|
-
import { dirname as dirname3, join as
|
|
1037
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
607
1038
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
608
1039
|
var CDP = createRequire(import.meta.url)("chrome-remote-interface");
|
|
609
1040
|
var CSP_HEADERS = /* @__PURE__ */ new Set([
|
|
@@ -682,7 +1113,7 @@ async function serializeArgAsync(client, arg) {
|
|
|
682
1113
|
}
|
|
683
1114
|
async function installDockIcon(client) {
|
|
684
1115
|
try {
|
|
685
|
-
const iconPath =
|
|
1116
|
+
const iconPath = join8(dirname3(fileURLToPath2(import.meta.url)), "viewer", "icon.png");
|
|
686
1117
|
const icon = await readFile5(iconPath);
|
|
687
1118
|
await client.Browser.setDockTile({ image: icon.toString("base64") });
|
|
688
1119
|
} catch {
|
|
@@ -690,10 +1121,11 @@ async function installDockIcon(client) {
|
|
|
690
1121
|
}
|
|
691
1122
|
async function launchChromeViewer(opts) {
|
|
692
1123
|
mkdirSync(opts.userDataDir, { recursive: true });
|
|
1124
|
+
const baseUrl = `http://localhost:${String(opts.port)}`;
|
|
693
1125
|
const chrome = await launch({
|
|
694
|
-
startingUrl:
|
|
1126
|
+
startingUrl: baseUrl,
|
|
695
1127
|
chromeFlags: [
|
|
696
|
-
`--app
|
|
1128
|
+
`--app=${baseUrl}`,
|
|
697
1129
|
"--no-first-run",
|
|
698
1130
|
"--no-default-browser-check",
|
|
699
1131
|
"--disable-extensions"
|
|
@@ -709,6 +1141,9 @@ async function launchChromeViewer(opts) {
|
|
|
709
1141
|
await new Promise((r) => setTimeout(r, 300));
|
|
710
1142
|
try {
|
|
711
1143
|
client = await CDP({ port: cdpPort });
|
|
1144
|
+
if (opts.path) {
|
|
1145
|
+
void client.send("Page.navigate", { url: `${baseUrl}${opts.path}` });
|
|
1146
|
+
}
|
|
712
1147
|
break;
|
|
713
1148
|
} catch {
|
|
714
1149
|
if (attempt === 9) {
|
|
@@ -1203,10 +1638,12 @@ var DevUI = ({
|
|
|
1203
1638
|
outputDir,
|
|
1204
1639
|
credentials: initialCredentials,
|
|
1205
1640
|
credentialMode: initialCredentialMode,
|
|
1206
|
-
activeCredentialProfile: initialActiveProfile
|
|
1641
|
+
activeCredentialProfile: initialActiveProfile,
|
|
1642
|
+
lastPath: initialLastPath
|
|
1207
1643
|
}) => {
|
|
1208
1644
|
const credentialsRef = useRef(initialCredentials);
|
|
1209
1645
|
const activeProfileRef = useRef(initialActiveProfile);
|
|
1646
|
+
const lastPathRef = useRef(initialLastPath);
|
|
1210
1647
|
const [credMode, setCredMode] = useState5("main");
|
|
1211
1648
|
const [credentialMode, setCredentialMode] = useState5(
|
|
1212
1649
|
initialCredentialMode
|
|
@@ -1248,8 +1685,9 @@ var DevUI = ({
|
|
|
1248
1685
|
chromeHandleRef.current = null;
|
|
1249
1686
|
void launchChromeViewer({
|
|
1250
1687
|
port,
|
|
1251
|
-
userDataDir:
|
|
1252
|
-
broadcast
|
|
1688
|
+
userDataDir: join9(outputDir, ".chrome"),
|
|
1689
|
+
broadcast,
|
|
1690
|
+
...lastPathRef.current !== void 0 && { path: lastPathRef.current }
|
|
1253
1691
|
}).then((handle) => {
|
|
1254
1692
|
chromeHandleRef.current = handle;
|
|
1255
1693
|
process.on("exit", () => {
|
|
@@ -1370,7 +1808,7 @@ var DevUI = ({
|
|
|
1370
1808
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
1371
1809
|
useEffect4(() => {
|
|
1372
1810
|
const viewerPath = getViewerPath();
|
|
1373
|
-
void fileExists(
|
|
1811
|
+
void fileExists(join9(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
1374
1812
|
if (!viewerBuilt) {
|
|
1375
1813
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
1376
1814
|
setStatus("error");
|
|
@@ -1384,7 +1822,8 @@ var DevUI = ({
|
|
|
1384
1822
|
activeProfileRef,
|
|
1385
1823
|
outputDir,
|
|
1386
1824
|
broadcast,
|
|
1387
|
-
setProxyCacheSize
|
|
1825
|
+
setProxyCacheSize,
|
|
1826
|
+
lastPathRef
|
|
1388
1827
|
);
|
|
1389
1828
|
const server = createServer(handler);
|
|
1390
1829
|
const wss = new WebSocketServer({ server });
|
|
@@ -1572,6 +2011,7 @@ function devCommand(program2) {
|
|
|
1572
2011
|
let credentials = null;
|
|
1573
2012
|
let credentialMode;
|
|
1574
2013
|
let activeCredentialProfile;
|
|
2014
|
+
const { lastPath } = await loadConfig(outputDir);
|
|
1575
2015
|
if (options.credentials) {
|
|
1576
2016
|
credentials = await loadCredentialsFromFile(options.credentials);
|
|
1577
2017
|
} else {
|
|
@@ -1614,7 +2054,8 @@ function devCommand(program2) {
|
|
|
1614
2054
|
outputDir,
|
|
1615
2055
|
credentials,
|
|
1616
2056
|
...credentialMode !== void 0 && { credentialMode },
|
|
1617
|
-
...activeCredentialProfile !== void 0 && { activeCredentialProfile }
|
|
2057
|
+
...activeCredentialProfile !== void 0 && { activeCredentialProfile },
|
|
2058
|
+
...lastPath !== void 0 && { lastPath }
|
|
1618
2059
|
}),
|
|
1619
2060
|
{ exitOnCtrlC: false }
|
|
1620
2061
|
);
|