@mistweaverco/kulala-cli 0.8.2 → 0.9.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/README.md +32 -5
- package/dist/cli.cjs +556 -289
- package/dist/install-backend.cjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
# kulala-cli
|
|
6
6
|
|
|
7
7
|
[![npm][badge-npm]][link-npm]
|
|
8
|
-
[![
|
|
8
|
+
[![Made with love][badge-made-with-love]][contributors]
|
|
9
9
|
[![Discord][badge-discord]][discord]
|
|
10
|
+
[![Development status][badge-development-status]][development-status]
|
|
11
|
+
[![Our manifesto][badge-our-manifesto]][our-manifesto]
|
|
12
|
+
[![AI Policty][badge-ai-policy]][ai-policy]
|
|
10
13
|
|
|
11
14
|
[Install](#install) •
|
|
12
15
|
[Usage](#usage)
|
|
@@ -19,6 +22,17 @@ that supports the Jetbrains .http spec (with full scripting support).
|
|
|
19
22
|
|
|
20
23
|
<p></p>
|
|
21
24
|
|
|
25
|
+
# Other tools 🔧 from the Kulala 🐼 family 🌈
|
|
26
|
+
|
|
27
|
+
[Kulala for Neovim][kulala.nvim] •
|
|
28
|
+
[Kulala Formatter (and converter)][kulala-fmt] •
|
|
29
|
+
[Kulala Desktop][kulala-desktop] •
|
|
30
|
+
[Kulala for Visual Studio Code][kulala.vscode] •
|
|
31
|
+
[Kulala Core][kulala-core]
|
|
32
|
+
[Kulala Github Action][kulala-github-action]
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
22
36
|
</div>
|
|
23
37
|
|
|
24
38
|
## Install
|
|
@@ -216,9 +230,22 @@ docker buildx build --push \
|
|
|
216
230
|
```
|
|
217
231
|
|
|
218
232
|
[logo]: https://raw.githubusercontent.com/mistweaverco/kulala-cli/main/assets/logo.svg
|
|
219
|
-
[discord]: https://mistweaverco.com/discord
|
|
220
|
-
[badge-discord]: https://mistweaverco.com/assets/badges/discord.svg
|
|
221
|
-
[badge-github]: https://img.shields.io/github/v/release/mistweaverco/kulala-cli?style=for-the-badge
|
|
222
|
-
[link-github]: https://github.com/mistweaverco/kulala-cli/releases/latest
|
|
223
233
|
[badge-npm]: https://img.shields.io/npm/v/@mistweaverco/kulala-cli?style=for-the-badge
|
|
224
234
|
[link-npm]: https://www.npmjs.com/package/@mistweaverco/kulala-cli
|
|
235
|
+
[badge-discord]: https://mistweaverco.com/assets/badges/discord.svg
|
|
236
|
+
[discord]: https://mistweaverco.com/discord
|
|
237
|
+
[badge-made-with-love]: https://mistweaverco.com/assets/badges/made-with-love.svg
|
|
238
|
+
[contributors]: https://github.com/mistweaverco/kulala-cli/graphs/contributors
|
|
239
|
+
[kulala.nvim]: https://github.com/mistweaverco/kulala.nvim
|
|
240
|
+
[kulala-fmt]: https://github.com/mistweaverco/kulala-fmt
|
|
241
|
+
[kulala-desktop]: https://github.com/mistweaverco/kulala-desktop
|
|
242
|
+
[kulala.vscode]: https://github.com/mistweaverco/kulala.vscode
|
|
243
|
+
[kulala-core]: https://github.com/mistweaverco/kulala-core
|
|
244
|
+
[kulala-github-action]: https://github.com/mistweaverco/kulala-github-action
|
|
245
|
+
[demo-image]: https://github.com/user-attachments/assets/a7b3b01f-0115-44dc-94d2-8abd4db6fb60
|
|
246
|
+
[badge-development-status]: https://mistweaverco.com/assets/badges/development-status.svg
|
|
247
|
+
[development-status]: https://mistweaverco.com/roadmap?filter=kulala-cli
|
|
248
|
+
[badge-ai-policy]: https://mistweaverco.com/assets/badges/ai-policy.svg
|
|
249
|
+
[ai-policy]: https://mistweaverco.com/ai-policy
|
|
250
|
+
[badge-our-manifesto]: https://mistweaverco.com/assets/badges/our-manifesto.svg
|
|
251
|
+
[our-manifesto]: https://mistweaverco.com/manifesto
|
package/dist/cli.cjs
CHANGED
|
@@ -41,12 +41,12 @@ fs = __toESM(fs, 1);
|
|
|
41
41
|
let path = require("path");
|
|
42
42
|
path = __toESM(path, 1);
|
|
43
43
|
let stream_promises = require("stream/promises");
|
|
44
|
-
let node_async_hooks = require("node:async_hooks");
|
|
45
44
|
let node_readline = require("node:readline");
|
|
46
45
|
node_readline = __toESM(node_readline, 1);
|
|
46
|
+
let node_async_hooks = require("node:async_hooks");
|
|
47
47
|
var package_default = {
|
|
48
48
|
name: "@mistweaverco/kulala-cli",
|
|
49
|
-
version: "0.
|
|
49
|
+
version: "0.9.0",
|
|
50
50
|
repository: {
|
|
51
51
|
"type": "git",
|
|
52
52
|
"url": "https://github.com/mistweaverco/kulala-cli"
|
|
@@ -3474,7 +3474,7 @@ function fileWalker(inputPath, extensions) {
|
|
|
3474
3474
|
}
|
|
3475
3475
|
//#endregion
|
|
3476
3476
|
//#region src/versions/backend.ts
|
|
3477
|
-
var KULALA_CORE_VERSION = "0.24.
|
|
3477
|
+
var KULALA_CORE_VERSION = "0.24.4";
|
|
3478
3478
|
//#endregion
|
|
3479
3479
|
//#region src/lib/downloader/index.ts
|
|
3480
3480
|
var BINARY_NAME = "kulala-core";
|
|
@@ -3632,63 +3632,8 @@ var downloader = {
|
|
|
3632
3632
|
tryInstallBackend
|
|
3633
3633
|
};
|
|
3634
3634
|
//#endregion
|
|
3635
|
-
//#region src/lib/
|
|
3636
|
-
var
|
|
3637
|
-
async function executablePath() {
|
|
3638
|
-
if (!cachedExecutable) cachedExecutable = await downloader.ensureInstalled();
|
|
3639
|
-
if (!cachedExecutable) throw new Error("kulala-core executable not resolved");
|
|
3640
|
-
return cachedExecutable;
|
|
3641
|
-
}
|
|
3642
|
-
function invoke(payload, options = {}) {
|
|
3643
|
-
const exe = cachedExecutable;
|
|
3644
|
-
if (!exe) throw new Error("kulala-core executable not resolved");
|
|
3645
|
-
const result = (0, node_child_process.spawnSync)(exe, [], {
|
|
3646
|
-
input: `${JSON.stringify(payload)}\n`,
|
|
3647
|
-
encoding: "utf-8",
|
|
3648
|
-
maxBuffer: 50 * 1024 * 1024,
|
|
3649
|
-
cwd: options.cwd,
|
|
3650
|
-
env: process.env
|
|
3651
|
-
});
|
|
3652
|
-
if (result.error) throw result.error;
|
|
3653
|
-
if (result.status !== 0) throw new Error(result.stderr?.trim() || `kulala-core exited with code ${result.status ?? "unknown"}`);
|
|
3654
|
-
const stdout = result.stdout?.trim();
|
|
3655
|
-
if (!stdout) throw new Error("kulala-core returned empty output");
|
|
3656
|
-
return JSON.parse(stdout);
|
|
3657
|
-
}
|
|
3658
|
-
async function runHttp(options, invokeOptions = {}) {
|
|
3659
|
-
await executablePath();
|
|
3660
|
-
return invoke({
|
|
3661
|
-
action: "run",
|
|
3662
|
-
content: options.content,
|
|
3663
|
-
filepath: options.filepath,
|
|
3664
|
-
env: options.env,
|
|
3665
|
-
limit: options.limit,
|
|
3666
|
-
haltOnError: options.haltOnError
|
|
3667
|
-
}, invokeOptions);
|
|
3668
|
-
}
|
|
3669
|
-
async function environments(options = {}, invokeOptions = {}) {
|
|
3670
|
-
await executablePath();
|
|
3671
|
-
return invoke({
|
|
3672
|
-
action: "environments",
|
|
3673
|
-
cwd: options.cwd,
|
|
3674
|
-
filepath: options.filepath
|
|
3675
|
-
}, invokeOptions);
|
|
3676
|
-
}
|
|
3677
|
-
async function curl$1(options, invokeOptions = {}) {
|
|
3678
|
-
await executablePath();
|
|
3679
|
-
return invoke({
|
|
3680
|
-
action: "curl",
|
|
3681
|
-
argv: options.argv
|
|
3682
|
-
}, invokeOptions);
|
|
3683
|
-
}
|
|
3684
|
-
var kulalaCore = {
|
|
3685
|
-
runHttp,
|
|
3686
|
-
environments,
|
|
3687
|
-
curl: curl$1
|
|
3688
|
-
};
|
|
3689
|
-
//#endregion
|
|
3690
|
-
//#region node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
3691
|
-
var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
3635
|
+
//#region src/lib/output/shared.ts
|
|
3636
|
+
var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
3692
3637
|
var p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
3693
3638
|
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
3694
3639
|
var formatter = (open, close, replace = open) => (input) => {
|
|
@@ -3753,7 +3698,303 @@ var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
3753
3698
|
};
|
|
3754
3699
|
module.exports = createColors();
|
|
3755
3700
|
module.exports.createColors = createColors;
|
|
3756
|
-
}));
|
|
3701
|
+
})))(), 1);
|
|
3702
|
+
function isPromptResponse(item) {
|
|
3703
|
+
if ("prompt" in item && item.prompt === true) return true;
|
|
3704
|
+
const maybe = item;
|
|
3705
|
+
return Boolean(maybe.promptId && maybe.promptType);
|
|
3706
|
+
}
|
|
3707
|
+
function findFirstPromptItem(wrapper) {
|
|
3708
|
+
return (Array.isArray(wrapper) ? wrapper : wrapper.data).find((item) => isPromptResponse(item));
|
|
3709
|
+
}
|
|
3710
|
+
function isSkippedResponse(item) {
|
|
3711
|
+
return "skipped" in item && item.skipped === true;
|
|
3712
|
+
}
|
|
3713
|
+
function isWebSocketResponse(item) {
|
|
3714
|
+
return "protocol" in item && item.protocol === "websocket";
|
|
3715
|
+
}
|
|
3716
|
+
function isErrorResponse(item) {
|
|
3717
|
+
return item.success === false && !isPromptResponse(item);
|
|
3718
|
+
}
|
|
3719
|
+
function isSuccessResponse(item) {
|
|
3720
|
+
return item.success === true && !isSkippedResponse(item) && !isWebSocketResponse(item);
|
|
3721
|
+
}
|
|
3722
|
+
function responseBodyText(body) {
|
|
3723
|
+
if (!body) return "";
|
|
3724
|
+
if (body.type === "json") return body.formatted ?? JSON.stringify(body.content, null, 2);
|
|
3725
|
+
if (body.type === "binary") return "";
|
|
3726
|
+
return body.content;
|
|
3727
|
+
}
|
|
3728
|
+
function responseBodyLanguage(body) {
|
|
3729
|
+
if (!body) return "text";
|
|
3730
|
+
if (body.type === "json") return "json";
|
|
3731
|
+
if (body.type === "binary") return "text";
|
|
3732
|
+
const mediaType = body.mediaType?.toLowerCase() ?? "";
|
|
3733
|
+
if (mediaType.includes("json")) return "json";
|
|
3734
|
+
if (mediaType.includes("xml")) return "xml";
|
|
3735
|
+
if (mediaType.includes("html")) return "html";
|
|
3736
|
+
if (mediaType.includes("javascript") || mediaType.includes("ecmascript")) return "javascript";
|
|
3737
|
+
if (mediaType.includes("graphql")) return "graphql";
|
|
3738
|
+
return "text";
|
|
3739
|
+
}
|
|
3740
|
+
function formatMs(ms) {
|
|
3741
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
3742
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
3743
|
+
}
|
|
3744
|
+
function escapeCell(value) {
|
|
3745
|
+
return value.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
3746
|
+
}
|
|
3747
|
+
function mdTable(rows) {
|
|
3748
|
+
if (rows.length === 0) return "";
|
|
3749
|
+
const header = rows[0];
|
|
3750
|
+
const separator = header.map(() => "---");
|
|
3751
|
+
const body = rows.slice(1);
|
|
3752
|
+
const formatRow = (row) => `| ${row.join(" | ")} |`;
|
|
3753
|
+
return [
|
|
3754
|
+
formatRow(header),
|
|
3755
|
+
formatRow(separator),
|
|
3756
|
+
...body.map(formatRow)
|
|
3757
|
+
].join("\n");
|
|
3758
|
+
}
|
|
3759
|
+
function isStructuredScriptLine(line) {
|
|
3760
|
+
return (line.kind === "test" || line.kind === "assert") && (line.status === "pass" || line.status === "fail");
|
|
3761
|
+
}
|
|
3762
|
+
function finalizeOpenTest(openTest, tests) {
|
|
3763
|
+
if (!openTest) return;
|
|
3764
|
+
if (!tests.includes(openTest)) tests.push(openTest);
|
|
3765
|
+
}
|
|
3766
|
+
function assertMessageAlreadyShown(message, tests) {
|
|
3767
|
+
return tests.some((test) => test.error === message || test.asserts.some((assert) => assert.message === message));
|
|
3768
|
+
}
|
|
3769
|
+
function parseAssertionTree(lines) {
|
|
3770
|
+
const tests = [];
|
|
3771
|
+
const standaloneAsserts = [];
|
|
3772
|
+
let openTest = null;
|
|
3773
|
+
const hasStructuredOutput = (lines ?? []).some((line) => line.kind === "assert" || line.kind === "test");
|
|
3774
|
+
for (const line of lines ?? []) {
|
|
3775
|
+
if (line.kind === "assert") {
|
|
3776
|
+
const assert = {
|
|
3777
|
+
pass: line.status === "pass",
|
|
3778
|
+
message: line.message
|
|
3779
|
+
};
|
|
3780
|
+
if (line.testName) {
|
|
3781
|
+
if (!openTest || openTest.name !== line.testName) {
|
|
3782
|
+
finalizeOpenTest(openTest, tests);
|
|
3783
|
+
openTest = {
|
|
3784
|
+
name: line.testName,
|
|
3785
|
+
pass: true,
|
|
3786
|
+
asserts: []
|
|
3787
|
+
};
|
|
3788
|
+
}
|
|
3789
|
+
openTest.asserts.push(assert);
|
|
3790
|
+
if (!assert.pass) openTest.pass = false;
|
|
3791
|
+
} else {
|
|
3792
|
+
finalizeOpenTest(openTest, tests);
|
|
3793
|
+
openTest = null;
|
|
3794
|
+
standaloneAsserts.push(assert);
|
|
3795
|
+
}
|
|
3796
|
+
continue;
|
|
3797
|
+
}
|
|
3798
|
+
if (line.kind === "test") {
|
|
3799
|
+
const parsed = {
|
|
3800
|
+
pass: line.status === "pass",
|
|
3801
|
+
name: line.testName,
|
|
3802
|
+
error: line.status === "fail" && line.level === "error" ? line.message : void 0
|
|
3803
|
+
};
|
|
3804
|
+
if (openTest && openTest.name === parsed.name) {
|
|
3805
|
+
openTest.pass = parsed.pass;
|
|
3806
|
+
openTest.error = parsed.error;
|
|
3807
|
+
if (!parsed.pass && parsed.error && openTest.asserts.length === 0) openTest.asserts.push({
|
|
3808
|
+
pass: false,
|
|
3809
|
+
message: parsed.error
|
|
3810
|
+
});
|
|
3811
|
+
finalizeOpenTest(openTest, tests);
|
|
3812
|
+
openTest = null;
|
|
3813
|
+
continue;
|
|
3814
|
+
}
|
|
3815
|
+
finalizeOpenTest(openTest, tests);
|
|
3816
|
+
openTest = null;
|
|
3817
|
+
if (!parsed.name) continue;
|
|
3818
|
+
const testGroup = {
|
|
3819
|
+
name: parsed.name,
|
|
3820
|
+
pass: parsed.pass,
|
|
3821
|
+
error: parsed.error,
|
|
3822
|
+
asserts: []
|
|
3823
|
+
};
|
|
3824
|
+
if (!parsed.pass && parsed.error) testGroup.asserts.push({
|
|
3825
|
+
pass: false,
|
|
3826
|
+
message: parsed.error
|
|
3827
|
+
});
|
|
3828
|
+
tests.push(testGroup);
|
|
3829
|
+
continue;
|
|
3830
|
+
}
|
|
3831
|
+
if (line.level === "error" && line.kind !== "log") {
|
|
3832
|
+
const message = line.message;
|
|
3833
|
+
if (hasStructuredOutput || assertMessageAlreadyShown(message, tests)) continue;
|
|
3834
|
+
finalizeOpenTest(openTest, tests);
|
|
3835
|
+
openTest = null;
|
|
3836
|
+
standaloneAsserts.push({
|
|
3837
|
+
pass: false,
|
|
3838
|
+
message
|
|
3839
|
+
});
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
finalizeOpenTest(openTest, tests);
|
|
3843
|
+
return {
|
|
3844
|
+
tests,
|
|
3845
|
+
standaloneAsserts
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
function isPreRequestPhase(origin) {
|
|
3849
|
+
if (!origin) return false;
|
|
3850
|
+
const phase = String(origin.phase);
|
|
3851
|
+
return phase === "preRequest" || phase === "pre-request" || phase === "pre_request";
|
|
3852
|
+
}
|
|
3853
|
+
function scriptDisplayPath(originFile, requestFile) {
|
|
3854
|
+
if (!originFile) return;
|
|
3855
|
+
if (requestFile) {
|
|
3856
|
+
const relative = node_path.default.relative(node_path.default.dirname(requestFile), originFile);
|
|
3857
|
+
if (relative && !relative.startsWith("..")) return relative;
|
|
3858
|
+
}
|
|
3859
|
+
return originFile.split("/").pop();
|
|
3860
|
+
}
|
|
3861
|
+
function formatScriptOrigin(origin, requestFile) {
|
|
3862
|
+
if (!origin) return "[?]";
|
|
3863
|
+
const source = origin.source ?? "?";
|
|
3864
|
+
const file = scriptDisplayPath(origin.file, requestFile);
|
|
3865
|
+
const location = origin.line !== void 0 ? `L${origin.line}${origin.column !== void 0 ? `:${origin.column}` : ""}` : `directive L${origin.httpDirectiveLine ?? "?"}`;
|
|
3866
|
+
return file ? `[${source} · ${file} · ${location}]` : `[${source} · ${location}]`;
|
|
3867
|
+
}
|
|
3868
|
+
function splitScriptConsole(lines) {
|
|
3869
|
+
const pre = [];
|
|
3870
|
+
const post = [];
|
|
3871
|
+
const hasStructuredOutput = (lines ?? []).some((line) => line.kind === "assert" || line.kind === "test");
|
|
3872
|
+
const tree = parseAssertionTree(lines);
|
|
3873
|
+
const skipScriptErrors = /* @__PURE__ */ new Set();
|
|
3874
|
+
for (const test of tree.tests) {
|
|
3875
|
+
if (test.error) skipScriptErrors.add(test.error);
|
|
3876
|
+
for (const assert of test.asserts) skipScriptErrors.add(assert.message);
|
|
3877
|
+
}
|
|
3878
|
+
for (const assert of tree.standaloneAsserts) skipScriptErrors.add(assert.message);
|
|
3879
|
+
for (const line of lines ?? []) {
|
|
3880
|
+
if (isStructuredScriptLine(line)) continue;
|
|
3881
|
+
if (line.level === "error" && line.message.startsWith("Error executing script: ")) {
|
|
3882
|
+
const message = line.message.replace(/^Error executing script: /, "");
|
|
3883
|
+
if (hasStructuredOutput || skipScriptErrors.has(message)) continue;
|
|
3884
|
+
}
|
|
3885
|
+
if (isPreRequestPhase(line.origin)) pre.push(line);
|
|
3886
|
+
else post.push(line);
|
|
3887
|
+
}
|
|
3888
|
+
return {
|
|
3889
|
+
pre,
|
|
3890
|
+
post
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
function formatLabeledField(label, value) {
|
|
3894
|
+
return import_picocolors.default.bold(`${import_picocolors.default.cyan(`${label}:`)} ${value}`);
|
|
3895
|
+
}
|
|
3896
|
+
function formatRunHeader(filepath, blockName) {
|
|
3897
|
+
return [formatLabeledField("Filepath", filepath), formatLabeledField("Block name", blockName)].join("\n");
|
|
3898
|
+
}
|
|
3899
|
+
function itemDisplayName(item) {
|
|
3900
|
+
if ("blockName" in item && item.blockName) return item.blockName;
|
|
3901
|
+
return itemTitle(item);
|
|
3902
|
+
}
|
|
3903
|
+
function itemTitle(item) {
|
|
3904
|
+
if (isPromptResponse(item)) return `Prompt: ${item.promptType}`;
|
|
3905
|
+
if (isSkippedResponse(item)) return item.blockName ? `Skipped — ${item.blockName}` : "Skipped";
|
|
3906
|
+
if (isWebSocketResponse(item)) return `WebSocket — ${item.url}`;
|
|
3907
|
+
if (isErrorResponse(item)) return `${item.request?.method ?? "REQUEST"} ${item.url ?? item.blockName ?? "unknown"}`;
|
|
3908
|
+
if (isSuccessResponse(item)) return `${item.request?.method ?? "GET"} ${item.url}`;
|
|
3909
|
+
return "Unknown request";
|
|
3910
|
+
}
|
|
3911
|
+
//#endregion
|
|
3912
|
+
//#region src/lib/kulala-core/index.ts
|
|
3913
|
+
var cachedExecutable = null;
|
|
3914
|
+
async function executablePath() {
|
|
3915
|
+
if (!cachedExecutable) cachedExecutable = await downloader.ensureInstalled();
|
|
3916
|
+
if (!cachedExecutable) throw new Error("kulala-core executable not resolved");
|
|
3917
|
+
return cachedExecutable;
|
|
3918
|
+
}
|
|
3919
|
+
function invokeRaw(payload, options = {}) {
|
|
3920
|
+
const exe = cachedExecutable;
|
|
3921
|
+
if (!exe) throw new Error("kulala-core executable not resolved");
|
|
3922
|
+
const result = (0, node_child_process.spawnSync)(exe, [], {
|
|
3923
|
+
input: `${JSON.stringify(payload)}\n`,
|
|
3924
|
+
encoding: "utf-8",
|
|
3925
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
3926
|
+
cwd: options.cwd,
|
|
3927
|
+
env: process.env
|
|
3928
|
+
});
|
|
3929
|
+
if (result.error) throw result.error;
|
|
3930
|
+
return {
|
|
3931
|
+
stdout: result.stdout ?? "",
|
|
3932
|
+
stderr: result.stderr ?? "",
|
|
3933
|
+
status: result.status
|
|
3934
|
+
};
|
|
3935
|
+
}
|
|
3936
|
+
function tryDecodeWrapper(stdout) {
|
|
3937
|
+
const raw = stdout.trim();
|
|
3938
|
+
if (!raw) return;
|
|
3939
|
+
try {
|
|
3940
|
+
const wrapper = JSON.parse(raw);
|
|
3941
|
+
if (wrapper && typeof wrapper === "object" && wrapper.type) return wrapper;
|
|
3942
|
+
} catch {
|
|
3943
|
+
return;
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
function parseInvokeResponse(job) {
|
|
3947
|
+
const wrapper = tryDecodeWrapper(job.stdout);
|
|
3948
|
+
const first = wrapper?.type === "responses" ? wrapper.data[0] : void 0;
|
|
3949
|
+
const isPrompt = Boolean(first && isPromptResponse(first));
|
|
3950
|
+
if (job.status !== 0 && !isPrompt) throw new Error(job.stderr?.trim() || `kulala-core exited with code ${job.status ?? "unknown"}`);
|
|
3951
|
+
if (!wrapper) throw new Error(job.stderr?.trim() || "kulala-core returned empty or invalid output");
|
|
3952
|
+
return wrapper;
|
|
3953
|
+
}
|
|
3954
|
+
async function runHttp(options, invokeOptions = {}) {
|
|
3955
|
+
await executablePath();
|
|
3956
|
+
return parseInvokeResponse(invokeRaw({
|
|
3957
|
+
action: "run",
|
|
3958
|
+
content: options.content,
|
|
3959
|
+
filepath: options.filepath,
|
|
3960
|
+
env: options.env,
|
|
3961
|
+
limit: options.limit,
|
|
3962
|
+
haltOnError: options.haltOnError
|
|
3963
|
+
}, invokeOptions));
|
|
3964
|
+
}
|
|
3965
|
+
async function continueHttp(options, invokeOptions = {}) {
|
|
3966
|
+
await executablePath();
|
|
3967
|
+
return parseInvokeResponse(invokeRaw({
|
|
3968
|
+
action: "continue",
|
|
3969
|
+
promptId: options.promptId,
|
|
3970
|
+
inputs: options.inputs
|
|
3971
|
+
}, invokeOptions));
|
|
3972
|
+
}
|
|
3973
|
+
async function environments(options = {}, invokeOptions = {}) {
|
|
3974
|
+
await executablePath();
|
|
3975
|
+
const job = invokeRaw({
|
|
3976
|
+
action: "environments",
|
|
3977
|
+
cwd: options.cwd,
|
|
3978
|
+
filepath: options.filepath
|
|
3979
|
+
}, invokeOptions);
|
|
3980
|
+
if (job.status !== 0) throw new Error(job.stderr?.trim() || `kulala-core exited with code ${job.status ?? "unknown"}`);
|
|
3981
|
+
const raw = job.stdout.trim();
|
|
3982
|
+
if (!raw) throw new Error("kulala-core returned empty output");
|
|
3983
|
+
return JSON.parse(raw);
|
|
3984
|
+
}
|
|
3985
|
+
async function curl$1(options, invokeOptions = {}) {
|
|
3986
|
+
await executablePath();
|
|
3987
|
+
return parseInvokeResponse(invokeRaw({
|
|
3988
|
+
action: "curl",
|
|
3989
|
+
argv: options.argv
|
|
3990
|
+
}, invokeOptions));
|
|
3991
|
+
}
|
|
3992
|
+
var kulalaCore = {
|
|
3993
|
+
runHttp,
|
|
3994
|
+
continueHttp,
|
|
3995
|
+
environments,
|
|
3996
|
+
curl: curl$1
|
|
3997
|
+
};
|
|
3757
3998
|
//#endregion
|
|
3758
3999
|
//#region node_modules/.pnpm/highlight.js@10.7.3/node_modules/highlight.js/lib/core.js
|
|
3759
4000
|
var require_core = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -62702,8 +62943,8 @@ var require_theme = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
62702
62943
|
exports.parse = parse;
|
|
62703
62944
|
}));
|
|
62704
62945
|
//#endregion
|
|
62705
|
-
//#region
|
|
62706
|
-
var
|
|
62946
|
+
//#region src/lib/output/highlight.ts
|
|
62947
|
+
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
62707
62948
|
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
62708
62949
|
if (k2 === void 0) k2 = k;
|
|
62709
62950
|
Object.defineProperty(o, k2, {
|
|
@@ -62818,11 +63059,7 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
62818
63059
|
exports.supportsLanguage = supportsLanguage;
|
|
62819
63060
|
exports.default = highlight;
|
|
62820
63061
|
__exportStar(require_theme(), exports);
|
|
62821
|
-
}));
|
|
62822
|
-
//#endregion
|
|
62823
|
-
//#region src/lib/output/highlight.ts
|
|
62824
|
-
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
62825
|
-
var import_dist = require_dist();
|
|
63062
|
+
})))();
|
|
62826
63063
|
var colorOverride;
|
|
62827
63064
|
function setColorEnabled(enabled) {
|
|
62828
63065
|
colorOverride = enabled;
|
|
@@ -66666,212 +66903,6 @@ function renderImageInline(body) {
|
|
|
66666
66903
|
return null;
|
|
66667
66904
|
}
|
|
66668
66905
|
//#endregion
|
|
66669
|
-
//#region src/lib/output/shared.ts
|
|
66670
|
-
function isPromptResponse(item) {
|
|
66671
|
-
return "prompt" in item && item.prompt === true;
|
|
66672
|
-
}
|
|
66673
|
-
function isSkippedResponse(item) {
|
|
66674
|
-
return "skipped" in item && item.skipped === true;
|
|
66675
|
-
}
|
|
66676
|
-
function isWebSocketResponse(item) {
|
|
66677
|
-
return "protocol" in item && item.protocol === "websocket";
|
|
66678
|
-
}
|
|
66679
|
-
function isErrorResponse(item) {
|
|
66680
|
-
return item.success === false && !isPromptResponse(item);
|
|
66681
|
-
}
|
|
66682
|
-
function isSuccessResponse(item) {
|
|
66683
|
-
return item.success === true && !isSkippedResponse(item) && !isWebSocketResponse(item);
|
|
66684
|
-
}
|
|
66685
|
-
function responseBodyText(body) {
|
|
66686
|
-
if (!body) return "";
|
|
66687
|
-
if (body.type === "json") return body.formatted ?? JSON.stringify(body.content, null, 2);
|
|
66688
|
-
if (body.type === "binary") return "";
|
|
66689
|
-
return body.content;
|
|
66690
|
-
}
|
|
66691
|
-
function responseBodyLanguage(body) {
|
|
66692
|
-
if (!body) return "text";
|
|
66693
|
-
if (body.type === "json") return "json";
|
|
66694
|
-
if (body.type === "binary") return "text";
|
|
66695
|
-
const mediaType = body.mediaType?.toLowerCase() ?? "";
|
|
66696
|
-
if (mediaType.includes("json")) return "json";
|
|
66697
|
-
if (mediaType.includes("xml")) return "xml";
|
|
66698
|
-
if (mediaType.includes("html")) return "html";
|
|
66699
|
-
if (mediaType.includes("javascript") || mediaType.includes("ecmascript")) return "javascript";
|
|
66700
|
-
if (mediaType.includes("graphql")) return "graphql";
|
|
66701
|
-
return "text";
|
|
66702
|
-
}
|
|
66703
|
-
function formatMs(ms) {
|
|
66704
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
66705
|
-
return `${(ms / 1e3).toFixed(2)}s`;
|
|
66706
|
-
}
|
|
66707
|
-
function escapeCell(value) {
|
|
66708
|
-
return value.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
66709
|
-
}
|
|
66710
|
-
function mdTable(rows) {
|
|
66711
|
-
if (rows.length === 0) return "";
|
|
66712
|
-
const header = rows[0];
|
|
66713
|
-
const separator = header.map(() => "---");
|
|
66714
|
-
const body = rows.slice(1);
|
|
66715
|
-
const formatRow = (row) => `| ${row.join(" | ")} |`;
|
|
66716
|
-
return [
|
|
66717
|
-
formatRow(header),
|
|
66718
|
-
formatRow(separator),
|
|
66719
|
-
...body.map(formatRow)
|
|
66720
|
-
].join("\n");
|
|
66721
|
-
}
|
|
66722
|
-
function isStructuredScriptLine(line) {
|
|
66723
|
-
return (line.kind === "test" || line.kind === "assert") && (line.status === "pass" || line.status === "fail");
|
|
66724
|
-
}
|
|
66725
|
-
function finalizeOpenTest(openTest, tests) {
|
|
66726
|
-
if (!openTest) return;
|
|
66727
|
-
if (!tests.includes(openTest)) tests.push(openTest);
|
|
66728
|
-
}
|
|
66729
|
-
function assertMessageAlreadyShown(message, tests) {
|
|
66730
|
-
return tests.some((test) => test.error === message || test.asserts.some((assert) => assert.message === message));
|
|
66731
|
-
}
|
|
66732
|
-
function parseAssertionTree(lines) {
|
|
66733
|
-
const tests = [];
|
|
66734
|
-
const standaloneAsserts = [];
|
|
66735
|
-
let openTest = null;
|
|
66736
|
-
const hasStructuredOutput = (lines ?? []).some((line) => line.kind === "assert" || line.kind === "test");
|
|
66737
|
-
for (const line of lines ?? []) {
|
|
66738
|
-
if (line.kind === "assert") {
|
|
66739
|
-
const assert = {
|
|
66740
|
-
pass: line.status === "pass",
|
|
66741
|
-
message: line.message
|
|
66742
|
-
};
|
|
66743
|
-
if (line.testName) {
|
|
66744
|
-
if (!openTest || openTest.name !== line.testName) {
|
|
66745
|
-
finalizeOpenTest(openTest, tests);
|
|
66746
|
-
openTest = {
|
|
66747
|
-
name: line.testName,
|
|
66748
|
-
pass: true,
|
|
66749
|
-
asserts: []
|
|
66750
|
-
};
|
|
66751
|
-
}
|
|
66752
|
-
openTest.asserts.push(assert);
|
|
66753
|
-
if (!assert.pass) openTest.pass = false;
|
|
66754
|
-
} else {
|
|
66755
|
-
finalizeOpenTest(openTest, tests);
|
|
66756
|
-
openTest = null;
|
|
66757
|
-
standaloneAsserts.push(assert);
|
|
66758
|
-
}
|
|
66759
|
-
continue;
|
|
66760
|
-
}
|
|
66761
|
-
if (line.kind === "test") {
|
|
66762
|
-
const parsed = {
|
|
66763
|
-
pass: line.status === "pass",
|
|
66764
|
-
name: line.testName,
|
|
66765
|
-
error: line.status === "fail" && line.level === "error" ? line.message : void 0
|
|
66766
|
-
};
|
|
66767
|
-
if (openTest && openTest.name === parsed.name) {
|
|
66768
|
-
openTest.pass = parsed.pass;
|
|
66769
|
-
openTest.error = parsed.error;
|
|
66770
|
-
if (!parsed.pass && parsed.error && openTest.asserts.length === 0) openTest.asserts.push({
|
|
66771
|
-
pass: false,
|
|
66772
|
-
message: parsed.error
|
|
66773
|
-
});
|
|
66774
|
-
finalizeOpenTest(openTest, tests);
|
|
66775
|
-
openTest = null;
|
|
66776
|
-
continue;
|
|
66777
|
-
}
|
|
66778
|
-
finalizeOpenTest(openTest, tests);
|
|
66779
|
-
openTest = null;
|
|
66780
|
-
if (!parsed.name) continue;
|
|
66781
|
-
const testGroup = {
|
|
66782
|
-
name: parsed.name,
|
|
66783
|
-
pass: parsed.pass,
|
|
66784
|
-
error: parsed.error,
|
|
66785
|
-
asserts: []
|
|
66786
|
-
};
|
|
66787
|
-
if (!parsed.pass && parsed.error) testGroup.asserts.push({
|
|
66788
|
-
pass: false,
|
|
66789
|
-
message: parsed.error
|
|
66790
|
-
});
|
|
66791
|
-
tests.push(testGroup);
|
|
66792
|
-
continue;
|
|
66793
|
-
}
|
|
66794
|
-
if (line.level === "error" && line.kind !== "log") {
|
|
66795
|
-
const message = line.message;
|
|
66796
|
-
if (hasStructuredOutput || assertMessageAlreadyShown(message, tests)) continue;
|
|
66797
|
-
finalizeOpenTest(openTest, tests);
|
|
66798
|
-
openTest = null;
|
|
66799
|
-
standaloneAsserts.push({
|
|
66800
|
-
pass: false,
|
|
66801
|
-
message
|
|
66802
|
-
});
|
|
66803
|
-
}
|
|
66804
|
-
}
|
|
66805
|
-
finalizeOpenTest(openTest, tests);
|
|
66806
|
-
return {
|
|
66807
|
-
tests,
|
|
66808
|
-
standaloneAsserts
|
|
66809
|
-
};
|
|
66810
|
-
}
|
|
66811
|
-
function isPreRequestPhase(origin) {
|
|
66812
|
-
if (!origin) return false;
|
|
66813
|
-
const phase = String(origin.phase);
|
|
66814
|
-
return phase === "preRequest" || phase === "pre-request" || phase === "pre_request";
|
|
66815
|
-
}
|
|
66816
|
-
function scriptDisplayPath(originFile, requestFile) {
|
|
66817
|
-
if (!originFile) return;
|
|
66818
|
-
if (requestFile) {
|
|
66819
|
-
const relative = node_path.default.relative(node_path.default.dirname(requestFile), originFile);
|
|
66820
|
-
if (relative && !relative.startsWith("..")) return relative;
|
|
66821
|
-
}
|
|
66822
|
-
return originFile.split("/").pop();
|
|
66823
|
-
}
|
|
66824
|
-
function formatScriptOrigin(origin, requestFile) {
|
|
66825
|
-
if (!origin) return "[?]";
|
|
66826
|
-
const source = origin.source ?? "?";
|
|
66827
|
-
const file = scriptDisplayPath(origin.file, requestFile);
|
|
66828
|
-
const location = origin.line !== void 0 ? `L${origin.line}${origin.column !== void 0 ? `:${origin.column}` : ""}` : `directive L${origin.httpDirectiveLine ?? "?"}`;
|
|
66829
|
-
return file ? `[${source} · ${file} · ${location}]` : `[${source} · ${location}]`;
|
|
66830
|
-
}
|
|
66831
|
-
function splitScriptConsole(lines) {
|
|
66832
|
-
const pre = [];
|
|
66833
|
-
const post = [];
|
|
66834
|
-
const hasStructuredOutput = (lines ?? []).some((line) => line.kind === "assert" || line.kind === "test");
|
|
66835
|
-
const tree = parseAssertionTree(lines);
|
|
66836
|
-
const skipScriptErrors = /* @__PURE__ */ new Set();
|
|
66837
|
-
for (const test of tree.tests) {
|
|
66838
|
-
if (test.error) skipScriptErrors.add(test.error);
|
|
66839
|
-
for (const assert of test.asserts) skipScriptErrors.add(assert.message);
|
|
66840
|
-
}
|
|
66841
|
-
for (const assert of tree.standaloneAsserts) skipScriptErrors.add(assert.message);
|
|
66842
|
-
for (const line of lines ?? []) {
|
|
66843
|
-
if (isStructuredScriptLine(line)) continue;
|
|
66844
|
-
if (line.level === "error" && line.message.startsWith("Error executing script: ")) {
|
|
66845
|
-
const message = line.message.replace(/^Error executing script: /, "");
|
|
66846
|
-
if (hasStructuredOutput || skipScriptErrors.has(message)) continue;
|
|
66847
|
-
}
|
|
66848
|
-
if (isPreRequestPhase(line.origin)) pre.push(line);
|
|
66849
|
-
else post.push(line);
|
|
66850
|
-
}
|
|
66851
|
-
return {
|
|
66852
|
-
pre,
|
|
66853
|
-
post
|
|
66854
|
-
};
|
|
66855
|
-
}
|
|
66856
|
-
function formatLabeledField(label, value) {
|
|
66857
|
-
return import_picocolors.default.bold(`${import_picocolors.default.cyan(`${label}:`)} ${value}`);
|
|
66858
|
-
}
|
|
66859
|
-
function formatRunHeader(filepath, blockName) {
|
|
66860
|
-
return [formatLabeledField("Filepath", filepath), formatLabeledField("Block name", blockName)].join("\n");
|
|
66861
|
-
}
|
|
66862
|
-
function itemDisplayName(item) {
|
|
66863
|
-
if ("blockName" in item && item.blockName) return item.blockName;
|
|
66864
|
-
return itemTitle(item);
|
|
66865
|
-
}
|
|
66866
|
-
function itemTitle(item) {
|
|
66867
|
-
if (isPromptResponse(item)) return `Prompt: ${item.promptType}`;
|
|
66868
|
-
if (isSkippedResponse(item)) return item.blockName ? `Skipped — ${item.blockName}` : "Skipped";
|
|
66869
|
-
if (isWebSocketResponse(item)) return `WebSocket — ${item.url}`;
|
|
66870
|
-
if (isErrorResponse(item)) return `${item.request?.method ?? "REQUEST"} ${item.url ?? item.blockName ?? "unknown"}`;
|
|
66871
|
-
if (isSuccessResponse(item)) return `${item.request?.method ?? "GET"} ${item.url}`;
|
|
66872
|
-
return "Unknown request";
|
|
66873
|
-
}
|
|
66874
|
-
//#endregion
|
|
66875
66906
|
//#region src/lib/output/human.ts
|
|
66876
66907
|
function statusColor(status) {
|
|
66877
66908
|
if (status >= 200 && status < 300) return import_picocolors.default.green;
|
|
@@ -67018,6 +67049,13 @@ function formatItem(item, requestFile) {
|
|
|
67018
67049
|
function formatWrapper(wrapper, requestFile) {
|
|
67019
67050
|
return (wrapper.type === "error" ? wrapper.data : wrapper.data).map((entry) => formatItem(entry, requestFile)).join("\n\n");
|
|
67020
67051
|
}
|
|
67052
|
+
function printResponseItems(filepath, items) {
|
|
67053
|
+
if (items.length === 0) return;
|
|
67054
|
+
console.log(formatWrapper({
|
|
67055
|
+
type: "responses",
|
|
67056
|
+
data: items
|
|
67057
|
+
}, filepath));
|
|
67058
|
+
}
|
|
67021
67059
|
function printHumanReadable(results) {
|
|
67022
67060
|
const blocks = results.map((result) => formatWrapper(result.response, result.filepath));
|
|
67023
67061
|
console.log(blocks.join("\n\n"));
|
|
@@ -67239,6 +67277,139 @@ function printTests(results, options) {
|
|
|
67239
67277
|
if (blocks.length > 0 && !options.quiet) console.log(blocks.join("\n\n"));
|
|
67240
67278
|
}
|
|
67241
67279
|
//#endregion
|
|
67280
|
+
//#region src/lib/prompt.ts
|
|
67281
|
+
var pipedBuffer = "";
|
|
67282
|
+
var pipedEnded = false;
|
|
67283
|
+
var pipedStdinInitialized = false;
|
|
67284
|
+
var pipedWaiters = [];
|
|
67285
|
+
function flushPipedWaiters() {
|
|
67286
|
+
while (pipedWaiters.length > 0) {
|
|
67287
|
+
const newlineIndex = pipedBuffer.indexOf("\n");
|
|
67288
|
+
if (newlineIndex === -1) {
|
|
67289
|
+
if (pipedEnded) {
|
|
67290
|
+
const line = pipedBuffer.replace(/\r?\n$/u, "");
|
|
67291
|
+
pipedBuffer = "";
|
|
67292
|
+
pipedWaiters.shift()?.(line.length > 0 ? line : void 0);
|
|
67293
|
+
continue;
|
|
67294
|
+
}
|
|
67295
|
+
break;
|
|
67296
|
+
}
|
|
67297
|
+
const line = pipedBuffer.slice(0, newlineIndex).replace(/\r$/u, "");
|
|
67298
|
+
pipedBuffer = pipedBuffer.slice(newlineIndex + 1);
|
|
67299
|
+
pipedWaiters.shift()?.(line);
|
|
67300
|
+
}
|
|
67301
|
+
if (pipedEnded) while (pipedWaiters.length > 0) pipedWaiters.shift()?.(void 0);
|
|
67302
|
+
}
|
|
67303
|
+
function initPipedStdin() {
|
|
67304
|
+
if (pipedStdinInitialized || node_process.stdin.isTTY) return;
|
|
67305
|
+
pipedStdinInitialized = true;
|
|
67306
|
+
node_process.stdin.setEncoding("utf8");
|
|
67307
|
+
node_process.stdin.on("data", (chunk) => {
|
|
67308
|
+
pipedBuffer += chunk;
|
|
67309
|
+
flushPipedWaiters();
|
|
67310
|
+
});
|
|
67311
|
+
node_process.stdin.on("end", () => {
|
|
67312
|
+
pipedEnded = true;
|
|
67313
|
+
flushPipedWaiters();
|
|
67314
|
+
});
|
|
67315
|
+
node_process.stdin.resume();
|
|
67316
|
+
}
|
|
67317
|
+
async function readPipedLine() {
|
|
67318
|
+
initPipedStdin();
|
|
67319
|
+
const newlineIndex = pipedBuffer.indexOf("\n");
|
|
67320
|
+
if (newlineIndex !== -1) {
|
|
67321
|
+
const line = pipedBuffer.slice(0, newlineIndex).replace(/\r$/u, "");
|
|
67322
|
+
pipedBuffer = pipedBuffer.slice(newlineIndex + 1);
|
|
67323
|
+
return line;
|
|
67324
|
+
}
|
|
67325
|
+
if (pipedEnded) {
|
|
67326
|
+
const line = pipedBuffer.replace(/\r?\n$/u, "");
|
|
67327
|
+
pipedBuffer = "";
|
|
67328
|
+
return line.length > 0 ? line : void 0;
|
|
67329
|
+
}
|
|
67330
|
+
return new Promise((resolve) => {
|
|
67331
|
+
pipedWaiters.push(resolve);
|
|
67332
|
+
});
|
|
67333
|
+
}
|
|
67334
|
+
async function readVisibleLine(label) {
|
|
67335
|
+
if (!node_process.stdin.isTTY) return readPipedLine();
|
|
67336
|
+
const rl = (0, node_readline.createInterface)({
|
|
67337
|
+
input: node_process.stdin,
|
|
67338
|
+
output: node_process.stdout
|
|
67339
|
+
});
|
|
67340
|
+
try {
|
|
67341
|
+
return await new Promise((resolve) => {
|
|
67342
|
+
rl.question(`${label}: `, resolve);
|
|
67343
|
+
});
|
|
67344
|
+
} finally {
|
|
67345
|
+
rl.close();
|
|
67346
|
+
}
|
|
67347
|
+
}
|
|
67348
|
+
async function readHiddenLine(label) {
|
|
67349
|
+
if (!node_process.stdin.isTTY) return readPipedLine();
|
|
67350
|
+
if (typeof node_process.stdin.setRawMode !== "function") return readVisibleLine(label);
|
|
67351
|
+
node_process.stdout.write(`${label}: `);
|
|
67352
|
+
node_process.stdin.setRawMode(true);
|
|
67353
|
+
node_process.stdin.resume();
|
|
67354
|
+
node_process.stdin.setEncoding("utf8");
|
|
67355
|
+
return new Promise((resolve) => {
|
|
67356
|
+
let value = "";
|
|
67357
|
+
const cleanup = (result) => {
|
|
67358
|
+
node_process.stdin.setRawMode(false);
|
|
67359
|
+
node_process.stdin.pause();
|
|
67360
|
+
node_process.stdin.removeListener("data", onData);
|
|
67361
|
+
node_process.stdout.write("\n");
|
|
67362
|
+
resolve(result);
|
|
67363
|
+
};
|
|
67364
|
+
const onData = (chunk) => {
|
|
67365
|
+
for (const char of chunk) {
|
|
67366
|
+
if (char === "\n" || char === "\r" || char === "") {
|
|
67367
|
+
cleanup(value);
|
|
67368
|
+
return;
|
|
67369
|
+
}
|
|
67370
|
+
if (char === "") {
|
|
67371
|
+
cleanup(void 0);
|
|
67372
|
+
return;
|
|
67373
|
+
}
|
|
67374
|
+
if (char === "" || char === "\b") {
|
|
67375
|
+
if (value.length > 0) value = value.slice(0, -1);
|
|
67376
|
+
continue;
|
|
67377
|
+
}
|
|
67378
|
+
value += char;
|
|
67379
|
+
}
|
|
67380
|
+
};
|
|
67381
|
+
node_process.stdin.on("data", onData);
|
|
67382
|
+
});
|
|
67383
|
+
}
|
|
67384
|
+
async function readPromptValue(label, type) {
|
|
67385
|
+
if (type === "password") return readHiddenLine(label);
|
|
67386
|
+
return readVisibleLine(label);
|
|
67387
|
+
}
|
|
67388
|
+
async function collectPromptInputs(prompt) {
|
|
67389
|
+
const specs = prompt.inputs ?? [];
|
|
67390
|
+
if (specs.length === 0) {
|
|
67391
|
+
console.error(chalk.yellow("Kulala prompt has no inputs."));
|
|
67392
|
+
return;
|
|
67393
|
+
}
|
|
67394
|
+
const out = [];
|
|
67395
|
+
for (const spec of specs) {
|
|
67396
|
+
const id = spec.id;
|
|
67397
|
+
if (!id) return;
|
|
67398
|
+
const label = spec.label?.trim() || id;
|
|
67399
|
+
const value = await readPromptValue(label, spec.type ?? "text");
|
|
67400
|
+
if (value === void 0) return;
|
|
67401
|
+
if (spec.required && !value.trim()) {
|
|
67402
|
+
console.error(chalk.yellow(`Required input missing: ${label}`));
|
|
67403
|
+
return;
|
|
67404
|
+
}
|
|
67405
|
+
out.push({
|
|
67406
|
+
id,
|
|
67407
|
+
value
|
|
67408
|
+
});
|
|
67409
|
+
}
|
|
67410
|
+
return out;
|
|
67411
|
+
}
|
|
67412
|
+
//#endregion
|
|
67242
67413
|
//#region src/lib/runner/limit.ts
|
|
67243
67414
|
function buildRunLimit(options) {
|
|
67244
67415
|
const hasName = options.name !== void 0 && options.name.length > 0;
|
|
@@ -67297,6 +67468,7 @@ function resolveSingleHttpFile(inputPath) {
|
|
|
67297
67468
|
}
|
|
67298
67469
|
//#endregion
|
|
67299
67470
|
//#region src/lib/runner/index.ts
|
|
67471
|
+
var MAX_PROMPT_DEPTH = 7;
|
|
67300
67472
|
var HTTP_EXTENSIONS = [".http", ".rest"];
|
|
67301
67473
|
function shuffleFiles(items) {
|
|
67302
67474
|
const copy = [...items];
|
|
@@ -67319,20 +67491,107 @@ function resolveFiles(inputPath, shuffle) {
|
|
|
67319
67491
|
function responseHasFailure(result) {
|
|
67320
67492
|
return countResults(result.response).failed > 0;
|
|
67321
67493
|
}
|
|
67322
|
-
|
|
67494
|
+
function shouldStreamOutput(ctx) {
|
|
67495
|
+
return !ctx.json && !ctx.tests;
|
|
67496
|
+
}
|
|
67497
|
+
function itemsToStream(items, quiet) {
|
|
67498
|
+
if (!quiet) return items;
|
|
67499
|
+
return items.filter((item) => !isResponseSuccessful(item));
|
|
67500
|
+
}
|
|
67501
|
+
function streamResponseItems(filepath, items, ctx) {
|
|
67502
|
+
if (!shouldStreamOutput(ctx)) return;
|
|
67503
|
+
printResponseItems(filepath, itemsToStream(items, ctx.quiet ?? false));
|
|
67504
|
+
}
|
|
67505
|
+
function continueSucceeded(response) {
|
|
67506
|
+
return (response.type === "responses" ? response.data[0] : void 0)?.success === true;
|
|
67507
|
+
}
|
|
67508
|
+
function mergeRunResponses(accumulated, response) {
|
|
67509
|
+
if (response.type === "error" || accumulated.length === 0) return response;
|
|
67510
|
+
return {
|
|
67511
|
+
type: "responses",
|
|
67512
|
+
data: [...accumulated, ...response.data]
|
|
67513
|
+
};
|
|
67514
|
+
}
|
|
67515
|
+
function completedItemsBeforePrompt(response) {
|
|
67516
|
+
if (response.type !== "responses") return [];
|
|
67517
|
+
const promptIndex = response.data.findIndex((item) => isPromptResponse(item));
|
|
67518
|
+
if (promptIndex <= 0) return [];
|
|
67519
|
+
return response.data.slice(0, promptIndex);
|
|
67520
|
+
}
|
|
67521
|
+
function newItemsSinceAccumulated(accumulated, response) {
|
|
67522
|
+
if (response.type !== "responses") return [];
|
|
67523
|
+
return response.data.slice(accumulated.length);
|
|
67524
|
+
}
|
|
67525
|
+
function promptBlockName(promptItem) {
|
|
67526
|
+
if ("blockName" in promptItem && typeof promptItem.blockName === "string") return promptItem.blockName.trim() || void 0;
|
|
67527
|
+
}
|
|
67528
|
+
async function runFileWithPromptRetry(relativePath, env, limit, halt, output, depth = 0, accumulated = []) {
|
|
67323
67529
|
const absolutePath = node_path.default.resolve(process.cwd(), relativePath);
|
|
67324
67530
|
const content = node_fs.default.readFileSync(absolutePath, "utf-8");
|
|
67325
67531
|
const cwd = node_path.default.dirname(absolutePath);
|
|
67326
|
-
|
|
67327
|
-
|
|
67328
|
-
|
|
67329
|
-
|
|
67330
|
-
|
|
67331
|
-
|
|
67332
|
-
limit,
|
|
67333
|
-
haltOnError: halt
|
|
67334
|
-
}, { cwd })
|
|
67532
|
+
const runOptions = {
|
|
67533
|
+
content,
|
|
67534
|
+
filepath: absolutePath,
|
|
67535
|
+
env,
|
|
67536
|
+
limit,
|
|
67537
|
+
haltOnError: halt
|
|
67335
67538
|
};
|
|
67539
|
+
const response = await kulalaCore.runHttp(runOptions, { cwd });
|
|
67540
|
+
const promptItem = response.type === "responses" ? findFirstPromptItem(response) : void 0;
|
|
67541
|
+
if (!promptItem) {
|
|
67542
|
+
const final = mergeRunResponses(accumulated, response);
|
|
67543
|
+
streamResponseItems(relativePath, newItemsSinceAccumulated(accumulated, final), output);
|
|
67544
|
+
return {
|
|
67545
|
+
filepath: relativePath,
|
|
67546
|
+
response: final,
|
|
67547
|
+
outputStreamed: shouldStreamOutput(output)
|
|
67548
|
+
};
|
|
67549
|
+
}
|
|
67550
|
+
if (depth >= MAX_PROMPT_DEPTH) {
|
|
67551
|
+
console.error(chalk.red("Kulala: exceeded prompt / retry limit."));
|
|
67552
|
+
return {
|
|
67553
|
+
filepath: relativePath,
|
|
67554
|
+
response: mergeRunResponses(accumulated, response),
|
|
67555
|
+
outputStreamed: shouldStreamOutput(output)
|
|
67556
|
+
};
|
|
67557
|
+
}
|
|
67558
|
+
const completedBefore = completedItemsBeforePrompt(response);
|
|
67559
|
+
const newAccumulated = [...accumulated, ...completedBefore];
|
|
67560
|
+
streamResponseItems(relativePath, completedBefore, output);
|
|
67561
|
+
const inputs = await collectPromptInputs(promptItem);
|
|
67562
|
+
if (!inputs || !promptItem.promptId) {
|
|
67563
|
+
console.error(chalk.yellow("Prompt cancelled or incomplete."));
|
|
67564
|
+
return {
|
|
67565
|
+
filepath: relativePath,
|
|
67566
|
+
response: mergeRunResponses(newAccumulated, response),
|
|
67567
|
+
outputStreamed: shouldStreamOutput(output)
|
|
67568
|
+
};
|
|
67569
|
+
}
|
|
67570
|
+
const continued = await kulalaCore.continueHttp({
|
|
67571
|
+
promptId: promptItem.promptId,
|
|
67572
|
+
inputs
|
|
67573
|
+
}, { cwd });
|
|
67574
|
+
if (!continueSucceeded(continued)) {
|
|
67575
|
+
let err;
|
|
67576
|
+
if (continued.type === "error") err = continued.data[0]?.error;
|
|
67577
|
+
else {
|
|
67578
|
+
const item = continued.data[0];
|
|
67579
|
+
err = item && "error" in item ? item.error : void 0;
|
|
67580
|
+
}
|
|
67581
|
+
console.error(chalk.red(err ?? "Prompt continuation failed."));
|
|
67582
|
+
return {
|
|
67583
|
+
filepath: relativePath,
|
|
67584
|
+
response: continued
|
|
67585
|
+
};
|
|
67586
|
+
}
|
|
67587
|
+
const blockName = promptBlockName(promptItem);
|
|
67588
|
+
return runFileWithPromptRetry(relativePath, env, completedBefore.length > 0 && blockName ? [{
|
|
67589
|
+
filter: "name",
|
|
67590
|
+
name: blockName
|
|
67591
|
+
}] : limit, halt, output, depth + 1, newAccumulated);
|
|
67592
|
+
}
|
|
67593
|
+
async function runFile(relativePath, env, limit, halt, output) {
|
|
67594
|
+
return runFileWithPromptRetry(relativePath, env, limit, halt, output);
|
|
67336
67595
|
}
|
|
67337
67596
|
function hasFailures(results) {
|
|
67338
67597
|
return results.some((result) => responseHasFailure(result));
|
|
@@ -67340,20 +67599,28 @@ function hasFailures(results) {
|
|
|
67340
67599
|
async function run(inputPath, options) {
|
|
67341
67600
|
if (options.color === false) setColorEnabled(false);
|
|
67342
67601
|
if (options.report && !options.tests) options.tests = true;
|
|
67602
|
+
const output = {
|
|
67603
|
+
json: options.json,
|
|
67604
|
+
tests: options.tests,
|
|
67605
|
+
quiet: options.quiet
|
|
67606
|
+
};
|
|
67343
67607
|
const limit = buildRunLimit(options);
|
|
67344
67608
|
const files = limit ? [resolveSingleHttpFile(inputPath)] : resolveFiles(inputPath, options.shuffle ?? false);
|
|
67345
67609
|
const results = [];
|
|
67346
67610
|
const halt = options.halt ?? false;
|
|
67347
67611
|
for (const file of files) {
|
|
67348
|
-
const result = await runFile(file, options.env, limit, halt);
|
|
67612
|
+
const result = await runFile(file, options.env, limit, halt, output);
|
|
67349
67613
|
results.push(result);
|
|
67350
67614
|
if (halt && responseHasFailure(result)) break;
|
|
67351
67615
|
}
|
|
67352
|
-
const
|
|
67616
|
+
const pendingOutput = results.filter((result) => !result.outputStreamed);
|
|
67617
|
+
const outputResults = options.quiet && !options.tests ? filterFailedResults(pendingOutput) : pendingOutput;
|
|
67353
67618
|
if (options.tests) printTests(results, { quiet: options.quiet ?? false });
|
|
67354
|
-
else if (!options.quiet || outputResults.length > 0)
|
|
67355
|
-
|
|
67356
|
-
|
|
67619
|
+
else if (!options.quiet || outputResults.length > 0) {
|
|
67620
|
+
if (options.json) printJson(results);
|
|
67621
|
+
else if (options.report) printReport(pendingOutput);
|
|
67622
|
+
else if (pendingOutput.length > 0) printHumanReadable(outputResults);
|
|
67623
|
+
}
|
|
67357
67624
|
if (hasFailures(results)) process.exit(1);
|
|
67358
67625
|
}
|
|
67359
67626
|
//#endregion
|
package/dist/install-backend.cjs
CHANGED
|
@@ -29,7 +29,7 @@ let path = require("path");
|
|
|
29
29
|
path = __toESM(path, 1);
|
|
30
30
|
let stream_promises = require("stream/promises");
|
|
31
31
|
//#region src/versions/backend.ts
|
|
32
|
-
var KULALA_CORE_VERSION = "0.24.
|
|
32
|
+
var KULALA_CORE_VERSION = "0.24.4";
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/lib/downloader/index.ts
|
|
35
35
|
var BINARY_NAME = "kulala-core";
|