pi-supernova 0.5.0 → 0.6.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 +73 -11
- package/docs/CHANGELOG.md +46 -0
- package/docs/TOKEN_COSTS.md +63 -29
- package/index.js +7 -4
- package/package.json +2 -2
- package/src/bridge/catalog.js +14 -10
- package/src/bridge/host-bridge.js +810 -145
- package/src/bridge/native-tools.js +16 -6
- package/src/context/evidence.js +13 -5
- package/src/context/fuzzy.js +34 -13
- package/src/context/outline.js +11 -2
- package/src/context/repo-index.js +150 -15
- package/src/context/search.js +70 -17
- package/src/context/snap.js +98 -46
- package/src/context/surface.js +15 -9
- package/src/fs/check.js +10 -2
- package/src/fs/patch.js +4 -2
- package/src/fs/vfs.js +133 -36
- package/src/fs/workspace.js +7 -1
- package/src/output/bottleneck.js +36 -11
- package/src/output/format.js +44 -29
- package/src/runtime/guest-worker.js +135 -39
- package/src/runtime/parallel.js +4 -1
- package/src/runtime/program-batch.js +17 -6
- package/src/runtime/program-file.js +6 -3
- package/src/runtime/reference.js +5 -5
- package/src/runtime/runtime.js +17 -6
- package/src/shared/decode.js +15 -3
- package/src/ui/omp-frame.js +11 -4
- package/src/ui/render.js +2 -2
package/src/runtime/runtime.js
CHANGED
|
@@ -47,7 +47,7 @@ function prepareProgram(code) {
|
|
|
47
47
|
|
|
48
48
|
if (candidate && FUNCTION_TYPES.has(candidate.type)) {
|
|
49
49
|
expression = candidate;
|
|
50
|
-
expressionSource = code.slice(
|
|
50
|
+
expressionSource = code.slice(statement.start, statement.end).replace(/;\s*$/, "");
|
|
51
51
|
}
|
|
52
52
|
} catch (bodyError) {
|
|
53
53
|
expressionSource = code.trimEnd().replace(/;+\s*$/, "");
|
|
@@ -185,7 +185,10 @@ export async function runGuestProgram({ code, file, cwd = process.cwd(), data, n
|
|
|
185
185
|
|
|
186
186
|
if (signal?.aborted) return fail(ABORT_MESSAGE);
|
|
187
187
|
const runId = ++runSeq;
|
|
188
|
-
const
|
|
188
|
+
const requestedTimeout = Number(config.timeoutMs === undefined ? 60000 : config.timeoutMs);
|
|
189
|
+
|
|
190
|
+
if (!Number.isFinite(requestedTimeout) || requestedTimeout <= 0) return fail("timeoutMs must be a positive finite number");
|
|
191
|
+
const timeoutMs = Math.max(1, Math.min(2_147_483_647, Math.floor(requestedTimeout)));
|
|
189
192
|
const rssLimit = rssBytes() + (config.maxHeapMb ?? 512) * MEMORY_SLACK * 1048576;
|
|
190
193
|
|
|
191
194
|
return new Promise((resolve) => {
|
|
@@ -195,6 +198,7 @@ export async function runGuestProgram({ code, file, cwd = process.cwd(), data, n
|
|
|
195
198
|
let completing = false;
|
|
196
199
|
let hostError;
|
|
197
200
|
let notifyingHost = false;
|
|
201
|
+
let aborting = false;
|
|
198
202
|
const pending = new Set();
|
|
199
203
|
const inputController = new AbortController();
|
|
200
204
|
|
|
@@ -224,11 +228,13 @@ export async function runGuestProgram({ code, file, cwd = process.cwd(), data, n
|
|
|
224
228
|
};
|
|
225
229
|
|
|
226
230
|
const abort = () => {
|
|
227
|
-
if (finished) return;
|
|
231
|
+
if (finished || aborting) return;
|
|
232
|
+
aborting = true;
|
|
228
233
|
cancelHost();
|
|
229
234
|
|
|
230
235
|
try { onTimeout?.(); } catch {}
|
|
231
236
|
|
|
237
|
+
aborting = false;
|
|
232
238
|
finish(fail(ABORT_MESSAGE));
|
|
233
239
|
};
|
|
234
240
|
|
|
@@ -267,8 +273,11 @@ export async function runGuestProgram({ code, file, cwd = process.cwd(), data, n
|
|
|
267
273
|
handle?.worker.off("exit", onExit);
|
|
268
274
|
void killWorker(handle);
|
|
269
275
|
|
|
270
|
-
if (!outcome.ok) cancelHost();
|
|
271
|
-
|
|
276
|
+
if (pending.size || !outcome.ok) cancelHost();
|
|
277
|
+
// A host tool that ignores cancellation must not keep the result unsettled
|
|
278
|
+
// after the guest worker is gone. Give it a brief drain window only.
|
|
279
|
+
await Promise.race([Promise.allSettled(pending), new Promise(resolve => setTimeout(resolve, 250))]);
|
|
280
|
+
if (pending.size && outcome.ok) hostError ??= "program completed with a host call still running";
|
|
272
281
|
|
|
273
282
|
if (finished) return;
|
|
274
283
|
finish(outcome.ok && hostError ? fail(hostError) : outcome);
|
|
@@ -339,7 +348,9 @@ export async function runGuestProgram({ code, file, cwd = process.cwd(), data, n
|
|
|
339
348
|
await handle.ready;
|
|
340
349
|
|
|
341
350
|
if (finished || signal?.aborted) return abort();
|
|
342
|
-
|
|
351
|
+
let available = isFunction(nova.names) ? await nova.names() : [];
|
|
352
|
+
|
|
353
|
+
if (!Array.isArray(available)) available = [];
|
|
343
354
|
|
|
344
355
|
if (finished || signal?.aborted) return abort();
|
|
345
356
|
handle.worker.on("message", onMessage);
|
package/src/shared/decode.js
CHANGED
|
@@ -65,7 +65,9 @@ export function toPlain(value, seen = new Set(), depth = 0) {
|
|
|
65
65
|
if (value === null || value === undefined) return value;
|
|
66
66
|
const tag = toStr.call(value);
|
|
67
67
|
|
|
68
|
-
if (tag === "[object String]"
|
|
68
|
+
if (tag === "[object String]") return value.valueOf();
|
|
69
|
+
|
|
70
|
+
if (tag === "[object Number]" || tag === "[object Boolean]") return value.valueOf();
|
|
69
71
|
|
|
70
72
|
if (tag === "[object BigInt]") return value.toString() + "n";
|
|
71
73
|
|
|
@@ -84,7 +86,12 @@ export function toPlain(value, seen = new Set(), depth = 0) {
|
|
|
84
86
|
if (value instanceof Error) {
|
|
85
87
|
const out = { name: value.name, message: value.message };
|
|
86
88
|
|
|
87
|
-
if (value.cause !== undefined)
|
|
89
|
+
if (value.cause !== undefined) {
|
|
90
|
+
seen.add(value);
|
|
91
|
+
|
|
92
|
+
try { out.cause = toPlain(value.cause, seen, depth + 1); }
|
|
93
|
+
finally { seen.delete(value); }
|
|
94
|
+
}
|
|
88
95
|
|
|
89
96
|
return out;
|
|
90
97
|
}
|
|
@@ -93,7 +100,12 @@ export function toPlain(value, seen = new Set(), depth = 0) {
|
|
|
93
100
|
|
|
94
101
|
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return plainFromBinary(value);
|
|
95
102
|
|
|
96
|
-
if (isFunction(value.toJSON))
|
|
103
|
+
if (isFunction(value.toJSON)) {
|
|
104
|
+
seen.add(value);
|
|
105
|
+
|
|
106
|
+
try { return toPlain(value.toJSON(), seen, depth + 1); }
|
|
107
|
+
finally { seen.delete(value); }
|
|
108
|
+
}
|
|
97
109
|
seen.add(value);
|
|
98
110
|
|
|
99
111
|
try {
|
package/src/ui/omp-frame.js
CHANGED
|
@@ -38,7 +38,10 @@ function borderPaint(theme, state, borderColor) {
|
|
|
38
38
|
|
|
39
39
|
if (theme && isFunction(theme.fg)) {
|
|
40
40
|
try {
|
|
41
|
-
return (text) =>
|
|
41
|
+
return (text) => {
|
|
42
|
+
try { return theme.fg(key, text); }
|
|
43
|
+
catch { return text; }
|
|
44
|
+
};
|
|
42
45
|
} catch {
|
|
43
46
|
/* fall through */
|
|
44
47
|
}
|
|
@@ -51,10 +54,14 @@ const STATUS_PREFIX = { error: ["error", "✗ "], running: ["dim", "… "] };
|
|
|
51
54
|
|
|
52
55
|
function statusHeader(theme, { title, description, state, icon }) {
|
|
53
56
|
const resolved = icon ?? (state === "error" ? "error" : undefined);
|
|
57
|
+
const fg = (key, text) => {
|
|
58
|
+
try { return isFunction(theme?.fg) ? theme.fg(key, text) : text; }
|
|
59
|
+
catch { return text; }
|
|
60
|
+
};
|
|
54
61
|
const prefixSpec = STATUS_PREFIX[resolved];
|
|
55
|
-
const prefix = prefixSpec ?
|
|
56
|
-
const titleText =
|
|
57
|
-
const descText = description ?
|
|
62
|
+
const prefix = prefixSpec ? fg(prefixSpec[0], prefixSpec[1]) : "";
|
|
63
|
+
const titleText = fg("accent", title);
|
|
64
|
+
const descText = description ? fg("muted", description) : "";
|
|
58
65
|
|
|
59
66
|
return descText ? `${prefix}${titleText}: ${descText}` : `${prefix}${titleText}`;
|
|
60
67
|
}
|
package/src/ui/render.js
CHANGED
|
@@ -363,9 +363,9 @@ function opDuration(op, isPartial) {
|
|
|
363
363
|
*/
|
|
364
364
|
function formatOpRow(theme, op, width, isPartial, isError) {
|
|
365
365
|
const marker = opMarker(theme, op, isPartial, isError);
|
|
366
|
-
const toolText = op.tool.padEnd(TOOL_COL);
|
|
366
|
+
const toolText = op.tool.slice(0, TOOL_COL).padEnd(TOOL_COL);
|
|
367
367
|
const tool = theme.fg("syntaxFunction", toolText);
|
|
368
|
-
const durationText = opDuration(op, isPartial);
|
|
368
|
+
const durationText = opDuration(op, isPartial).slice(-DURATION_COL);
|
|
369
369
|
const duration = theme.fg("dim", durationText.padStart(DURATION_COL));
|
|
370
370
|
let prefix = `${marker} ${tool} ${duration} `;
|
|
371
371
|
let used = 2 + toolText.length + 1 + DURATION_COL + 2;
|