@rulvar/rulvar 1.22.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +126 -59
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sanitizeTerminalText } from "@rulvar/core";
|
|
1
|
+
import { maskSecrets, sanitizeTerminalText } from "@rulvar/core";
|
|
2
2
|
import { ANTHROPIC_MODELS, anthropic } from "@rulvar/anthropic";
|
|
3
3
|
import { OPENAI_MODELS, openai } from "@rulvar/openai";
|
|
4
4
|
export * from "@rulvar/core";
|
|
@@ -17,7 +17,24 @@ export * from "@rulvar/core";
|
|
|
17
17
|
* P2-1).
|
|
18
18
|
*/
|
|
19
19
|
function usd(amount) {
|
|
20
|
-
return `${amount.toFixed(4)} USD`;
|
|
20
|
+
return `${(typeof amount === "number" && Number.isFinite(amount) ? amount : 0).toFixed(4)} USD`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Defensive readers: the input is a raw iterable by contract, so a
|
|
24
|
+
* recognized event with a missing or mistyped field degrades its own
|
|
25
|
+
* line instead of throwing out of the render loop (v1.22.0 review
|
|
26
|
+
* P2-3; same discipline as the live progress reducer).
|
|
27
|
+
*/
|
|
28
|
+
function str$1(value) {
|
|
29
|
+
return typeof value === "string" ? value : "";
|
|
30
|
+
}
|
|
31
|
+
function num$1(value) {
|
|
32
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
33
|
+
}
|
|
34
|
+
function name(event) {
|
|
35
|
+
const agentType = str$1(event.agentType) || "anonymous";
|
|
36
|
+
const label = str$1(event.label);
|
|
37
|
+
return `${agentType}${label === "" ? "" : ` [${label}]`}`;
|
|
21
38
|
}
|
|
22
39
|
/**
|
|
23
40
|
* Renders events until the stream ends (the run settled). Returns after
|
|
@@ -31,34 +48,34 @@ async function renderProgress(events, options) {
|
|
|
31
48
|
const logs = options?.logs ?? true;
|
|
32
49
|
for await (const event of events) switch (event.type) {
|
|
33
50
|
case "run:start":
|
|
34
|
-
write(`run ${event.runId} started: ${event.workflow}${event.resumed ? " (resumed)" : ""}`);
|
|
51
|
+
write(`run ${str$1(event.runId)} started: ${str$1(event.workflow)}${event.resumed === true ? " (resumed)" : ""}`);
|
|
35
52
|
break;
|
|
36
53
|
case "phase:start":
|
|
37
|
-
write(`phase: ${event.phase}`);
|
|
54
|
+
write(`phase: ${str$1(event.phase)}`);
|
|
38
55
|
break;
|
|
39
56
|
case "agent:queued":
|
|
40
|
-
write(`agent ${event
|
|
57
|
+
write(`agent ${name(event)} queued`);
|
|
41
58
|
break;
|
|
42
59
|
case "agent:start":
|
|
43
|
-
write(`agent ${event
|
|
60
|
+
write(`agent ${name(event)} -> ${str$1(event.model)} (${str$1(event.role)})`);
|
|
44
61
|
break;
|
|
45
62
|
case "agent:end":
|
|
46
|
-
write(`agent ${event
|
|
63
|
+
write(`agent ${name(event)} ${str$1(event.status)} (${usd(event.costUsd)}, ${String(num$1(event.usage?.outputTokens))} out tokens)`);
|
|
47
64
|
break;
|
|
48
65
|
case "agent:error":
|
|
49
|
-
write(`agent ${event.agentType || "anonymous"} error: ${event.error
|
|
66
|
+
write(`agent ${str$1(event.agentType) || "anonymous"} error: ${str$1(event.error?.message)}${event.willRetry === true ? " (will retry)" : ""}`);
|
|
50
67
|
break;
|
|
51
68
|
case "agent:schema-retry":
|
|
52
|
-
write(`agent ${event.agentType || "anonymous"} schema retry ${event.attempt}/${event.maxAttempts}`);
|
|
69
|
+
write(`agent ${str$1(event.agentType) || "anonymous"} schema retry ${String(num$1(event.attempt))}/${String(num$1(event.maxAttempts))}`);
|
|
53
70
|
break;
|
|
54
71
|
case "budget:update":
|
|
55
|
-
write(`budget: spent ${usd(event.spentUsd)}` + (event.remainingUsd ===
|
|
72
|
+
write(`budget: spent ${usd(event.spentUsd)}` + (typeof event.remainingUsd === "number" ? `, remaining ${usd(event.remainingUsd)}` : ""));
|
|
56
73
|
break;
|
|
57
74
|
case "log":
|
|
58
|
-
if (logs && event.level !== "debug") write(`[${event.level}] ${event.msg}`);
|
|
75
|
+
if (logs && event.level !== "debug") write(`[${str$1(event.level)}] ${str$1(event.msg)}`);
|
|
59
76
|
break;
|
|
60
77
|
case "run:end":
|
|
61
|
-
write(`run finished: ${event.status} (total ${usd(event.totalUsd)})`);
|
|
78
|
+
write(`run finished: ${str$1(event.status)} (total ${usd(event.totalUsd)})`);
|
|
62
79
|
break;
|
|
63
80
|
default: break;
|
|
64
81
|
}
|
|
@@ -94,9 +111,11 @@ async function renderProgress(events, options) {
|
|
|
94
111
|
*/
|
|
95
112
|
/**
|
|
96
113
|
* Positive-integer option normalization (v1.21.0 review P3-2): a
|
|
97
|
-
* non-finite
|
|
98
|
-
*
|
|
99
|
-
*
|
|
114
|
+
* non-finite caller value falls back to the default and a below-minimum
|
|
115
|
+
* value CLAMPS to the minimum (wording fixed in the v1.22.0 review
|
|
116
|
+
* P4-2; the behavior always clamped), so no caller value can poison the
|
|
117
|
+
* geometry (a NaN width breaks the clip, a NaN fps yields a NaN
|
|
118
|
+
* interval). Fractions floor.
|
|
100
119
|
*/
|
|
101
120
|
function posIntOption(value, fallback, min) {
|
|
102
121
|
if (value === void 0 || !Number.isFinite(value)) return fallback;
|
|
@@ -183,9 +202,44 @@ function nodeOf(state, event, kind, title) {
|
|
|
183
202
|
* P2-1).
|
|
184
203
|
*/
|
|
185
204
|
const scrub = sanitizeTerminalText;
|
|
205
|
+
/**
|
|
206
|
+
* Defensive readers for recognized event types arriving from a RAW
|
|
207
|
+
* iterable: the engine's own bus always satisfies the types, but the
|
|
208
|
+
* documented raw-iterable source can hand the reducer any shape, and a
|
|
209
|
+
* missing or mistyped field must degrade the one row, never stop the
|
|
210
|
+
* view or reach a template literal as an object whose coercion could
|
|
211
|
+
* throw (v1.22.0 review P2-3).
|
|
212
|
+
*/
|
|
213
|
+
function str(value) {
|
|
214
|
+
return typeof value === "string" ? value : "";
|
|
215
|
+
}
|
|
216
|
+
function num(value) {
|
|
217
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
218
|
+
}
|
|
219
|
+
function numOpt(value) {
|
|
220
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* One safe form for every error a catch path surfaces: the message is
|
|
224
|
+
* secret-masked FIRST (the thrown value never went through the event
|
|
225
|
+
* masking boundary) and terminal-sanitized second, so a rejected
|
|
226
|
+
* source can neither leak a key-shaped fragment nor inject control
|
|
227
|
+
* sequences or forged lines into the sink (v1.22.0 review P2-2).
|
|
228
|
+
*/
|
|
229
|
+
function errorNotice(thrown) {
|
|
230
|
+
let message;
|
|
231
|
+
try {
|
|
232
|
+
message = thrown instanceof Error ? thrown.message : String(thrown);
|
|
233
|
+
} catch {
|
|
234
|
+
message = "unprintable thrown value";
|
|
235
|
+
}
|
|
236
|
+
return scrub(maskSecrets(`error: ${message}`));
|
|
237
|
+
}
|
|
186
238
|
function agentTitle(event) {
|
|
187
|
-
const
|
|
188
|
-
|
|
239
|
+
const agentType = str(event.agentType);
|
|
240
|
+
const label = str(event.label);
|
|
241
|
+
const base = agentType === "" ? "agent" : scrub(agentType);
|
|
242
|
+
return label === "" ? base : `${base} (${scrub(label)})`;
|
|
189
243
|
}
|
|
190
244
|
/** The tool event's span is the agent's own span or a child of it. */
|
|
191
245
|
function toolTarget(state, event) {
|
|
@@ -198,11 +252,11 @@ function applyEvent(state, event, now) {
|
|
|
198
252
|
state.runId = event.runId;
|
|
199
253
|
state.resumed = event.resumed === true;
|
|
200
254
|
state.startedAt ??= now;
|
|
201
|
-
state.title ??= scrub(event.workflow);
|
|
255
|
+
state.title ??= scrub(str(event.workflow));
|
|
202
256
|
break;
|
|
203
257
|
case "run:end":
|
|
204
|
-
state.status = event.status;
|
|
205
|
-
state.totalUsd = event.totalUsd;
|
|
258
|
+
state.status = str(event.status) || "interrupted";
|
|
259
|
+
state.totalUsd = numOpt(event.totalUsd);
|
|
206
260
|
state.endedAt = now;
|
|
207
261
|
for (const node of state.nodes.values()) {
|
|
208
262
|
if (node.endedAt === void 0 && node.kind !== "phase") {
|
|
@@ -214,36 +268,36 @@ function applyEvent(state, event, now) {
|
|
|
214
268
|
}
|
|
215
269
|
break;
|
|
216
270
|
case "phase:start": {
|
|
217
|
-
const node = nodeOf(state, event, "phase", scrub(event.phase));
|
|
271
|
+
const node = nodeOf(state, event, "phase", scrub(str(event.phase)));
|
|
218
272
|
node.startedAt = now;
|
|
219
273
|
node.status = "ok";
|
|
220
274
|
break;
|
|
221
275
|
}
|
|
222
276
|
case "budget:update":
|
|
223
|
-
state.spentUsd = event.spentUsd;
|
|
224
|
-
state.ceilingUsd = event.remainingUsd ===
|
|
277
|
+
state.spentUsd = num(event.spentUsd);
|
|
278
|
+
state.ceilingUsd = typeof event.remainingUsd === "number" && Number.isFinite(event.remainingUsd) ? num(event.spentUsd) + event.remainingUsd : void 0;
|
|
225
279
|
break;
|
|
226
280
|
case "log":
|
|
227
281
|
if (event.level === "warn" || event.level === "error") {
|
|
228
|
-
state.notices.push(scrub(`${event.level}: ${event.msg}`));
|
|
282
|
+
state.notices.push(scrub(`${str(event.level)}: ${str(event.msg)}`));
|
|
229
283
|
if (state.notices.length > 2) state.notices.shift();
|
|
230
284
|
}
|
|
231
285
|
break;
|
|
232
286
|
case "external:waiting":
|
|
233
|
-
state.banner = scrub(`waiting on external: ${event.key}`);
|
|
287
|
+
state.banner = scrub(`waiting on external: ${str(event.key)}`);
|
|
234
288
|
break;
|
|
235
289
|
case "approval:pending":
|
|
236
|
-
state.banner = scrub(`approval pending: ${event.toolName}`);
|
|
290
|
+
state.banner = scrub(`approval pending: ${str(event.toolName)}`);
|
|
237
291
|
break;
|
|
238
292
|
case "child:start": {
|
|
239
|
-
const node = nodeOf(state, event, "child", scrub(`${event.workflow} (${event.scope})`));
|
|
293
|
+
const node = nodeOf(state, event, "child", scrub(`${str(event.workflow)} (${str(event.scope)})`));
|
|
240
294
|
node.startedAt = now;
|
|
241
295
|
break;
|
|
242
296
|
}
|
|
243
297
|
case "child:end": {
|
|
244
298
|
const node = state.nodes.get(event.spanId);
|
|
245
299
|
if (node !== void 0) {
|
|
246
|
-
node.status = event.status;
|
|
300
|
+
node.status = str(event.status) || "interrupted";
|
|
247
301
|
node.endedAt = now;
|
|
248
302
|
}
|
|
249
303
|
break;
|
|
@@ -259,41 +313,41 @@ function applyEvent(state, event, now) {
|
|
|
259
313
|
const node = nodeOf(state, event, "agent", agentTitle(event));
|
|
260
314
|
if (node.status === "queued" || node.roles.length === 0) node.startedAt = now;
|
|
261
315
|
node.status = "running";
|
|
262
|
-
node.model = scrub(event.model);
|
|
316
|
+
node.model = scrub(str(event.model));
|
|
263
317
|
if (event.replayed === true) node.replayed = true;
|
|
264
318
|
const open = node.roles.at(-1);
|
|
265
319
|
if (open !== void 0 && open.endedAt === void 0) open.endedAt = now;
|
|
266
320
|
node.roles.push({
|
|
267
|
-
role: event.role,
|
|
321
|
+
role: str(event.role),
|
|
268
322
|
startedAt: now
|
|
269
323
|
});
|
|
270
324
|
break;
|
|
271
325
|
}
|
|
272
326
|
case "agent:stream": {
|
|
273
327
|
const node = state.nodes.get(event.spanId);
|
|
274
|
-
if (node !== void 0) node.streamedChars += event.delta.length;
|
|
328
|
+
if (node !== void 0) node.streamedChars += str(event.delta).length;
|
|
275
329
|
break;
|
|
276
330
|
}
|
|
277
331
|
case "agent:error": {
|
|
278
332
|
const node = state.nodes.get(event.spanId);
|
|
279
|
-
if (node !== void 0) node.badge = event.willRetry ? "retry" : scrub(`error: ${event.error?.message
|
|
333
|
+
if (node !== void 0) node.badge = event.willRetry ? "retry" : scrub(`error: ${str(event.error?.message)}`);
|
|
280
334
|
break;
|
|
281
335
|
}
|
|
282
336
|
case "agent:schema-retry": {
|
|
283
337
|
const node = state.nodes.get(event.spanId);
|
|
284
|
-
if (node !== void 0) node.badge = `schema ${String(event.attempt)}/${String(event.maxAttempts)}`;
|
|
338
|
+
if (node !== void 0) node.badge = `schema ${String(num(event.attempt))}/${String(num(event.maxAttempts))}`;
|
|
285
339
|
break;
|
|
286
340
|
}
|
|
287
341
|
case "agent:end": {
|
|
288
342
|
state.banner = void 0;
|
|
289
343
|
const node = nodeOf(state, event, "agent", agentTitle(event));
|
|
290
|
-
node.status = event.status;
|
|
344
|
+
node.status = str(event.status) || "interrupted";
|
|
291
345
|
node.endedAt = now;
|
|
292
346
|
node.usage = {
|
|
293
|
-
input: event.usage?.inputTokens
|
|
294
|
-
output: event.usage?.outputTokens
|
|
347
|
+
input: num(event.usage?.inputTokens),
|
|
348
|
+
output: num(event.usage?.outputTokens)
|
|
295
349
|
};
|
|
296
|
-
node.costUsd = event.costUsd;
|
|
350
|
+
node.costUsd = numOpt(event.costUsd);
|
|
297
351
|
if (event.replayed === true) node.replayed = true;
|
|
298
352
|
if (node.status === "ok") node.badge = void 0;
|
|
299
353
|
const open = node.roles.at(-1);
|
|
@@ -302,7 +356,7 @@ function applyEvent(state, event, now) {
|
|
|
302
356
|
}
|
|
303
357
|
case "tool:start": {
|
|
304
358
|
const node = toolTarget(state, event);
|
|
305
|
-
if (node !== void 0) node.toolActive = scrub(event.toolName);
|
|
359
|
+
if (node !== void 0) node.toolActive = scrub(str(event.toolName));
|
|
306
360
|
break;
|
|
307
361
|
}
|
|
308
362
|
case "tool:end": {
|
|
@@ -310,7 +364,7 @@ function applyEvent(state, event, now) {
|
|
|
310
364
|
if (node !== void 0) {
|
|
311
365
|
node.toolActive = void 0;
|
|
312
366
|
node.toolCount += 1;
|
|
313
|
-
if (event.outcome === "denied") node.badge = scrub(`tool ${event.toolName} denied`);
|
|
367
|
+
if (event.outcome === "denied") node.badge = scrub(`tool ${str(event.toolName)} denied`);
|
|
314
368
|
}
|
|
315
369
|
break;
|
|
316
370
|
}
|
|
@@ -322,7 +376,7 @@ function applyEvent(state, event, now) {
|
|
|
322
376
|
break;
|
|
323
377
|
case "spawn:rejected":
|
|
324
378
|
state.rejected += 1;
|
|
325
|
-
state.notices.push(`spawn rejected: ${event.code}`);
|
|
379
|
+
state.notices.push(scrub(`spawn rejected: ${str(event.code)}`));
|
|
326
380
|
if (state.notices.length > 2) state.notices.shift();
|
|
327
381
|
break;
|
|
328
382
|
default: break;
|
|
@@ -339,7 +393,7 @@ const GLYPHS = {
|
|
|
339
393
|
escalated: "!"
|
|
340
394
|
};
|
|
341
395
|
function paint(text, code, style) {
|
|
342
|
-
return style.color ?
|
|
396
|
+
return style.color ? `\u001B[${code}m${text}\u001B[0m` : text;
|
|
343
397
|
}
|
|
344
398
|
function nodeRow(node, now, spinner, style) {
|
|
345
399
|
const running = node.endedAt === void 0 && node.status === "running";
|
|
@@ -524,44 +578,57 @@ function progress(source, options) {
|
|
|
524
578
|
const rawRows = sink.rows;
|
|
525
579
|
const maxHeight = typeof rawRows === "number" && Number.isFinite(rawRows) ? Math.max(3, Math.floor(rawRows) - 1) : void 0;
|
|
526
580
|
const frame = composeFrame(state, clock.now(), tick, style, width, maxRows, maxHeight);
|
|
527
|
-
const erase = paintedLines > 0 ?
|
|
581
|
+
const erase = paintedLines > 0 ? `\u001B[${String(paintedLines)}A\u001B[0J` : "";
|
|
528
582
|
sink.write(erase + frame.join("\n") + "\n");
|
|
529
583
|
paintedLines = frame.length;
|
|
530
584
|
state.dirty = false;
|
|
531
585
|
};
|
|
532
586
|
const lineFor = (event, now) => {
|
|
533
587
|
switch (event.type) {
|
|
534
|
-
case "run:start": return `run ${event.runId} started: ${event.workflow}${event.resumed ? " (resumed)" : ""}`;
|
|
535
|
-
case "phase:start": return `phase: ${event.phase}`;
|
|
588
|
+
case "run:start": return `run ${str(event.runId)} started: ${str(event.workflow)}${event.resumed === true ? " (resumed)" : ""}`;
|
|
589
|
+
case "phase:start": return `phase: ${str(event.phase)}`;
|
|
536
590
|
case "agent:start": {
|
|
537
591
|
const node = state.nodes.get(event.spanId);
|
|
538
592
|
const inner = node !== void 0 && node.roles.length > 1;
|
|
539
|
-
return `agent ${agentTitle(event)} -> ${event.model} (${event.role})${inner ? " [inner phase]" : ""}`;
|
|
593
|
+
return `agent ${agentTitle(event)} -> ${str(event.model)} (${str(event.role)})${inner ? " [inner phase]" : ""}`;
|
|
540
594
|
}
|
|
541
595
|
case "agent:end": {
|
|
542
596
|
const node = state.nodes.get(event.spanId);
|
|
543
597
|
const elapsed = node === void 0 || node.replayed || node.startedAt <= 0 ? "" : ` in ${fmtDuration((node.endedAt ?? now) - node.startedAt)}`;
|
|
544
598
|
const roles = node !== void 0 && node.roles.length > 1 ? ` [${node.roles.map((slice) => slice.role).join(" > ")}]` : "";
|
|
545
|
-
return `agent ${agentTitle(event)} ${event.status}${elapsed}: in ${fmtTokens(event.usage?.inputTokens
|
|
599
|
+
return `agent ${agentTitle(event)} ${str(event.status)}${elapsed}: in ${fmtTokens(num(event.usage?.inputTokens))} out ${fmtTokens(num(event.usage?.outputTokens))}, ${fmtUsd(num(event.costUsd))}${roles}${event.replayed === true ? " (replay)" : ""}`;
|
|
546
600
|
}
|
|
547
|
-
case "agent:error": return `agent ${agentTitle(event)} error: ${event.error?.message
|
|
601
|
+
case "agent:error": return `agent ${agentTitle(event)} error: ${str(event.error?.message)}` + (event.willRetry ? " (will retry)" : "");
|
|
548
602
|
case "budget:update":
|
|
549
603
|
if (lastLinesBudgetAt !== void 0 && now - lastLinesBudgetAt < 1e3) return;
|
|
550
604
|
lastLinesBudgetAt = now;
|
|
551
|
-
return `budget: ${fmtUsd(event.spentUsd)}` + (event.remainingUsd ===
|
|
552
|
-
case "log": return event.level === "warn" || event.level === "error" ? `[${event.level}] ${event.msg}` : void 0;
|
|
553
|
-
case "external:waiting": return `waiting on external: ${event.key}`;
|
|
554
|
-
case "approval:pending": return `approval pending: ${event.toolName}`;
|
|
555
|
-
case "run:end": return `run finished: ${event.status} (total ${fmtUsd(event.totalUsd)})`;
|
|
605
|
+
return `budget: ${fmtUsd(num(event.spentUsd))}` + (typeof event.remainingUsd === "number" && Number.isFinite(event.remainingUsd) ? ` of ${fmtUsd(num(event.spentUsd) + event.remainingUsd)}` : "");
|
|
606
|
+
case "log": return event.level === "warn" || event.level === "error" ? `[${str(event.level)}] ${str(event.msg)}` : void 0;
|
|
607
|
+
case "external:waiting": return `waiting on external: ${str(event.key)}`;
|
|
608
|
+
case "approval:pending": return `approval pending: ${str(event.toolName)}`;
|
|
609
|
+
case "run:end": return `run finished: ${str(event.status)} (total ${fmtUsd(num(event.totalUsd))})`;
|
|
556
610
|
default: return;
|
|
557
611
|
}
|
|
558
612
|
};
|
|
613
|
+
const pushNotice = (notice) => {
|
|
614
|
+
state.notices.push(notice);
|
|
615
|
+
if (state.notices.length > 2) state.notices.shift();
|
|
616
|
+
if (mode === "lines") sink.write(scrub(notice) + "\n");
|
|
617
|
+
};
|
|
618
|
+
let malformedNoticed = false;
|
|
559
619
|
const onEvent = (event) => {
|
|
560
620
|
const now = clock.now();
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
621
|
+
try {
|
|
622
|
+
applyEvent(state, event, now);
|
|
623
|
+
if (mode === "lines") {
|
|
624
|
+
const line = lineFor(event, now);
|
|
625
|
+
if (line !== void 0) sink.write(scrub(line) + "\n");
|
|
626
|
+
}
|
|
627
|
+
} catch {
|
|
628
|
+
if (!malformedNoticed) {
|
|
629
|
+
malformedNoticed = true;
|
|
630
|
+
pushNotice("progress: skipped malformed event(s); view may be incomplete");
|
|
631
|
+
}
|
|
565
632
|
}
|
|
566
633
|
};
|
|
567
634
|
const finishLines = () => {
|
|
@@ -615,7 +682,7 @@ function progress(source, options) {
|
|
|
615
682
|
state.totalUsd = outcome.cost.totalUsd;
|
|
616
683
|
state.endedAt ??= clock.now();
|
|
617
684
|
}).catch((thrown) => {
|
|
618
|
-
|
|
685
|
+
pushNotice(errorNotice(thrown));
|
|
619
686
|
state.endedAt ??= clock.now();
|
|
620
687
|
}).finally(() => {
|
|
621
688
|
handleApi.stop(true);
|
|
@@ -625,7 +692,7 @@ function progress(source, options) {
|
|
|
625
692
|
else if (typeof source.then === "function") source.then((handle) => {
|
|
626
693
|
attachHandle(handle);
|
|
627
694
|
}).catch((thrown) => {
|
|
628
|
-
|
|
695
|
+
pushNotice(errorNotice(thrown));
|
|
629
696
|
state.endedAt ??= clock.now();
|
|
630
697
|
handleApi.stop(true);
|
|
631
698
|
});
|
|
@@ -636,7 +703,7 @@ function progress(source, options) {
|
|
|
636
703
|
onEvent(event);
|
|
637
704
|
}
|
|
638
705
|
} catch (thrown) {
|
|
639
|
-
|
|
706
|
+
pushNotice(errorNotice(thrown));
|
|
640
707
|
} finally {
|
|
641
708
|
state.endedAt ??= clock.now();
|
|
642
709
|
handleApi.stop(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/rulvar",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "Rulvar umbrella package: re-exports @rulvar/core, both first-class adapters, the file store, and the terminal progress renderer. Also installable through the unscoped alias package rulvar, which re-exports this one.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@rulvar/core": "1.
|
|
26
|
-
"@rulvar/anthropic": "1.
|
|
27
|
-
"@rulvar/openai": "1.
|
|
25
|
+
"@rulvar/core": "1.24.0",
|
|
26
|
+
"@rulvar/anthropic": "1.24.0",
|
|
27
|
+
"@rulvar/openai": "1.24.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^22.20.0",
|
|
31
31
|
"tsdown": "^0.22.3",
|
|
32
32
|
"typescript": "~6.0.3",
|
|
33
33
|
"zod": "^4.4.3",
|
|
34
|
-
"@rulvar/testing": "1.
|
|
34
|
+
"@rulvar/testing": "1.24.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|