@thedevlabs-io/labd 0.5.0 → 0.6.1
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/AGENTS.md +35 -12
- package/README.md +20 -15
- package/dist/labd.js +385 -98
- package/dist/labd.js.map +4 -4
- package/package.json +1 -1
package/dist/labd.js
CHANGED
|
@@ -433,6 +433,36 @@ var EXEC_TOOLS = ["run_command"];
|
|
|
433
433
|
function isExecTool(name) {
|
|
434
434
|
return EXEC_TOOLS.includes(name);
|
|
435
435
|
}
|
|
436
|
+
var AGENT_TOOLS = ["spawn_agent"];
|
|
437
|
+
function isAgentTool(name) {
|
|
438
|
+
return AGENT_TOOLS.includes(name);
|
|
439
|
+
}
|
|
440
|
+
var MAX_SUBAGENTS = 3;
|
|
441
|
+
var SUBAGENT_REPORT_CHARS = 8e3;
|
|
442
|
+
function subAgentCapabilities(parent) {
|
|
443
|
+
return parent.filter((c) => !isAgentTool(c));
|
|
444
|
+
}
|
|
445
|
+
function subAgentConversationId(parentId, callId) {
|
|
446
|
+
return parentId ? `${parentId}~helper~${callId}` : void 0;
|
|
447
|
+
}
|
|
448
|
+
function subAgentBrief(task) {
|
|
449
|
+
return `You are working as a helper for labd, the assistant the learner is talking to. It has handed you one piece of a larger job and is waiting on your report. The learner is the same person, in the same project, under the same rules: the same tools, the same approvals, and the same things you will not do.
|
|
450
|
+
|
|
451
|
+
Your task:
|
|
452
|
+
|
|
453
|
+
${task.trim()}
|
|
454
|
+
|
|
455
|
+
How to work:
|
|
456
|
+
- You start with none of the parent conversation, so the task above is all you know about it. If it is not enough to act on, say what is missing in your report rather than guessing at the intent.
|
|
457
|
+
- Do the task, and only the task. The parent decides what happens next, so do not widen the job, and do not ask the learner questions - your report goes to the parent, not to them.
|
|
458
|
+
- If a write or command you need is declined, do not look for another way round it. Stop and say so.
|
|
459
|
+
- End with a report the parent can act on without redoing your work: what you found or changed, file by file and with line numbers where they matter, and anything you could not finish and why. Keep it tight. Leave out how you went about it.`;
|
|
460
|
+
}
|
|
461
|
+
function subAgentReport(text) {
|
|
462
|
+
const clean = text.trim() || "The helper finished without a report.";
|
|
463
|
+
return clean.length <= SUBAGENT_REPORT_CHARS ? clean : `${clean.slice(0, SUBAGENT_REPORT_CHARS)}
|
|
464
|
+
... the helper's report was longer than this and was trimmed.`;
|
|
465
|
+
}
|
|
436
466
|
var AGENT_MODES = ["ask", "auto", "agent"];
|
|
437
467
|
var DEFAULT_AGENT_MODE = "auto";
|
|
438
468
|
function toAgentMode(raw) {
|
|
@@ -1319,6 +1349,154 @@ function trim(output) {
|
|
|
1319
1349
|
].join("");
|
|
1320
1350
|
}
|
|
1321
1351
|
|
|
1352
|
+
// packages/core/src/calls.ts
|
|
1353
|
+
var TOOL_OUTPUT_KEPT = 8e3;
|
|
1354
|
+
function keepOutput(text) {
|
|
1355
|
+
const clean = text.replace(/\s+$/, "");
|
|
1356
|
+
return clean.length <= TOOL_OUTPUT_KEPT ? clean : `${clean.slice(0, TOOL_OUTPUT_KEPT)}
|
|
1357
|
+
\u2026 trimmed here.`;
|
|
1358
|
+
}
|
|
1359
|
+
async function executeCall(call, env) {
|
|
1360
|
+
let preview;
|
|
1361
|
+
if (isWriteTool(call.name) || isExecTool(call.name)) {
|
|
1362
|
+
try {
|
|
1363
|
+
preview = previewTool(call, env.toolCtx);
|
|
1364
|
+
env.step({ status: "running", preview });
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1367
|
+
env.step({ status: "error", detail: message });
|
|
1368
|
+
return { id: call.id, content: message, isError: true };
|
|
1369
|
+
}
|
|
1370
|
+
} else {
|
|
1371
|
+
env.step({ status: "running" });
|
|
1372
|
+
}
|
|
1373
|
+
if (needsApproval(env.mode, call)) {
|
|
1374
|
+
env.step({ status: "awaiting", preview });
|
|
1375
|
+
const ok = env.approve ? await env.approve(call, preview) : false;
|
|
1376
|
+
if (env.signal.aborted) return "aborted";
|
|
1377
|
+
if (!ok) {
|
|
1378
|
+
env.step({ status: "skipped", preview });
|
|
1379
|
+
return {
|
|
1380
|
+
id: call.id,
|
|
1381
|
+
content: env.approve ? "The learner declined this, so nothing was done. Do not retry it. Explain what you would have done and why, and let them decide what to do next." : "This needed the learner to approve it and labd is running unattended, so nothing was done. Say what you would have done; do not try another way round it."
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
if (env.signal.aborted) return "aborted";
|
|
1386
|
+
try {
|
|
1387
|
+
const content = await runTool(call, env.toolCtx);
|
|
1388
|
+
if (isWriteTool(call.name)) {
|
|
1389
|
+
const input = call.input;
|
|
1390
|
+
env.wrote(String(input.path ?? input.from ?? ""));
|
|
1391
|
+
}
|
|
1392
|
+
if (isExecTool(call.name)) env.ran(String(call.input.command ?? ""));
|
|
1393
|
+
env.step({ status: isWriteTool(call.name) ? "applied" : "done", preview, output: keepOutput(content) });
|
|
1394
|
+
return { id: call.id, content };
|
|
1395
|
+
} catch (err) {
|
|
1396
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1397
|
+
env.step({ status: "error", preview, detail: message });
|
|
1398
|
+
return { id: call.id, content: message, isError: true };
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// packages/core/src/helper.ts
|
|
1403
|
+
var STALL_ROUNDS = 3;
|
|
1404
|
+
var LABEL_MAX = 80;
|
|
1405
|
+
function helperLabel(call) {
|
|
1406
|
+
const description = call.input.description;
|
|
1407
|
+
const text = typeof description === "string" ? description.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim() : "";
|
|
1408
|
+
return text ? text.length > LABEL_MAX ? `${text.slice(0, LABEL_MAX - 1)}\u2026` : text : "helper";
|
|
1409
|
+
}
|
|
1410
|
+
async function runHelper(call, env) {
|
|
1411
|
+
const task = call.input.task;
|
|
1412
|
+
if (typeof task !== "string" || !task.trim()) {
|
|
1413
|
+
return { id: call.id, content: "spawn_agent needs a `task`: the complete brief for the helper.", isError: true };
|
|
1414
|
+
}
|
|
1415
|
+
const label2 = helperLabel(call);
|
|
1416
|
+
const helper = { id: call.id, label: label2 };
|
|
1417
|
+
const ask = env.approve;
|
|
1418
|
+
const capabilities = subAgentCapabilities(env.capabilities);
|
|
1419
|
+
const conversationId = subAgentConversationId(env.sessionId, call.id);
|
|
1420
|
+
let wire = [{ role: "user", text: subAgentBrief(task) }];
|
|
1421
|
+
let report = "";
|
|
1422
|
+
const asked = /* @__PURE__ */ new Set();
|
|
1423
|
+
let stalled = 0;
|
|
1424
|
+
for (; ; ) {
|
|
1425
|
+
let text = "";
|
|
1426
|
+
const calls = [];
|
|
1427
|
+
let needTools = false;
|
|
1428
|
+
let failure = null;
|
|
1429
|
+
const stream = env.client.stream(
|
|
1430
|
+
{
|
|
1431
|
+
protocol: PROTOCOL_VERSION,
|
|
1432
|
+
messages: wire,
|
|
1433
|
+
context: buildContext(env.root),
|
|
1434
|
+
capabilities,
|
|
1435
|
+
...conversationId ? { conversationId } : {},
|
|
1436
|
+
...env.effort ? { effort: env.effort } : {}
|
|
1437
|
+
},
|
|
1438
|
+
env.signal
|
|
1439
|
+
);
|
|
1440
|
+
for await (const event of stream) {
|
|
1441
|
+
if (env.signal.aborted) break;
|
|
1442
|
+
if (event.type === "text") text += event.text;
|
|
1443
|
+
else if (event.type === "tool_call") calls.push(event.call);
|
|
1444
|
+
else if (event.type === "need_tools") needTools = true;
|
|
1445
|
+
else if (event.type === "error") failure = event.message;
|
|
1446
|
+
}
|
|
1447
|
+
if (env.signal.aborted) return "aborted";
|
|
1448
|
+
if (failure) {
|
|
1449
|
+
const sofar = report ? `
|
|
1450
|
+
|
|
1451
|
+
What it had reported before that:
|
|
1452
|
+
${subAgentReport(report)}` : "";
|
|
1453
|
+
return { id: call.id, content: `The helper stopped: ${failure}${sofar}`, isError: true };
|
|
1454
|
+
}
|
|
1455
|
+
wire = [...wire, { role: "assistant", text, ...calls.length ? { toolCalls: calls } : {} }];
|
|
1456
|
+
if (text.trim()) report = text;
|
|
1457
|
+
if (!needTools || !calls.length) break;
|
|
1458
|
+
const fresh = calls.some((c) => {
|
|
1459
|
+
if (isWriteTool(c.name) || isExecTool(c.name)) return true;
|
|
1460
|
+
const key = `${c.name}:${JSON.stringify(c.input)}`;
|
|
1461
|
+
if (asked.has(key)) return false;
|
|
1462
|
+
asked.add(key);
|
|
1463
|
+
return true;
|
|
1464
|
+
});
|
|
1465
|
+
stalled = fresh ? 0 : stalled + 1;
|
|
1466
|
+
if (stalled >= STALL_ROUNDS) {
|
|
1467
|
+
report = `${report}
|
|
1468
|
+
|
|
1469
|
+
(The helper kept asking for what it had already read, so it was stopped.)`.trim();
|
|
1470
|
+
break;
|
|
1471
|
+
}
|
|
1472
|
+
const results = [];
|
|
1473
|
+
for (const c of calls) {
|
|
1474
|
+
if (env.signal.aborted) return "aborted";
|
|
1475
|
+
if (isAgentTool(c.name)) {
|
|
1476
|
+
results.push({ id: c.id, content: "A helper cannot start helpers of its own. Do this part yourself.", isError: true });
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
const outcome = await executeCall(c, {
|
|
1480
|
+
mode: env.mode(),
|
|
1481
|
+
// Routed to this call's row: two helpers can run commands at once.
|
|
1482
|
+
toolCtx: { ...env.toolCtx, onCommandOutput: (line) => env.toolCtx.onCommandOutput?.(line, `${call.id}/${c.id}`) },
|
|
1483
|
+
signal: env.signal,
|
|
1484
|
+
approve: ask ? (pending, preview) => ask(pending, preview, label2) : void 0,
|
|
1485
|
+
step: (s) => env.step({ ...s, call: c, helper }),
|
|
1486
|
+
wrote: env.wrote,
|
|
1487
|
+
ran: env.ran
|
|
1488
|
+
});
|
|
1489
|
+
if (outcome === "aborted") {
|
|
1490
|
+
env.step({ call: c, helper, status: "skipped", detail: "Stopped." });
|
|
1491
|
+
return "aborted";
|
|
1492
|
+
}
|
|
1493
|
+
results.push(outcome);
|
|
1494
|
+
}
|
|
1495
|
+
wire = [...wire, { role: "tool", results }];
|
|
1496
|
+
}
|
|
1497
|
+
return { id: call.id, content: subAgentReport(report) };
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1322
1500
|
// packages/core/src/agent.ts
|
|
1323
1501
|
var CLI_CAPABILITIES = [
|
|
1324
1502
|
"read_file",
|
|
@@ -1328,18 +1506,15 @@ var CLI_CAPABILITIES = [
|
|
|
1328
1506
|
"create_file",
|
|
1329
1507
|
"move_file",
|
|
1330
1508
|
"delete_file",
|
|
1331
|
-
"run_command"
|
|
1509
|
+
"run_command",
|
|
1510
|
+
// Helpers run here, in this process, on the same rules - see helper.ts.
|
|
1511
|
+
"spawn_agent"
|
|
1332
1512
|
];
|
|
1333
|
-
var
|
|
1334
|
-
function keepOutput(text) {
|
|
1335
|
-
const clean = text.replace(/\s+$/, "");
|
|
1336
|
-
return clean.length <= TOOL_OUTPUT_KEPT ? clean : `${clean.slice(0, TOOL_OUTPUT_KEPT)}
|
|
1337
|
-
\u2026 trimmed here.`;
|
|
1338
|
-
}
|
|
1339
|
-
var STALL_ROUNDS = 3;
|
|
1513
|
+
var STALL_ROUNDS2 = 3;
|
|
1340
1514
|
var COMPACT_AT = 75;
|
|
1341
1515
|
async function runTurn(question, opts) {
|
|
1342
|
-
const { session, client, ui
|
|
1516
|
+
const { session, client, ui } = opts;
|
|
1517
|
+
const modeNow = () => opts.currentMode?.() ?? opts.mode;
|
|
1343
1518
|
const turnId = randomUUID2();
|
|
1344
1519
|
const controller = new AbortController();
|
|
1345
1520
|
opts.signal?.addEventListener("abort", () => controller.abort(), { once: true });
|
|
@@ -1348,10 +1523,17 @@ async function runTurn(question, opts) {
|
|
|
1348
1523
|
checkpoints: opts.checkpoints,
|
|
1349
1524
|
turn: { sessionId: session.id, turnId },
|
|
1350
1525
|
commandTimeoutMs: opts.commandTimeoutMs ?? 12e4,
|
|
1351
|
-
onCommandOutput: (
|
|
1526
|
+
onCommandOutput: (line2, key) => ui.commandOutput?.(line2, key)
|
|
1352
1527
|
};
|
|
1353
1528
|
session.add({ kind: "user", text: question, ...opts.attachments?.length ? { attachments: opts.attachments.map((a) => ({ path: a.path })) } : {} }, turnId);
|
|
1354
1529
|
const result = { text: "", turnId, wrote: [], ran: [], aborted: false };
|
|
1530
|
+
const ask = ui.approve;
|
|
1531
|
+
let line = Promise.resolve();
|
|
1532
|
+
const approve = ask ? (call, preview, helper) => {
|
|
1533
|
+
const answer = line.then(() => controller.signal.aborted ? false : ask(call, preview, helper));
|
|
1534
|
+
line = answer.catch(() => void 0);
|
|
1535
|
+
return answer;
|
|
1536
|
+
} : void 0;
|
|
1355
1537
|
const asked = /* @__PURE__ */ new Set();
|
|
1356
1538
|
let stalled = 0;
|
|
1357
1539
|
for (let round = 0; ; round++) {
|
|
@@ -1430,20 +1612,79 @@ async function runTurn(question, opts) {
|
|
|
1430
1612
|
return true;
|
|
1431
1613
|
});
|
|
1432
1614
|
stalled = fresh ? 0 : stalled + 1;
|
|
1433
|
-
if (stalled >=
|
|
1615
|
+
if (stalled >= STALL_ROUNDS2) {
|
|
1434
1616
|
ui.error(
|
|
1435
1617
|
`labd asked for the same things ${stalled} rounds running, so it stopped rather than keep going round. Tell it which file to start in, or ask for a narrower piece of this.`
|
|
1436
1618
|
);
|
|
1437
1619
|
session.add({ kind: "tool", results: calls.map((c) => stopped(c, "error", "Stopped: labd was repeating itself.")) }, turnId);
|
|
1438
1620
|
return result;
|
|
1439
1621
|
}
|
|
1440
|
-
const results =
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1622
|
+
const results = new Array(calls.length);
|
|
1623
|
+
const working = [];
|
|
1624
|
+
try {
|
|
1625
|
+
let helpers = 0;
|
|
1626
|
+
calls.forEach((call, at2) => {
|
|
1627
|
+
if (!isAgentTool(call.name)) return;
|
|
1628
|
+
const label2 = helperLabel(call);
|
|
1629
|
+
if (helpers++ >= MAX_SUBAGENTS) {
|
|
1630
|
+
const why = `Only ${MAX_SUBAGENTS} helpers can run at once, so this one was not started. Do it yourself, or start it once the others have reported.`;
|
|
1631
|
+
ui.tool({ call, status: "error", detail: why });
|
|
1632
|
+
results[at2] = { id: call.id, content: why, isError: true };
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
ui.tool({ call, status: "running", detail: label2 });
|
|
1636
|
+
working.push(
|
|
1637
|
+
runHelper(call, {
|
|
1638
|
+
client,
|
|
1639
|
+
root: opts.root,
|
|
1640
|
+
mode: modeNow,
|
|
1641
|
+
effort: opts.effort,
|
|
1642
|
+
capabilities: CLI_CAPABILITIES,
|
|
1643
|
+
sessionId: session.id,
|
|
1644
|
+
toolCtx,
|
|
1645
|
+
signal: controller.signal,
|
|
1646
|
+
approve,
|
|
1647
|
+
step: (step) => ui.tool(step),
|
|
1648
|
+
wrote: (path) => result.wrote.push(path),
|
|
1649
|
+
ran: (command) => result.ran.push(command)
|
|
1650
|
+
}).catch((err) => ({
|
|
1651
|
+
id: call.id,
|
|
1652
|
+
content: `The helper failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1653
|
+
isError: true
|
|
1654
|
+
})).then((outcome) => {
|
|
1655
|
+
if (outcome === "aborted") {
|
|
1656
|
+
results[at2] = stopped(call);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
results[at2] = outcome;
|
|
1660
|
+
ui.tool({ call, status: outcome.isError ? "error" : "done", detail: label2, output: keepOutput(outcome.content) });
|
|
1661
|
+
})
|
|
1662
|
+
);
|
|
1663
|
+
});
|
|
1664
|
+
for (const [at2, call] of calls.entries()) {
|
|
1665
|
+
if (isAgentTool(call.name)) continue;
|
|
1666
|
+
if (controller.signal.aborted) {
|
|
1667
|
+
results[at2] = stopped(call);
|
|
1668
|
+
continue;
|
|
1669
|
+
}
|
|
1670
|
+
const outcome = await executeCall(call, {
|
|
1671
|
+
mode: modeNow(),
|
|
1672
|
+
// Output names its row, so it cannot land in a helper's command
|
|
1673
|
+
// running at the same moment.
|
|
1674
|
+
toolCtx: { ...toolCtx, onCommandOutput: (line2) => ui.commandOutput?.(line2, call.id) },
|
|
1675
|
+
signal: controller.signal,
|
|
1676
|
+
approve,
|
|
1677
|
+
step: (step) => ui.tool({ ...step, call }),
|
|
1678
|
+
wrote: (path) => result.wrote.push(path),
|
|
1679
|
+
ran: (command) => result.ran.push(command)
|
|
1680
|
+
});
|
|
1681
|
+
results[at2] = outcome === "aborted" ? stopped(call) : outcome;
|
|
1445
1682
|
}
|
|
1446
|
-
|
|
1683
|
+
await Promise.all(working);
|
|
1684
|
+
} catch (err) {
|
|
1685
|
+
controller.abort();
|
|
1686
|
+
await Promise.allSettled(working);
|
|
1687
|
+
throw err;
|
|
1447
1688
|
}
|
|
1448
1689
|
session.add({ kind: "tool", results }, turnId);
|
|
1449
1690
|
if (controller.signal.aborted) {
|
|
@@ -1455,52 +1696,6 @@ async function runTurn(question, opts) {
|
|
|
1455
1696
|
ui.tool({ call, status, detail: why });
|
|
1456
1697
|
return { id: call.id, content: why, isError: true };
|
|
1457
1698
|
}
|
|
1458
|
-
async function runOne(call) {
|
|
1459
|
-
let preview;
|
|
1460
|
-
if (isWriteTool(call.name) || isExecTool(call.name)) {
|
|
1461
|
-
try {
|
|
1462
|
-
preview = previewTool(call, toolCtx);
|
|
1463
|
-
ui.tool({ call, status: "running", preview });
|
|
1464
|
-
} catch (err) {
|
|
1465
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1466
|
-
ui.tool({ call, status: "error", detail: message });
|
|
1467
|
-
return { id: call.id, content: message, isError: true };
|
|
1468
|
-
}
|
|
1469
|
-
} else {
|
|
1470
|
-
ui.tool({ call, status: "running" });
|
|
1471
|
-
}
|
|
1472
|
-
if (needsApproval(mode, call)) {
|
|
1473
|
-
ui.tool({ call, status: "awaiting", preview });
|
|
1474
|
-
const ok = ui.approve ? await ui.approve(call, preview) : false;
|
|
1475
|
-
if (controller.signal.aborted) return stopped(call);
|
|
1476
|
-
if (!ok) {
|
|
1477
|
-
ui.tool({ call, status: "skipped", preview });
|
|
1478
|
-
return {
|
|
1479
|
-
id: call.id,
|
|
1480
|
-
content: ui.approve ? "The learner declined this, so nothing was done. Do not retry it. Explain what you would have done and why, and let them decide what to do next." : "This needed the learner to approve it and labd is running unattended, so nothing was done. Say what you would have done; do not try another way round it."
|
|
1481
|
-
};
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
try {
|
|
1485
|
-
const content = await runTool(call, toolCtx);
|
|
1486
|
-
if (isWriteTool(call.name)) {
|
|
1487
|
-
const input = call.input;
|
|
1488
|
-
result.wrote.push(String(input.path ?? input.from ?? ""));
|
|
1489
|
-
}
|
|
1490
|
-
if (isExecTool(call.name)) result.ran.push(String(call.input.command ?? ""));
|
|
1491
|
-
ui.tool({
|
|
1492
|
-
call,
|
|
1493
|
-
status: isWriteTool(call.name) ? "applied" : "done",
|
|
1494
|
-
preview,
|
|
1495
|
-
output: keepOutput(content)
|
|
1496
|
-
});
|
|
1497
|
-
return { id: call.id, content };
|
|
1498
|
-
} catch (err) {
|
|
1499
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1500
|
-
ui.tool({ call, status: "error", preview, detail: message });
|
|
1501
|
-
return { id: call.id, content: message, isError: true };
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
1699
|
}
|
|
1505
1700
|
async function compact(opts) {
|
|
1506
1701
|
const controller = new AbortController();
|
|
@@ -1898,9 +2093,16 @@ function setColor(value) {
|
|
|
1898
2093
|
on = value;
|
|
1899
2094
|
}
|
|
1900
2095
|
var wrap = (open, close = "0") => (text) => on ? `${ESC}[${open}m${text}${ESC}[${close}m` : text;
|
|
2096
|
+
function lightBackground() {
|
|
2097
|
+
const bg = Number(process.env.COLORFGBG?.split(";").at(-1));
|
|
2098
|
+
return bg === 7 || bg === 15;
|
|
2099
|
+
}
|
|
1901
2100
|
var paint = {
|
|
1902
|
-
/**
|
|
1903
|
-
|
|
2101
|
+
/**
|
|
2102
|
+
* labd's accent. 214 is the nearest xterm cube entry to the brand orange.
|
|
2103
|
+
* Closes the foreground only, so it can sit inside a `band` without ending it.
|
|
2104
|
+
*/
|
|
2105
|
+
accent: wrap("38;5;214", "39"),
|
|
1904
2106
|
bold: wrap("1", "22"),
|
|
1905
2107
|
dim: wrap("2", "22"),
|
|
1906
2108
|
muted: wrap("90"),
|
|
@@ -1912,6 +2114,11 @@ var paint = {
|
|
|
1912
2114
|
/** For the one place a background is worth it: the cursor cell in the box. */
|
|
1913
2115
|
invert: wrap("7", "27")
|
|
1914
2116
|
};
|
|
2117
|
+
function band(text, visible, width) {
|
|
2118
|
+
if (!on) return text;
|
|
2119
|
+
const bg = lightBackground() ? "48;5;254" : "48;5;236";
|
|
2120
|
+
return `${ESC}[${bg}m${text}${" ".repeat(Math.max(0, width - visible))}${ESC}[49m`;
|
|
2121
|
+
}
|
|
1915
2122
|
function stripColor(text) {
|
|
1916
2123
|
return text.replace(new RegExp(`${ESC}\\[[0-9;]*m`, "g"), "");
|
|
1917
2124
|
}
|
|
@@ -2073,7 +2280,8 @@ var LABELS = {
|
|
|
2073
2280
|
create_file: "Create",
|
|
2074
2281
|
move_file: "Move",
|
|
2075
2282
|
delete_file: "Delete",
|
|
2076
|
-
run_command: "Run"
|
|
2283
|
+
run_command: "Run",
|
|
2284
|
+
spawn_agent: "Helper"
|
|
2077
2285
|
};
|
|
2078
2286
|
function approvalCard(preview, call, mode, width) {
|
|
2079
2287
|
const out = [""];
|
|
@@ -3183,7 +3391,6 @@ function wrap2(text, width, first, rest) {
|
|
|
3183
3391
|
}
|
|
3184
3392
|
|
|
3185
3393
|
// packages/tui/src/transcript.ts
|
|
3186
|
-
var MAX_PROSE_WIDTH = 100;
|
|
3187
3394
|
var LIVE_LINES = 8;
|
|
3188
3395
|
var Transcript = class {
|
|
3189
3396
|
entries = [];
|
|
@@ -3203,6 +3410,17 @@ var Transcript = class {
|
|
|
3203
3410
|
this.entries.push(entry);
|
|
3204
3411
|
return entry;
|
|
3205
3412
|
}
|
|
3413
|
+
/**
|
|
3414
|
+
* Move a block to the bottom. For an approval card, which must stay the last
|
|
3415
|
+
* thing on screen while it waits: a helper that keeps working adds rows below
|
|
3416
|
+
* it, and a card pushed up past the fold is one approved without being read.
|
|
3417
|
+
*/
|
|
3418
|
+
toEnd(entry) {
|
|
3419
|
+
const at2 = this.entries.indexOf(entry);
|
|
3420
|
+
if (at2 === -1 || at2 === this.entries.length - 1) return;
|
|
3421
|
+
this.entries.splice(at2, 1);
|
|
3422
|
+
this.entries.push(entry);
|
|
3423
|
+
}
|
|
3206
3424
|
/** Say a block changed, so its cached lines are dropped on the next render. */
|
|
3207
3425
|
touch(entry) {
|
|
3208
3426
|
entry.version++;
|
|
@@ -3274,14 +3492,17 @@ function splitStreaming(text) {
|
|
|
3274
3492
|
return { complete: complete2.join("\n"), tail };
|
|
3275
3493
|
}
|
|
3276
3494
|
function proseWidth(width) {
|
|
3277
|
-
return Math.max(20,
|
|
3495
|
+
return Math.max(20, width - 2);
|
|
3278
3496
|
}
|
|
3279
3497
|
function renderBlock(block, width) {
|
|
3280
3498
|
const inner = proseWidth(width);
|
|
3281
3499
|
switch (block.kind) {
|
|
3282
3500
|
case "user":
|
|
3283
3501
|
return block.text.split("\n").flatMap(
|
|
3284
|
-
(line, i) => wrapPlain(line, inner - 2).map((piece, j) =>
|
|
3502
|
+
(line, i) => wrapPlain(line, inner - 2).map((piece, j) => {
|
|
3503
|
+
const text = i === 0 && j === 0 ? `${paint.accent(">")} ${piece}` : ` ${piece}`;
|
|
3504
|
+
return band(text, visibleWidth(text), width);
|
|
3505
|
+
})
|
|
3285
3506
|
);
|
|
3286
3507
|
case "assistant":
|
|
3287
3508
|
return [];
|
|
@@ -3295,7 +3516,10 @@ function renderBlock(block, width) {
|
|
|
3295
3516
|
return out;
|
|
3296
3517
|
}
|
|
3297
3518
|
case "approval": {
|
|
3298
|
-
const out =
|
|
3519
|
+
const out = [
|
|
3520
|
+
...block.helper ? [` ${paint.accent("from a helper:")} ${paint.muted(block.helper)}`] : [],
|
|
3521
|
+
...approvalCard(block.preview, block.call, block.mode, inner)
|
|
3522
|
+
];
|
|
3299
3523
|
out.push(
|
|
3300
3524
|
block.answer === null ? ` ${paint.yellow("y")} ${paint.muted("to allow \xB7")} ${paint.yellow("n")} ${paint.muted("or esc to decline")}` : ` ${block.answer === "allowed" ? paint.green("allowed") : paint.muted("declined")}`
|
|
3301
3525
|
);
|
|
@@ -4469,11 +4693,18 @@ function fileTag(line) {
|
|
|
4469
4693
|
return { at: at2, partial };
|
|
4470
4694
|
}
|
|
4471
4695
|
function label(step) {
|
|
4472
|
-
|
|
4696
|
+
if (step.call.name === "spawn_agent") return `working with a helper: ${detail(step)}`;
|
|
4697
|
+
const own = `${step.call.name.replace(/_/g, " ")} ${detail(step)}`;
|
|
4698
|
+
return step.helper ? `${step.helper.label}: ${own}` : own;
|
|
4699
|
+
}
|
|
4700
|
+
function stepKey(step) {
|
|
4701
|
+
return step.helper ? `${step.helper.id}/${step.call.id}` : step.call.id;
|
|
4473
4702
|
}
|
|
4474
4703
|
function detail(step) {
|
|
4475
4704
|
const input = step.call.input;
|
|
4476
|
-
|
|
4705
|
+
if (step.call.name === "spawn_agent") return String(input.description ?? "helper");
|
|
4706
|
+
const own = String(input.why ?? input.path ?? input.from ?? input.query ?? "");
|
|
4707
|
+
return step.helper ? `\u21B3 ${step.helper.label} \xB7 ${own}` : own;
|
|
4477
4708
|
}
|
|
4478
4709
|
function verbatim(call) {
|
|
4479
4710
|
const i = call.input;
|
|
@@ -4489,6 +4720,10 @@ function verbatim(call) {
|
|
|
4489
4720
|
return `${str("from")} \u2192 ${str("to")}`;
|
|
4490
4721
|
case "list_dir":
|
|
4491
4722
|
return str("path") || "/";
|
|
4723
|
+
// The whole brief: what the helper was actually told is what a learner
|
|
4724
|
+
// wants when its report surprises them.
|
|
4725
|
+
case "spawn_agent":
|
|
4726
|
+
return str("task");
|
|
4492
4727
|
default:
|
|
4493
4728
|
return str("path");
|
|
4494
4729
|
}
|
|
@@ -4580,6 +4815,8 @@ async function runInteractive(runtime) {
|
|
|
4580
4815
|
abort = new AbortController();
|
|
4581
4816
|
const markdown = new MarkdownStream(renderer.contentWidth);
|
|
4582
4817
|
let opened = false;
|
|
4818
|
+
let held = null;
|
|
4819
|
+
const say = (line) => held ? held.push(line) : renderer.print(line);
|
|
4583
4820
|
const ui = {
|
|
4584
4821
|
text(chunk) {
|
|
4585
4822
|
const ready = markdown.push(chunk);
|
|
@@ -4601,7 +4838,7 @@ async function runInteractive(runtime) {
|
|
|
4601
4838
|
}
|
|
4602
4839
|
}
|
|
4603
4840
|
if (step.status === "running" || step.status === "awaiting") {
|
|
4604
|
-
startSpinner(label(step));
|
|
4841
|
+
if (!held) startSpinner(label(step));
|
|
4605
4842
|
return;
|
|
4606
4843
|
}
|
|
4607
4844
|
for (const line of toolBlock(
|
|
@@ -4611,19 +4848,27 @@ async function runInteractive(runtime) {
|
|
|
4611
4848
|
{ input: verbatim(step.call), output: step.output ?? step.detail },
|
|
4612
4849
|
renderer.contentWidth
|
|
4613
4850
|
)) {
|
|
4614
|
-
|
|
4851
|
+
say(line);
|
|
4615
4852
|
}
|
|
4616
4853
|
},
|
|
4617
|
-
async approve(call, preview) {
|
|
4854
|
+
async approve(call, preview, helper) {
|
|
4618
4855
|
stopSpinner();
|
|
4856
|
+
if (helper) renderer.print(` ${paint.accent("from a helper:")} ${paint.muted(helper)}`);
|
|
4619
4857
|
for (const line of approvalCard(preview, call, state.mode, renderer.contentWidth)) {
|
|
4620
4858
|
renderer.print(line);
|
|
4621
4859
|
}
|
|
4622
4860
|
const verb = call.name === "run_command" ? "run this command" : "apply this change";
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4861
|
+
held = [];
|
|
4862
|
+
try {
|
|
4863
|
+
const answer = await prompt.read(`${verb}? [y/N]`);
|
|
4864
|
+
const ok = answer.kind === "line" && /^y(es)?$/i.test(answer.text.trim());
|
|
4865
|
+
renderer.print(` ${ok ? paint.green("allowed") : paint.muted("declined")}`);
|
|
4866
|
+
return ok;
|
|
4867
|
+
} finally {
|
|
4868
|
+
const waiting = held;
|
|
4869
|
+
held = null;
|
|
4870
|
+
for (const line of waiting) renderer.print(line);
|
|
4871
|
+
}
|
|
4627
4872
|
},
|
|
4628
4873
|
error(message) {
|
|
4629
4874
|
stopSpinner();
|
|
@@ -4634,7 +4879,7 @@ async function runInteractive(runtime) {
|
|
|
4634
4879
|
if (info2.credits) state.credits = info2.credits;
|
|
4635
4880
|
},
|
|
4636
4881
|
commandOutput(line) {
|
|
4637
|
-
|
|
4882
|
+
say(paint.dim(` | ${line.replace(/\n/g, "\n | ")}`));
|
|
4638
4883
|
}
|
|
4639
4884
|
};
|
|
4640
4885
|
startSpinner("thinking");
|
|
@@ -4817,6 +5062,14 @@ async function runScreen(runtime, opts) {
|
|
|
4817
5062
|
const history = new History();
|
|
4818
5063
|
const state = {
|
|
4819
5064
|
mode: runtime.settings.mode,
|
|
5065
|
+
/**
|
|
5066
|
+
* The mode the running turn is held to, when shift+tab has moved `mode` up
|
|
5067
|
+
* to `agent` mid-answer. Going up does not apply until the next question -
|
|
5068
|
+
* a habit keypress must not let the very next command run unasked - while
|
|
5069
|
+
* going down applies at once, being the safe direction. Null when the turn
|
|
5070
|
+
* simply follows `mode`.
|
|
5071
|
+
*/
|
|
5072
|
+
heldMode: null,
|
|
4820
5073
|
effort: runtime.settings.effort,
|
|
4821
5074
|
context: null,
|
|
4822
5075
|
credits: null,
|
|
@@ -4952,7 +5205,8 @@ async function runScreen(runtime, opts) {
|
|
|
4952
5205
|
`${paint.muted(basename5(runtime.root))}${runtime.branch ? ` ${paint.muted(runtime.branch)}` : ""}`,
|
|
4953
5206
|
paint.dim(`session ${session}`)
|
|
4954
5207
|
].join(paint.dim(" \xB7 "));
|
|
4955
|
-
const
|
|
5208
|
+
const shown = state.mode === "agent" ? paint.red(paint.bold("agent")) : state.mode === "auto" ? paint.accent("auto") : paint.muted("ask");
|
|
5209
|
+
const mode = state.heldMode ? `${shown}${paint.dim(" (next question)")}` : shown;
|
|
4956
5210
|
const right = `${mode}${state.effort ? paint.dim(` \xB7 think ${state.effort}`) : ""} `;
|
|
4957
5211
|
return spread(` ${left}`, right, width);
|
|
4958
5212
|
}
|
|
@@ -4966,7 +5220,7 @@ async function runScreen(runtime, opts) {
|
|
|
4966
5220
|
else if (state.popup) left = d("\u2191\u2193 move \xB7 tab/enter accept \xB7 esc close");
|
|
4967
5221
|
else {
|
|
4968
5222
|
const described = describe(editor.currentLine, runtime);
|
|
4969
|
-
left = described.hint ? described.hint : d("enter send \xB7 shift+
|
|
5223
|
+
left = described.hint ? described.hint : d("enter send \xB7 shift+tab mode \xB7 / commands \xB7 @ files \xB7 pgup/pgdn scroll \xB7 ctrl+c stop \xB7 ctrl+d quit");
|
|
4970
5224
|
}
|
|
4971
5225
|
const bits = [];
|
|
4972
5226
|
if (state.context) {
|
|
@@ -5050,6 +5304,7 @@ async function runScreen(runtime, opts) {
|
|
|
5050
5304
|
if (key.sequence === "n" || key.sequence === "N" || key.name === "escape") return answerApproval(false);
|
|
5051
5305
|
return;
|
|
5052
5306
|
}
|
|
5307
|
+
if (key.name === "tab" && key.shift) return cycleMode();
|
|
5053
5308
|
if (key.ctrl && key.name === "d") {
|
|
5054
5309
|
if (editor.isEmpty) quit();
|
|
5055
5310
|
return;
|
|
@@ -5127,6 +5382,25 @@ async function runScreen(runtime, opts) {
|
|
|
5127
5382
|
state.ctrlCAt = now;
|
|
5128
5383
|
notice("press ctrl+c again to quit");
|
|
5129
5384
|
}
|
|
5385
|
+
function effectiveMode() {
|
|
5386
|
+
return state.heldMode ?? state.mode;
|
|
5387
|
+
}
|
|
5388
|
+
function cycleMode() {
|
|
5389
|
+
const previous = effectiveMode();
|
|
5390
|
+
const next = AGENT_MODES[(AGENT_MODES.indexOf(state.mode) + 1) % AGENT_MODES.length];
|
|
5391
|
+
state.mode = next;
|
|
5392
|
+
const running = state.abort !== null;
|
|
5393
|
+
state.heldMode = next === "agent" && running ? previous : null;
|
|
5394
|
+
notice(`${next}: ${MODE_CAPTION[next]}`, 4e3);
|
|
5395
|
+
if (next === "agent") {
|
|
5396
|
+
note(
|
|
5397
|
+
` ${paint.red(paint.bold("agent"))} ${paint.muted(
|
|
5398
|
+
running ? `- from your next question. This answer stays on ${previous}.` : "- commands now run without asking, and cannot be put back."
|
|
5399
|
+
)}
|
|
5400
|
+
${paint.muted("For this session only. shift+tab again to leave it.")}`
|
|
5401
|
+
);
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5130
5404
|
function answerApproval(ok) {
|
|
5131
5405
|
const approval = state.approval;
|
|
5132
5406
|
if (!approval) return;
|
|
@@ -5241,7 +5515,10 @@ async function runScreen(runtime, opts) {
|
|
|
5241
5515
|
});
|
|
5242
5516
|
if (outcome.farewell) state.farewell = outcome.farewell;
|
|
5243
5517
|
if (outcome.exit) return quit();
|
|
5244
|
-
if (outcome.mode)
|
|
5518
|
+
if (outcome.mode) {
|
|
5519
|
+
state.mode = outcome.mode;
|
|
5520
|
+
state.heldMode = null;
|
|
5521
|
+
}
|
|
5245
5522
|
if (outcome.effort !== void 0) state.effort = outcome.effort;
|
|
5246
5523
|
schedule();
|
|
5247
5524
|
}
|
|
@@ -5254,6 +5531,7 @@ async function runScreen(runtime, opts) {
|
|
|
5254
5531
|
["shift+enter, ctrl+j, or a trailing \\", "new line"],
|
|
5255
5532
|
["/ and @", "commands and files, with a list"],
|
|
5256
5533
|
["tab", "complete"],
|
|
5534
|
+
["shift+tab", "next mode: ask, auto, agent"],
|
|
5257
5535
|
["pgup / pgdn, wheel", "scroll the transcript"],
|
|
5258
5536
|
["home / end", "top / bottom (with an empty box)"],
|
|
5259
5537
|
["esc", "close a list or dialog; jump back to the bottom"],
|
|
@@ -5336,6 +5614,7 @@ async function runScreen(runtime, opts) {
|
|
|
5336
5614
|
}
|
|
5337
5615
|
}
|
|
5338
5616
|
async function ask(input) {
|
|
5617
|
+
state.heldMode = null;
|
|
5339
5618
|
transcript.add({ kind: "user", text: input });
|
|
5340
5619
|
state.asked = true;
|
|
5341
5620
|
state.answer = null;
|
|
@@ -5372,7 +5651,8 @@ async function runScreen(runtime, opts) {
|
|
|
5372
5651
|
}
|
|
5373
5652
|
}
|
|
5374
5653
|
closeAnswer();
|
|
5375
|
-
|
|
5654
|
+
const key = stepKey(step);
|
|
5655
|
+
let entry = state.toolBlocks.get(key);
|
|
5376
5656
|
if (!entry) {
|
|
5377
5657
|
entry = transcript.add({
|
|
5378
5658
|
kind: "tool",
|
|
@@ -5382,7 +5662,11 @@ async function runScreen(runtime, opts) {
|
|
|
5382
5662
|
input: verbatim(step.call) || void 0,
|
|
5383
5663
|
live: []
|
|
5384
5664
|
});
|
|
5385
|
-
state.toolBlocks.set(
|
|
5665
|
+
state.toolBlocks.set(key, entry);
|
|
5666
|
+
if (state.approval) {
|
|
5667
|
+
transcript.toEnd(state.approval.entry);
|
|
5668
|
+
if (viewport.follow) viewport.end();
|
|
5669
|
+
}
|
|
5386
5670
|
}
|
|
5387
5671
|
entry.block.status = step.status;
|
|
5388
5672
|
if (step.status !== "running" && step.status !== "awaiting") {
|
|
@@ -5393,10 +5677,10 @@ async function runScreen(runtime, opts) {
|
|
|
5393
5677
|
if (step.status === "running" || step.status === "awaiting") setBusy(label(step));
|
|
5394
5678
|
schedule();
|
|
5395
5679
|
},
|
|
5396
|
-
approve(call, preview) {
|
|
5680
|
+
approve(call, preview, helper) {
|
|
5397
5681
|
setBusy(null);
|
|
5398
5682
|
closeAnswer();
|
|
5399
|
-
const entry = transcript.add({ kind: "approval", call, preview, mode:
|
|
5683
|
+
const entry = transcript.add({ kind: "approval", call, preview, helper, mode: effectiveMode(), answer: null });
|
|
5400
5684
|
viewport.end();
|
|
5401
5685
|
return new Promise((resolve2) => {
|
|
5402
5686
|
state.approval = { entry, resolve: resolve2 };
|
|
@@ -5413,11 +5697,8 @@ async function runScreen(runtime, opts) {
|
|
|
5413
5697
|
if (info2.credits) state.credits = info2.credits;
|
|
5414
5698
|
schedule();
|
|
5415
5699
|
},
|
|
5416
|
-
commandOutput(line) {
|
|
5417
|
-
|
|
5418
|
-
for (const entry of state.toolBlocks.values()) {
|
|
5419
|
-
if (entry.block.name === "run_command" && entry.block.status === "running") target = entry;
|
|
5420
|
-
}
|
|
5700
|
+
commandOutput(line, key) {
|
|
5701
|
+
const target = key ? state.toolBlocks.get(key) : void 0;
|
|
5421
5702
|
if (!target) return;
|
|
5422
5703
|
target.block.live.push(...line.replace(/\n$/, "").split("\n"));
|
|
5423
5704
|
transcript.touch(target);
|
|
@@ -5431,6 +5712,7 @@ async function runScreen(runtime, opts) {
|
|
|
5431
5712
|
client: runtime.client,
|
|
5432
5713
|
root: runtime.root,
|
|
5433
5714
|
mode: state.mode,
|
|
5715
|
+
currentMode: effectiveMode,
|
|
5434
5716
|
checkpoints: runtime.checkpoints,
|
|
5435
5717
|
effort: state.effort,
|
|
5436
5718
|
attachments,
|
|
@@ -5453,6 +5735,7 @@ async function runScreen(runtime, opts) {
|
|
|
5453
5735
|
transcript.add({ kind: "error", text: err instanceof Error ? err.message : String(err) });
|
|
5454
5736
|
} finally {
|
|
5455
5737
|
if (state.abort === abort) state.abort = null;
|
|
5738
|
+
state.heldMode = null;
|
|
5456
5739
|
if (state.approval) answerApproval(false);
|
|
5457
5740
|
setBusy(null);
|
|
5458
5741
|
}
|
|
@@ -5637,6 +5920,7 @@ async function runPrint(runtime, opts) {
|
|
|
5637
5920
|
emit({
|
|
5638
5921
|
type: "tool",
|
|
5639
5922
|
name: step.call.name,
|
|
5923
|
+
...step.helper ? { helper: step.helper } : {},
|
|
5640
5924
|
status: step.status,
|
|
5641
5925
|
input: step.call.input,
|
|
5642
5926
|
detail: step.detail,
|
|
@@ -5644,7 +5928,8 @@ async function runPrint(runtime, opts) {
|
|
|
5644
5928
|
output: step.output
|
|
5645
5929
|
});
|
|
5646
5930
|
} else if (step.status !== "running") {
|
|
5647
|
-
|
|
5931
|
+
const who = step.helper ? `${step.helper.label} > ` : "";
|
|
5932
|
+
toStderr(`${paint.dim(`${who}${step.call.name}: ${step.status}${step.detail ? ` - ${step.detail}` : ""}`)}
|
|
5648
5933
|
`);
|
|
5649
5934
|
}
|
|
5650
5935
|
if (step.status === "skipped") declined = true;
|
|
@@ -5803,6 +6088,8 @@ async function runRpc(runtime) {
|
|
|
5803
6088
|
tool(step) {
|
|
5804
6089
|
notify("labd/tool", {
|
|
5805
6090
|
name: step.call.name,
|
|
6091
|
+
// Which helper made the call, when one did: its spawn_agent call id and name.
|
|
6092
|
+
...step.helper ? { helper: step.helper } : {},
|
|
5806
6093
|
status: step.status,
|
|
5807
6094
|
input: step.call.input,
|
|
5808
6095
|
detail: step.detail,
|
|
@@ -5816,8 +6103,8 @@ async function runRpc(runtime) {
|
|
|
5816
6103
|
done(info2) {
|
|
5817
6104
|
notify("labd/done", info2);
|
|
5818
6105
|
},
|
|
5819
|
-
commandOutput(line) {
|
|
5820
|
-
notify("labd/command_output", { line });
|
|
6106
|
+
commandOutput(line, key) {
|
|
6107
|
+
notify("labd/command_output", { line, ...key ? { key } : {} });
|
|
5821
6108
|
},
|
|
5822
6109
|
/**
|
|
5823
6110
|
* Ask the host. A host that never answers gets a refusal after a timeout
|
|
@@ -5825,7 +6112,7 @@ async function runRpc(runtime) {
|
|
|
5825
6112
|
* alternative is writing to someone's files because their integration was
|
|
5826
6113
|
* asleep.
|
|
5827
6114
|
*/
|
|
5828
|
-
approve(call, preview) {
|
|
6115
|
+
approve(call, preview, helper) {
|
|
5829
6116
|
return new Promise((resolve2) => {
|
|
5830
6117
|
if (closed) return resolve2(false);
|
|
5831
6118
|
const id = nextId++;
|
|
@@ -5836,7 +6123,7 @@ async function runRpc(runtime) {
|
|
|
5836
6123
|
clearTimeout(timer);
|
|
5837
6124
|
resolve2(approved);
|
|
5838
6125
|
});
|
|
5839
|
-
out({ jsonrpc: "2.0", id, method: "labd/approve", params: { call, preview } });
|
|
6126
|
+
out({ jsonrpc: "2.0", id, method: "labd/approve", params: { call, preview, ...helper ? { helper } : {} } });
|
|
5840
6127
|
});
|
|
5841
6128
|
}
|
|
5842
6129
|
};
|
|
@@ -5866,7 +6153,7 @@ async function runRpc(runtime) {
|
|
|
5866
6153
|
}
|
|
5867
6154
|
|
|
5868
6155
|
// packages/cli/src/index.ts
|
|
5869
|
-
var VERSION = true ? "0.
|
|
6156
|
+
var VERSION = true ? "0.6.1" : "0.0.0-dev";
|
|
5870
6157
|
async function main(argv) {
|
|
5871
6158
|
const args = parse(argv);
|
|
5872
6159
|
if (args.color !== void 0) setColor(args.color);
|