@tracecode/harness 0.9.8 → 0.9.9
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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
|
|
5
5
|
This repo uses Git tags as release boundaries. Version notes below summarize what shipped in each tagged release.
|
|
6
6
|
|
|
7
|
+
## [0.9.9] - 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added a unified kernel journal: one append-only, absolutely-ordered log (a single sequence counter) of every kernel-observed transaction — filesystem writes, process `exec`/`exit`, and HTTP requests — emitted only from kernel-internal observation points, so in-workspace code cannot forge entries and every event is attributed by actor/pid. `Authorization` is stored as a non-reversible fingerprint (never the raw value), and `externalHttp` responses may attach an opaque `annotation`. The journal is exposed both live on the workspace event stream (`kernel-journal` events, ordered consistently with buffered output) and as a queryable `journal(sinceSeq?)` snapshot. HTTP journal records additionally carry redacted grading metadata: idempotency-key and request/response body fingerprints, plus `Content-Type`, `Retry-After`, and `X-RateLimit-*` values.
|
|
12
|
+
- Added a virtual-network host registry (`resolveHost`) and a `ping` reachability command: loopback, in-workspace HTTP listeners, and `externalHttp`-allowlisted hosts all resolve through one primitive with deterministic, hash-derived synthetic IP and latency (no wall clock or RNG). `ping` produces ping-shaped output and fails gracefully with an unknown-host error instead of a raw kernel throw.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Unified host reachability across `curl`, `ping`, and `workspace.http.request` through `resolveHost`: an unknown host now returns a typed `EHOSTUNREACH` (rendered by `curl` as exit 7, "Host unreachable") rather than leaking a raw kernel error, while a known host with a closed port still returns `ECONNREFUSED`; host allowlist/blocklist policy is unchanged. Also corrected the diagnostic port reported for failed HTTPS connections.
|
|
17
|
+
- Optimized C++ and C# batch execution: test cases that are safe to co-execute now share a single compile-and-run pass, with an automatic per-case fallback when a batch requires isolation.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed `curl` URL scheme resolution and replaced raw kernel HTTP errors with typed ones so nothing leaks to the terminal: bare hostnames, `host:port`, and `localhost:3000` now resolve correctly, unsupported schemes return a proper `curl` protocol error, and malformed requests surface as graceful `curl` diagnostics instead of a raw `EINVAL`.
|
|
22
|
+
|
|
7
23
|
## [0.9.8] - 2026-07-04
|
|
8
24
|
|
|
9
25
|
### Added
|
package/package.json
CHANGED
|
@@ -10518,6 +10518,80 @@ async function handleCompileRun(payload) {
|
|
|
10518
10518
|
}
|
|
10519
10519
|
}
|
|
10520
10520
|
|
|
10521
|
+
function cppBatchIsolationReason(source) {
|
|
10522
|
+
const text = stripComments(String(source ?? ''));
|
|
10523
|
+
if (/\b(?:static|thread_local)\b/.test(text)) {
|
|
10524
|
+
return 'static-storage';
|
|
10525
|
+
}
|
|
10526
|
+
if (cppHasFileScopeMutableDeclaration(text)) {
|
|
10527
|
+
return 'file-scope-state';
|
|
10528
|
+
}
|
|
10529
|
+
return '';
|
|
10530
|
+
}
|
|
10531
|
+
|
|
10532
|
+
function cppHasFileScopeMutableDeclaration(source) {
|
|
10533
|
+
let depth = 0;
|
|
10534
|
+
let statement = '';
|
|
10535
|
+
|
|
10536
|
+
const considerStatement = (rawStatement) => {
|
|
10537
|
+
const normalized = rawStatement
|
|
10538
|
+
.replace(/#[^\n]*(?:\n|$)/g, '')
|
|
10539
|
+
.replace(/\s+/g, ' ')
|
|
10540
|
+
.trim();
|
|
10541
|
+
if (!normalized) return false;
|
|
10542
|
+
if (/^(?:using|typedef|template|class|struct|enum|namespace|extern\s+"C")\b/.test(normalized)) return false;
|
|
10543
|
+
if (/\b(?:const|constexpr)\b/.test(normalized)) return false;
|
|
10544
|
+
if (/\(/.test(normalized)) return false;
|
|
10545
|
+
if (/^(?:return|if|for|while|switch|do|break|continue)\b/.test(normalized)) return false;
|
|
10546
|
+
return /^(?:inline\s+|volatile\s+|mutable\s+|unsigned\s+|signed\s+|long\s+|short\s+)*[A-Za-z_:][A-Za-z0-9_:<>,\s*&]*\s+[*&\s]*[A-Za-z_][A-Za-z0-9_]*(?:\s*(?:=|,|\[|;))/.test(normalized);
|
|
10547
|
+
};
|
|
10548
|
+
|
|
10549
|
+
for (const char of source) {
|
|
10550
|
+
if (depth === 0) {
|
|
10551
|
+
statement += char;
|
|
10552
|
+
}
|
|
10553
|
+
if (char === '{') {
|
|
10554
|
+
depth += 1;
|
|
10555
|
+
continue;
|
|
10556
|
+
}
|
|
10557
|
+
if (char === '}') {
|
|
10558
|
+
depth = Math.max(0, depth - 1);
|
|
10559
|
+
continue;
|
|
10560
|
+
}
|
|
10561
|
+
if (depth === 0 && char === ';') {
|
|
10562
|
+
if (considerStatement(statement)) return true;
|
|
10563
|
+
statement = '';
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
|
|
10567
|
+
return false;
|
|
10568
|
+
}
|
|
10569
|
+
|
|
10570
|
+
function cppOpsClassBatchIsolationReason(inputBatch) {
|
|
10571
|
+
if (!Array.isArray(inputBatch) || inputBatch.length <= 1) return '';
|
|
10572
|
+
const firstOperations = Array.isArray(inputBatch[0]?.operations)
|
|
10573
|
+
? inputBatch[0].operations
|
|
10574
|
+
: Array.isArray(inputBatch[0]?.ops)
|
|
10575
|
+
? inputBatch[0].ops
|
|
10576
|
+
: [];
|
|
10577
|
+
for (let caseIndex = 1; caseIndex < inputBatch.length; caseIndex += 1) {
|
|
10578
|
+
const operations = Array.isArray(inputBatch[caseIndex]?.operations)
|
|
10579
|
+
? inputBatch[caseIndex].operations
|
|
10580
|
+
: Array.isArray(inputBatch[caseIndex]?.ops)
|
|
10581
|
+
? inputBatch[caseIndex].ops
|
|
10582
|
+
: [];
|
|
10583
|
+
if (operations.length !== firstOperations.length) {
|
|
10584
|
+
return 'heterogeneous-ops-class';
|
|
10585
|
+
}
|
|
10586
|
+
for (let operationIndex = 0; operationIndex < operations.length; operationIndex += 1) {
|
|
10587
|
+
if (operations[operationIndex] !== firstOperations[operationIndex]) {
|
|
10588
|
+
return 'heterogeneous-ops-class';
|
|
10589
|
+
}
|
|
10590
|
+
}
|
|
10591
|
+
}
|
|
10592
|
+
return '';
|
|
10593
|
+
}
|
|
10594
|
+
|
|
10521
10595
|
async function handleCompileRunBatch(payload) {
|
|
10522
10596
|
const startedAt = now();
|
|
10523
10597
|
const source = payload && typeof payload.code === 'string' ? payload.code : '';
|
|
@@ -10562,17 +10636,94 @@ async function handleCompileRunBatch(payload) {
|
|
|
10562
10636
|
};
|
|
10563
10637
|
}
|
|
10564
10638
|
|
|
10565
|
-
const
|
|
10566
|
-
|
|
10567
|
-
|
|
10639
|
+
const isolationReason = executionStyle === 'ops-class'
|
|
10640
|
+
? (cppOpsClassBatchIsolationReason(inputBatch) || cppBatchIsolationReason(source))
|
|
10641
|
+
: cppBatchIsolationReason(source);
|
|
10642
|
+
if (isolationReason) {
|
|
10643
|
+
const results = [];
|
|
10644
|
+
for (const inputs of inputBatch) {
|
|
10645
|
+
results.push(await handleCompileRun({ ...payload, inputs, executionStyle }));
|
|
10646
|
+
}
|
|
10647
|
+
const success = results.every((result) => result.success === true);
|
|
10648
|
+
return {
|
|
10649
|
+
success,
|
|
10650
|
+
results,
|
|
10651
|
+
consoleOutput: results.flatMap((result) => result.consoleOutput ?? []),
|
|
10652
|
+
...(success ? {} : { error: results.find((result) => result.success !== true)?.error ?? 'C++ batch execution failed.' }),
|
|
10653
|
+
timings: {
|
|
10654
|
+
...baseTimings(),
|
|
10655
|
+
batchMode: 'per-case-fallback',
|
|
10656
|
+
batchCaseCount: inputBatch.length,
|
|
10657
|
+
batchFallbackReason: isolationReason,
|
|
10658
|
+
},
|
|
10659
|
+
};
|
|
10660
|
+
}
|
|
10661
|
+
|
|
10662
|
+
let preparedDriverSource;
|
|
10663
|
+
try {
|
|
10664
|
+
preparedDriverSource = executionStyle === 'ops-class'
|
|
10665
|
+
? buildOpsClassBatchDriverSource(source, functionName, inputBatch, { executionStyle })
|
|
10666
|
+
: buildBatchDriverSource(source, functionName, inputBatch, { executionStyle });
|
|
10667
|
+
} catch (error) {
|
|
10668
|
+
return failedBatchResult(error instanceof Error ? error.message : String(error));
|
|
10669
|
+
}
|
|
10670
|
+
|
|
10671
|
+
const batchTimings = (timings = {}) => ({
|
|
10672
|
+
...timings,
|
|
10673
|
+
totalMs: elapsedMs(startedAt),
|
|
10674
|
+
batchMode: 'compile-once',
|
|
10675
|
+
batchCaseCount: inputBatch.length,
|
|
10676
|
+
});
|
|
10677
|
+
|
|
10678
|
+
const failedBatchEntries = (result) => inputBatch.map(() => ({
|
|
10679
|
+
success: false,
|
|
10680
|
+
output: null,
|
|
10681
|
+
error: result?.error ?? 'C++ batch execution failed.',
|
|
10682
|
+
consoleOutput: result?.consoleOutput ?? [],
|
|
10683
|
+
timings: result?.timings ?? {},
|
|
10684
|
+
}));
|
|
10685
|
+
|
|
10686
|
+
const result = await compileAndRun(source, functionName, {}, {
|
|
10687
|
+
executionStyle,
|
|
10688
|
+
preparedDriverSource,
|
|
10689
|
+
stdinText: JSON.stringify(inputBatch),
|
|
10690
|
+
});
|
|
10691
|
+
|
|
10692
|
+
if (!result?.success) {
|
|
10693
|
+
return {
|
|
10694
|
+
success: false,
|
|
10695
|
+
results: failedBatchEntries(result),
|
|
10696
|
+
consoleOutput: result?.consoleOutput ?? [],
|
|
10697
|
+
error: result?.error ?? 'C++ batch execution failed.',
|
|
10698
|
+
timings: batchTimings(result?.timings),
|
|
10699
|
+
};
|
|
10568
10700
|
}
|
|
10569
|
-
|
|
10701
|
+
|
|
10702
|
+
if (!Array.isArray(result.output) || result.output.length !== inputBatch.length) {
|
|
10703
|
+
const error = `C++ batch driver returned ${Array.isArray(result.output) ? result.output.length : 'non-array'} results for ${inputBatch.length} cases.`;
|
|
10704
|
+
return {
|
|
10705
|
+
success: false,
|
|
10706
|
+
results: failedBatchEntries({ ...result, error }),
|
|
10707
|
+
consoleOutput: result.consoleOutput ?? [],
|
|
10708
|
+
error,
|
|
10709
|
+
timings: batchTimings(result.timings),
|
|
10710
|
+
};
|
|
10711
|
+
}
|
|
10712
|
+
|
|
10713
|
+
const results = result.output.map((output, index) => ({
|
|
10714
|
+
success: true,
|
|
10715
|
+
output,
|
|
10716
|
+
consoleOutput: index === 0 ? (result.consoleOutput ?? []) : [],
|
|
10717
|
+
executionTimeMs: index === 0 ? result.executionTimeMs : 0,
|
|
10718
|
+
timings: index === 0
|
|
10719
|
+
? { ...(result.timings ?? {}), batchCaseIndex: index }
|
|
10720
|
+
: { runMs: 0, totalMs: 0, compileCacheHit: true, batchCaseIndex: index },
|
|
10721
|
+
}));
|
|
10570
10722
|
return {
|
|
10571
|
-
success,
|
|
10723
|
+
success: true,
|
|
10572
10724
|
results,
|
|
10573
|
-
consoleOutput:
|
|
10574
|
-
|
|
10575
|
-
timings: { ...baseTimings(), batchMode: 'per-case-isolated', batchCaseCount: inputBatch.length },
|
|
10725
|
+
consoleOutput: result.consoleOutput ?? [],
|
|
10726
|
+
timings: batchTimings(result.timings),
|
|
10576
10727
|
};
|
|
10577
10728
|
}
|
|
10578
10729
|
|
|
@@ -1807,11 +1807,173 @@ function indentCSharpSource(code, spaces = 4) {
|
|
|
1807
1807
|
.join('\n');
|
|
1808
1808
|
}
|
|
1809
1809
|
|
|
1810
|
+
function splitCSharpParameterList(source) {
|
|
1811
|
+
const parameters = [];
|
|
1812
|
+
let current = '';
|
|
1813
|
+
let genericDepth = 0;
|
|
1814
|
+
let bracketDepth = 0;
|
|
1815
|
+
for (const char of String(source ?? '')) {
|
|
1816
|
+
if (char === '<') genericDepth += 1;
|
|
1817
|
+
else if (char === '>') genericDepth = Math.max(0, genericDepth - 1);
|
|
1818
|
+
else if (char === '[') bracketDepth += 1;
|
|
1819
|
+
else if (char === ']') bracketDepth = Math.max(0, bracketDepth - 1);
|
|
1820
|
+
if (char === ',' && genericDepth === 0 && bracketDepth === 0) {
|
|
1821
|
+
parameters.push(current.trim());
|
|
1822
|
+
current = '';
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
current += char;
|
|
1826
|
+
}
|
|
1827
|
+
if (current.trim()) parameters.push(current.trim());
|
|
1828
|
+
return parameters;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
function parseCSharpBatchParameter(source, index) {
|
|
1832
|
+
let withoutDefault = String(source ?? '').replace(/=.*/, '').trim();
|
|
1833
|
+
while (/^\s*\[[^\]]+\]\s*/.test(withoutDefault)) {
|
|
1834
|
+
withoutDefault = withoutDefault.replace(/^\s*\[[^\]]+\]\s*/, '').trim();
|
|
1835
|
+
}
|
|
1836
|
+
if (!withoutDefault) return null;
|
|
1837
|
+
const parts = withoutDefault.split(/\s+/).filter(Boolean);
|
|
1838
|
+
let modifier = '';
|
|
1839
|
+
while (parts.length > 0 && ['this', 'params', 'ref', 'out', 'in'].includes(parts[0])) {
|
|
1840
|
+
const next = parts.shift();
|
|
1841
|
+
if (next === 'ref' || next === 'out' || next === 'in') modifier = next;
|
|
1842
|
+
}
|
|
1843
|
+
const name = csharpIdentifier(parts.pop());
|
|
1844
|
+
const type = parts.join(' ').trim();
|
|
1845
|
+
if (!name || !type) return null;
|
|
1846
|
+
return { name, type, modifier, index };
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
function parseCSharpBatchCallableSignature(code, functionName) {
|
|
1850
|
+
const requestedMethodName = csharpIdentifier(functionName);
|
|
1851
|
+
if (!requestedMethodName) return null;
|
|
1852
|
+
const escapedName = requestedMethodName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1853
|
+
const pattern = new RegExp(
|
|
1854
|
+
`((?:(?:public|private|protected|internal|static|virtual|override|sealed|new|async|extern|partial)\\s+)*)` +
|
|
1855
|
+
`([A-Za-z_][A-Za-z0-9_<>.,?\\[\\]\\s]*?)\\s+(${escapedName})\\s*\\(([^)]*)\\)`,
|
|
1856
|
+
'im'
|
|
1857
|
+
);
|
|
1858
|
+
const match = pattern.exec(String(code ?? ''));
|
|
1859
|
+
if (!match) return null;
|
|
1860
|
+
const methodName = csharpIdentifier(match[3]) ?? requestedMethodName;
|
|
1861
|
+
const parameters = splitCSharpParameterList(match[4])
|
|
1862
|
+
.map((parameter, index) => parseCSharpBatchParameter(parameter, index));
|
|
1863
|
+
if (parameters.some((parameter) => !parameter)) return null;
|
|
1864
|
+
return {
|
|
1865
|
+
methodName,
|
|
1866
|
+
returnType: match[2].trim(),
|
|
1867
|
+
isStatic: /\bstatic\b/.test(match[1] || ''),
|
|
1868
|
+
parameters,
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
function buildCSharpDirectBatchScriptSource(payload) {
|
|
1873
|
+
const code = String(payload?.code ?? '');
|
|
1874
|
+
const executionStyle = payload?.executionStyle ?? 'solution-method';
|
|
1875
|
+
const functionName = String(payload?.functionName ?? '');
|
|
1876
|
+
if (!functionName.trim() || executionStyle === 'ops-class') return null;
|
|
1877
|
+
const signature = parseCSharpBatchCallableSignature(code, functionName);
|
|
1878
|
+
if (!signature) return null;
|
|
1879
|
+
const declarations = [];
|
|
1880
|
+
const argumentsList = [];
|
|
1881
|
+
for (const parameter of signature.parameters) {
|
|
1882
|
+
const localName = `__tracecodeArg${parameter.index}`;
|
|
1883
|
+
if (parameter.modifier === 'out') {
|
|
1884
|
+
declarations.push(` ${parameter.type} ${localName} = default!;`);
|
|
1885
|
+
} else {
|
|
1886
|
+
declarations.push(` var ${localName} = TraceCode.Internal.TraceCodeJsonInput.Read<${parameter.type}>(${csharpStringLiteral(parameter.name)}, ${parameter.index});`);
|
|
1887
|
+
}
|
|
1888
|
+
argumentsList.push(`${parameter.modifier ? `${parameter.modifier} ` : ''}${localName}`);
|
|
1889
|
+
}
|
|
1890
|
+
const receiver = executionStyle === 'function'
|
|
1891
|
+
? ''
|
|
1892
|
+
: signature.isStatic
|
|
1893
|
+
? 'Solution.'
|
|
1894
|
+
: '__tracecodeSolution.';
|
|
1895
|
+
const solutionDeclaration = executionStyle === 'function' || signature.isStatic
|
|
1896
|
+
? ''
|
|
1897
|
+
: ' var __tracecodeSolution = new Solution();\n';
|
|
1898
|
+
const callExpression = `${receiver}${signature.methodName}(${argumentsList.join(', ')})`;
|
|
1899
|
+
const returnsVoid = signature.returnType === 'void';
|
|
1900
|
+
const invocation = returnsVoid
|
|
1901
|
+
? ` ${callExpression};\n return ${signature.parameters.length > 0 ? '__tracecodeArg0' : 'null'};`
|
|
1902
|
+
: ` return ${callExpression};`;
|
|
1903
|
+
|
|
1904
|
+
return `${code}
|
|
1905
|
+
|
|
1906
|
+
object? result;
|
|
1907
|
+
{
|
|
1908
|
+
var __tracecodeBatchCases = TraceCode.Internal.TraceCodeJsonInput.Read<System.Text.Json.JsonElement[]>("__tracecodeBatchInputs", 0) ?? System.Array.Empty<System.Text.Json.JsonElement>();
|
|
1909
|
+
var __tracecodeBatchResults = new System.Collections.Generic.List<object?>();
|
|
1910
|
+
|
|
1911
|
+
foreach (var __tracecodeBatchCase in __tracecodeBatchCases)
|
|
1912
|
+
{
|
|
1913
|
+
var __tracecodeBatchClock = System.Diagnostics.Stopwatch.StartNew();
|
|
1914
|
+
var __tracecodeOriginalOut = System.Console.Out;
|
|
1915
|
+
using var __tracecodeCaseOut = new System.IO.StringWriter();
|
|
1916
|
+
try
|
|
1917
|
+
{
|
|
1918
|
+
System.Console.SetOut(__tracecodeCaseOut);
|
|
1919
|
+
__TraceCodeSetCurrentInputsJson(__tracecodeBatchCase.GetRawText());
|
|
1920
|
+
object? __tracecodeOutput = __TraceCodeRunBatchCase();
|
|
1921
|
+
__tracecodeBatchClock.Stop();
|
|
1922
|
+
__tracecodeBatchResults.Add(new System.Collections.Generic.Dictionary<string, object?>
|
|
1923
|
+
{
|
|
1924
|
+
["success"] = true,
|
|
1925
|
+
["output"] = __tracecodeOutput,
|
|
1926
|
+
["consoleOutput"] = __TraceCodeSplitConsole(__tracecodeCaseOut.ToString()),
|
|
1927
|
+
["timings"] = new System.Collections.Generic.Dictionary<string, object?> { ["runMs"] = __tracecodeBatchClock.Elapsed.TotalMilliseconds },
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
catch (System.Exception __tracecodeError)
|
|
1931
|
+
{
|
|
1932
|
+
__tracecodeBatchClock.Stop();
|
|
1933
|
+
__tracecodeBatchResults.Add(new System.Collections.Generic.Dictionary<string, object?>
|
|
1934
|
+
{
|
|
1935
|
+
["success"] = false,
|
|
1936
|
+
["error"] = __tracecodeError.GetBaseException().Message,
|
|
1937
|
+
["output"] = null,
|
|
1938
|
+
["consoleOutput"] = __TraceCodeSplitConsole(__tracecodeCaseOut.ToString()),
|
|
1939
|
+
["timings"] = new System.Collections.Generic.Dictionary<string, object?> { ["runMs"] = __tracecodeBatchClock.Elapsed.TotalMilliseconds },
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
finally
|
|
1943
|
+
{
|
|
1944
|
+
System.Console.SetOut(__tracecodeOriginalOut);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
result = __tracecodeBatchResults;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
object? __TraceCodeRunBatchCase()
|
|
1952
|
+
{
|
|
1953
|
+
${solutionDeclaration}${declarations.join('\n')}
|
|
1954
|
+
${invocation}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
void __TraceCodeSetCurrentInputsJson(string __tracecodeInputsJson)
|
|
1958
|
+
{
|
|
1959
|
+
var __tracecodeField = typeof(TraceCode.CSharpHost.CompilerHost).GetField(
|
|
1960
|
+
"currentInputsJson",
|
|
1961
|
+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
|
1962
|
+
__tracecodeField?.SetValue(null, __tracecodeInputsJson);
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
string[] __TraceCodeSplitConsole(string __tracecodeText) =>
|
|
1966
|
+
__tracecodeText.Replace("\\r\\n", "\\n", System.StringComparison.Ordinal).Split('\\n', System.StringSplitOptions.RemoveEmptyEntries);
|
|
1967
|
+
`;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1810
1970
|
function buildCSharpBatchScriptSource(payload) {
|
|
1811
1971
|
const code = String(payload?.code ?? '');
|
|
1812
1972
|
const executionStyle = payload?.executionStyle ?? 'solution-method';
|
|
1813
1973
|
const functionName = String(payload?.functionName ?? '');
|
|
1814
1974
|
const functionNameLiteral = csharpStringLiteral(functionName);
|
|
1975
|
+
const directBatchSource = buildCSharpDirectBatchScriptSource(payload);
|
|
1976
|
+
if (directBatchSource) return directBatchSource;
|
|
1815
1977
|
|
|
1816
1978
|
if (executionStyle === 'ops-class') {
|
|
1817
1979
|
const className = csharpIdentifier(functionName);
|
|
@@ -2243,6 +2405,17 @@ function normalizeCSharpBatchEntry(entry, timings = {}) {
|
|
|
2243
2405
|
};
|
|
2244
2406
|
}
|
|
2245
2407
|
|
|
2408
|
+
function csharpBatchIsolationReason(payload) {
|
|
2409
|
+
if (payload?.executionStyle === 'ops-class') {
|
|
2410
|
+
return 'ops-class-reflection';
|
|
2411
|
+
}
|
|
2412
|
+
const code = String(payload?.code ?? '');
|
|
2413
|
+
if (/\bstatic\b/.test(code)) {
|
|
2414
|
+
return 'static-storage';
|
|
2415
|
+
}
|
|
2416
|
+
return '';
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2246
2419
|
async function executeCSharpCodePayload(payload, messageType = 'execute-code') {
|
|
2247
2420
|
const startedAt = now();
|
|
2248
2421
|
const request = {
|
|
@@ -2315,21 +2488,63 @@ async function executeCSharpCodeBatch(message) {
|
|
|
2315
2488
|
};
|
|
2316
2489
|
}
|
|
2317
2490
|
|
|
2318
|
-
const
|
|
2319
|
-
|
|
2320
|
-
const
|
|
2321
|
-
|
|
2491
|
+
const isolationReason = csharpBatchIsolationReason(message.payload ?? {});
|
|
2492
|
+
if (isolationReason) {
|
|
2493
|
+
const results = [];
|
|
2494
|
+
for (const inputs of inputBatch) {
|
|
2495
|
+
const result = await executeCSharpCodePayload({ ...message.payload, inputs }, 'execute-code');
|
|
2496
|
+
results.push(normalizeCSharpBatchEntry(result, result.timings));
|
|
2497
|
+
}
|
|
2498
|
+
const consoleOutput = results.flatMap((entry) => entry.consoleOutput ?? []);
|
|
2499
|
+
const success = results.every((entry) => entry.success === true);
|
|
2500
|
+
return {
|
|
2501
|
+
success,
|
|
2502
|
+
results,
|
|
2503
|
+
consoleOutput,
|
|
2504
|
+
...(success ? {} : { error: results.find((entry) => entry.success !== true)?.error ?? 'C# batch execution failed.' }),
|
|
2505
|
+
timings: {
|
|
2506
|
+
totalMs: elapsedMs(startedAt),
|
|
2507
|
+
batchMode: 'per-case-fallback',
|
|
2508
|
+
batchCaseCount: inputBatch.length,
|
|
2509
|
+
batchFallbackReason: isolationReason,
|
|
2510
|
+
runMs: results.reduce((sum, entry) => sum + (entry.timings?.runMs ?? 0), 0),
|
|
2511
|
+
},
|
|
2512
|
+
};
|
|
2322
2513
|
}
|
|
2514
|
+
|
|
2515
|
+
let batchSource;
|
|
2516
|
+
try {
|
|
2517
|
+
batchSource = buildCSharpBatchScriptSource(message.payload ?? {});
|
|
2518
|
+
} catch (error) {
|
|
2519
|
+
return {
|
|
2520
|
+
success: false,
|
|
2521
|
+
results: [],
|
|
2522
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2523
|
+
consoleOutput: [],
|
|
2524
|
+
timings: { totalMs: elapsedMs(startedAt) },
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
const result = await executeCSharpCodePayload({
|
|
2529
|
+
...message.payload,
|
|
2530
|
+
code: batchSource,
|
|
2531
|
+
functionName: '',
|
|
2532
|
+
executionStyle: 'function',
|
|
2533
|
+
inputs: { __tracecodeBatchInputs: inputBatch },
|
|
2534
|
+
}, 'execute-code');
|
|
2535
|
+
const batchEntries = Array.isArray(result?.output) ? result.output : [];
|
|
2536
|
+
const results = batchEntries.map((entry) => normalizeCSharpBatchEntry(entry));
|
|
2323
2537
|
const consoleOutput = results.flatMap((entry) => entry.consoleOutput ?? []);
|
|
2324
2538
|
const success = results.length === inputBatch.length && results.every((entry) => entry.success === true);
|
|
2325
2539
|
return {
|
|
2326
2540
|
success,
|
|
2327
2541
|
results,
|
|
2328
2542
|
consoleOutput,
|
|
2329
|
-
...(success ? {} : { error: results.find((entry) => entry.success !== true)?.error ?? 'C# batch execution failed.' }),
|
|
2543
|
+
...(success ? {} : { error: result?.error ?? results.find((entry) => entry.success !== true)?.error ?? 'C# batch execution failed.' }),
|
|
2330
2544
|
timings: {
|
|
2545
|
+
...(result?.timings && typeof result.timings === 'object' ? result.timings : {}),
|
|
2331
2546
|
totalMs: elapsedMs(startedAt),
|
|
2332
|
-
batchMode: '
|
|
2547
|
+
batchMode: 'compile-once',
|
|
2333
2548
|
batchCaseCount: inputBatch.length,
|
|
2334
2549
|
runMs: results.reduce((sum, entry) => sum + (entry.timings?.runMs ?? 0), 0),
|
|
2335
2550
|
},
|
|
@@ -3716,7 +3716,7 @@ function unzipSync(data, opts) {
|
|
|
3716
3716
|
// packages/harness-javascript/package.json
|
|
3717
3717
|
var package_default = {
|
|
3718
3718
|
name: "@tracecode/harness-javascript",
|
|
3719
|
-
version: "0.9.
|
|
3719
|
+
version: "0.9.9",
|
|
3720
3720
|
description: "JavaScript and TypeScript runtime helpers and browser worker assets for TraceCode harness.",
|
|
3721
3721
|
license: "AGPL-3.0-only",
|
|
3722
3722
|
homepage: "https://tracecode.app",
|