anpord 0.1.26 → 0.1.28
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/api-context.cjs +1 -1
- package/dist/api-context.d.cts +1 -1
- package/dist/api-context.d.mts +1 -1
- package/dist/api-context.mjs +1 -1
- package/dist/{api-mocks-CMB0IJFX.cjs → api-mocks-BsUGpsim.cjs} +14 -0
- package/dist/{api-mocks-CmytjGmi.d.cts → api-mocks-CBa3MWVP.d.cts} +4 -4
- package/dist/{api-mocks-CmytjGmi.d.mts → api-mocks-CBa3MWVP.d.mts} +4 -4
- package/dist/{api-mocks-C0uY0UBb.mjs → api-mocks-DH1C7any.mjs} +3 -1
- package/dist/api-runtime.cjs +1 -1
- package/dist/api-runtime.d.cts +1 -1
- package/dist/api-runtime.d.mts +1 -1
- package/dist/api-runtime.mjs +1 -1
- package/dist/api.cjs +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.mts +1 -1
- package/dist/api.mjs +1 -1
- package/dist/bin.cjs +540 -261
- package/dist/bin.mjs +538 -259
- package/dist/cli-runtime.cjs +3 -3
- package/dist/cli-runtime.mjs +3 -3
- package/dist/{compiler-BtVNqh3R.mjs → compiler-DDc7Towh.mjs} +35 -20
- package/dist/{compiler-s8dJGvE6.cjs → compiler-DKWUVkxB.cjs} +35 -20
- package/dist/{errors-ZfXkocHp.cjs → errors-D1L76YFH.cjs} +127 -106
- package/dist/{errors-B6JK0hbj.mjs → errors-DaYv6_WJ.mjs} +110 -101
- package/dist/{eval-definition-Dz3dHY1S.d.cts → eval-definition-CuuketNm.d.cts} +12 -12
- package/dist/{eval-definition-Dz3dHY1S.d.mts → eval-definition-CuuketNm.d.mts} +12 -12
- package/dist/eval.cjs +1 -1
- package/dist/eval.d.cts +2 -2
- package/dist/eval.d.mts +2 -2
- package/dist/eval.mjs +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1735 -189
- package/dist/index.d.mts +1735 -189
- package/dist/index.mjs +2 -2
- package/dist/mcp-runtime.cjs +4 -12
- package/dist/mcp-runtime.mjs +5 -13
- package/dist/{runtime-LjI7Hqj3.cjs → runtime-BcX6BpI5.cjs} +3 -9
- package/dist/{runtime-BTq5czA4.mjs → runtime-CjDUik7_.mjs} +3 -9
- package/dist/sandbox-env-B8cLIcku.cjs +44 -0
- package/dist/sandbox-env-s-smXj2C.mjs +9 -0
- package/dist/source.d.cts +1 -1
- package/dist/source.d.mts +1 -1
- package/dist/types-7YOtajZL.d.cts +462 -0
- package/dist/types-CwZvwO-F.d.mts +462 -0
- package/dist/validator-runtime.cjs +8 -7
- package/dist/validator-runtime.d.cts +1 -1
- package/dist/validator-runtime.d.mts +1 -1
- package/dist/validator-runtime.mjs +8 -7
- package/package.json +1 -1
- package/dist/types-BsW7R-jL.d.mts +0 -2004
- package/dist/types-D8kjPlPR.d.cts +0 -2004
package/dist/bin.cjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const require_eval_judges = require("./eval-judges-CO0ds-HQ.cjs");
|
|
3
|
-
const require_api_mocks = require("./api-mocks-
|
|
4
|
-
const require_errors = require("./errors-
|
|
5
|
-
const require_compiler = require("./compiler-
|
|
3
|
+
const require_api_mocks = require("./api-mocks-BsUGpsim.cjs");
|
|
4
|
+
const require_errors = require("./errors-D1L76YFH.cjs");
|
|
5
|
+
const require_compiler = require("./compiler-DKWUVkxB.cjs");
|
|
6
6
|
const require_eval_turns = require("./eval-turns-B9dd8Vfb.cjs");
|
|
7
|
+
const require_sandbox_env = require("./sandbox-env-B8cLIcku.cjs");
|
|
7
8
|
let effect = require("effect");
|
|
8
9
|
let _effect_platform = require("@effect/platform");
|
|
9
10
|
let node_fs_promises = require("node:fs/promises");
|
|
11
|
+
let node_path = require("node:path");
|
|
10
12
|
let _effect_cli = require("@effect/cli");
|
|
11
13
|
let _effect_platform_node = require("@effect/platform-node");
|
|
12
14
|
let yaml = require("yaml");
|
|
13
|
-
let node_path = require("node:path");
|
|
14
15
|
let node_fs = require("node:fs");
|
|
15
16
|
let node_os = require("node:os");
|
|
16
17
|
let node_child_process = require("node:child_process");
|
|
17
18
|
let node_crypto = require("node:crypto");
|
|
18
19
|
//#region package.json
|
|
19
|
-
var version$1 = "0.1.
|
|
20
|
+
var version$1 = "0.1.28";
|
|
20
21
|
//#endregion
|
|
21
22
|
//#region ../template/src/extract.ts
|
|
22
23
|
/** Reads escapes too, so text the renderer leaves literal is never reported as
|
|
@@ -81,7 +82,7 @@ const add = _effect_cli.Command.make("add", {
|
|
|
81
82
|
onSome: (wanted) => found.authMethods.find((entry) => entry.id === wanted)
|
|
82
83
|
});
|
|
83
84
|
if (method === void 0) return yield* note(`${integration} has no auth method called ${effect.Option.getOrElse(wantedMethod, () => "")}.`);
|
|
84
|
-
if (method.kind === "device") return yield* note(`${integration} signs in through a browser. Connect it at
|
|
85
|
+
if (method.kind === "device") return yield* note(`${integration} signs in through a browser. Connect it at ${require_errors.WEB_ORIGIN}/settings/connections.`);
|
|
85
86
|
const values = {};
|
|
86
87
|
for (const field of method.fields) values[field.name] = yield* readSecret(field.label);
|
|
87
88
|
const created = yield* api.connectors.add({ payload: {
|
|
@@ -639,6 +640,190 @@ const buildGithubCheck = (outcomes, webUrl) => {
|
|
|
639
640
|
};
|
|
640
641
|
};
|
|
641
642
|
//#endregion
|
|
643
|
+
//#region src/cli/labelled-row.ts
|
|
644
|
+
const LABEL_WIDTH = 9;
|
|
645
|
+
const labelled = (label, value, paint) => ` ${paint.dim(label.padEnd(LABEL_WIDTH))}${value}`;
|
|
646
|
+
const continued$1 = (value) => ` ${" ".repeat(LABEL_WIDTH)}${value}`;
|
|
647
|
+
//#endregion
|
|
648
|
+
//#region src/cli/paint.ts
|
|
649
|
+
const ESCAPE = String.fromCharCode(27);
|
|
650
|
+
const SHADES = {
|
|
651
|
+
blue: {
|
|
652
|
+
fallback: 111,
|
|
653
|
+
rgb: [
|
|
654
|
+
122,
|
|
655
|
+
162,
|
|
656
|
+
247
|
|
657
|
+
]
|
|
658
|
+
},
|
|
659
|
+
cyan: {
|
|
660
|
+
fallback: 80,
|
|
661
|
+
rgb: [
|
|
662
|
+
108,
|
|
663
|
+
196,
|
|
664
|
+
207
|
|
665
|
+
]
|
|
666
|
+
},
|
|
667
|
+
dim: {
|
|
668
|
+
fallback: 243,
|
|
669
|
+
rgb: [
|
|
670
|
+
118,
|
|
671
|
+
125,
|
|
672
|
+
135
|
|
673
|
+
]
|
|
674
|
+
},
|
|
675
|
+
green: {
|
|
676
|
+
fallback: 114,
|
|
677
|
+
rgb: [
|
|
678
|
+
108,
|
|
679
|
+
194,
|
|
680
|
+
135
|
|
681
|
+
]
|
|
682
|
+
},
|
|
683
|
+
lavender: {
|
|
684
|
+
fallback: 146,
|
|
685
|
+
rgb: [
|
|
686
|
+
170,
|
|
687
|
+
160,
|
|
688
|
+
204
|
|
689
|
+
]
|
|
690
|
+
},
|
|
691
|
+
magenta: {
|
|
692
|
+
fallback: 141,
|
|
693
|
+
rgb: [
|
|
694
|
+
182,
|
|
695
|
+
156,
|
|
696
|
+
246
|
|
697
|
+
]
|
|
698
|
+
},
|
|
699
|
+
red: {
|
|
700
|
+
fallback: 167,
|
|
701
|
+
rgb: [
|
|
702
|
+
229,
|
|
703
|
+
104,
|
|
704
|
+
107
|
|
705
|
+
]
|
|
706
|
+
},
|
|
707
|
+
rose: {
|
|
708
|
+
fallback: 181,
|
|
709
|
+
rgb: [
|
|
710
|
+
204,
|
|
711
|
+
158,
|
|
712
|
+
172
|
|
713
|
+
]
|
|
714
|
+
},
|
|
715
|
+
sand: {
|
|
716
|
+
fallback: 180,
|
|
717
|
+
rgb: [
|
|
718
|
+
200,
|
|
719
|
+
176,
|
|
720
|
+
138
|
|
721
|
+
]
|
|
722
|
+
},
|
|
723
|
+
slate: {
|
|
724
|
+
fallback: 110,
|
|
725
|
+
rgb: [
|
|
726
|
+
138,
|
|
727
|
+
164,
|
|
728
|
+
204
|
|
729
|
+
]
|
|
730
|
+
},
|
|
731
|
+
teal: {
|
|
732
|
+
fallback: 109,
|
|
733
|
+
rgb: [
|
|
734
|
+
128,
|
|
735
|
+
184,
|
|
736
|
+
178
|
|
737
|
+
]
|
|
738
|
+
},
|
|
739
|
+
yellow: {
|
|
740
|
+
fallback: 179,
|
|
741
|
+
rgb: [
|
|
742
|
+
217,
|
|
743
|
+
165,
|
|
744
|
+
91
|
|
745
|
+
]
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
const TRUE_COLOUR = /* @__PURE__ */ new Set(["truecolor", "24bit"]);
|
|
749
|
+
const wrap = (code) => (text) => `${ESCAPE}[${code}m${text}${ESCAPE}[0m`;
|
|
750
|
+
const shadeCode = ({ fallback, rgb }, trueColour) => trueColour ? `38;2;${rgb.join(";")}` : `38;5;${fallback}`;
|
|
751
|
+
const unpainted = (text) => text;
|
|
752
|
+
const colouredWith = (trueColour) => Object.fromEntries([["bold", wrap("1")], ...Object.entries(SHADES).map(([name, shade]) => [name, wrap(shadeCode(shade, trueColour))])]);
|
|
753
|
+
const MONOCHROME = Object.fromEntries(["bold", ...Object.keys(SHADES)].map((name) => [name, unpainted]));
|
|
754
|
+
const paletteFor = (colour) => colour ? colouredWith(TRUE_COLOUR.has(process.env.COLORTERM ?? "")) : MONOCHROME;
|
|
755
|
+
//#endregion
|
|
756
|
+
//#region src/cli/text-wrap.ts
|
|
757
|
+
const NARROWEST$1 = 20;
|
|
758
|
+
const LEADING_SPACE = /^\s*/;
|
|
759
|
+
const WORDS = /\s+/;
|
|
760
|
+
const TAB = /\t/g;
|
|
761
|
+
const CARRIAGE = /\r\n?/g;
|
|
762
|
+
const wrapLine = (line, width) => {
|
|
763
|
+
if (line.length <= width) return [line];
|
|
764
|
+
const indent = LEADING_SPACE.exec(line)?.[0] ?? "";
|
|
765
|
+
const lines = [];
|
|
766
|
+
let current = "";
|
|
767
|
+
for (const word of line.trim().split(WORDS)) {
|
|
768
|
+
const next = current === "" ? `${indent}${word}` : `${current} ${word}`;
|
|
769
|
+
if (next.length > width && current !== "") {
|
|
770
|
+
lines.push(current);
|
|
771
|
+
current = `${indent}${word}`;
|
|
772
|
+
} else current = next;
|
|
773
|
+
}
|
|
774
|
+
lines.push(current);
|
|
775
|
+
return lines;
|
|
776
|
+
};
|
|
777
|
+
const wrapText = (text, width) => {
|
|
778
|
+
const kept = [];
|
|
779
|
+
for (const line of text.replace(CARRIAGE, "\n").replace(TAB, " ").split("\n")) {
|
|
780
|
+
const trimmed = line.trimEnd();
|
|
781
|
+
if (trimmed !== "" || kept.length > 0 && kept.at(-1) !== "") kept.push(trimmed);
|
|
782
|
+
}
|
|
783
|
+
while (kept.at(-1) === "") kept.pop();
|
|
784
|
+
return kept.flatMap((line) => line === "" ? [""] : wrapLine(line, Math.max(NARROWEST$1, width)));
|
|
785
|
+
};
|
|
786
|
+
//#endregion
|
|
787
|
+
//#region src/cli/transcript-writer.ts
|
|
788
|
+
const PLAIN = {
|
|
789
|
+
colour: false,
|
|
790
|
+
width: 80
|
|
791
|
+
};
|
|
792
|
+
const NARROWEST = 40;
|
|
793
|
+
const UNKNOWN_WIDTH = 100;
|
|
794
|
+
const MARGIN = " ";
|
|
795
|
+
const INDENT = " ";
|
|
796
|
+
const WHITESPACE$1 = /\s+/g;
|
|
797
|
+
const terminalStyle = (colour) => colour && process.env.NO_COLOR === void 0 ? {
|
|
798
|
+
colour: true,
|
|
799
|
+
width: Math.max(NARROWEST, process.stderr.columns ?? UNKNOWN_WIDTH)
|
|
800
|
+
} : PLAIN;
|
|
801
|
+
const stderrStyle = () => terminalStyle(process.stderr.isTTY === true);
|
|
802
|
+
const flat = (text) => text.replace(WHITESPACE$1, " ").trim();
|
|
803
|
+
const clipped$1 = (text, width) => text.length > width ? `${text.slice(0, Math.max(1, width - 1))}…` : text;
|
|
804
|
+
const writerFor = (style) => {
|
|
805
|
+
const paint = paletteFor(style.colour);
|
|
806
|
+
const room = Math.max(1, style.width - 2 - 2);
|
|
807
|
+
const line = (text) => `${MARGIN}${text}`;
|
|
808
|
+
const nested = (text, depth = 1) => line(`${INDENT.repeat(depth)}${text}`);
|
|
809
|
+
const indented = (text, depth, tone = (row) => row) => wrapText(text, room - 2 * (depth - 1)).map((row) => row === "" ? "" : nested(tone(row), depth));
|
|
810
|
+
const header = ({ caseName, ordinal, variant }) => line(`${paint.bold(caseName)} ${paint.dim(variant)}${ordinal === null ? "" : paint.dim(` · trial ${ordinal}`)}`);
|
|
811
|
+
const heading = (glyph, label, tone) => line(tone(`${glyph} ${paint.bold(label)}`));
|
|
812
|
+
const branch = (text) => nested(`${paint.dim("├")} ${text}`);
|
|
813
|
+
const close = (text) => nested(`${paint.dim("└")} ${text}`);
|
|
814
|
+
return {
|
|
815
|
+
branch,
|
|
816
|
+
close,
|
|
817
|
+
header,
|
|
818
|
+
heading,
|
|
819
|
+
indented,
|
|
820
|
+
line,
|
|
821
|
+
nested,
|
|
822
|
+
paint,
|
|
823
|
+
room
|
|
824
|
+
};
|
|
825
|
+
};
|
|
826
|
+
//#endregion
|
|
642
827
|
//#region src/cli/eval-report.ts
|
|
643
828
|
const reportJson = effect.Schema.encodeSync(effect.Schema.parseJson(effect.Schema.Array(SuiteOutcome)));
|
|
644
829
|
const appendSummary = (text) => effect.Effect.gen(function* () {
|
|
@@ -647,7 +832,8 @@ const appendSummary = (text) => effect.Effect.gen(function* () {
|
|
|
647
832
|
});
|
|
648
833
|
const reportStarted = (label, id) => effect.Effect.gen(function* () {
|
|
649
834
|
const url = batchUrl(yield* require_errors.webUrlConfig, id);
|
|
650
|
-
|
|
835
|
+
const paint = paletteFor(stderrStyle().colour);
|
|
836
|
+
yield* note(labelled("Watch", `${url} ${paint.dim(label)}`, paint));
|
|
651
837
|
yield* appendSummary(`[Batch ${id}](${url}) started.`);
|
|
652
838
|
});
|
|
653
839
|
const writeReport = (outcomes, path) => effect.Effect.gen(function* () {
|
|
@@ -758,20 +944,19 @@ const CONCERN_REASONS = {
|
|
|
758
944
|
//#region src/cli/eval-usage.ts
|
|
759
945
|
const THOUSAND = 1e3;
|
|
760
946
|
const MILLION = 1e6;
|
|
761
|
-
const
|
|
762
|
-
const batchUsage = (batch) => {
|
|
947
|
+
const sumUsage = (readings, totalOf, usd) => {
|
|
763
948
|
const concerns = /* @__PURE__ */ new Set();
|
|
764
949
|
let inputTokens = 0;
|
|
765
950
|
let outputTokens = 0;
|
|
766
951
|
let totalTokens = 0;
|
|
767
|
-
for (const
|
|
768
|
-
if (!
|
|
769
|
-
inputTokens +=
|
|
770
|
-
outputTokens +=
|
|
771
|
-
totalTokens +=
|
|
952
|
+
for (const reading of readings) {
|
|
953
|
+
if (!reading.usage) continue;
|
|
954
|
+
inputTokens += reading.usage.inputTokens;
|
|
955
|
+
outputTokens += reading.usage.outputTokens;
|
|
956
|
+
totalTokens += totalOf(reading.usage);
|
|
772
957
|
for (const concern of usageConcerns({
|
|
773
|
-
turns:
|
|
774
|
-
usage:
|
|
958
|
+
turns: reading.commands,
|
|
959
|
+
usage: reading.usage
|
|
775
960
|
})) concerns.add(concern);
|
|
776
961
|
}
|
|
777
962
|
return {
|
|
@@ -779,42 +964,20 @@ const batchUsage = (batch) => {
|
|
|
779
964
|
inputTokens,
|
|
780
965
|
outputTokens,
|
|
781
966
|
totalTokens,
|
|
782
|
-
usd
|
|
967
|
+
usd
|
|
783
968
|
};
|
|
784
969
|
};
|
|
970
|
+
const batchUsage = (batch) => sumUsage(batch.runs.flatMap((run) => run.trials), (usage) => usage.totalTokens, batch.costs?.estimatedEquivalentUsd ?? null);
|
|
785
971
|
const formatTokens = (value) => {
|
|
786
972
|
if (value >= MILLION) return `${(value / MILLION).toFixed(1)}M`;
|
|
787
973
|
return value >= THOUSAND ? `${Math.round(value / THOUSAND)}k` : String(value);
|
|
788
974
|
};
|
|
789
|
-
const formatUsd = (value) => value <
|
|
975
|
+
const formatUsd = (value) => value < .01 ? "<$0.01" : `$${value.toFixed(2)}`;
|
|
790
976
|
const usageLines = (usage) => {
|
|
791
977
|
if (usage.totalTokens === 0) return [];
|
|
792
978
|
const spend = usage.usd === null ? "" : `, ${formatUsd(usage.usd)} est.`;
|
|
793
979
|
return [`${formatTokens(usage.totalTokens)} tokens (${formatTokens(usage.inputTokens)} in, ${formatTokens(usage.outputTokens)} out)${spend}`, ...usage.concerns.map((concern) => CONCERN_REASONS[concern])];
|
|
794
980
|
};
|
|
795
|
-
const localUsage = (cases, costs) => {
|
|
796
|
-
const concerns = /* @__PURE__ */ new Set();
|
|
797
|
-
let inputTokens = 0;
|
|
798
|
-
let outputTokens = 0;
|
|
799
|
-
let totalTokens = 0;
|
|
800
|
-
for (const one of cases) {
|
|
801
|
-
if (!one.usage) continue;
|
|
802
|
-
inputTokens += one.usage.inputTokens;
|
|
803
|
-
outputTokens += one.usage.outputTokens;
|
|
804
|
-
totalTokens += one.usage.inputTokens + one.usage.outputTokens;
|
|
805
|
-
for (const concern of usageConcerns({
|
|
806
|
-
turns: one.commands,
|
|
807
|
-
usage: one.usage
|
|
808
|
-
})) concerns.add(concern);
|
|
809
|
-
}
|
|
810
|
-
return {
|
|
811
|
-
concerns: [...concerns],
|
|
812
|
-
inputTokens,
|
|
813
|
-
outputTokens,
|
|
814
|
-
totalTokens,
|
|
815
|
-
usd: costs?.estimatedEquivalentUsd ?? null
|
|
816
|
-
};
|
|
817
|
-
};
|
|
818
981
|
const PAYERS = [
|
|
819
982
|
"model",
|
|
820
983
|
"user",
|
|
@@ -824,7 +987,16 @@ const breakdownLine = (costs) => {
|
|
|
824
987
|
const parts = PAYERS.flatMap((component) => costs?.components.filter((part) => part.component === component).map(({ usd }) => `${require_errors.COST_COMPONENT_LABELS[component]} ${usd === null ? "not priced" : formatUsd(usd)}`) ?? []);
|
|
825
988
|
return parts.length > 1 ? [parts.join(", ")] : [];
|
|
826
989
|
};
|
|
827
|
-
const
|
|
990
|
+
const localUsage = (cases, costs = null) => {
|
|
991
|
+
const [spend, ...concerns] = usageLines(sumUsage(cases, (usage) => usage.inputTokens + usage.outputTokens, costs?.estimatedEquivalentUsd ?? null));
|
|
992
|
+
return spend === void 0 ? {
|
|
993
|
+
concerns: [],
|
|
994
|
+
lines: []
|
|
995
|
+
} : {
|
|
996
|
+
concerns,
|
|
997
|
+
lines: [spend, ...breakdownLine(costs)]
|
|
998
|
+
};
|
|
999
|
+
};
|
|
828
1000
|
//#endregion
|
|
829
1001
|
//#region ../schema/src/domain/shell-word.ts
|
|
830
1002
|
const ESCAPED_IN_DOUBLE = /* @__PURE__ */ new Set([
|
|
@@ -921,117 +1093,153 @@ const callSubjectOf = (input) => {
|
|
|
921
1093
|
return firstText(SUBJECT_KEYS.map((key) => fields[key])) ?? firstText(Object.values(fields));
|
|
922
1094
|
};
|
|
923
1095
|
//#endregion
|
|
924
|
-
//#region src/
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
bold: unpainted,
|
|
941
|
-
cyan: unpainted,
|
|
942
|
-
dim: unpainted,
|
|
943
|
-
green: unpainted,
|
|
944
|
-
magenta: unpainted,
|
|
945
|
-
red: unpainted,
|
|
946
|
-
yellow: unpainted
|
|
947
|
-
};
|
|
948
|
-
const paletteFor = (colour) => colour ? COLOURED : MONOCHROME;
|
|
949
|
-
//#endregion
|
|
950
|
-
//#region src/cli/text-wrap.ts
|
|
951
|
-
const NARROWEST$1 = 20;
|
|
952
|
-
const LEADING_SPACE = /^\s*/;
|
|
953
|
-
const WORDS = /\s+/;
|
|
954
|
-
const TAB = /\t/g;
|
|
955
|
-
const CARRIAGE = /\r\n?/g;
|
|
956
|
-
const wrapLine = (line, width) => {
|
|
957
|
-
if (line.length <= width) return [line];
|
|
958
|
-
const indent = LEADING_SPACE.exec(line)?.[0] ?? "";
|
|
959
|
-
const lines = [];
|
|
960
|
-
let current = "";
|
|
961
|
-
for (const word of line.trim().split(WORDS)) {
|
|
962
|
-
const next = current === "" ? `${indent}${word}` : `${current} ${word}`;
|
|
963
|
-
if (next.length > width && current !== "") {
|
|
964
|
-
lines.push(current);
|
|
965
|
-
current = `${indent}${word}`;
|
|
966
|
-
} else current = next;
|
|
1096
|
+
//#region ../schema/src/domain/step-title.ts
|
|
1097
|
+
const describeStep = (entry) => {
|
|
1098
|
+
switch (entry._tag) {
|
|
1099
|
+
case "command": return describeCommand(entry.command);
|
|
1100
|
+
case "fileChange": return describeFiles("wrote", "Wrote", entry.paths);
|
|
1101
|
+
case "toolCall": return {
|
|
1102
|
+
target: callSubjectOf(entry.input),
|
|
1103
|
+
title: `Called ${entry.name}`,
|
|
1104
|
+
verb: "called"
|
|
1105
|
+
};
|
|
1106
|
+
case "message": return {
|
|
1107
|
+
target: null,
|
|
1108
|
+
title: summarizeMessage(entry.text),
|
|
1109
|
+
verb: entry.role === "user" ? "you" : "agent"
|
|
1110
|
+
};
|
|
1111
|
+
default: return entry;
|
|
967
1112
|
}
|
|
968
|
-
lines.push(current);
|
|
969
|
-
return lines;
|
|
970
1113
|
};
|
|
971
|
-
const
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1114
|
+
const describeCommand = (command) => {
|
|
1115
|
+
const segments = splitSegments(commandText(command));
|
|
1116
|
+
const [first] = segments;
|
|
1117
|
+
if (first === void 0) return {
|
|
1118
|
+
target: null,
|
|
1119
|
+
title: "Ran a command",
|
|
1120
|
+
verb: "ran"
|
|
1121
|
+
};
|
|
1122
|
+
const written = segments.flatMap(redirectTargetOf);
|
|
1123
|
+
if (written.length > 0) return describeFiles("wrote", "Wrote", written);
|
|
1124
|
+
if (segments.every((words) => READERS.has(words[0] ?? ""))) {
|
|
1125
|
+
const files = segments.flatMap((words) => operandsOf(words).at(-1) ?? []);
|
|
1126
|
+
return files.length > 0 ? describeFiles("read", "Read", files) : describeRun(first);
|
|
976
1127
|
}
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1128
|
+
return SEARCHERS.has(first[0] ?? "") ? describeSearch(first) : describeRun(first);
|
|
1129
|
+
};
|
|
1130
|
+
const plainText = (text) => text.replace(MARKUP, "").replace(WHITESPACE, " ").trim();
|
|
1131
|
+
const summarizeMessage = (text) => {
|
|
1132
|
+
const plain = plainText(text);
|
|
1133
|
+
return SENTENCE.exec(plain)?.[1] ?? plain;
|
|
1134
|
+
};
|
|
1135
|
+
const READERS = /* @__PURE__ */ new Set([
|
|
1136
|
+
"bat",
|
|
1137
|
+
"cat",
|
|
1138
|
+
"head",
|
|
1139
|
+
"less",
|
|
1140
|
+
"nl",
|
|
1141
|
+
"sed",
|
|
1142
|
+
"tail"
|
|
1143
|
+
]);
|
|
1144
|
+
const SEARCHERS = /* @__PURE__ */ new Set([
|
|
1145
|
+
"ag",
|
|
1146
|
+
"fd",
|
|
1147
|
+
"find",
|
|
1148
|
+
"grep",
|
|
1149
|
+
"ls",
|
|
1150
|
+
"rg",
|
|
1151
|
+
"tree"
|
|
1152
|
+
]);
|
|
1153
|
+
const RUNNERS = /* @__PURE__ */ new Set([
|
|
1154
|
+
"bunx",
|
|
1155
|
+
"npx",
|
|
1156
|
+
"pnpx"
|
|
1157
|
+
]);
|
|
1158
|
+
const SCRIPT_RUNNERS = /* @__PURE__ */ new Set([
|
|
1159
|
+
"bun",
|
|
1160
|
+
"npm",
|
|
1161
|
+
"pnpm",
|
|
1162
|
+
"yarn"
|
|
1163
|
+
]);
|
|
1164
|
+
const TOKEN$1 = /'[^']*'|"[^"]*"|&&|\|\||[|;]|[^\s|;&]+/g;
|
|
1165
|
+
const SEPARATORS = /* @__PURE__ */ new Set([
|
|
1166
|
+
"&&",
|
|
1167
|
+
"||",
|
|
1168
|
+
";"
|
|
1169
|
+
]);
|
|
1170
|
+
const QUOTES = /^['"]|['"]$/g;
|
|
1171
|
+
const MARKUP = /[*`#>_]+/g;
|
|
1172
|
+
const SENTENCE = /^(.+?[.!?])(?:\s|$)/;
|
|
991
1173
|
const WHITESPACE = /\s+/g;
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1174
|
+
const splitSegments = (script) => {
|
|
1175
|
+
const segments = [[]];
|
|
1176
|
+
let piped = false;
|
|
1177
|
+
for (const token of script.match(TOKEN$1) ?? []) if (SEPARATORS.has(token)) {
|
|
1178
|
+
segments.push([]);
|
|
1179
|
+
piped = false;
|
|
1180
|
+
} else if (token === "|") piped = true;
|
|
1181
|
+
else if (!piped) segments.at(-1)?.push(token.replace(QUOTES, ""));
|
|
1182
|
+
return segments.filter((words) => words.length > 0);
|
|
1183
|
+
};
|
|
1184
|
+
const REDIRECT = /^>>?/;
|
|
1185
|
+
const DISCARDED = "/dev/null";
|
|
1186
|
+
const targetAt = (words, index) => {
|
|
1187
|
+
const word = words[index] ?? "";
|
|
1188
|
+
if (word === ">" || word === ">>") return words[index + 1];
|
|
1189
|
+
return REDIRECT.test(word) ? word.replace(REDIRECT, "") : void 0;
|
|
1190
|
+
};
|
|
1191
|
+
const redirectTargetOf = (words) => words.flatMap((_, index) => {
|
|
1192
|
+
const target = targetAt(words, index);
|
|
1193
|
+
return target === void 0 || target === "" || target === DISCARDED ? [] : [target];
|
|
1194
|
+
});
|
|
1195
|
+
const operandsOf = (words) => words.slice(1).filter((word) => !word.startsWith("-"));
|
|
1196
|
+
const baseName = (path) => path.split("/").at(-1) ?? path;
|
|
1197
|
+
const describeFiles = (verb, word, paths) => {
|
|
1198
|
+
const files = paths.map(baseName);
|
|
1199
|
+
const [only] = files;
|
|
1200
|
+
return {
|
|
1201
|
+
target: files.join(", "),
|
|
1202
|
+
title: files.length === 1 && only !== void 0 ? `${word} ${only}` : `${word} ${files.length} files`,
|
|
1203
|
+
verb
|
|
1008
1204
|
};
|
|
1009
|
-
|
|
1010
|
-
|
|
1205
|
+
};
|
|
1206
|
+
const describeSearch = (words) => {
|
|
1207
|
+
const [program] = words;
|
|
1208
|
+
const operands = operandsOf(words);
|
|
1209
|
+
if (program === "ls" || program === "tree" || words.includes("--files")) return {
|
|
1210
|
+
target: program === "ls" ? operands[0] ?? null : null,
|
|
1211
|
+
title: "Listed files",
|
|
1212
|
+
verb: "searched"
|
|
1213
|
+
};
|
|
1214
|
+
const [pattern, where = null] = operands;
|
|
1011
1215
|
return {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
heading,
|
|
1016
|
-
indented,
|
|
1017
|
-
line,
|
|
1018
|
-
paint,
|
|
1019
|
-
room
|
|
1216
|
+
target: where,
|
|
1217
|
+
title: pattern === void 0 ? "Searched files" : `Searched for ${pattern}`,
|
|
1218
|
+
verb: "searched"
|
|
1020
1219
|
};
|
|
1021
1220
|
};
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1221
|
+
const describeRun = (words) => {
|
|
1222
|
+
const [program = "command", first, second] = words;
|
|
1223
|
+
const operands = operandsOf(words);
|
|
1224
|
+
if (RUNNERS.has(program) && first !== void 0) {
|
|
1225
|
+
const tool = [first, operands[1]].filter(Boolean).join(" ");
|
|
1226
|
+
return {
|
|
1227
|
+
target: tool,
|
|
1228
|
+
title: `Ran ${tool}`,
|
|
1229
|
+
verb: "ran"
|
|
1230
|
+
};
|
|
1030
1231
|
}
|
|
1031
|
-
if (
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1232
|
+
if (SCRIPT_RUNNERS.has(program) && first === "run" && second !== void 0) return {
|
|
1233
|
+
target: second,
|
|
1234
|
+
title: `Ran the ${second} script`,
|
|
1235
|
+
verb: "ran"
|
|
1236
|
+
};
|
|
1237
|
+
const tool = program === "git" && first !== void 0 ? `git ${first}` : program;
|
|
1238
|
+
return {
|
|
1239
|
+
target: tool,
|
|
1240
|
+
title: `Ran ${tool}`,
|
|
1241
|
+
verb: "ran"
|
|
1242
|
+
};
|
|
1035
1243
|
};
|
|
1036
1244
|
//#endregion
|
|
1037
1245
|
//#region src/cli/duration.ts
|
|
@@ -1047,9 +1255,55 @@ const formatDuration = (ms) => {
|
|
|
1047
1255
|
return `${Math.floor(seconds / MINUTE$1)}m${String(seconds % MINUTE$1).padStart(2, "0")}s`;
|
|
1048
1256
|
};
|
|
1049
1257
|
//#endregion
|
|
1258
|
+
//#region src/cli/transcript-step.ts
|
|
1259
|
+
const BRANCH_WIDTH = 2;
|
|
1260
|
+
const VERB_WIDTH = 7;
|
|
1261
|
+
const NOTABLE_MS = 1e3;
|
|
1262
|
+
const GAP = " ";
|
|
1263
|
+
const VERB_TONES = {
|
|
1264
|
+
ran: "sand",
|
|
1265
|
+
read: "slate",
|
|
1266
|
+
search: "teal",
|
|
1267
|
+
wrote: "rose"
|
|
1268
|
+
};
|
|
1269
|
+
const unless = (text, tone) => text === "" ? "" : tone(text);
|
|
1270
|
+
const tookBetween = (startedAt, finishedAt) => startedAt === null || startedAt === void 0 || finishedAt === null ? null : Math.max(0, finishedAt - startedAt);
|
|
1271
|
+
const commandParts = (step) => {
|
|
1272
|
+
const title = describeCommand(step.command);
|
|
1273
|
+
return {
|
|
1274
|
+
detail: title.verb === "read" || title.verb === "wrote" ? title.target ?? title.title : flat(commandText(step.command)),
|
|
1275
|
+
failure: step.exitCode !== null && step.exitCode !== 0 ? `exit ${step.exitCode}` : null,
|
|
1276
|
+
tookMs: tookBetween(step.startedAtMillis, step.finishedAtMillis),
|
|
1277
|
+
verb: title.verb === "searched" ? "search" : title.verb
|
|
1278
|
+
};
|
|
1279
|
+
};
|
|
1280
|
+
const partsOf = (step) => {
|
|
1281
|
+
if (step._tag === "command") return commandParts(step);
|
|
1282
|
+
if (step._tag === "fileChange") return {
|
|
1283
|
+
detail: describeStep(step).target ?? "",
|
|
1284
|
+
failure: null,
|
|
1285
|
+
tookMs: null,
|
|
1286
|
+
verb: "wrote"
|
|
1287
|
+
};
|
|
1288
|
+
return {
|
|
1289
|
+
detail: flat(callSubjectOf(step.input) ?? ""),
|
|
1290
|
+
failure: step.error === void 0 ? null : "failed",
|
|
1291
|
+
tookMs: tookBetween(step.startedAtMillis, step.finishedAtMillis),
|
|
1292
|
+
verb: step.name
|
|
1293
|
+
};
|
|
1294
|
+
};
|
|
1295
|
+
const stepLine = (step, { branch, paint, room }) => {
|
|
1296
|
+
const { detail, failure, tookMs, verb } = partsOf(step);
|
|
1297
|
+
const took = tookMs === null || tookMs < NOTABLE_MS ? "" : `${GAP}${formatDuration(tookMs)}`;
|
|
1298
|
+
const failed = failure === null ? "" : `${GAP}✗ ${failure}`;
|
|
1299
|
+
const label = verb.padEnd(VERB_WIDTH);
|
|
1300
|
+
const width = room - BRANCH_WIDTH - label.length - 1 - took.length - failed.length;
|
|
1301
|
+
return branch(`${(failure === null ? paint[VERB_TONES[verb] ?? "lavender"] : paint.red)(label)} ${clipped$1(detail, Math.max(1, width))}${unless(took, paint.dim)}${unless(failed, paint.red)}`);
|
|
1302
|
+
};
|
|
1303
|
+
//#endregion
|
|
1050
1304
|
//#region src/cli/transcript-turn.ts
|
|
1051
|
-
const CENT = .01;
|
|
1052
1305
|
const openedTurn = (previous, startedAt) => ({
|
|
1306
|
+
answering: false,
|
|
1053
1307
|
costUsd: null,
|
|
1054
1308
|
endedAt: null,
|
|
1055
1309
|
number: (previous?.number ?? 0) + 1,
|
|
@@ -1070,7 +1324,7 @@ const repliedTurn = (previous, reply) => {
|
|
|
1070
1324
|
const durationOf = (turn) => turn.startedAt === null || turn.endedAt === null ? null : formatDuration(Math.max(0, turn.endedAt - turn.startedAt));
|
|
1071
1325
|
const costOf = (turn) => {
|
|
1072
1326
|
if (turn.costUsd === null) return null;
|
|
1073
|
-
return turn.costUsd > 0 && turn.costUsd <
|
|
1327
|
+
return turn.costUsd > 0 && turn.costUsd < .01 ? "<$0.01" : `$${turn.costUsd.toFixed(2)}`;
|
|
1074
1328
|
};
|
|
1075
1329
|
const turnFacts = (turn) => [
|
|
1076
1330
|
`turn ${turn.number}`,
|
|
@@ -1087,11 +1341,19 @@ const validationSummary = (validation) => {
|
|
|
1087
1341
|
};
|
|
1088
1342
|
//#endregion
|
|
1089
1343
|
//#region src/cli/outcome-mark.ts
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1344
|
+
const GLYPHS = {
|
|
1345
|
+
failed: "✗",
|
|
1346
|
+
passed: "✓",
|
|
1347
|
+
"timed out": "○",
|
|
1348
|
+
void: "○"
|
|
1349
|
+
};
|
|
1350
|
+
const outcomeTone = (status, paint) => {
|
|
1351
|
+
if (status === "passed") return paint.green;
|
|
1352
|
+
if (status === "failed") return paint.red;
|
|
1353
|
+
return status in GLYPHS ? paint.yellow : paint.dim;
|
|
1094
1354
|
};
|
|
1355
|
+
const outcomeGlyph = (status, paint) => outcomeTone(status, paint)(GLYPHS[status] ?? "·");
|
|
1356
|
+
const outcomeMark = (status, paint) => outcomeTone(status, paint)(status in GLYPHS ? `${GLYPHS[status]} ${status}` : status);
|
|
1095
1357
|
//#endregion
|
|
1096
1358
|
//#region src/cli/transcript-verdict.ts
|
|
1097
1359
|
const SUMMARY_LINES = 3;
|
|
@@ -1109,39 +1371,30 @@ const checksOf = (verdict) => {
|
|
|
1109
1371
|
summary: null
|
|
1110
1372
|
}));
|
|
1111
1373
|
};
|
|
1112
|
-
const
|
|
1113
|
-
if (status === "passed") return paint.green("✓");
|
|
1114
|
-
if (status === "failed" || status === "error") return paint.red(status === "error" ? "!" : "✗");
|
|
1115
|
-
return paint.dim(status === "skipped" ? "–" : "·");
|
|
1116
|
-
};
|
|
1374
|
+
const failing = (check) => check.status === "failed" || check.status === "error";
|
|
1117
1375
|
const checkLines = (check, write) => {
|
|
1118
1376
|
const timing = check.durationMs === null ? "" : write.paint.dim(` · ${formatDuration(check.durationMs)}`);
|
|
1119
|
-
const
|
|
1120
|
-
const summary = check.summary === null || check.summary === check.name ? [] : write.indented(check.summary,
|
|
1121
|
-
return [write.
|
|
1377
|
+
const mark = write.paint.red(check.status === "error" ? "!" : "✗");
|
|
1378
|
+
const summary = check.summary === null || check.summary === check.name ? [] : write.indented(check.summary, 2).slice(0, SUMMARY_LINES);
|
|
1379
|
+
return [write.nested(`${mark} ${check.name}${timing}`), ...summary];
|
|
1122
1380
|
};
|
|
1123
1381
|
const outcomeOf$1 = (verdict, paint) => {
|
|
1124
1382
|
const mark = outcomeMark(verdict.status, paint);
|
|
1125
1383
|
if (verdict.status !== "void" && verdict.status !== "timed out") return mark;
|
|
1126
1384
|
const why = verdict.failure ?? (verdict.voidFields.length === 0 ? "not scored" : verdict.voidFields.join(", "));
|
|
1127
|
-
return `${mark}${paint.
|
|
1385
|
+
return `${mark}${paint.dim(` · ${why}`)}`;
|
|
1128
1386
|
};
|
|
1129
1387
|
const verdictLines = (verdict, write) => {
|
|
1130
1388
|
const checks = checksOf(verdict);
|
|
1131
1389
|
const passed = checks.filter((check) => check.status === "passed").length;
|
|
1132
1390
|
const tally = checks.length === 0 ? "" : write.paint.dim(` · ${passed} of ${checks.length} checks passed`);
|
|
1133
|
-
return [
|
|
1134
|
-
...checks.length === 0 ? [] : [...write.heading("checks", write.paint.blue), ...checks.flatMap((check) => checkLines(check, write))],
|
|
1135
|
-
write.blank,
|
|
1136
|
-
write.close(`${outcomeOf$1(verdict, write.paint)}${tally}`)
|
|
1137
|
-
];
|
|
1391
|
+
return [write.line(`${outcomeOf$1(verdict, write.paint)}${tally}`), ...checks.filter(failing).flatMap((check) => checkLines(check, write))];
|
|
1138
1392
|
};
|
|
1139
1393
|
//#endregion
|
|
1140
1394
|
//#region src/cli/transcript.ts
|
|
1141
1395
|
const EMPTY_TRANSCRIPT = {
|
|
1142
1396
|
closed: /* @__PURE__ */ new Set(),
|
|
1143
1397
|
current: null,
|
|
1144
|
-
printed: false,
|
|
1145
1398
|
turns: /* @__PURE__ */ new Map()
|
|
1146
1399
|
};
|
|
1147
1400
|
var Draft = class {
|
|
@@ -1150,29 +1403,41 @@ var Draft = class {
|
|
|
1150
1403
|
lines = [];
|
|
1151
1404
|
turns;
|
|
1152
1405
|
write;
|
|
1153
|
-
printed;
|
|
1154
1406
|
constructor(transcript, style) {
|
|
1155
1407
|
this.closed = new Set(transcript.closed);
|
|
1156
1408
|
this.current = transcript.current;
|
|
1157
|
-
this.printed = transcript.printed;
|
|
1158
1409
|
this.turns = new Map(transcript.turns);
|
|
1159
1410
|
this.write = writerFor(style);
|
|
1160
1411
|
}
|
|
1161
1412
|
enter(speaker) {
|
|
1162
1413
|
if (speaker.key !== this.current) {
|
|
1163
|
-
|
|
1164
|
-
this.lines.push(this.write.header(speaker));
|
|
1414
|
+
this.lines.push("", this.write.header(speaker));
|
|
1165
1415
|
this.current = speaker.key;
|
|
1166
1416
|
}
|
|
1167
1417
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1418
|
+
asUser(key, text, startedAt) {
|
|
1419
|
+
const { heading, indented, paint } = this.write;
|
|
1420
|
+
this.closeTurn(key);
|
|
1421
|
+
this.turns.set(key, openedTurn(this.turns.get(key), startedAt));
|
|
1422
|
+
this.lines.push("", heading("❯", "User", paint.blue), ...indented(text, 1));
|
|
1423
|
+
}
|
|
1424
|
+
asAgent(key) {
|
|
1425
|
+
const turn = this.turns.get(key) ?? openedTurn(void 0, null);
|
|
1426
|
+
if (!turn.answering) {
|
|
1427
|
+
const { heading, paint } = this.write;
|
|
1428
|
+
this.lines.push(heading("◆", "Agent", paint.magenta));
|
|
1429
|
+
}
|
|
1430
|
+
this.turns.set(key, {
|
|
1431
|
+
...turn,
|
|
1432
|
+
answering: true
|
|
1433
|
+
});
|
|
1170
1434
|
}
|
|
1171
1435
|
closeTurn(key) {
|
|
1172
1436
|
const turn = this.turns.get(key);
|
|
1173
1437
|
if (turn?.open === true) {
|
|
1174
|
-
const {
|
|
1175
|
-
|
|
1438
|
+
const { close, nested, paint } = this.write;
|
|
1439
|
+
const facts = turn.replied ? turnFacts(turn) : `${turnFacts(turn)} · no reply`;
|
|
1440
|
+
this.lines.push(turn.answering ? close(paint.dim(facts)) : nested(paint.dim(facts)));
|
|
1176
1441
|
this.turns.set(key, {
|
|
1177
1442
|
...turn,
|
|
1178
1443
|
open: false
|
|
@@ -1185,7 +1450,6 @@ var Draft = class {
|
|
|
1185
1450
|
transcript: {
|
|
1186
1451
|
closed: this.closed,
|
|
1187
1452
|
current: this.current,
|
|
1188
|
-
printed: this.printed || this.lines.length > 0,
|
|
1189
1453
|
turns: this.turns
|
|
1190
1454
|
}
|
|
1191
1455
|
};
|
|
@@ -1193,20 +1457,19 @@ var Draft = class {
|
|
|
1193
1457
|
};
|
|
1194
1458
|
const transcribe = (transcript, spoken, style) => {
|
|
1195
1459
|
const draft = new Draft(transcript, style);
|
|
1196
|
-
const { paint } = draft.write;
|
|
1197
1460
|
for (const { entry, speaker } of spoken) {
|
|
1198
1461
|
draft.enter(speaker);
|
|
1199
|
-
if (entry._tag !== "message")
|
|
1200
|
-
|
|
1201
|
-
draft.
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1462
|
+
if (entry._tag !== "message") {
|
|
1463
|
+
draft.asAgent(speaker.key);
|
|
1464
|
+
draft.lines.push(stepLine(entry, draft.write));
|
|
1465
|
+
} else if (entry.role === "user") draft.asUser(speaker.key, entry.text, entry.finishedAtMillis ?? null);
|
|
1466
|
+
else {
|
|
1467
|
+
draft.asAgent(speaker.key);
|
|
1205
1468
|
draft.turns.set(speaker.key, repliedTurn(draft.turns.get(speaker.key), {
|
|
1206
1469
|
costUsd: entry.usage?.costUsd ?? null,
|
|
1207
1470
|
finishedAtMillis: entry.finishedAtMillis ?? null
|
|
1208
1471
|
}));
|
|
1209
|
-
draft.
|
|
1472
|
+
draft.lines.push(...draft.write.indented(entry.text, 1));
|
|
1210
1473
|
}
|
|
1211
1474
|
}
|
|
1212
1475
|
return draft.done();
|
|
@@ -1216,7 +1479,7 @@ const settle = (transcript, settled, style) => {
|
|
|
1216
1479
|
for (const { speaker, verdict } of settled) if (!draft.closed.has(speaker.key)) {
|
|
1217
1480
|
draft.enter(speaker);
|
|
1218
1481
|
draft.closeTurn(speaker.key);
|
|
1219
|
-
draft.lines.push(...verdictLines(verdict, draft.write));
|
|
1482
|
+
draft.lines.push("", ...verdictLines(verdict, draft.write));
|
|
1220
1483
|
draft.closed.add(speaker.key);
|
|
1221
1484
|
draft.current = null;
|
|
1222
1485
|
}
|
|
@@ -1236,12 +1499,7 @@ const makeTranscriber = (style) => effect.Effect.map(effect.Ref.make(EMPTY_TRANS
|
|
|
1236
1499
|
});
|
|
1237
1500
|
//#endregion
|
|
1238
1501
|
//#region src/cli/batch-progress.ts
|
|
1239
|
-
const
|
|
1240
|
-
const BOLD = "\x1B[1m";
|
|
1241
|
-
const GREEN = "\x1B[32m";
|
|
1242
|
-
const RED = "\x1B[31m";
|
|
1243
|
-
const YELLOW = "\x1B[33m";
|
|
1244
|
-
const RESET = "\x1B[0m";
|
|
1502
|
+
const { bold, dim, green, red, yellow } = paletteFor(true);
|
|
1245
1503
|
const DONE$1 = "●";
|
|
1246
1504
|
const RUNNING = "◐";
|
|
1247
1505
|
const FILLED = "▰";
|
|
@@ -1249,31 +1507,30 @@ const HOLLOW = "▱";
|
|
|
1249
1507
|
const PERCENT = 100;
|
|
1250
1508
|
const SECONDS = 1e3;
|
|
1251
1509
|
const MINUTE = 60;
|
|
1252
|
-
const paint = (colour, text) => `${colour}${text}${RESET}`;
|
|
1253
1510
|
const formatElapsed = (ms) => {
|
|
1254
1511
|
const total = Math.floor(ms / SECONDS);
|
|
1255
1512
|
const minutes = Math.floor(total / MINUTE);
|
|
1256
1513
|
return minutes === 0 ? `${total}s` : `${minutes}m${String(total % MINUTE).padStart(2, "0")}s`;
|
|
1257
1514
|
};
|
|
1258
1515
|
const formatStatus = (run) => {
|
|
1259
|
-
if (run.status === "finished") return
|
|
1260
|
-
return run.status === "failed" ?
|
|
1516
|
+
if (run.status === "finished") return green(DONE$1);
|
|
1517
|
+
return run.status === "failed" ? red(DONE$1) : yellow(RUNNING);
|
|
1261
1518
|
};
|
|
1262
1519
|
const formatTrialProgress = (run, trials) => {
|
|
1263
1520
|
const settled = run.trials.filter((trial) => trial.status !== "queued" && trial.status !== "running").length;
|
|
1264
|
-
return `${FILLED.repeat(settled)}${
|
|
1521
|
+
return `${FILLED.repeat(settled)}${dim(HOLLOW.repeat(Math.max(0, trials - settled)))}`;
|
|
1265
1522
|
};
|
|
1266
1523
|
const formatPassRate = (run) => {
|
|
1267
1524
|
const rate = run.distribution.passRate;
|
|
1268
|
-
if (run.distribution.scored === 0) return
|
|
1525
|
+
if (run.distribution.scored === 0) return dim("—");
|
|
1269
1526
|
const shown = `${Math.round(rate * PERCENT)}%`;
|
|
1270
|
-
return
|
|
1527
|
+
return (rate === 1 ? green : red)(shown);
|
|
1271
1528
|
};
|
|
1272
1529
|
const formatActivity = (run) => {
|
|
1273
1530
|
const running = run.trials.find((trial) => trial.status === "running");
|
|
1274
1531
|
if (running === void 0) return [];
|
|
1275
1532
|
const counts = [`${running.commands} cmd`, ...running.filesChanged.length === 0 ? [] : [`${running.filesChanged.length} files`]].join(", ");
|
|
1276
|
-
return [
|
|
1533
|
+
return [dim(` ${counts}`)];
|
|
1277
1534
|
};
|
|
1278
1535
|
const widest = (batch) => batch.runs.reduce((width, run) => Math.max(width, formatVariant(run.variant).length), 0);
|
|
1279
1536
|
const byCase = (batch) => Map.groupBy(batch.runs, (run) => run.case.id).values();
|
|
@@ -1281,7 +1538,7 @@ const formatBatch = (batch, trials, elapsedMs) => {
|
|
|
1281
1538
|
const width = widest(batch);
|
|
1282
1539
|
const lines = [];
|
|
1283
1540
|
for (const runs of byCase(batch)) {
|
|
1284
|
-
lines.push(` ${
|
|
1541
|
+
lines.push(` ${bold(runs[0]?.case.name ?? "")}`);
|
|
1285
1542
|
for (const run of runs) {
|
|
1286
1543
|
lines.push(` ${formatStatus(run)} ${formatVariant(run.variant).padEnd(width)} ${formatTrialProgress(run, trials)} ${formatPassRate(run)}`);
|
|
1287
1544
|
lines.push(...formatActivity(run));
|
|
@@ -1290,8 +1547,8 @@ const formatBatch = (batch, trials, elapsedMs) => {
|
|
|
1290
1547
|
}
|
|
1291
1548
|
const usage = batchUsage(batch);
|
|
1292
1549
|
const [spend, ...concerns] = usageLines(usage);
|
|
1293
|
-
lines.push(
|
|
1294
|
-
for (const concern of concerns) lines.push(
|
|
1550
|
+
lines.push(dim(spend === void 0 ? ` ${formatElapsed(elapsedMs)} elapsed` : ` ${formatElapsed(elapsedMs)} elapsed · ${spend}`));
|
|
1551
|
+
for (const concern of concerns) lines.push(yellow(` ${concern}`));
|
|
1295
1552
|
return lines;
|
|
1296
1553
|
};
|
|
1297
1554
|
const up = (rows) => `[${rows}A[0J`;
|
|
@@ -1374,7 +1631,7 @@ const followBatch = (id, api) => effect.Stream.unwrap(effect.Effect.gen(function
|
|
|
1374
1631
|
const TICK = 1e3;
|
|
1375
1632
|
const FLOOR_POLL = 15e3;
|
|
1376
1633
|
const running = (batch) => batch.status === "running";
|
|
1377
|
-
const settledIn = (batch) => batch.runs.flatMap((run) => run.trials).filter((trial) =>
|
|
1634
|
+
const settledIn = (batch) => batch.runs.flatMap((run) => run.trials).filter((trial) => require_errors.isSettledTrial(trial.status)).length;
|
|
1378
1635
|
var EvalWaitTimeout = class extends effect.Data.TaggedError("EvalWaitTimeout") {
|
|
1379
1636
|
get message() {
|
|
1380
1637
|
return `Timed out after ${this.seconds}s waiting for ${this.batchId}. The batch was not cancelled.`;
|
|
@@ -1412,15 +1669,15 @@ const waitForBatch = (id, watcher, timeoutSeconds) => effect.Effect.gen(function
|
|
|
1412
1669
|
}), effect.Effect.withSpan("Cli.waitForBatch", { attributes: { batchId: id } }));
|
|
1413
1670
|
//#endregion
|
|
1414
1671
|
//#region src/cli/open-browser.ts
|
|
1415
|
-
const
|
|
1416
|
-
const opened = (url) => {
|
|
1417
|
-
const chosen = process.env[BROWSER];
|
|
1672
|
+
const browserConfig = effect.Config.string("ANPORD_BROWSER").pipe(effect.Config.option, effect.Config.map(effect.Option.getOrUndefined));
|
|
1673
|
+
const opened = (url, chosen) => {
|
|
1418
1674
|
if (process.platform === "darwin") return chosen === void 0 ? _effect_platform.Command.make("open", url) : _effect_platform.Command.make("open", "-a", chosen, url);
|
|
1419
1675
|
return process.platform === "win32" ? _effect_platform.Command.make("start", url) : _effect_platform.Command.make(chosen ?? "xdg-open", url);
|
|
1420
1676
|
};
|
|
1421
1677
|
const openBrowser = (url) => effect.Effect.gen(function* () {
|
|
1422
|
-
|
|
1423
|
-
|
|
1678
|
+
const chosen = yield* browserConfig;
|
|
1679
|
+
if (chosen === "none") return;
|
|
1680
|
+
yield* (yield* _effect_platform.CommandExecutor.CommandExecutor).exitCode(opened(url, chosen));
|
|
1424
1681
|
}).pipe(effect.Effect.ignore);
|
|
1425
1682
|
//#endregion
|
|
1426
1683
|
//#region src/cli/batch-outcome.ts
|
|
@@ -2743,13 +3000,12 @@ const decodeGeminiLine = (line, at) => {
|
|
|
2743
3000
|
//#endregion
|
|
2744
3001
|
//#region ../eval/src/adapters/harness/opencode-config.ts
|
|
2745
3002
|
const CONFIG_VARIABLE = "OPENCODE_CONFIG_CONTENT";
|
|
2746
|
-
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2747
3003
|
const decodeJson$1 = effect.Schema.decodeUnknownOption(effect.Schema.parseJson());
|
|
2748
|
-
const parsed = (value) => decodeJson$1(value).pipe(effect.Option.filter(
|
|
3004
|
+
const parsed = (value) => decodeJson$1(value).pipe(effect.Option.filter(effect.Predicate.isRecord), effect.Option.getOrElse(() => ({})));
|
|
2749
3005
|
const stringsOf = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
2750
3006
|
const merged = (base, extra) => Object.fromEntries([...Object.entries(base), ...Object.entries(extra).map(([key, value]) => {
|
|
2751
3007
|
const current = base[key];
|
|
2752
|
-
return [key,
|
|
3008
|
+
return [key, effect.Predicate.isRecord(current) && effect.Predicate.isRecord(value) ? merged(current, value) : value];
|
|
2753
3009
|
})]);
|
|
2754
3010
|
const opencodeConfigContent = (env, systemPromptPath) => {
|
|
2755
3011
|
const own = parsed(env[CONFIG_VARIABLE]);
|
|
@@ -3218,20 +3474,28 @@ const localCache = (store, staging) => ({
|
|
|
3218
3474
|
//#endregion
|
|
3219
3475
|
//#region ../eval/src/adapters/sandbox/local-detached.ts
|
|
3220
3476
|
const call$1 = providerCall("local");
|
|
3477
|
+
const KILLED = 137;
|
|
3221
3478
|
const read$1 = (path) => effect.Effect.tryPromise(() => (0, node_fs_promises.readFile)(path, "utf8")).pipe(effect.Effect.orElseSucceed(() => ""));
|
|
3222
3479
|
const localDetached = (root, path, env) => {
|
|
3223
3480
|
const runs = (0, node_path.join)(root, ".anpord-runs");
|
|
3224
3481
|
const fileOf = (id, suffix) => (0, node_path.join)(runs, `${id}.${suffix}`);
|
|
3482
|
+
const exits = /* @__PURE__ */ new Map();
|
|
3483
|
+
const closedWith = /* @__PURE__ */ new Map();
|
|
3225
3484
|
return {
|
|
3226
|
-
progress: (started) => effect.Effect.
|
|
3227
|
-
|
|
3228
|
-
read$1(fileOf(started.id, "
|
|
3229
|
-
read$1(fileOf(started.id, "
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3485
|
+
progress: (started) => effect.Effect.gen(function* () {
|
|
3486
|
+
const closed = closedWith.get(started.id);
|
|
3487
|
+
const status = (yield* read$1(fileOf(started.id, "exit"))).trim();
|
|
3488
|
+
const [stdout, stderr] = yield* effect.Effect.all([read$1(fileOf(started.id, "out")), read$1(fileOf(started.id, "err"))], { concurrency: "unbounded" });
|
|
3489
|
+
return {
|
|
3490
|
+
exitCode: status === "" ? closed ?? null : Number(status),
|
|
3491
|
+
stderr,
|
|
3492
|
+
stdout
|
|
3493
|
+
};
|
|
3494
|
+
}),
|
|
3495
|
+
settled: (started) => {
|
|
3496
|
+
const exit = exits.get(started.id);
|
|
3497
|
+
return exit === void 0 ? effect.Effect.never : effect.Effect.promise(() => exit);
|
|
3498
|
+
},
|
|
3235
3499
|
start: (command, options) => effect.Effect.gen(function* () {
|
|
3236
3500
|
const id = `run-${yield* effect.Random.nextIntBetween(0, 1e6)}`;
|
|
3237
3501
|
const [out, err, exit] = [
|
|
@@ -3240,7 +3504,7 @@ const localDetached = (root, path, env) => {
|
|
|
3240
3504
|
"exit"
|
|
3241
3505
|
].map((suffix) => JSON.stringify(fileOf(id, suffix)));
|
|
3242
3506
|
yield* call$1(() => (0, node_fs_promises.mkdir)(runs, { recursive: true }));
|
|
3243
|
-
yield* effect.Effect.try({
|
|
3507
|
+
const child = yield* effect.Effect.try({
|
|
3244
3508
|
catch: unavailableFor("local"),
|
|
3245
3509
|
try: () => (0, node_child_process.spawn)(`{ ${command} ; } > ${out} 2> ${err}; printf %s $? > ${exit}`, {
|
|
3246
3510
|
cwd: options?.cwd ?? root,
|
|
@@ -3252,8 +3516,13 @@ const localDetached = (root, path, env) => {
|
|
|
3252
3516
|
},
|
|
3253
3517
|
shell: "/bin/bash",
|
|
3254
3518
|
stdio: "ignore"
|
|
3255
|
-
})
|
|
3519
|
+
})
|
|
3256
3520
|
});
|
|
3521
|
+
exits.set(id, new Promise((resolve) => child.once("close", (code) => {
|
|
3522
|
+
closedWith.set(id, code ?? KILLED);
|
|
3523
|
+
resolve();
|
|
3524
|
+
})));
|
|
3525
|
+
child.unref();
|
|
3257
3526
|
return {
|
|
3258
3527
|
id,
|
|
3259
3528
|
session: id
|
|
@@ -3514,6 +3783,9 @@ const stepResultsOf = (script, output) => {
|
|
|
3514
3783
|
};
|
|
3515
3784
|
const withoutMarks = (output) => output.replace(MARK_LINES, "");
|
|
3516
3785
|
//#endregion
|
|
3786
|
+
//#region ../eval/src/adapters/scorers/scorer-timeout.ts
|
|
3787
|
+
const SCORER_TIMEOUT_MS = 3e5;
|
|
3788
|
+
//#endregion
|
|
3517
3789
|
//#region ../eval/src/adapters/scorers/shell-pipeline.ts
|
|
3518
3790
|
const isUnguardedPipeline = (command) => {
|
|
3519
3791
|
let quote = null;
|
|
@@ -3693,10 +3965,7 @@ const executeValidation = (input) => effect.Effect.gen(function* () {
|
|
|
3693
3965
|
//#region ../eval/src/domain/answer-file.ts
|
|
3694
3966
|
const ANSWER_PATH = (home) => `${home}/.anpord-answer.txt`;
|
|
3695
3967
|
const TRANSCRIPT_PATH = (home) => `${home}/.anpord-transcript.txt`;
|
|
3696
|
-
const ANSWER_ENV = "ANPORD_ANSWER_FILE";
|
|
3697
|
-
const TRANSCRIPT_ENV = "ANPORD_TRANSCRIPT_FILE";
|
|
3698
3968
|
const TURNS_PATH = (home) => `${home}/.anpord-turns.json`;
|
|
3699
|
-
const TURNS_ENV = "ANPORD_TURNS_FILE";
|
|
3700
3969
|
//#endregion
|
|
3701
3970
|
//#region ../eval/src/domain/journal.ts
|
|
3702
3971
|
const commandsIn = (events) => events.filter((event) => event._tag === "Command").length;
|
|
@@ -3726,9 +3995,9 @@ const writeAnswer = (sandbox, events, turns) => effect.Effect.all([
|
|
|
3726
3995
|
sandbox.writeFile(TURNS_PATH(sandbox.home), JSON.stringify(turns))
|
|
3727
3996
|
], { discard: true });
|
|
3728
3997
|
const answerEnv = (sandbox) => ({
|
|
3729
|
-
[ANSWER_ENV]: ANSWER_PATH(sandbox.home),
|
|
3730
|
-
[TRANSCRIPT_ENV]: TRANSCRIPT_PATH(sandbox.home),
|
|
3731
|
-
[TURNS_ENV]: TURNS_PATH(sandbox.home)
|
|
3998
|
+
[require_sandbox_env.ANSWER_ENV]: ANSWER_PATH(sandbox.home),
|
|
3999
|
+
[require_sandbox_env.TRANSCRIPT_ENV]: TRANSCRIPT_PATH(sandbox.home),
|
|
4000
|
+
[require_sandbox_env.TURNS_ENV]: TURNS_PATH(sandbox.home)
|
|
3732
4001
|
});
|
|
3733
4002
|
const resultStatus = (passed) => passed ? "passed" : "failed";
|
|
3734
4003
|
const processError = (execution) => {
|
|
@@ -3795,7 +4064,7 @@ const scoreCommand = (request) => effect.Effect.gen(function* () {
|
|
|
3795
4064
|
...request.env,
|
|
3796
4065
|
...answerEnv(request.sandbox)
|
|
3797
4066
|
},
|
|
3798
|
-
timeoutMs:
|
|
4067
|
+
timeoutMs: SCORER_TIMEOUT_MS
|
|
3799
4068
|
},
|
|
3800
4069
|
records: [record],
|
|
3801
4070
|
observe: request.onValidation,
|
|
@@ -3905,11 +4174,11 @@ const scoreValidator = (request) => effect.Effect.gen(function* () {
|
|
|
3905
4174
|
command: `node ${shellQuote(path)}`,
|
|
3906
4175
|
options: {
|
|
3907
4176
|
cwd: request.workspace,
|
|
3908
|
-
timeoutMs:
|
|
4177
|
+
timeoutMs: SCORER_TIMEOUT_MS,
|
|
3909
4178
|
env: {
|
|
3910
4179
|
...request.env,
|
|
3911
4180
|
...answerEnv(request.sandbox),
|
|
3912
|
-
|
|
4181
|
+
[require_sandbox_env.PREPARE_VALUE_ENV]: JSON.stringify(request.prepared ?? {})
|
|
3913
4182
|
}
|
|
3914
4183
|
},
|
|
3915
4184
|
records,
|
|
@@ -4893,7 +5162,6 @@ const runProfileInstall = (input) => {
|
|
|
4893
5162
|
};
|
|
4894
5163
|
//#endregion
|
|
4895
5164
|
//#region ../eval/src/domain/prepare-output.ts
|
|
4896
|
-
const MARKER = "ANPORD_PREPARE_RESULT=";
|
|
4897
5165
|
const PREPARED_LIMIT = 16e3;
|
|
4898
5166
|
const CARRIED_LIMIT = PREPARED_LIMIT * 2;
|
|
4899
5167
|
const LINE_BREAK = /[\r\n]/;
|
|
@@ -4907,9 +5175,9 @@ const NOTHING_STREAMED = {
|
|
|
4907
5175
|
stdout: ""
|
|
4908
5176
|
};
|
|
4909
5177
|
const readPrepareValue = (output) => {
|
|
4910
|
-
const line = output.split("\n").findLast((entry) => entry.startsWith(
|
|
5178
|
+
const line = output.split("\n").findLast((entry) => entry.startsWith(require_sandbox_env.PREPARE_RESULT_MARKER));
|
|
4911
5179
|
if (line === void 0) return effect.Either.left("it printed no result, so its output was cut off");
|
|
4912
|
-
const encoded = line.slice(
|
|
5180
|
+
const encoded = line.slice(require_sandbox_env.PREPARE_RESULT_MARKER.length);
|
|
4913
5181
|
if (encoded.length > PREPARED_LIMIT) return effect.Either.left(`it returned ${encoded.length} characters and the limit is ${PREPARED_LIMIT}. Return a summary and keep large data in files`);
|
|
4914
5182
|
return decodeJson(encoded).pipe(effect.Either.mapLeft(() => "its result was not valid JSON"), effect.Either.flatMap((value) => effect.Either.mapLeft(decodeObject(value), () => "it returned something other than an object")));
|
|
4915
5183
|
};
|
|
@@ -4923,14 +5191,14 @@ const completeLines = (text) => {
|
|
|
4923
5191
|
const shownPrepareOutput = (carried, arrived, known) => {
|
|
4924
5192
|
const stdout = completeLines(carried.stdout + arrived.stdout);
|
|
4925
5193
|
const stderr = completeLines(carried.stderr + arrived.stderr);
|
|
4926
|
-
return [require_api_mocks.redactSecrets([...stdout.lines, ...stderr.lines].filter((line) => !line.includes(
|
|
5194
|
+
return [require_api_mocks.redactSecrets([...stdout.lines, ...stderr.lines].filter((line) => !line.includes(require_sandbox_env.PREPARE_RESULT_MARKER)).join("\n"), known).slice(-400).trim(), {
|
|
4927
5195
|
stderr: stderr.carry,
|
|
4928
5196
|
stdout: stdout.carry
|
|
4929
5197
|
}];
|
|
4930
5198
|
};
|
|
4931
5199
|
//#endregion
|
|
4932
5200
|
//#region ../eval/src/services/polled-command.ts
|
|
4933
|
-
const FIRST_CHECK_MS =
|
|
5201
|
+
const FIRST_CHECK_MS = 500;
|
|
4934
5202
|
const SLOWEST_CHECK_MS = 3e4;
|
|
4935
5203
|
const WIDENING = 1.5;
|
|
4936
5204
|
const CHECK_RETRY = effect.Schedule.exponential("200 millis").pipe(effect.Schedule.compose(effect.Schedule.recurs(3)));
|
|
@@ -4950,7 +5218,7 @@ const pollUntilDone = (input) => effect.Effect.gen(function* () {
|
|
|
4950
5218
|
}, {
|
|
4951
5219
|
body: () => effect.Effect.gen(function* () {
|
|
4952
5220
|
const millis = yield* effect.Ref.getAndUpdate(gap, (current) => Math.min(Math.round(current * WIDENING), SLOWEST_CHECK_MS));
|
|
4953
|
-
yield* input.suspender.waitFor(effect.Duration.millis(millis));
|
|
5221
|
+
yield* effect.Effect.raceFirst(input.suspender.waitFor(effect.Duration.millis(millis)), input.resumable.settled(started));
|
|
4954
5222
|
const progress = yield* check;
|
|
4955
5223
|
yield* report(progress);
|
|
4956
5224
|
return {
|
|
@@ -4972,9 +5240,8 @@ const pollUntilDone = (input) => effect.Effect.gen(function* () {
|
|
|
4972
5240
|
});
|
|
4973
5241
|
//#endregion
|
|
4974
5242
|
//#region ../eval/src/services/long-command.ts
|
|
4975
|
-
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
4976
5243
|
const runLongCommand = (sandbox, command, options) => effect.Effect.gen(function* () {
|
|
4977
|
-
const timeoutMs = options?.timeoutMs ??
|
|
5244
|
+
const timeoutMs = options?.timeoutMs ?? 12e4;
|
|
4978
5245
|
const exec = {
|
|
4979
5246
|
cwd: options?.cwd,
|
|
4980
5247
|
env: options?.env,
|
|
@@ -5016,7 +5283,7 @@ const runPrepare = (input) => effect.Effect.scoped(effect.Effect.gen(function* (
|
|
|
5016
5283
|
mounted: effect.Option.isSome(cache)
|
|
5017
5284
|
}));
|
|
5018
5285
|
const env = {
|
|
5019
|
-
...restored ? {
|
|
5286
|
+
...restored ? { [require_sandbox_env.CACHE_RESTORED_ENV]: "1" } : {},
|
|
5020
5287
|
...input.forwarded
|
|
5021
5288
|
};
|
|
5022
5289
|
const carried = yield* effect.Ref.make(NOTHING_STREAMED);
|
|
@@ -5099,7 +5366,7 @@ const prepareWorkspace = (input) => effect.Effect.gen(function* () {
|
|
|
5099
5366
|
sandbox: input.sandbox,
|
|
5100
5367
|
version: input.harnessVersion
|
|
5101
5368
|
});
|
|
5102
|
-
yield* runCommand(input.sandbox, `mkdir -p ${input.workspace}`, { timeoutMs:
|
|
5369
|
+
yield* runCommand(input.sandbox, `mkdir -p ${input.workspace}`, { timeoutMs: MKDIR_TIMEOUT_MS });
|
|
5103
5370
|
yield* materialiseStage(input, "home");
|
|
5104
5371
|
yield* materialise(input);
|
|
5105
5372
|
yield* materialiseStage(input, "workspace");
|
|
@@ -5734,7 +6001,7 @@ const runVariant = (request, variant, transcript, options) => effect.Effect.gen(
|
|
|
5734
6001
|
return yield* effect.Effect.forEach(request.cases.flatMap((subject) => ordinals.map((ordinal) => [subject, ordinal])), ([subject, ordinal]) => attempt(subject, ordinal), { concurrency: 1 });
|
|
5735
6002
|
}).pipe(effect.Effect.provide(options.credentials === void 0 || options.credentials.size === 0 ? EvalLocalLive : evalLocalWith(credentialResolverFrom(options.credentials))), effect.Effect.scoped);
|
|
5736
6003
|
const runLocally = (request, options = {}) => effect.Effect.gen(function* () {
|
|
5737
|
-
const transcript = yield* makeTranscriber(
|
|
6004
|
+
const transcript = yield* makeTranscriber(stderrStyle());
|
|
5738
6005
|
return (yield* effect.Effect.forEach(request.variants, (variant) => runVariant(request, variant, transcript, options), { concurrency: 1 })).flat();
|
|
5739
6006
|
}).pipe(effect.Effect.withConfigProvider(localConfig));
|
|
5740
6007
|
//#endregion
|
|
@@ -5869,32 +6136,44 @@ const runStoredCase = (caseId, variants, options, save) => effect.Effect.gen(fun
|
|
|
5869
6136
|
//#endregion
|
|
5870
6137
|
//#region src/cli/local-report.ts
|
|
5871
6138
|
const STATUSES = [
|
|
5872
|
-
"passed",
|
|
5873
6139
|
"failed",
|
|
6140
|
+
"timed out",
|
|
5874
6141
|
"void",
|
|
5875
|
-
"
|
|
6142
|
+
"passed"
|
|
5876
6143
|
];
|
|
5877
|
-
const trialName = (one, numbered) => `${one.name}
|
|
5878
|
-
const tallyOf = (cases
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
6144
|
+
const trialName = (one, numbered) => numbered ? `${one.name} #${one.ordinal}` : one.name;
|
|
6145
|
+
const tallyOf = (cases, paint) => {
|
|
6146
|
+
return `${STATUSES.flatMap((status) => {
|
|
6147
|
+
const count = cases.filter((one) => one.status === status).length;
|
|
6148
|
+
return count === 0 ? [] : [outcomeTone(status, paint)(`${count} ${status}`)];
|
|
6149
|
+
}).join(paint.dim(" | "))} ${paint.dim(`(${cases.length})`)}`;
|
|
6150
|
+
};
|
|
6151
|
+
const trialLines = (cases, paint) => {
|
|
5883
6152
|
const numbered = cases.some((one) => one.ordinal > 1);
|
|
5884
|
-
const
|
|
5885
|
-
const
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
})
|
|
6153
|
+
const nameWidth = Math.max(...cases.map((one) => trialName(one, numbered).length));
|
|
6154
|
+
const variantWidth = Math.max(...cases.map((one) => one.variant.length));
|
|
6155
|
+
return cases.flatMap((one) => [` ${outcomeGlyph(one.status, paint)} ${trialName(one, numbered).padEnd(nameWidth)} ${paint.dim(one.variant.padEnd(variantWidth))} ${paint.dim(formatDuration(one.durationMs))}`, ...one.reason === null ? [] : [` ${outcomeTone(one.status, paint)(one.status)} ${paint.dim(`· ${one.reason}`)}`]]);
|
|
6156
|
+
};
|
|
6157
|
+
const usageRows = (cases, costs, paint) => {
|
|
6158
|
+
const { concerns, lines } = localUsage(cases, costs);
|
|
6159
|
+
const [first, ...rest] = lines;
|
|
6160
|
+
return first === void 0 ? [] : [
|
|
6161
|
+
labelled("Usage", first, paint),
|
|
6162
|
+
...rest.map(continued$1),
|
|
6163
|
+
...concerns.map((concern) => continued$1(paint.yellow(`⚠ ${concern}`)))
|
|
5895
6164
|
];
|
|
5896
6165
|
};
|
|
5897
|
-
const
|
|
6166
|
+
const summaryLines = (label, cases, costs, link, paint = paletteFor(false)) => [
|
|
6167
|
+
...cases.length === 0 ? [] : [...trialLines(cases, paint), ""],
|
|
6168
|
+
labelled("Suite", label, paint),
|
|
6169
|
+
labelled("Trials", cases.length === 0 ? "none ran" : tallyOf(cases, paint), paint),
|
|
6170
|
+
...usageRows(cases, costs, paint),
|
|
6171
|
+
...effect.Option.match(link, {
|
|
6172
|
+
onNone: () => [],
|
|
6173
|
+
onSome: (url) => [labelled("Results", url, paint)]
|
|
6174
|
+
})
|
|
6175
|
+
];
|
|
6176
|
+
const reportLocal = (label, cases, costs, link) => note(["", ...summaryLines(label, cases, costs, link, paletteFor(stderrStyle().colour))].join("\n"));
|
|
5898
6177
|
const localProblems = (label, cases) => {
|
|
5899
6178
|
const missed = cases.filter((one) => one.status !== "passed").length;
|
|
5900
6179
|
return missed === 0 ? [] : [`${label}: ${missed} of ${cases.length} trials did not pass.`];
|
|
@@ -6036,7 +6315,7 @@ const whoami = _effect_cli.Command.make("whoami", { asJson: asJson$2 }, ({ asJso
|
|
|
6036
6315
|
if (wantsJson) return yield* json(found);
|
|
6037
6316
|
return yield* effect.Effect.forEach(whoamiLines(found), row);
|
|
6038
6317
|
})).pipe(_effect_cli.Command.withDescription("Show the organization and key ANPORD_API_KEY acts for"));
|
|
6039
|
-
const announceOrganization = require_errors.AnpordApi.pipe(effect.Effect.flatMap((api) => api.auth.whoami({ payload: {} })), effect.Effect.flatMap(({ organization }) => note(
|
|
6318
|
+
const announceOrganization = require_errors.AnpordApi.pipe(effect.Effect.flatMap((api) => api.auth.whoami({ payload: {} })), effect.Effect.flatMap(({ organization }) => note(labelled("Org", `${organization.name} (${organization.slug})`, paletteFor(stderrStyle().colour)))), effect.Effect.ignore);
|
|
6040
6319
|
//#endregion
|
|
6041
6320
|
//#region src/cli/suite-local.ts
|
|
6042
6321
|
var LocalTimeout = class extends effect.Data.TaggedError("LocalTimeout") {
|
|
@@ -6246,7 +6525,7 @@ const commandsWith = (prompts) => [
|
|
|
6246
6525
|
const commands = commandsWith(false);
|
|
6247
6526
|
//#endregion
|
|
6248
6527
|
//#region src/cli/failure.ts
|
|
6249
|
-
const MISSING_KEY =
|
|
6528
|
+
const MISSING_KEY = `Set ANPORD_API_KEY to an API key from ${require_errors.WEB_ORIGIN}/settings/keys`;
|
|
6250
6529
|
const EXIT_GATE_FAILED = 2;
|
|
6251
6530
|
const tagOf = (error) => typeof error === "object" && error !== null && "_tag" in error ? error._tag : void 0;
|
|
6252
6531
|
const describe = (error) => {
|