neko-harness 0.3.0 → 0.3.2
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 +3 -1
- package/dist/client/assets/index-DhW2urBC.css +2 -0
- package/dist/client/assets/index-Dz-jYu0K.js +129 -0
- package/dist/client/index.html +2 -2
- package/dist/gateway.js +661 -157
- package/dist/neko.js +3149 -297
- package/package.json +1 -1
- package/dist/client/assets/index-DrXtf9P_.js +0 -83
- package/dist/client/assets/index-Dv47_XaY.css +0 -2
package/dist/neko.js
CHANGED
|
@@ -79,7 +79,7 @@ function updateAction(input) {
|
|
|
79
79
|
return "install";
|
|
80
80
|
return "none";
|
|
81
81
|
}
|
|
82
|
-
var RUNNING_VERSION = "0.3.
|
|
82
|
+
var RUNNING_VERSION = "0.3.2", APPLICATION_PROTOCOL = 4, ApplicationProtocolError;
|
|
83
83
|
var init_application_version = __esm(() => {
|
|
84
84
|
ApplicationProtocolError = class ApplicationProtocolError extends Error {
|
|
85
85
|
constructor() {
|
|
@@ -803,7 +803,10 @@ function summarizeToolCall(name, args) {
|
|
|
803
803
|
const record = args ?? {};
|
|
804
804
|
switch (name) {
|
|
805
805
|
case "subagent":
|
|
806
|
-
return {
|
|
806
|
+
return {
|
|
807
|
+
args: record.action === "list" ? "List agents" : `${record.agentId ?? record.type}: ${record.title}`,
|
|
808
|
+
detail: String(record.task ?? "")
|
|
809
|
+
};
|
|
807
810
|
case "find_files":
|
|
808
811
|
case "search_text":
|
|
809
812
|
return {
|
|
@@ -843,6 +846,51 @@ function toolResultText(content) {
|
|
|
843
846
|
return content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text ?? "").join(`
|
|
844
847
|
`);
|
|
845
848
|
}
|
|
849
|
+
function countDiffLines(diff) {
|
|
850
|
+
let added = 0;
|
|
851
|
+
let removed = 0;
|
|
852
|
+
for (const line of diff.split(`
|
|
853
|
+
`)) {
|
|
854
|
+
if (line.startsWith("+") && !line.startsWith("+++"))
|
|
855
|
+
added++;
|
|
856
|
+
else if (line.startsWith("-") && !line.startsWith("---"))
|
|
857
|
+
removed++;
|
|
858
|
+
}
|
|
859
|
+
return { added, removed };
|
|
860
|
+
}
|
|
861
|
+
function editResultDiff(details) {
|
|
862
|
+
if (typeof details !== "object" || details === null)
|
|
863
|
+
return null;
|
|
864
|
+
const diff = details.diff;
|
|
865
|
+
return typeof diff === "string" ? diff : null;
|
|
866
|
+
}
|
|
867
|
+
function synthesizedWriteDiff(args) {
|
|
868
|
+
const record = args ?? {};
|
|
869
|
+
if (typeof record.content !== "string")
|
|
870
|
+
return null;
|
|
871
|
+
const content = record.content;
|
|
872
|
+
const shown = [];
|
|
873
|
+
let offset = 0;
|
|
874
|
+
let bytes = 0;
|
|
875
|
+
while (offset < content.length && shown.length < WRITE_DIFF_MAX_LINES) {
|
|
876
|
+
const newline = content.indexOf(`
|
|
877
|
+
`, offset);
|
|
878
|
+
const end = newline === -1 ? content.length : newline;
|
|
879
|
+
const overhead = shown.length === 0 ? 2 : 3;
|
|
880
|
+
const remaining = WRITE_DIFF_MAX_BYTES - bytes - overhead;
|
|
881
|
+
if (end - offset > remaining)
|
|
882
|
+
break;
|
|
883
|
+
const line = content.slice(offset, end);
|
|
884
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
885
|
+
if (lineBytes > remaining)
|
|
886
|
+
break;
|
|
887
|
+
shown.push(`+ ${line}`);
|
|
888
|
+
bytes += lineBytes + overhead;
|
|
889
|
+
offset = newline === -1 ? content.length : end + 1;
|
|
890
|
+
}
|
|
891
|
+
return { diff: shown.join(`
|
|
892
|
+
`), added: shown.length, removed: 0, truncated: offset < content.length };
|
|
893
|
+
}
|
|
846
894
|
function totalUsage(state) {
|
|
847
895
|
const total = {
|
|
848
896
|
input: 0,
|
|
@@ -875,6 +923,8 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
875
923
|
if (message.role !== "toolResult")
|
|
876
924
|
continue;
|
|
877
925
|
const diagnostics = entry.data?.diagnostics ?? [];
|
|
926
|
+
const diff = message.toolName === "edit" ? editResultDiff(message.details) : null;
|
|
927
|
+
const counts = diff === null ? null : countDiffLines(diff);
|
|
878
928
|
results.set(message.toolCallId, {
|
|
879
929
|
type: "tool",
|
|
880
930
|
key: `t${message.toolCallId}`,
|
|
@@ -891,7 +941,10 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
891
941
|
].filter(Boolean).join(`
|
|
892
942
|
`),
|
|
893
943
|
durationMs: message.durationMs ?? null,
|
|
894
|
-
note: null
|
|
944
|
+
note: null,
|
|
945
|
+
diff,
|
|
946
|
+
diffAdded: counts?.added ?? null,
|
|
947
|
+
diffRemoved: counts?.removed ?? null
|
|
895
948
|
});
|
|
896
949
|
}
|
|
897
950
|
}
|
|
@@ -926,6 +979,7 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
926
979
|
const defaultImagePrompt = entry.kind === NekoInput.kind ? savedDefaultImagePrompt(message.content, entry.data?.defaultImagePrompt) : undefined;
|
|
927
980
|
items.push({
|
|
928
981
|
type: "user",
|
|
982
|
+
...entry.data?.subagentRoundId ? { subagentRoundId: entry.data.subagentRoundId } : {},
|
|
929
983
|
key: `e${entry.id}`,
|
|
930
984
|
id: entry.id,
|
|
931
985
|
text: defaultImagePrompt && Array.isArray(message.content) ? userText(message.content.slice(1)) : userText(message.content),
|
|
@@ -948,6 +1002,7 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
948
1002
|
} else {
|
|
949
1003
|
const summary = summarizeToolCall(block.name, block.arguments);
|
|
950
1004
|
const slot = live.tools?.find((s) => s.callId === block.id);
|
|
1005
|
+
const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
|
|
951
1006
|
items.push({
|
|
952
1007
|
type: "tool",
|
|
953
1008
|
key: `t${block.id}`,
|
|
@@ -960,7 +1015,11 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
960
1015
|
output: slot?.output ?? null,
|
|
961
1016
|
result: null,
|
|
962
1017
|
durationMs: null,
|
|
963
|
-
note: ran ? null : "Not run: response interrupted."
|
|
1018
|
+
note: ran ? null : "Not run: response interrupted.",
|
|
1019
|
+
diff: synthesized?.diff ?? null,
|
|
1020
|
+
diffAdded: synthesized?.added ?? null,
|
|
1021
|
+
diffRemoved: synthesized?.removed ?? null,
|
|
1022
|
+
diffTruncated: synthesized?.truncated ?? false
|
|
964
1023
|
});
|
|
965
1024
|
}
|
|
966
1025
|
}
|
|
@@ -1008,7 +1067,17 @@ function projectChatView(view, modelLabel, options = {}) {
|
|
|
1008
1067
|
}
|
|
1009
1068
|
function withArgs(item, name, args) {
|
|
1010
1069
|
const summary = summarizeToolCall(name, args);
|
|
1011
|
-
|
|
1070
|
+
const synthesized = name === "write" ? synthesizedWriteDiff(args) : null;
|
|
1071
|
+
return {
|
|
1072
|
+
...item,
|
|
1073
|
+
name,
|
|
1074
|
+
summary: summary.args,
|
|
1075
|
+
detail: summary.detail ?? null,
|
|
1076
|
+
diff: synthesized?.diff ?? item.diff,
|
|
1077
|
+
diffAdded: synthesized?.added ?? item.diffAdded,
|
|
1078
|
+
diffRemoved: synthesized?.removed ?? item.diffRemoved,
|
|
1079
|
+
diffTruncated: synthesized?.truncated ?? false
|
|
1080
|
+
};
|
|
1012
1081
|
}
|
|
1013
1082
|
function assistantItem(message, id) {
|
|
1014
1083
|
let thinking = "";
|
|
@@ -1061,13 +1130,18 @@ ${block.text}`;
|
|
|
1061
1130
|
if (block.type === "toolCall") {
|
|
1062
1131
|
const slot = live.tools?.find((candidate) => candidate.callId === block.id);
|
|
1063
1132
|
const summary = summarizeToolCall(block.name, block.arguments);
|
|
1133
|
+
const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
|
|
1064
1134
|
toolCalls.push({
|
|
1065
1135
|
callId: block.id,
|
|
1066
1136
|
name: block.name,
|
|
1067
1137
|
summary: summary.args,
|
|
1068
1138
|
detail: summary.detail ?? null,
|
|
1069
1139
|
phase: slot === undefined || slot.status === "pending" ? "pending" : slot.status,
|
|
1070
|
-
output: slot?.status === "running" ? slot.output ?? null : null
|
|
1140
|
+
output: slot?.status === "running" ? slot.output ?? null : null,
|
|
1141
|
+
diff: synthesized?.diff ?? null,
|
|
1142
|
+
diffAdded: synthesized?.added ?? null,
|
|
1143
|
+
diffRemoved: synthesized?.removed ?? null,
|
|
1144
|
+
diffTruncated: synthesized?.truncated ?? false
|
|
1071
1145
|
});
|
|
1072
1146
|
}
|
|
1073
1147
|
}
|
|
@@ -1087,10 +1161,12 @@ function contextTokens(entries) {
|
|
|
1087
1161
|
}
|
|
1088
1162
|
return null;
|
|
1089
1163
|
}
|
|
1164
|
+
var WRITE_DIFF_MAX_LINES = 2000, WRITE_DIFF_MAX_BYTES;
|
|
1090
1165
|
var init_projection = __esm(() => {
|
|
1091
1166
|
init_image_prompt();
|
|
1092
1167
|
init_input();
|
|
1093
1168
|
init_workspace();
|
|
1169
|
+
WRITE_DIFF_MAX_BYTES = 64 * 1024;
|
|
1094
1170
|
});
|
|
1095
1171
|
|
|
1096
1172
|
// packages/core/src/prompt/frontmatter.ts
|
|
@@ -1485,164 +1561,403 @@ var init_invoke = __esm(() => {
|
|
|
1485
1561
|
init_skills();
|
|
1486
1562
|
});
|
|
1487
1563
|
|
|
1564
|
+
// packages/core/src/subagent-usage.ts
|
|
1565
|
+
function subtractSubagentUsage(end, start) {
|
|
1566
|
+
const result = emptySubagentUsage();
|
|
1567
|
+
for (const bucket of ["models", "tools"]) {
|
|
1568
|
+
for (const [key, usage] of Object.entries(end[bucket])) {
|
|
1569
|
+
const before = start[bucket][key];
|
|
1570
|
+
const cost = usage.cost;
|
|
1571
|
+
const next = {
|
|
1572
|
+
input: usage.input - (before?.input ?? 0),
|
|
1573
|
+
output: usage.output - (before?.output ?? 0),
|
|
1574
|
+
cacheRead: usage.cacheRead - (before?.cacheRead ?? 0),
|
|
1575
|
+
cacheWrite: usage.cacheWrite - (before?.cacheWrite ?? 0),
|
|
1576
|
+
totalTokens: usage.totalTokens - (before?.totalTokens ?? 0),
|
|
1577
|
+
cost: {
|
|
1578
|
+
input: cost.input - (before?.cost.input ?? 0),
|
|
1579
|
+
output: cost.output - (before?.cost.output ?? 0),
|
|
1580
|
+
cacheRead: cost.cacheRead - (before?.cost.cacheRead ?? 0),
|
|
1581
|
+
cacheWrite: cost.cacheWrite - (before?.cost.cacheWrite ?? 0),
|
|
1582
|
+
total: cost.total - (before?.cost.total ?? 0)
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
if (usage.reasoning !== undefined)
|
|
1586
|
+
next.reasoning = usage.reasoning - (before?.reasoning ?? 0);
|
|
1587
|
+
if (usage.cacheWrite1h !== undefined)
|
|
1588
|
+
next.cacheWrite1h = usage.cacheWrite1h - (before?.cacheWrite1h ?? 0);
|
|
1589
|
+
result[bucket][key] = next;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return result;
|
|
1593
|
+
}
|
|
1594
|
+
function subagentUsageTotals(state) {
|
|
1595
|
+
const totals = totalUsage(state);
|
|
1596
|
+
return {
|
|
1597
|
+
input: totals.input,
|
|
1598
|
+
output: totals.output,
|
|
1599
|
+
cacheRead: totals.cacheRead,
|
|
1600
|
+
cacheWrite: totals.cacheWrite,
|
|
1601
|
+
cost: totals.cost.total
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
var emptySubagentUsage = () => ({ models: {}, tools: {} });
|
|
1605
|
+
var init_subagent_usage = __esm(() => {
|
|
1606
|
+
init_projection();
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1488
1609
|
// packages/core/src/subagents.ts
|
|
1489
1610
|
import {
|
|
1490
1611
|
AssistantEntry,
|
|
1491
1612
|
configure,
|
|
1492
1613
|
defineDoc,
|
|
1493
1614
|
defineExtension as defineExtension3,
|
|
1494
|
-
|
|
1615
|
+
defineTask,
|
|
1616
|
+
defineTool as defineTool2,
|
|
1617
|
+
LiveDoc,
|
|
1618
|
+
UsageDoc
|
|
1495
1619
|
} from "@earendil-works/pi-durable";
|
|
1496
1620
|
import { Type as Type2 } from "typebox";
|
|
1621
|
+
import { Value } from "typebox/value";
|
|
1497
1622
|
async function refreshDelegations(tx, id) {
|
|
1498
1623
|
const doc = await tx.doc(DelegationsDoc, id);
|
|
1624
|
+
const identities = await tx.doc(SubagentsDoc, id);
|
|
1499
1625
|
for (const item of doc.items) {
|
|
1626
|
+
item.agentId ??= agentIdFor(item.childId);
|
|
1627
|
+
item.round ??= doc.items.filter((d) => d.childId === item.childId && d.taskId <= item.taskId).length;
|
|
1500
1628
|
if (item.historyThrough !== undefined)
|
|
1501
1629
|
continue;
|
|
1502
|
-
if (item.
|
|
1503
|
-
|
|
1630
|
+
if (item.inputEntryId === undefined) {
|
|
1631
|
+
const submission = await tx.submissionByRequest(item.childId, `subagent:${item.taskId}`);
|
|
1632
|
+
if (submission?.type === "input" && submission.entry !== undefined)
|
|
1633
|
+
item.inputEntryId = submission.entry;
|
|
1634
|
+
}
|
|
1635
|
+
let identity = identities.items.find((a) => a.childId === item.childId);
|
|
1636
|
+
if (!identity) {
|
|
1637
|
+
const role = await tx.doc(SubagentDoc, item.childId);
|
|
1638
|
+
if (role.parentId !== id || role.role !== item.role)
|
|
1639
|
+
continue;
|
|
1640
|
+
identity = {
|
|
1641
|
+
agentId: item.agentId,
|
|
1642
|
+
parentId: id,
|
|
1643
|
+
childId: item.childId,
|
|
1644
|
+
role: item.role,
|
|
1645
|
+
cwd: "",
|
|
1646
|
+
title: item.title,
|
|
1647
|
+
createdAt: item.createdAt,
|
|
1648
|
+
activeRoundId: item.taskId
|
|
1649
|
+
};
|
|
1650
|
+
identities.items.push(identity);
|
|
1651
|
+
identity = identities.items.at(-1);
|
|
1652
|
+
}
|
|
1504
1653
|
const task = await tx.task(item.taskId);
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1654
|
+
const runner = item.runnerId === undefined ? undefined : await tx.task(item.runnerId);
|
|
1655
|
+
const live = await tx.doc(LiveDoc, item.childId);
|
|
1656
|
+
const idle = live.run === undefined && !live.compactions?.length;
|
|
1657
|
+
if (task?.state.status === "terminal") {
|
|
1658
|
+
if (item.status === "queued" || item.status === "running") {
|
|
1659
|
+
item.status = task.state.outcome.status === "aborted" ? "cancelled" : "failed";
|
|
1660
|
+
item.endedAt ??= Date.now();
|
|
1661
|
+
}
|
|
1662
|
+
if (identity.activeRoundId === item.taskId && idle && (!runner || runner.state.status === "terminal"))
|
|
1663
|
+
identity.activeRoundId = null;
|
|
1664
|
+
}
|
|
1509
1665
|
}
|
|
1510
1666
|
return JSON.parse(JSON.stringify(doc.items));
|
|
1511
1667
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1668
|
+
function summarizeSubagents(rounds, identities = []) {
|
|
1669
|
+
const groups = new Map;
|
|
1670
|
+
for (const round of rounds) {
|
|
1671
|
+
const id = round.agentId ?? agentIdFor(round.childId);
|
|
1672
|
+
groups.set(id, [...groups.get(id) ?? [], round]);
|
|
1673
|
+
}
|
|
1674
|
+
return [...groups].map(([agentId, entries]) => {
|
|
1675
|
+
const first = entries[0];
|
|
1676
|
+
const last = entries.at(-1);
|
|
1677
|
+
const identity = identities.find((a) => a.agentId === agentId);
|
|
1678
|
+
const active = entries.find((r) => identity ? r.taskId === identity.activeRoundId : r.status === "running" || r.status === "queued");
|
|
1679
|
+
return {
|
|
1680
|
+
agentId,
|
|
1681
|
+
parentId: first.parentId,
|
|
1682
|
+
childId: first.childId,
|
|
1683
|
+
role: first.role,
|
|
1684
|
+
title: identity?.title ?? first.title,
|
|
1685
|
+
status: active ? active.status === "queued" ? "queued" : "running" : "idle",
|
|
1686
|
+
activeRoundId: active?.taskId ?? null,
|
|
1687
|
+
lastRoundId: last.taskId,
|
|
1688
|
+
lastReport: last.report?.slice(0, 512) ?? null,
|
|
1689
|
+
roundCount: entries.length,
|
|
1690
|
+
taskTitle: (active ?? last).title,
|
|
1691
|
+
approvalCount: active?.approvalCount ?? 0,
|
|
1692
|
+
createdAt: first.createdAt,
|
|
1693
|
+
...first.historyThrough !== undefined ? { historyThrough: first.historyThrough, historyUsage: first.historyUsage } : {}
|
|
1694
|
+
};
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
async function acquireSlot(tx, round, cwd) {
|
|
1698
|
+
const slots = await tx.doc(SlotsDoc);
|
|
1699
|
+
const live = [];
|
|
1700
|
+
for (const slot of slots.items) {
|
|
1701
|
+
const task = await tx.task(slot.taskId);
|
|
1702
|
+
if (task && task.state.status !== "terminal")
|
|
1703
|
+
live.push(slot);
|
|
1704
|
+
}
|
|
1705
|
+
slots.items = live;
|
|
1706
|
+
if (live.some((slot) => slot.taskId === round.taskId))
|
|
1707
|
+
return true;
|
|
1708
|
+
if (live.filter((slot) => slot.parentId === round.parentId).length >= 3 || round.role === "coder" && live.some((slot) => slot.coder && slot.cwd === cwd))
|
|
1709
|
+
return false;
|
|
1710
|
+
slots.items.push({ taskId: round.taskId, parentId: round.parentId, cwd, coder: round.role === "coder" });
|
|
1711
|
+
return true;
|
|
1551
1712
|
}
|
|
1552
1713
|
function createSubagentExtension(prepare, discard) {
|
|
1714
|
+
const finish = async (tx, input, status, report) => {
|
|
1715
|
+
const round = (await tx.doc(DelegationsDoc, input.parentId)).items.find((r) => r.taskId === input.taskId);
|
|
1716
|
+
round.status = status;
|
|
1717
|
+
round.report = report;
|
|
1718
|
+
round.endedAt ??= Date.now();
|
|
1719
|
+
round.usageEnd = JSON.parse(JSON.stringify(await tx.doc(UsageDoc, input.childId)));
|
|
1720
|
+
round.roundUsage = round.usageStart ? subagentUsageTotals(subtractSubagentUsage(round.usageEnd, round.usageStart)) : round.startedAt === null ? subagentUsageTotals(emptySubagentUsage()) : null;
|
|
1721
|
+
};
|
|
1722
|
+
const RoundTask = defineTask({
|
|
1723
|
+
name: "app.neko.subagent-round",
|
|
1724
|
+
version: 1,
|
|
1725
|
+
initial: () => ({ phase: "admission" }),
|
|
1726
|
+
phases: {
|
|
1727
|
+
admission: async (task, runtime, ctx) => {
|
|
1728
|
+
const env = await runtime.env(ctx);
|
|
1729
|
+
const canonical = env && await env.canonicalPath(task.input.cwd, ctx);
|
|
1730
|
+
const slotCwd = canonical?.ok ? canonical.value : task.input.cwd;
|
|
1731
|
+
let admitted = false;
|
|
1732
|
+
while (!admitted) {
|
|
1733
|
+
await runtime.commit(async (tx) => {
|
|
1734
|
+
const round = (await tx.doc(DelegationsDoc, task.input.parentId)).items.find((r) => r.taskId === task.input.taskId);
|
|
1735
|
+
if (!await acquireSlot(tx, round, slotCwd))
|
|
1736
|
+
return;
|
|
1737
|
+
admitted = true;
|
|
1738
|
+
const duplicate = await tx.submissionByRequest(task.input.childId, `subagent:${round.taskId}`);
|
|
1739
|
+
if (!duplicate && !round.usageStart)
|
|
1740
|
+
round.usageStart = JSON.parse(JSON.stringify(await tx.doc(UsageDoc, task.input.childId)));
|
|
1741
|
+
round.status = "running";
|
|
1742
|
+
round.startedAt ??= Date.now();
|
|
1743
|
+
return { status: "running", checkpoint: { phase: "deliver" } };
|
|
1744
|
+
}, ctx);
|
|
1745
|
+
if (!admitted)
|
|
1746
|
+
await runtime.sleep(runtime.now() + 100, ctx);
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
deliver: async (task, runtime, ctx) => {
|
|
1750
|
+
const input = task.input;
|
|
1751
|
+
const child = await runtime.conversation(input.childId, ctx);
|
|
1752
|
+
const requestId = `subagent:${input.taskId}`;
|
|
1753
|
+
try {
|
|
1754
|
+
let duplicate = false;
|
|
1755
|
+
await runtime.commit(async (tx) => {
|
|
1756
|
+
duplicate = !!await tx.submissionByRequest(input.childId, requestId);
|
|
1757
|
+
}, ctx);
|
|
1758
|
+
if (!duplicate)
|
|
1759
|
+
await prepare(input.childId, requestId, input.cwd);
|
|
1760
|
+
const submission = await child.submit({
|
|
1761
|
+
type: "input",
|
|
1762
|
+
content: input.task,
|
|
1763
|
+
requestId,
|
|
1764
|
+
whenBusy: "reject",
|
|
1765
|
+
entry: {
|
|
1766
|
+
kind: NekoInput.kind,
|
|
1767
|
+
data: { at: Date.now(), prompt: input.task, images: [], subagentRoundId: input.taskId }
|
|
1768
|
+
}
|
|
1769
|
+
}, ctx);
|
|
1770
|
+
const placed = await submission.status(ctx);
|
|
1771
|
+
await runtime.commit(async (tx) => {
|
|
1772
|
+
if (placed.type === "input" && placed.entry !== undefined)
|
|
1773
|
+
(await tx.doc(DelegationsDoc, input.parentId)).items.find((r) => r.taskId === input.taskId).inputEntryId = placed.entry;
|
|
1774
|
+
return { status: "running", checkpoint: { phase: "settle" } };
|
|
1775
|
+
}, ctx);
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
discard(input.childId, requestId);
|
|
1778
|
+
if (ctx.abortSignal?.aborted)
|
|
1779
|
+
throw error;
|
|
1780
|
+
await child.abort(ctx);
|
|
1781
|
+
const report = `Subagent failed: ${String(error)}`;
|
|
1782
|
+
await runtime.commit(async (tx) => {
|
|
1783
|
+
await finish(tx, input, "failed", report);
|
|
1784
|
+
return { status: "terminal", outcome: { status: "completed", result: { status: "failed", report } } };
|
|
1785
|
+
}, ctx);
|
|
1786
|
+
}
|
|
1787
|
+
},
|
|
1788
|
+
settle: async (task, runtime, ctx) => {
|
|
1789
|
+
const input = task.input;
|
|
1790
|
+
const child = await runtime.conversation(input.childId, ctx);
|
|
1791
|
+
const submission = await child.submit({ type: "input", content: input.task, requestId: `subagent:${input.taskId}` }, ctx);
|
|
1792
|
+
const settled = await submission.wait(ctx);
|
|
1793
|
+
await child.waitForIdle(ctx);
|
|
1794
|
+
await runtime.commit(async (tx) => {
|
|
1795
|
+
let report = "";
|
|
1796
|
+
let status = "failed";
|
|
1797
|
+
const round = (await tx.doc(DelegationsDoc, input.parentId)).items.find((r) => r.taskId === input.taskId);
|
|
1798
|
+
if (settled.type === "input" && settled.entry !== undefined)
|
|
1799
|
+
round.inputEntryId = settled.entry;
|
|
1800
|
+
if (settled.status === "done" && settled.type === "input") {
|
|
1801
|
+
round.answerEntryId = settled.answer;
|
|
1802
|
+
const message = (await tx.entry(AssistantEntry, settled.answer))?.model?.[0];
|
|
1803
|
+
report = message?.role === "assistant" ? message.content.flatMap((b) => b.type === "text" ? [b.text] : []).join("") : "";
|
|
1804
|
+
status = "completed";
|
|
1805
|
+
} else if (settled.status === "unanswered") {
|
|
1806
|
+
status = settled.reason === "aborted" ? "cancelled" : "failed";
|
|
1807
|
+
report = `Subagent ${status}: ${settled.reason}`;
|
|
1808
|
+
}
|
|
1809
|
+
await finish(tx, input, status, report);
|
|
1810
|
+
return { status: "terminal", outcome: { status: "completed", result: { status, report } } };
|
|
1811
|
+
}, ctx);
|
|
1812
|
+
}
|
|
1813
|
+
},
|
|
1814
|
+
abort: async (task, runtime, ctx) => {
|
|
1815
|
+
const input = task.input;
|
|
1816
|
+
let own = false;
|
|
1817
|
+
await runtime.commit(async (tx) => {
|
|
1818
|
+
own = (await tx.doc(SubagentsDoc, input.parentId)).items.some((a) => a.childId === input.childId && a.activeRoundId === input.taskId);
|
|
1819
|
+
}, ctx);
|
|
1820
|
+
if (own)
|
|
1821
|
+
await (await runtime.conversation(input.childId, ctx))?.abort(ctx);
|
|
1822
|
+
await runtime.commit(async (tx) => {
|
|
1823
|
+
await finish(tx, input, "cancelled", "Subagent cancelled");
|
|
1824
|
+
return { status: "terminal", outcome: { status: "aborted" } };
|
|
1825
|
+
}, ctx);
|
|
1826
|
+
}
|
|
1827
|
+
});
|
|
1553
1828
|
const extension = defineExtension3({
|
|
1554
1829
|
name: "neko-subagents",
|
|
1830
|
+
tasks: [RoundTask],
|
|
1555
1831
|
tools: [
|
|
1556
1832
|
defineTool2({
|
|
1557
1833
|
name: "subagent",
|
|
1558
|
-
description: "
|
|
1559
|
-
parameters
|
|
1560
|
-
|
|
1561
|
-
title: Type2.String({ minLength: 1, maxLength: 80 }),
|
|
1562
|
-
task: Type2.String({ minLength: 1, maxLength: 32768 })
|
|
1563
|
-
}),
|
|
1834
|
+
description: "Manage persistent foreground subagents. create (default): type explore/plan/coder, title, task. continue: agentId, title, task; reuses its own context, only while idle. list: discover this session's agents, optional cursor/limit. Explore Bash requires per-call user approval. Keep constraints explicit; verify and integrate final reports. Subagents cannot delegate.",
|
|
1835
|
+
parameters,
|
|
1836
|
+
structuredOutputSchema,
|
|
1564
1837
|
replay: "safe",
|
|
1565
|
-
execute: async (
|
|
1566
|
-
if (!
|
|
1567
|
-
throw new Error("
|
|
1838
|
+
execute: async (input, api, context) => {
|
|
1839
|
+
if (!Value.Check(actionParameters, input))
|
|
1840
|
+
throw new Error("Invalid subagent arguments. create requires type/title/task; continue requires agentId/title/task; list accepts only cursor/limit. Do not mix fields from different actions.");
|
|
1841
|
+
const args = input;
|
|
1568
1842
|
if ((await api.snapshot(SubagentDoc, api.conversationId, context))?.role)
|
|
1569
1843
|
throw new Error("Subagents cannot delegate.");
|
|
1844
|
+
if (args.action === "list") {
|
|
1845
|
+
const list = await api.commit(async (tx) => {
|
|
1846
|
+
const rounds = await refreshDelegations(tx, api.conversationId);
|
|
1847
|
+
return summarizeSubagents(rounds, (await tx.doc(SubagentsDoc, api.conversationId)).items).filter((a) => a.historyThrough === undefined);
|
|
1848
|
+
}, context);
|
|
1849
|
+
const offset = args.cursor ?? 0;
|
|
1850
|
+
const items = list.slice(offset, offset + (args.limit ?? 50));
|
|
1851
|
+
const result = { items, next: offset + items.length < list.length ? offset + items.length : null };
|
|
1852
|
+
return { output: [{ type: "text", text: JSON.stringify(result) }], structuredOutput: result };
|
|
1853
|
+
}
|
|
1854
|
+
if (!args.task.trim() || !args.title.trim() || Buffer.byteLength(args.task) > 32768)
|
|
1855
|
+
throw new Error("Task/title must be nonempty; task limit is 32 KiB.");
|
|
1570
1856
|
const agent = await api.agent(context);
|
|
1571
|
-
const
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
await
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1857
|
+
const round = await api.commit(async (tx) => {
|
|
1858
|
+
const rounds = await refreshDelegations(tx, api.conversationId);
|
|
1859
|
+
const receipt = rounds.find((r) => r.taskId === api.taskId);
|
|
1860
|
+
if (receipt?.runnerId !== undefined)
|
|
1861
|
+
return receipt;
|
|
1862
|
+
const identities = await tx.doc(SubagentsDoc, api.conversationId);
|
|
1863
|
+
let identity;
|
|
1864
|
+
if (args.action === "continue") {
|
|
1865
|
+
identity = identities.items.find((a) => a.agentId === args.agentId);
|
|
1866
|
+
if (!identity)
|
|
1867
|
+
throw new Error("Unknown subagent or it belongs to another conversation.");
|
|
1868
|
+
const info = await tx.doc(SubagentDoc, identity.childId);
|
|
1869
|
+
if (info.parentId !== api.conversationId || info.role !== identity.role)
|
|
1870
|
+
throw new Error("Subagent ownership mismatch.");
|
|
1871
|
+
if (identity.activeRoundId !== null)
|
|
1872
|
+
throw new Error("Subagent is busy; continue only when idle.");
|
|
1873
|
+
} else if (receipt) {
|
|
1874
|
+
identity = identities.items.find((a) => a.childId === receipt.childId);
|
|
1875
|
+
}
|
|
1876
|
+
const existing = identity ? undefined : (await tx.scanConversations({ ownerTaskId: api.taskId }, 1)).items[0];
|
|
1877
|
+
const child = identity ? await tx.conversation(identity.childId) : existing;
|
|
1878
|
+
if (!identity) {
|
|
1879
|
+
const created = child ?? await tx.createConversation({ ownership: { kind: "task", taskId: api.taskId } });
|
|
1880
|
+
const role = args.action === "continue" ? "explore" : args.type;
|
|
1881
|
+
await configure(tx, created.id, {
|
|
1882
|
+
model: agent.model,
|
|
1883
|
+
thinkingLevel: agent.thinkingLevel,
|
|
1884
|
+
cwd: agent.cwd,
|
|
1885
|
+
extensions: agent.extensions.filter((e) => e.name !== extension.name),
|
|
1886
|
+
tools: agent.tools.filter((t) => t.name !== "subagent" && (role === "coder" || READ_TOOLS.has(t.name) || role === "explore" && t.name === "bash"))
|
|
1887
|
+
});
|
|
1888
|
+
Object.assign(await tx.doc(SubagentDoc, created.id), { role, parentId: api.conversationId });
|
|
1889
|
+
identity = {
|
|
1890
|
+
agentId: agentIdFor(created.id),
|
|
1891
|
+
parentId: api.conversationId,
|
|
1892
|
+
childId: created.id,
|
|
1893
|
+
role,
|
|
1894
|
+
cwd: agent.cwd ?? "",
|
|
1895
|
+
title: args.title,
|
|
1896
|
+
createdAt: Date.now(),
|
|
1897
|
+
activeRoundId: null
|
|
1898
|
+
};
|
|
1899
|
+
identities.items.push(identity);
|
|
1900
|
+
}
|
|
1901
|
+
const record = receipt ?? {
|
|
1585
1902
|
parentId: api.conversationId,
|
|
1586
1903
|
taskId: api.taskId,
|
|
1587
1904
|
callId: api.callId,
|
|
1588
|
-
childId:
|
|
1589
|
-
|
|
1905
|
+
childId: identity.childId,
|
|
1906
|
+
agentId: identity.agentId,
|
|
1907
|
+
round: rounds.filter((r) => r.childId === identity.childId).length + 1,
|
|
1908
|
+
role: identity.role,
|
|
1590
1909
|
title: args.title,
|
|
1591
1910
|
createdAt: Date.now(),
|
|
1592
1911
|
startedAt: null,
|
|
1593
1912
|
endedAt: null,
|
|
1594
1913
|
status: "queued",
|
|
1595
1914
|
report: null
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1915
|
+
};
|
|
1916
|
+
identities.items.find((a) => a.agentId === identity.agentId).activeRoundId = api.taskId;
|
|
1917
|
+
const runner = await tx.createTask(RoundTask, {
|
|
1918
|
+
parentId: api.conversationId,
|
|
1919
|
+
childId: identity.childId,
|
|
1920
|
+
taskId: api.taskId,
|
|
1921
|
+
task: args.task,
|
|
1922
|
+
cwd: identity.cwd || agent.cwd || ""
|
|
1923
|
+
}, { ownership: { kind: "task", taskId: api.taskId } });
|
|
1924
|
+
record.runnerId = runner;
|
|
1925
|
+
const doc = await tx.doc(DelegationsDoc, api.conversationId);
|
|
1926
|
+
if (receipt)
|
|
1927
|
+
Object.assign(doc.items.find((r) => r.taskId === receipt.taskId), record);
|
|
1928
|
+
else
|
|
1929
|
+
doc.items.push(record);
|
|
1930
|
+
return record;
|
|
1606
1931
|
}, context);
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
try {
|
|
1614
|
-
submission = await child.submit({
|
|
1615
|
-
type: "input",
|
|
1616
|
-
content: args.task,
|
|
1617
|
-
requestId,
|
|
1618
|
-
entry: { kind: NekoInput.kind, data: { at: Date.now(), prompt: args.task, images: [] } }
|
|
1619
|
-
}, context);
|
|
1620
|
-
} catch (error) {
|
|
1621
|
-
discard(childId, requestId);
|
|
1622
|
-
throw error;
|
|
1623
|
-
}
|
|
1624
|
-
const settled = await submission.wait(context);
|
|
1625
|
-
let report = "";
|
|
1626
|
-
let status = "failed";
|
|
1627
|
-
if (settled.status === "done" && settled.type === "input") {
|
|
1628
|
-
const entry = await api.commit((tx) => tx.entry(AssistantEntry, settled.answer), context);
|
|
1629
|
-
const message = entry?.model?.[0];
|
|
1630
|
-
report = message?.role === "assistant" ? message.content.flatMap((b) => b.type === "text" ? [b.text] : []).join("") : "";
|
|
1631
|
-
status = "completed";
|
|
1632
|
-
} else if (settled.status === "unanswered") {
|
|
1633
|
-
status = settled.reason === "aborted" ? "cancelled" : "failed";
|
|
1634
|
-
report = `Subagent ${status}: ${settled.reason}`;
|
|
1635
|
-
}
|
|
1636
|
-
await api.commit(async (tx) => {
|
|
1637
|
-
const item = (await tx.doc(DelegationsDoc, api.conversationId)).items.find((d) => d.taskId === api.taskId);
|
|
1638
|
-
item.status = status;
|
|
1639
|
-
item.report = report;
|
|
1640
|
-
item.endedAt = Date.now();
|
|
1932
|
+
await api.details({
|
|
1933
|
+
conversationId: round.childId,
|
|
1934
|
+
agentId: round.agentId,
|
|
1935
|
+
roundId: round.taskId,
|
|
1936
|
+
role: round.role,
|
|
1937
|
+
title: round.title
|
|
1641
1938
|
}, context);
|
|
1939
|
+
const settled = await api.waitForTask(round.runnerId, context);
|
|
1940
|
+
const outcome = settled.state.outcome;
|
|
1941
|
+
const result = outcome.status === "completed" ? outcome.result : { status: outcome.status === "aborted" ? "cancelled" : "failed", report: `Subagent ${outcome.status}` };
|
|
1642
1942
|
return {
|
|
1643
|
-
output: [
|
|
1644
|
-
|
|
1645
|
-
|
|
1943
|
+
output: [
|
|
1944
|
+
{
|
|
1945
|
+
type: "text",
|
|
1946
|
+
text: `Agent: ${round.agentId}
|
|
1947
|
+
Status: ${result.status}
|
|
1948
|
+
${result.report || "Subagent completed without a text report."}`
|
|
1949
|
+
}
|
|
1950
|
+
],
|
|
1951
|
+
isError: result.status !== "completed",
|
|
1952
|
+
structuredOutput: { agentId: round.agentId, roundId: round.taskId, ...result },
|
|
1953
|
+
details: {
|
|
1954
|
+
conversationId: round.childId,
|
|
1955
|
+
agentId: round.agentId,
|
|
1956
|
+
roundId: round.taskId,
|
|
1957
|
+
role: round.role,
|
|
1958
|
+
title: round.title,
|
|
1959
|
+
status: result.status
|
|
1960
|
+
}
|
|
1646
1961
|
};
|
|
1647
1962
|
}
|
|
1648
1963
|
})
|
|
@@ -1651,11 +1966,67 @@ function createSubagentExtension(prepare, discard) {
|
|
|
1651
1966
|
return extension;
|
|
1652
1967
|
}
|
|
1653
1968
|
async function listDelegations(harness, parent, context) {
|
|
1969
|
+
const rounds = await harness.commit((tx) => refreshDelegations(tx, parent), context);
|
|
1970
|
+
for (const round of rounds) {
|
|
1971
|
+
if (round.historyThrough !== undefined)
|
|
1972
|
+
continue;
|
|
1973
|
+
const task = await harness.getTask(round.taskId, context);
|
|
1974
|
+
if (task?.state.status !== "terminal")
|
|
1975
|
+
continue;
|
|
1976
|
+
const child = await harness.conversation(round.childId, context);
|
|
1977
|
+
const live = await harness.snapshot(LiveDoc, round.childId, context);
|
|
1978
|
+
const identity = (await harness.snapshot(SubagentsDoc, parent, context))?.items.find((a) => a.childId === round.childId);
|
|
1979
|
+
if (identity?.activeRoundId === round.taskId && live?.run !== undefined)
|
|
1980
|
+
await child?.abort(context);
|
|
1981
|
+
}
|
|
1654
1982
|
return harness.commit((tx) => refreshDelegations(tx, parent), context);
|
|
1655
1983
|
}
|
|
1656
|
-
|
|
1984
|
+
async function installSubagentCoordinator(harness, parents, context) {
|
|
1985
|
+
const known = new Set(parents);
|
|
1986
|
+
let running = false;
|
|
1987
|
+
let dirty = false;
|
|
1988
|
+
const reconcile = async () => {
|
|
1989
|
+
if (running) {
|
|
1990
|
+
dirty = true;
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
running = true;
|
|
1994
|
+
try {
|
|
1995
|
+
do {
|
|
1996
|
+
dirty = false;
|
|
1997
|
+
for (const id of known)
|
|
1998
|
+
await listDelegations(harness, id, context);
|
|
1999
|
+
} while (dirty);
|
|
2000
|
+
} finally {
|
|
2001
|
+
running = false;
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
for (const parent of parents) {
|
|
2005
|
+
await harness.commit((tx) => refreshDelegations(tx, parent), context);
|
|
2006
|
+
for (const identity of (await harness.snapshot(SubagentsDoc, parent, context))?.items ?? []) {
|
|
2007
|
+
if (identity.cwd)
|
|
2008
|
+
continue;
|
|
2009
|
+
const child = await harness.conversation(identity.childId, context);
|
|
2010
|
+
const cwd = (await child?.agent(context))?.cwd;
|
|
2011
|
+
if (cwd)
|
|
2012
|
+
await harness.commit(async (tx) => {
|
|
2013
|
+
(await tx.doc(SubagentsDoc, parent)).items.find((a) => a.agentId === identity.agentId).cwd = cwd;
|
|
2014
|
+
}, context);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
const stop = harness.subscribeCommits(({ changes }) => {
|
|
2018
|
+
for (const c of changes)
|
|
2019
|
+
if (c.type === "document" && c.record.kind === "app.neko.delegations" && c.conversationId !== undefined)
|
|
2020
|
+
known.add(c.conversationId);
|
|
2021
|
+
if (changes.some((c) => c.type === "task" && c.value.state.status === "terminal"))
|
|
2022
|
+
reconcile().catch(() => {});
|
|
2023
|
+
});
|
|
2024
|
+
harness.closed.finally(stop).catch(() => {});
|
|
2025
|
+
}
|
|
2026
|
+
var agentIdFor = (childId) => `agent-${childId}`, DelegationsDoc, SubagentsDoc, SubagentDoc, SlotsDoc, ROLE_PROMPTS, SUBAGENT_DELIVERY = " Work from the assigned task, your own prior conversation context and project resources; you cannot see the main conversation. Do not delegate or ask the user directly. Your final message must be a self-contained delivery to the main agent, including evidence, results and limitations. Skills never expand your allowed tools.", READ_TOOLS, actionParameters, parameters, structuredOutputSchema;
|
|
1657
2027
|
var init_subagents = __esm(() => {
|
|
1658
2028
|
init_input();
|
|
2029
|
+
init_subagent_usage();
|
|
1659
2030
|
DelegationsDoc = defineDoc({
|
|
1660
2031
|
kind: "app.neko.delegations",
|
|
1661
2032
|
version: 1,
|
|
@@ -1664,6 +2035,14 @@ var init_subagents = __esm(() => {
|
|
|
1664
2035
|
fork: "initial",
|
|
1665
2036
|
initial: () => ({ items: [] })
|
|
1666
2037
|
});
|
|
2038
|
+
SubagentsDoc = defineDoc({
|
|
2039
|
+
kind: "app.neko.subagents",
|
|
2040
|
+
version: 1,
|
|
2041
|
+
scope: "conversation",
|
|
2042
|
+
history: "latest",
|
|
2043
|
+
fork: "initial",
|
|
2044
|
+
initial: () => ({ items: [] })
|
|
2045
|
+
});
|
|
1667
2046
|
SubagentDoc = defineDoc({
|
|
1668
2047
|
kind: "app.neko.subagent",
|
|
1669
2048
|
version: 1,
|
|
@@ -1684,6 +2063,60 @@ var init_subagents = __esm(() => {
|
|
|
1684
2063
|
coder: "You are neko's coding subagent. Implement only the assigned scope and verify it. Coordinate through the main agent; do not overwrite unrelated changes. Report changed files and verification results."
|
|
1685
2064
|
};
|
|
1686
2065
|
READ_TOOLS = new Set(["read", "find_files", "search_text", "web_search", "web_extract"]);
|
|
2066
|
+
actionParameters = Type2.Union([
|
|
2067
|
+
Type2.Object({
|
|
2068
|
+
action: Type2.Optional(Type2.Literal("create")),
|
|
2069
|
+
type: Type2.Enum(["explore", "plan", "coder"]),
|
|
2070
|
+
title: Type2.String({ minLength: 1, maxLength: 80 }),
|
|
2071
|
+
task: Type2.String({ minLength: 1, maxLength: 32768 })
|
|
2072
|
+
}, { additionalProperties: false }),
|
|
2073
|
+
Type2.Object({
|
|
2074
|
+
action: Type2.Literal("continue"),
|
|
2075
|
+
agentId: Type2.String(),
|
|
2076
|
+
title: Type2.String({ minLength: 1, maxLength: 80 }),
|
|
2077
|
+
task: Type2.String({ minLength: 1, maxLength: 32768 })
|
|
2078
|
+
}, { additionalProperties: false }),
|
|
2079
|
+
Type2.Object({
|
|
2080
|
+
action: Type2.Literal("list"),
|
|
2081
|
+
cursor: Type2.Optional(Type2.Integer({ minimum: 0 })),
|
|
2082
|
+
limit: Type2.Optional(Type2.Integer({ minimum: 1, maximum: 100 }))
|
|
2083
|
+
}, { additionalProperties: false })
|
|
2084
|
+
]);
|
|
2085
|
+
parameters = Type2.Object({
|
|
2086
|
+
action: Type2.Optional(Type2.String({ enum: ["create", "continue", "list"], description: "Defaults to create." })),
|
|
2087
|
+
type: Type2.Optional(Type2.String({ enum: ["explore", "plan", "coder"], description: "Required for create only." })),
|
|
2088
|
+
agentId: Type2.Optional(Type2.String({ description: "Required for continue only; use an ID returned by create/list." })),
|
|
2089
|
+
title: Type2.Optional(Type2.String({ minLength: 1, maxLength: 80, description: "Required for create/continue." })),
|
|
2090
|
+
task: Type2.Optional(Type2.String({ minLength: 1, maxLength: 32768, description: "Required for create/continue." })),
|
|
2091
|
+
cursor: Type2.Optional(Type2.Integer({ minimum: 0, description: "List pagination cursor only." })),
|
|
2092
|
+
limit: Type2.Optional(Type2.Integer({ minimum: 1, maximum: 100, description: "List page size only." }))
|
|
2093
|
+
}, { additionalProperties: false });
|
|
2094
|
+
structuredOutputSchema = Type2.Union([
|
|
2095
|
+
Type2.Object({
|
|
2096
|
+
agentId: Type2.String(),
|
|
2097
|
+
roundId: Type2.Integer(),
|
|
2098
|
+
status: Type2.Enum(["completed", "failed", "cancelled"]),
|
|
2099
|
+
report: Type2.String()
|
|
2100
|
+
}, { additionalProperties: false }),
|
|
2101
|
+
Type2.Object({
|
|
2102
|
+
items: Type2.Array(Type2.Object({
|
|
2103
|
+
agentId: Type2.String(),
|
|
2104
|
+
parentId: Type2.Integer(),
|
|
2105
|
+
childId: Type2.Integer(),
|
|
2106
|
+
role: Type2.Enum(["explore", "plan", "coder"]),
|
|
2107
|
+
title: Type2.String(),
|
|
2108
|
+
status: Type2.Enum(["idle", "queued", "running"]),
|
|
2109
|
+
activeRoundId: Type2.Union([Type2.Integer(), Type2.Null()]),
|
|
2110
|
+
lastRoundId: Type2.Integer(),
|
|
2111
|
+
lastReport: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()])),
|
|
2112
|
+
roundCount: Type2.Integer(),
|
|
2113
|
+
taskTitle: Type2.String(),
|
|
2114
|
+
approvalCount: Type2.Integer(),
|
|
2115
|
+
createdAt: Type2.Number()
|
|
2116
|
+
}, { additionalProperties: false })),
|
|
2117
|
+
next: Type2.Union([Type2.Integer(), Type2.Null()])
|
|
2118
|
+
}, { additionalProperties: false })
|
|
2119
|
+
]);
|
|
1687
2120
|
});
|
|
1688
2121
|
|
|
1689
2122
|
// packages/core/src/prompt/prompt.ts
|
|
@@ -1744,7 +2177,7 @@ var init_prompt = __esm(() => {
|
|
|
1744
2177
|
KEYS = ["preamble", "rules", "project_context", "skills", "cwd"];
|
|
1745
2178
|
TOOL_GUIDELINES = {
|
|
1746
2179
|
subagent: [
|
|
1747
|
-
"Delegate only independent, sufficiently scoped work when isolation or parallelism helps. Handle simple tasks directly. Pass necessary context and user constraints; research-only requests must not become coding tasks. Verify and integrate reports. Do not modify files concurrently with a coder assigned those files."
|
|
2180
|
+
"Delegate only independent, sufficiently scoped work when isolation or parallelism helps. Handle simple tasks directly. Pass necessary context and user constraints; research-only requests must not become coding tasks. For related follow-up work, list and continue a suitable idle subagent using its stable agentId; busy means no task was accepted. Do not change its role. Verify and integrate reports. Do not modify files concurrently with a coder assigned those files."
|
|
1748
2181
|
],
|
|
1749
2182
|
find_files: [
|
|
1750
2183
|
"Use find_files to discover files; query is a literal substring. Narrow the directory when results are partial."
|
|
@@ -1899,9 +2332,9 @@ import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
|
|
|
1899
2332
|
import {
|
|
1900
2333
|
defineDoc as defineDoc2,
|
|
1901
2334
|
defineExtension as defineExtension5,
|
|
1902
|
-
defineTask,
|
|
2335
|
+
defineTask as defineTask2,
|
|
1903
2336
|
InboxDoc,
|
|
1904
|
-
LiveDoc
|
|
2337
|
+
LiveDoc as LiveDoc2
|
|
1905
2338
|
} from "@earendil-works/pi-durable";
|
|
1906
2339
|
function shortText(value, limit = 60) {
|
|
1907
2340
|
return [
|
|
@@ -1943,7 +2376,7 @@ function mergeUsage(base, extra) {
|
|
|
1943
2376
|
function namingTask() {
|
|
1944
2377
|
let active = 0;
|
|
1945
2378
|
const waits = new Set;
|
|
1946
|
-
return
|
|
2379
|
+
return defineTask2({
|
|
1947
2380
|
name: "app.neko.name",
|
|
1948
2381
|
version: 1,
|
|
1949
2382
|
initial: () => ({ phase: "wait", until: Date.now() + 100 }),
|
|
@@ -2157,7 +2590,7 @@ class SessionMetadataManager {
|
|
|
2157
2590
|
const answer = record.status === "done" ? (await this.storage.entry(record.answer, this.context))?.entry.model?.[0] : undefined;
|
|
2158
2591
|
return { record, data, answer: answer?.role === "assistant" ? answer : undefined };
|
|
2159
2592
|
}));
|
|
2160
|
-
const live = await this.harness.snapshot(
|
|
2593
|
+
const live = await this.harness.snapshot(LiveDoc2, id, this.context);
|
|
2161
2594
|
await this.harness.commit(async (tx) => {
|
|
2162
2595
|
const d = await tx.doc(SessionMetadataDoc, id);
|
|
2163
2596
|
for (const { record, data, answer } of updates) {
|
|
@@ -2359,7 +2792,8 @@ function createApprovalExtension(service) {
|
|
|
2359
2792
|
const child = await approvals.harness.conversation(api.conversationId, context);
|
|
2360
2793
|
const agent = await child.agent(context);
|
|
2361
2794
|
const cwd = await realpath2(agent.cwd);
|
|
2362
|
-
const
|
|
2795
|
+
const identity = (await api.snapshot(SubagentsDoc, parent, context))?.items.find((a) => a.childId === api.conversationId);
|
|
2796
|
+
const delegation = (await api.snapshot(DelegationsDoc, parent, context))?.items.find((d) => d.childId === api.conversationId && d.historyThrough === undefined && d.taskId === identity?.activeRoundId);
|
|
2363
2797
|
if (!delegation)
|
|
2364
2798
|
return { block: "Missing delegation" };
|
|
2365
2799
|
await approvals.ensure(parent, {
|
|
@@ -2990,7 +3424,7 @@ import {
|
|
|
2990
3424
|
Harness,
|
|
2991
3425
|
LiveDoc as importLiveDoc,
|
|
2992
3426
|
MemoryStorage,
|
|
2993
|
-
UsageDoc,
|
|
3427
|
+
UsageDoc as UsageDoc2,
|
|
2994
3428
|
watchEvents
|
|
2995
3429
|
} from "@earendil-works/pi-durable";
|
|
2996
3430
|
import { createNodePhotonImages } from "@earendil-works/pi-durable/images/node";
|
|
@@ -3073,6 +3507,7 @@ async function createNekoRuntime(options = {}) {
|
|
|
3073
3507
|
approvals = new ToolApprovals(harness, context);
|
|
3074
3508
|
const existing = await scanConversations();
|
|
3075
3509
|
try {
|
|
3510
|
+
await installSubagentCoordinator(harness, existing.map((r) => r.id), context);
|
|
3076
3511
|
await prepareApprovalConversations(harness, existing.map((r) => r.id), approvalExtension, context);
|
|
3077
3512
|
for (const record of existing) {
|
|
3078
3513
|
const target = await harness.conversation(record.id, context);
|
|
@@ -3257,7 +3692,7 @@ async function createNekoRuntime(options = {}) {
|
|
|
3257
3692
|
return watchEvents(harness, target.id, context);
|
|
3258
3693
|
},
|
|
3259
3694
|
async usage() {
|
|
3260
|
-
return mergeUsage(await harness.snapshot(
|
|
3695
|
+
return mergeUsage(await harness.snapshot(UsageDoc2, target.id, context) ?? { models: {}, tools: {} }, (await harness.snapshot(SessionMetadataDoc, target.id, context))?.namingUsage ?? { models: {}, tools: {} });
|
|
3261
3696
|
},
|
|
3262
3697
|
compactionRecord() {
|
|
3263
3698
|
return readCompaction(harness, storage, target.id, context);
|
|
@@ -3306,7 +3741,7 @@ async function createNekoRuntime(options = {}) {
|
|
|
3306
3741
|
async globalUsage() {
|
|
3307
3742
|
let total = { models: {}, tools: {} };
|
|
3308
3743
|
for (const record of await scanConversations()) {
|
|
3309
|
-
total = mergeUsage(total, await harness.snapshot(
|
|
3744
|
+
total = mergeUsage(total, await harness.snapshot(UsageDoc2, record.id, context) ?? { models: {}, tools: {} });
|
|
3310
3745
|
total = mergeUsage(total, (await harness.snapshot(SessionMetadataDoc, record.id, context))?.namingUsage ?? { models: {}, tools: {} });
|
|
3311
3746
|
}
|
|
3312
3747
|
return total;
|
|
@@ -3341,14 +3776,24 @@ async function createNekoRuntime(options = {}) {
|
|
|
3341
3776
|
}
|
|
3342
3777
|
cursor = page.next;
|
|
3343
3778
|
} while (cursor);
|
|
3779
|
+
const frozen = new Map;
|
|
3344
3780
|
for (const reference of references) {
|
|
3345
3781
|
if (!calls.has(reference.callId))
|
|
3346
3782
|
continue;
|
|
3347
|
-
|
|
3348
|
-
|
|
3783
|
+
let snapshot = frozen.get(reference.childId);
|
|
3784
|
+
if (!snapshot) {
|
|
3785
|
+
const latest = await tx.scanEntries({ conversationId: reference.childId }, 1);
|
|
3786
|
+
snapshot = {
|
|
3787
|
+
through: latest.items[0]?.id ?? 0,
|
|
3788
|
+
state: JSON.parse(JSON.stringify(await tx.doc(UsageDoc2, reference.childId)))
|
|
3789
|
+
};
|
|
3790
|
+
frozen.set(reference.childId, snapshot);
|
|
3791
|
+
}
|
|
3792
|
+
const usage = totalUsage(snapshot.state);
|
|
3349
3793
|
inherited.push({
|
|
3350
3794
|
...reference,
|
|
3351
|
-
historyThrough: reference.historyThrough ??
|
|
3795
|
+
historyThrough: reference.historyThrough ?? snapshot.through,
|
|
3796
|
+
roundUsage: reference.roundUsage ?? (reference.usageStart ? subagentUsageTotals(subtractSubagentUsage(snapshot.state, reference.usageStart)) : null),
|
|
3352
3797
|
historyUsage: reference.historyUsage ?? {
|
|
3353
3798
|
input: usage.input,
|
|
3354
3799
|
output: usage.output,
|
|
@@ -3561,6 +4006,7 @@ var init_runtime = __esm(() => {
|
|
|
3561
4006
|
init_prompt();
|
|
3562
4007
|
init_resources();
|
|
3563
4008
|
init_session_metadata();
|
|
4009
|
+
init_subagent_usage();
|
|
3564
4010
|
init_subagents();
|
|
3565
4011
|
init_tool_approvals();
|
|
3566
4012
|
init_web_search();
|
|
@@ -3615,6 +4061,7 @@ var init_src = __esm(() => {
|
|
|
3615
4061
|
init_frontmatter();
|
|
3616
4062
|
init_runtime();
|
|
3617
4063
|
init_session_metadata();
|
|
4064
|
+
init_subagent_usage();
|
|
3618
4065
|
init_subagents();
|
|
3619
4066
|
init_tool_approvals();
|
|
3620
4067
|
init_workspace();
|
|
@@ -3674,6 +4121,60 @@ function compactInstructions(text) {
|
|
|
3674
4121
|
return match ? match[1]?.trim() ?? "" : null;
|
|
3675
4122
|
}
|
|
3676
4123
|
|
|
4124
|
+
// packages/core/src/conversation-items.ts
|
|
4125
|
+
function userText2(item) {
|
|
4126
|
+
if (item.skill === undefined)
|
|
4127
|
+
return item.text;
|
|
4128
|
+
return item.skill.args === "" ? `/skill:${item.skill.name}` : `/skill:${item.skill.name} ${item.skill.args}`;
|
|
4129
|
+
}
|
|
4130
|
+
function toolStatus(item) {
|
|
4131
|
+
return item.phase !== "done" ? item.phase : item.isError ? "error" : "ok";
|
|
4132
|
+
}
|
|
4133
|
+
function toolOutput(item) {
|
|
4134
|
+
return (item.phase === "done" ? item.result : item.output) ?? "";
|
|
4135
|
+
}
|
|
4136
|
+
function imageLabel(image) {
|
|
4137
|
+
const size = image.width > 0 && image.height > 0 ? ` \xB7 ${image.width}\xD7${image.height}` : "";
|
|
4138
|
+
return `${image.name} \xB7 ${image.mimeType}${size}`;
|
|
4139
|
+
}
|
|
4140
|
+
function formatDuration(ms) {
|
|
4141
|
+
return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;
|
|
4142
|
+
}
|
|
4143
|
+
function oneLine(text) {
|
|
4144
|
+
return text.replace(/\s+/g, " ").trim();
|
|
4145
|
+
}
|
|
4146
|
+
var FALLBACK_EXPORT_TITLE = "neko-session";
|
|
4147
|
+
|
|
4148
|
+
// packages/core/src/input-history.ts
|
|
4149
|
+
function promptHistory(items) {
|
|
4150
|
+
const entries = [];
|
|
4151
|
+
for (const item of items) {
|
|
4152
|
+
if (item.type !== "user" || item.subagentRoundId !== undefined)
|
|
4153
|
+
continue;
|
|
4154
|
+
const text = userText2(item).trim();
|
|
4155
|
+
if (text === "" || entries.at(-1) === text)
|
|
4156
|
+
continue;
|
|
4157
|
+
entries.push(text);
|
|
4158
|
+
}
|
|
4159
|
+
return entries.reverse().slice(0, INPUT_HISTORY_LIMIT);
|
|
4160
|
+
}
|
|
4161
|
+
var INPUT_HISTORY_LIMIT = 100;
|
|
4162
|
+
var init_input_history = () => {};
|
|
4163
|
+
|
|
4164
|
+
// packages/core/src/session-display.ts
|
|
4165
|
+
function relativeTime(at, now, language = "en") {
|
|
4166
|
+
const minutes = Math.floor(Math.max(0, now - at) / 60000);
|
|
4167
|
+
if (minutes < 1)
|
|
4168
|
+
return language === "zh" ? "\u521A\u521A" : "now";
|
|
4169
|
+
const hours = Math.floor(minutes / 60), days = Math.floor(hours / 24);
|
|
4170
|
+
if (days >= 30)
|
|
4171
|
+
return new Date(at).toLocaleDateString(language === "zh" ? "zh-CN" : "en-GB");
|
|
4172
|
+
const value = days || hours || minutes;
|
|
4173
|
+
const unit = days ? ["\u5929", "d"] : hours ? ["\u5C0F\u65F6", "h"] : ["\u5206\u949F", "m"];
|
|
4174
|
+
return language === "zh" ? `${value} ${unit[0]}\u524D` : `${value}${unit[1]}`;
|
|
4175
|
+
}
|
|
4176
|
+
var sessionName = (session, empty = "New session") => session.title || session.firstPromptPreview || empty, messageTime = (session) => session.lastMessageAt ?? session.createdAt, byMessage = (a, b) => messageTime(b) - messageTime(a) || Number(b.id) - Number(a.id), byVisited = (a, b) => b.lastUsedAt - a.lastUsedAt || Number(b.id) - Number(a.id);
|
|
4177
|
+
|
|
3677
4178
|
// packages/gateway/src/contract.ts
|
|
3678
4179
|
import { method, remote } from "@earendil-works/chord";
|
|
3679
4180
|
import { Type as Type4 } from "typebox";
|
|
@@ -3687,7 +4188,7 @@ function contract(name, def) {
|
|
|
3687
4188
|
]));
|
|
3688
4189
|
return remote(name, { ...def, variants });
|
|
3689
4190
|
}
|
|
3690
|
-
var rpc = (args, result) => [args, result], str, num, bool, nil, integer, nullableString, phase, level, thinking, model, change, usage, image, skill, call, DelegationSchema, ChatViewSchema, SessionSummarySchema, DirectoryStateSchema, WorkspaceSummarySchema, WorkspaceStateSchema, credentialStatus, CredentialStateSchema, AttachmentSchema, chatInput, NekoSessionDirectory, NekoSessionManagement, resize, inputLimits, modelInfo, NekoModels, imageChunk, NekoSubagent, NekoChat, browse, page, NekoWorkspaces, provider, NekoCredentials, FileCandidatesSchema, NekoWorkspaceFiles, marketSkill, preview, scope, installResult, NekoSkillMarket, ApplicationInfoSchema, NekoApplicationInfo;
|
|
4191
|
+
var rpc = (args, result) => [args, result], str, num, bool, nil, integer, nullableString, phase, level, thinking, model, change, usage, image, skill, call, DelegationSchema, SubagentSummarySchema, ChatViewSchema, SessionSummarySchema, DirectoryStateSchema, WorkspaceSummarySchema, WorkspaceStateSchema, credentialStatus, CredentialStateSchema, AttachmentSchema, chatInput, NekoSessionDirectory, NekoSessionManagement, resize, inputLimits, modelInfo, NekoModels, imageChunk, NekoSubagent, NekoChat, browse, page, NekoWorkspaces, provider, NekoCredentials, FileCandidatesSchema, NekoWorkspaceFiles, marketSkill, preview, scope, installResult, NekoSkillMarket, ApplicationInfoSchema, NekoApplicationInfo;
|
|
3691
4192
|
var init_contract = __esm(() => {
|
|
3692
4193
|
str = Type4.String();
|
|
3693
4194
|
num = Type4.Number();
|
|
@@ -3717,10 +4218,20 @@ var init_contract = __esm(() => {
|
|
|
3717
4218
|
summary: str,
|
|
3718
4219
|
detail: nullableString,
|
|
3719
4220
|
phase,
|
|
3720
|
-
output: nullableString
|
|
4221
|
+
output: nullableString,
|
|
4222
|
+
diff: nullableString,
|
|
4223
|
+
diffAdded: Type4.Union([num, nil]),
|
|
4224
|
+
diffRemoved: Type4.Union([num, nil]),
|
|
4225
|
+
diffTruncated: Type4.Optional(bool)
|
|
3721
4226
|
});
|
|
3722
4227
|
DelegationSchema = Type4.Object({
|
|
3723
4228
|
parentId: integer,
|
|
4229
|
+
agentId: Type4.Optional(str),
|
|
4230
|
+
round: Type4.Optional(integer),
|
|
4231
|
+
runnerId: Type4.Optional(integer),
|
|
4232
|
+
inputEntryId: Type4.Optional(integer),
|
|
4233
|
+
answerEntryId: Type4.Optional(integer),
|
|
4234
|
+
roundUsage: Type4.Optional(Type4.Union([usage, nil])),
|
|
3724
4235
|
taskId: integer,
|
|
3725
4236
|
callId: str,
|
|
3726
4237
|
childId: integer,
|
|
@@ -3735,8 +4246,27 @@ var init_contract = __esm(() => {
|
|
|
3735
4246
|
historyThrough: Type4.Optional(integer),
|
|
3736
4247
|
historyUsage: Type4.Optional(usage)
|
|
3737
4248
|
});
|
|
4249
|
+
SubagentSummarySchema = Type4.Object({
|
|
4250
|
+
agentId: str,
|
|
4251
|
+
parentId: integer,
|
|
4252
|
+
childId: integer,
|
|
4253
|
+
role: Type4.Enum(["explore", "plan", "coder"]),
|
|
4254
|
+
title: str,
|
|
4255
|
+
status: Type4.Enum(["idle", "queued", "running"]),
|
|
4256
|
+
activeRoundId: Type4.Union([integer, nil]),
|
|
4257
|
+
lastRoundId: integer,
|
|
4258
|
+
lastReport: Type4.Optional(nullableString),
|
|
4259
|
+
roundCount: integer,
|
|
4260
|
+
taskTitle: str,
|
|
4261
|
+
approvalCount: integer,
|
|
4262
|
+
createdAt: num,
|
|
4263
|
+
historyThrough: Type4.Optional(integer),
|
|
4264
|
+
historyUsage: Type4.Optional(usage)
|
|
4265
|
+
});
|
|
3738
4266
|
ChatViewSchema = Type4.Object({
|
|
3739
4267
|
historyBefore: Type4.Optional(Type4.Union([integer, nil])),
|
|
4268
|
+
agents: Type4.Optional(Type4.Array(SubagentSummarySchema)),
|
|
4269
|
+
rounds: Type4.Optional(Type4.Array(DelegationSchema)),
|
|
3740
4270
|
subagents: Type4.Optional(Type4.Array(DelegationSchema)),
|
|
3741
4271
|
taskUsage: Type4.Optional(usage),
|
|
3742
4272
|
model: str,
|
|
@@ -3800,7 +4330,11 @@ var init_contract = __esm(() => {
|
|
|
3800
4330
|
output: nullableString,
|
|
3801
4331
|
result: nullableString,
|
|
3802
4332
|
durationMs: Type4.Union([num, nil]),
|
|
3803
|
-
note: nullableString
|
|
4333
|
+
note: nullableString,
|
|
4334
|
+
diff: nullableString,
|
|
4335
|
+
diffAdded: Type4.Union([num, nil]),
|
|
4336
|
+
diffRemoved: Type4.Union([num, nil]),
|
|
4337
|
+
diffTruncated: Type4.Optional(bool)
|
|
3804
4338
|
}),
|
|
3805
4339
|
Type4.Object({ type: Type4.Literal("system"), order: Type4.Optional(num), key: str, id: integer, text: str })
|
|
3806
4340
|
])),
|
|
@@ -3892,7 +4426,12 @@ var init_contract = __esm(() => {
|
|
|
3892
4426
|
imageChunk = Type4.Object({ data: str, total: integer, mimeType: str });
|
|
3893
4427
|
NekoSubagent = contract("neko.subagent", {
|
|
3894
4428
|
version: 1,
|
|
3895
|
-
input: Type4.Object({
|
|
4429
|
+
input: Type4.Object({
|
|
4430
|
+
sessionId: str,
|
|
4431
|
+
attachmentId: str,
|
|
4432
|
+
taskId: Type4.Optional(integer),
|
|
4433
|
+
agentId: Type4.Optional(str)
|
|
4434
|
+
}),
|
|
3896
4435
|
variants: {
|
|
3897
4436
|
ready: {
|
|
3898
4437
|
state: { revision: integer },
|
|
@@ -3905,7 +4444,7 @@ var init_contract = __esm(() => {
|
|
|
3905
4444
|
}), Type4.Object({ token: integer, data: str, next: Type4.Union([integer, nil]) })),
|
|
3906
4445
|
getImage: rpc(Type4.Object({ entryId: integer, contentIndex: integer, offset: integer }), imageChunk),
|
|
3907
4446
|
decideApproval: rpc(Type4.Object({ id: integer, version: str, decision: Type4.Enum(["allowed", "denied"]) }), Type4.Enum(["pending", "allowed", "denied", "cancelled"])),
|
|
3908
|
-
stop: rpc(nil, nil)
|
|
4447
|
+
stop: rpc(Type4.Union([nil, Type4.Object({ taskId: integer })]), nil)
|
|
3909
4448
|
}
|
|
3910
4449
|
}
|
|
3911
4450
|
}
|
|
@@ -4312,17 +4851,18 @@ class ApprovalQueue {
|
|
|
4312
4851
|
update(entries) {
|
|
4313
4852
|
const pending = entries.filter((d) => d.approvalCount && d.historyThrough === undefined);
|
|
4314
4853
|
for (const [id, reader] of this.#readers) {
|
|
4315
|
-
if (!pending.some((d) => d.taskId === id)) {
|
|
4854
|
+
if (!pending.some((d) => (d.agentId ?? d.taskId) === id)) {
|
|
4316
4855
|
this.#readers.delete(id);
|
|
4317
4856
|
reader.stop();
|
|
4318
4857
|
}
|
|
4319
4858
|
}
|
|
4320
4859
|
for (const entry of pending) {
|
|
4321
|
-
|
|
4860
|
+
const key = entry.agentId ?? entry.taskId;
|
|
4861
|
+
if (this.#readers.has(key))
|
|
4322
4862
|
continue;
|
|
4323
|
-
const service = this.#connect(
|
|
4863
|
+
const service = this.#connect(key);
|
|
4324
4864
|
const reader = { service, title: entry.title, stop: () => {} };
|
|
4325
|
-
this.#readers.set(
|
|
4865
|
+
this.#readers.set(key, reader);
|
|
4326
4866
|
reader.stop = service.view.subscribe(() => this.#changed());
|
|
4327
4867
|
}
|
|
4328
4868
|
this.#changed();
|
|
@@ -4392,10 +4932,10 @@ function createGatewayConnection(link, serverId) {
|
|
|
4392
4932
|
let closing;
|
|
4393
4933
|
const connection = {
|
|
4394
4934
|
application,
|
|
4395
|
-
subagent(
|
|
4935
|
+
subagent(target) {
|
|
4396
4936
|
if (!attachment)
|
|
4397
4937
|
throw new Error("No active session");
|
|
4398
|
-
const input = { ...attachment, taskId };
|
|
4938
|
+
const input = { ...attachment, ...typeof target === "string" ? { agentId: target } : { taskId: target } };
|
|
4399
4939
|
return subagentClient(() => host.get(NekoSubagent, input, { at: serverId }));
|
|
4400
4940
|
},
|
|
4401
4941
|
host,
|
|
@@ -4620,8 +5160,8 @@ var init_palette = __esm(() => {
|
|
|
4620
5160
|
codeFg: { fg: "#C0CAF5" },
|
|
4621
5161
|
border: { fg: "#737DA2" },
|
|
4622
5162
|
borderMuted: { fg: "#545E7C" },
|
|
4623
|
-
diffAdded: { fg: "#9ECE6A" },
|
|
4624
|
-
diffRemoved: { fg: "#F7768E" },
|
|
5163
|
+
diffAdded: { fg: "#9ECE6A", bg: "#232C32" },
|
|
5164
|
+
diffRemoved: { fg: "#F7768E", bg: "#302735" },
|
|
4625
5165
|
diffContext: { fg: "#9AA5CE" },
|
|
4626
5166
|
syntaxComment: { fg: "#8993B3", italic: true },
|
|
4627
5167
|
syntaxKeyword: { fg: "#BB9AF7", bold: true },
|
|
@@ -4655,8 +5195,8 @@ var init_palette = __esm(() => {
|
|
|
4655
5195
|
codeFg: { fg: sakura.s800 },
|
|
4656
5196
|
border: { fg: ink.s300 },
|
|
4657
5197
|
borderMuted: { fg: ink.s200 },
|
|
4658
|
-
diffAdded: { fg: "#1A7F37" },
|
|
4659
|
-
diffRemoved: { fg: sakura.s800 },
|
|
5198
|
+
diffAdded: { fg: "#1A7F37", bg: "#E4F3E8" },
|
|
5199
|
+
diffRemoved: { fg: sakura.s800, bg: "#FBE7EC" },
|
|
4660
5200
|
diffContext: { fg: ink.s400 },
|
|
4661
5201
|
syntaxComment: { fg: ink.s600, italic: true },
|
|
4662
5202
|
syntaxKeyword: { fg: sakura.s800 },
|
|
@@ -4749,6 +5289,10 @@ function getActiveThemeMode() {
|
|
|
4749
5289
|
function delegate(name) {
|
|
4750
5290
|
return (text) => activeTheme[name](text);
|
|
4751
5291
|
}
|
|
5292
|
+
function diffBackgroundAnsi(kind) {
|
|
5293
|
+
const style = (activeMode === "dark" ? DARK_PALETTE : LIGHT_PALETTE)[kind === "added" ? "diffAdded" : "diffRemoved"];
|
|
5294
|
+
return backgroundAnsi(parseColor(style.bg), getTerminalColorMode());
|
|
5295
|
+
}
|
|
4752
5296
|
var darkTheme, lightTheme, THEMES, activeMode = "dark", activeTheme, theme, sgr = (attrs) => (text) => styleText(text, {
|
|
4753
5297
|
...attrs.bold !== undefined ? { bold: attrs.bold } : {},
|
|
4754
5298
|
...attrs.italic !== undefined ? { italic: attrs.italic } : {},
|
|
@@ -14173,7 +14717,7 @@ function solidBlock(lines, fullWidth) {
|
|
|
14173
14717
|
const max = Math.max(fullWidth ?? 0, ...lines.map((line) => line.width));
|
|
14174
14718
|
return lines.map((line) => theme.codeBg(line.styled + " ".repeat(Math.max(0, max - line.width))));
|
|
14175
14719
|
}
|
|
14176
|
-
function
|
|
14720
|
+
function htmlToSegmentLines(html) {
|
|
14177
14721
|
const segments = [];
|
|
14178
14722
|
const scopes = [];
|
|
14179
14723
|
let textBuffer = "";
|
|
@@ -14226,25 +14770,31 @@ function renderHighlighted(html, fullWidth) {
|
|
|
14226
14770
|
}
|
|
14227
14771
|
flushText();
|
|
14228
14772
|
const lines = [];
|
|
14229
|
-
let current =
|
|
14230
|
-
let currentWidth = 0;
|
|
14773
|
+
let current = [];
|
|
14231
14774
|
for (const segment of segments) {
|
|
14232
14775
|
const parts = segment.text.split(`
|
|
14233
14776
|
`);
|
|
14234
14777
|
for (const [i, part] of parts.entries()) {
|
|
14235
14778
|
if (i > 0) {
|
|
14236
|
-
lines.push(
|
|
14237
|
-
current =
|
|
14238
|
-
currentWidth = 0;
|
|
14779
|
+
lines.push(current);
|
|
14780
|
+
current = [];
|
|
14239
14781
|
}
|
|
14240
14782
|
if (part === "")
|
|
14241
14783
|
continue;
|
|
14242
|
-
|
|
14243
|
-
current += segment.slot === "plain" ? theme.codeFg(part) : theme[segment.slot](part);
|
|
14784
|
+
current.push({ slot: segment.slot, text: part });
|
|
14244
14785
|
}
|
|
14245
14786
|
}
|
|
14246
|
-
lines.push(
|
|
14247
|
-
return
|
|
14787
|
+
lines.push(current);
|
|
14788
|
+
return lines;
|
|
14789
|
+
}
|
|
14790
|
+
function styleSegmentLine(segments) {
|
|
14791
|
+
return {
|
|
14792
|
+
styled: segments.map((s) => s.slot === "plain" ? theme.codeFg(s.text) : theme[s.slot](s.text)).join(""),
|
|
14793
|
+
width: segments.reduce((total, s) => total + visibleWidth(s.text), 0)
|
|
14794
|
+
};
|
|
14795
|
+
}
|
|
14796
|
+
function renderHighlighted(html, fullWidth) {
|
|
14797
|
+
return solidBlock(htmlToSegmentLines(html).map(styleSegmentLine), fullWidth);
|
|
14248
14798
|
}
|
|
14249
14799
|
function normalizeLang(lang) {
|
|
14250
14800
|
if (lang === undefined)
|
|
@@ -14252,6 +14802,28 @@ function normalizeLang(lang) {
|
|
|
14252
14802
|
const lowered = lang.trim().toLowerCase();
|
|
14253
14803
|
return LANG_ALIASES[lowered] ?? lowered;
|
|
14254
14804
|
}
|
|
14805
|
+
function highlightCodeToSegments(code, lang) {
|
|
14806
|
+
const normalized = normalizeLang(lang);
|
|
14807
|
+
if (normalized === "" || core_default.getLanguage(normalized) === undefined)
|
|
14808
|
+
return null;
|
|
14809
|
+
try {
|
|
14810
|
+
return htmlToSegmentLines(core_default.highlight(code, { language: normalized }).value);
|
|
14811
|
+
} catch {
|
|
14812
|
+
return null;
|
|
14813
|
+
}
|
|
14814
|
+
}
|
|
14815
|
+
function languageForPath(path) {
|
|
14816
|
+
if (path === undefined)
|
|
14817
|
+
return;
|
|
14818
|
+
const base = path.slice(path.lastIndexOf("/") + 1).toLowerCase();
|
|
14819
|
+
const dot = base.lastIndexOf(".");
|
|
14820
|
+
if (dot <= 0)
|
|
14821
|
+
return;
|
|
14822
|
+
const ext = base.slice(dot + 1);
|
|
14823
|
+
if (ext === "" || core_default.getLanguage(ext) === undefined)
|
|
14824
|
+
return;
|
|
14825
|
+
return ext;
|
|
14826
|
+
}
|
|
14255
14827
|
function highlightCodeToAnsiLines(code, lang, fullWidth) {
|
|
14256
14828
|
const normalized = normalizeLang(lang);
|
|
14257
14829
|
if (normalized !== "" && core_default.getLanguage(normalized) !== undefined) {
|
|
@@ -14571,32 +15143,1894 @@ var init_approval_dock = __esm(() => {
|
|
|
14571
15143
|
init_theme();
|
|
14572
15144
|
});
|
|
14573
15145
|
|
|
14574
|
-
//
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
15146
|
+
// node_modules/marked/lib/marked.esm.js
|
|
15147
|
+
function I() {
|
|
15148
|
+
return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
|
|
15149
|
+
}
|
|
15150
|
+
function W(l) {
|
|
15151
|
+
P = l;
|
|
15152
|
+
}
|
|
15153
|
+
function C(l) {
|
|
15154
|
+
let e = [];
|
|
15155
|
+
return (t) => {
|
|
15156
|
+
let n = Math.max(0, Math.min(3, t - 1)), s = e[n];
|
|
15157
|
+
return s || (s = l(n), e[n] = s), s;
|
|
15158
|
+
};
|
|
15159
|
+
}
|
|
15160
|
+
function h(l, e = "") {
|
|
15161
|
+
let t = typeof l == "string" ? l : l.source, n = { replace: (s, r) => {
|
|
15162
|
+
let o = typeof r == "string" ? r : r.source;
|
|
15163
|
+
return o = o.replace(x.caret, "$1"), t = t.replace(s, o), n;
|
|
15164
|
+
}, getRegex: () => new RegExp(t, e) };
|
|
15165
|
+
return n;
|
|
15166
|
+
}
|
|
15167
|
+
function O(l, e) {
|
|
15168
|
+
if (e) {
|
|
15169
|
+
if (x.escapeTest.test(l))
|
|
15170
|
+
return l.replace(x.escapeReplace, Re);
|
|
15171
|
+
} else if (x.escapeTestNoEncode.test(l))
|
|
15172
|
+
return l.replace(x.escapeReplaceNoEncode, Re);
|
|
15173
|
+
return l;
|
|
15174
|
+
}
|
|
15175
|
+
function Te(l) {
|
|
15176
|
+
return l.replace(x.numericCharacterReference, (e, t, n) => {
|
|
15177
|
+
let s = t === undefined ? Number.parseInt(n, 16) : Number.parseInt(t, 10);
|
|
15178
|
+
return s === 0 || s > 1114111 || s >= 55296 && s <= 57343 ? "\uFFFD" : String.fromCodePoint(s);
|
|
15179
|
+
});
|
|
15180
|
+
}
|
|
15181
|
+
function re(l) {
|
|
15182
|
+
try {
|
|
15183
|
+
l = encodeURI(l).replace(x.percentDecode, "%");
|
|
15184
|
+
} catch {
|
|
15185
|
+
return null;
|
|
15186
|
+
}
|
|
15187
|
+
return l;
|
|
15188
|
+
}
|
|
15189
|
+
function se(l, e) {
|
|
15190
|
+
let t = l.replace(x.findPipe, (r, o, i) => {
|
|
15191
|
+
let u = false, a = o;
|
|
15192
|
+
for (;--a >= 0 && i[a] === "\\"; )
|
|
15193
|
+
u = !u;
|
|
15194
|
+
return u ? "|" : " |";
|
|
15195
|
+
}), n = t.split(x.splitPipe), s = 0;
|
|
15196
|
+
if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e)
|
|
15197
|
+
if (n.length > e)
|
|
15198
|
+
n.splice(e);
|
|
15199
|
+
else
|
|
15200
|
+
for (;n.length < e; )
|
|
15201
|
+
n.push("");
|
|
15202
|
+
for (;s < n.length; s++)
|
|
15203
|
+
n[s] = n[s].trim().replace(x.slashPipe, "|");
|
|
15204
|
+
return n;
|
|
15205
|
+
}
|
|
15206
|
+
function L(l, e, t) {
|
|
15207
|
+
let n = l.length;
|
|
15208
|
+
if (n === 0)
|
|
15209
|
+
return "";
|
|
15210
|
+
let s = 0;
|
|
15211
|
+
for (;s < n; ) {
|
|
15212
|
+
let r = l.charAt(n - s - 1);
|
|
15213
|
+
if (r === e && !t)
|
|
15214
|
+
s++;
|
|
15215
|
+
else if (r !== e && t)
|
|
15216
|
+
s++;
|
|
15217
|
+
else
|
|
15218
|
+
break;
|
|
15219
|
+
}
|
|
15220
|
+
return l.slice(0, n - s);
|
|
15221
|
+
}
|
|
15222
|
+
function ie(l) {
|
|
15223
|
+
let e = l.split(`
|
|
15224
|
+
`), t = e.length - 1;
|
|
15225
|
+
for (;t >= 0 && x.blankLine.test(e[t]); )
|
|
15226
|
+
t--;
|
|
15227
|
+
return e.length - t <= 2 ? l : e.slice(0, t + 1).join(`
|
|
15228
|
+
`);
|
|
15229
|
+
}
|
|
15230
|
+
function q(l) {
|
|
15231
|
+
return l.trim().toLowerCase().toUpperCase().toLowerCase();
|
|
15232
|
+
}
|
|
15233
|
+
function oe(l, e) {
|
|
15234
|
+
if (l.indexOf(e[0]) === -1 && l.indexOf(e[1]) === -1)
|
|
15235
|
+
return -1;
|
|
15236
|
+
let t = 0;
|
|
15237
|
+
for (let n = 0;n < l.length; n++)
|
|
15238
|
+
if (l[n] === "\\")
|
|
15239
|
+
n++;
|
|
15240
|
+
else if (l[n] === e[0])
|
|
15241
|
+
t++;
|
|
15242
|
+
else if (l[n] === e[1] && (t--, t < 0))
|
|
15243
|
+
return n;
|
|
15244
|
+
return t > 0 ? -2 : -1;
|
|
15245
|
+
}
|
|
15246
|
+
function ae(l, e = 0) {
|
|
15247
|
+
let t = e, n = "";
|
|
15248
|
+
for (let s of l)
|
|
15249
|
+
if (s === "\t") {
|
|
15250
|
+
let r = 4 - t % 4;
|
|
15251
|
+
n += " ".repeat(r), t += r;
|
|
15252
|
+
} else
|
|
15253
|
+
n += s, t++;
|
|
15254
|
+
return n;
|
|
15255
|
+
}
|
|
15256
|
+
function Oe(l, e, t, n, s) {
|
|
15257
|
+
let r = e.href, o = e.title || null, i = l[1].replace(s.other.outputLinkReplace, "$1"), u = l[0].charAt(0) === "!";
|
|
15258
|
+
n.state.inLink = true;
|
|
15259
|
+
let a = n.state.linkEmitted, p = n.state.inRawBlock;
|
|
15260
|
+
n.state.linkEmitted = false;
|
|
15261
|
+
let c = n.inlineTokens(i), d = n.state.linkEmitted;
|
|
15262
|
+
if (n.state.linkEmitted = a, n.state.inLink = false, !u) {
|
|
15263
|
+
if (d) {
|
|
15264
|
+
n.state.inRawBlock = p;
|
|
15265
|
+
return;
|
|
14597
15266
|
}
|
|
14598
|
-
|
|
14599
|
-
|
|
15267
|
+
n.state.linkEmitted = true;
|
|
15268
|
+
}
|
|
15269
|
+
return { type: u ? "image" : "link", raw: t, href: r, title: o, text: i, tokens: c };
|
|
15270
|
+
}
|
|
15271
|
+
function Pt(l, e, t) {
|
|
15272
|
+
let n = l.match(t.other.indentCodeCompensation);
|
|
15273
|
+
if (n === null)
|
|
15274
|
+
return e;
|
|
15275
|
+
let s = n[1];
|
|
15276
|
+
return e.split(`
|
|
15277
|
+
`).map((r) => {
|
|
15278
|
+
let o = r.match(t.other.beginningSpace);
|
|
15279
|
+
if (o === null)
|
|
15280
|
+
return r;
|
|
15281
|
+
let [i] = o;
|
|
15282
|
+
return r.slice(Math.min(i.length, s.length));
|
|
15283
|
+
}).join(`
|
|
15284
|
+
`);
|
|
15285
|
+
}
|
|
15286
|
+
function we(l, e, t, n) {
|
|
15287
|
+
if (!e.includes("<"))
|
|
15288
|
+
return false;
|
|
15289
|
+
for (let s = 0;s < e.length; s++) {
|
|
15290
|
+
if (e[s] === "\\") {
|
|
15291
|
+
s++;
|
|
15292
|
+
continue;
|
|
15293
|
+
}
|
|
15294
|
+
if (e[s] === "`") {
|
|
15295
|
+
let i = n.inline.code.exec(e.slice(s));
|
|
15296
|
+
if (i) {
|
|
15297
|
+
s += i[0].length - 1;
|
|
15298
|
+
continue;
|
|
15299
|
+
}
|
|
15300
|
+
}
|
|
15301
|
+
if (e[s] !== "<")
|
|
15302
|
+
continue;
|
|
15303
|
+
let r = l.slice(t + s), o = n.inline.tag.exec(r) || n.inline.autolink.exec(r);
|
|
15304
|
+
if (o) {
|
|
15305
|
+
if (o[0].length > e.length - s)
|
|
15306
|
+
return true;
|
|
15307
|
+
s += o[0].length - 1;
|
|
15308
|
+
}
|
|
15309
|
+
}
|
|
15310
|
+
return false;
|
|
15311
|
+
}
|
|
15312
|
+
function k(l, e) {
|
|
15313
|
+
return E.parse(l, e);
|
|
15314
|
+
}
|
|
15315
|
+
function yt(...l) {
|
|
15316
|
+
return E.use(...l), k.defaults = E.defaults, W(k.defaults), k;
|
|
15317
|
+
}
|
|
15318
|
+
var P, A, _e, x, $e, Le, ze, G, Ae, J, he, de, Ee, V, Me, Y, Ie, Ce, N = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul", ee, Be, ke = (l) => h(V).replace("hr", G).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", l).replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", N).getRegex(), De, qe, ve, te, ue, Ze, He, Ge, Ne, ge, Qe, $, B, Q, je, Fe, fe, Ue, Ke, We, me, Xe, Je, Ve, Ye, xe = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)", et, tt, nt = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)", rt, st, it = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)", ot, at, lt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)", ut, pt, ct, ht, dt, be, U, kt, gt, ft, pe, mt, xt, ce, bt, Rt, ne, Tt, X, Ot, j, D, wt, Re = (l) => wt[l], y = class {
|
|
15319
|
+
options;
|
|
15320
|
+
rules;
|
|
15321
|
+
lexer;
|
|
15322
|
+
constructor(e) {
|
|
15323
|
+
this.options = e || P;
|
|
15324
|
+
}
|
|
15325
|
+
space(e) {
|
|
15326
|
+
let t = this.rules.block.newline.exec(e);
|
|
15327
|
+
if (t && t[0].length > 0)
|
|
15328
|
+
return { type: "space", raw: t[0] };
|
|
15329
|
+
}
|
|
15330
|
+
code(e) {
|
|
15331
|
+
let t = this.rules.block.code.exec(e);
|
|
15332
|
+
if (t) {
|
|
15333
|
+
let n = this.options.pedantic ? t[0] : ie(t[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
|
|
15334
|
+
return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
|
|
15335
|
+
}
|
|
15336
|
+
}
|
|
15337
|
+
fences(e) {
|
|
15338
|
+
let t = this.rules.block.fences.exec(e);
|
|
15339
|
+
if (t) {
|
|
15340
|
+
let n = t[0], s = Pt(n, t[3] || "", this.rules);
|
|
15341
|
+
return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: s };
|
|
15342
|
+
}
|
|
15343
|
+
}
|
|
15344
|
+
heading(e) {
|
|
15345
|
+
let t = this.rules.block.heading.exec(e);
|
|
15346
|
+
if (t) {
|
|
15347
|
+
let n = t[2].trim();
|
|
15348
|
+
if (this.rules.other.endingHash.test(n)) {
|
|
15349
|
+
let s = L(n, "#");
|
|
15350
|
+
(this.options.pedantic || !s || this.rules.other.endingSpaceTabChar.test(s)) && (n = s.trim());
|
|
15351
|
+
}
|
|
15352
|
+
return { type: "heading", raw: L(t[0], `
|
|
15353
|
+
`), depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
|
|
15354
|
+
}
|
|
15355
|
+
}
|
|
15356
|
+
hr(e) {
|
|
15357
|
+
let t = this.rules.block.hr.exec(e);
|
|
15358
|
+
if (t)
|
|
15359
|
+
return { type: "hr", raw: L(t[0], `
|
|
15360
|
+
`) };
|
|
15361
|
+
}
|
|
15362
|
+
blockquote(e) {
|
|
15363
|
+
let t = this.rules.block.blockquote.exec(e);
|
|
15364
|
+
if (t) {
|
|
15365
|
+
let n = L(t[0], `
|
|
15366
|
+
`).split(`
|
|
15367
|
+
`), s = "", r = "", o = [];
|
|
15368
|
+
for (;n.length > 0; ) {
|
|
15369
|
+
let i = false, u = [], a;
|
|
15370
|
+
for (a = 0;a < n.length; a++)
|
|
15371
|
+
if (this.rules.other.blockquoteStart.test(n[a]))
|
|
15372
|
+
u.push(n[a]), i = true;
|
|
15373
|
+
else if (!i)
|
|
15374
|
+
u.push(n[a]);
|
|
15375
|
+
else
|
|
15376
|
+
break;
|
|
15377
|
+
n = n.slice(a);
|
|
15378
|
+
let p = u.join(`
|
|
15379
|
+
`), c = p.replace(this.rules.other.blockquoteSetextReplace, `
|
|
15380
|
+
$1`).replace(this.rules.other.blockquoteSetextReplace2, "");
|
|
15381
|
+
s = s ? `${s}
|
|
15382
|
+
${p}` : p, r = r ? `${r}
|
|
15383
|
+
${c}` : c;
|
|
15384
|
+
let d = this.lexer.state.top;
|
|
15385
|
+
if (this.lexer.state.top = true, this.lexer.blockTokens(c, o, true), this.lexer.state.top = d, n.length === 0)
|
|
15386
|
+
break;
|
|
15387
|
+
let m = o.at(-1);
|
|
15388
|
+
if (m?.type === "code")
|
|
15389
|
+
break;
|
|
15390
|
+
if (m?.type === "blockquote") {
|
|
15391
|
+
let b = m, g = n.join(`
|
|
15392
|
+
`), w = b.raw + `
|
|
15393
|
+
` + g.replace(this.rules.other.blockquoteSetextReplace2, ""), f = this.blockquote(w);
|
|
15394
|
+
o[o.length - 1] = f;
|
|
15395
|
+
let M = w.substring(f.raw.length).replace(/^\n/, ""), v = M ? M.split(`
|
|
15396
|
+
`).length : 0, Z = v ? n.slice(0, -v) : n;
|
|
15397
|
+
Z.length > 0 && (s = `${s}
|
|
15398
|
+
${Z.join(`
|
|
15399
|
+
`)}`), r = r.substring(0, r.length - b.text.length) + f.text;
|
|
15400
|
+
break;
|
|
15401
|
+
} else if (m?.type === "list") {
|
|
15402
|
+
let b = m, g = b.raw + `
|
|
15403
|
+
` + n.join(`
|
|
15404
|
+
`), w = this.list(g);
|
|
15405
|
+
o[o.length - 1] = w, s = s.substring(0, s.length - m.raw.length) + w.raw, r = r.substring(0, r.length - b.raw.length) + w.raw, n = g.substring(o.at(-1).raw.length).split(`
|
|
15406
|
+
`);
|
|
15407
|
+
continue;
|
|
15408
|
+
}
|
|
15409
|
+
}
|
|
15410
|
+
return { type: "blockquote", raw: s, tokens: o, text: r };
|
|
15411
|
+
}
|
|
15412
|
+
}
|
|
15413
|
+
list(e) {
|
|
15414
|
+
let t = this.rules.block.list.exec(e);
|
|
15415
|
+
if (t) {
|
|
15416
|
+
let n = t[1].trim(), s = n.length > 1, r = { type: "list", raw: "", ordered: s, start: s ? +n.slice(0, -1) : "", loose: false, items: [] };
|
|
15417
|
+
n = s ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = s ? n : "[*+-]");
|
|
15418
|
+
let o = this.rules.other.listItemRegex(n), i = false;
|
|
15419
|
+
for (;e; ) {
|
|
15420
|
+
let a = false, p = "", c = "";
|
|
15421
|
+
if (!(t = o.exec(e)) || this.rules.block.hr.test(e))
|
|
15422
|
+
break;
|
|
15423
|
+
p = t[0], e = e.substring(p.length);
|
|
15424
|
+
let d = t[2].split(`
|
|
15425
|
+
`, 1)[0], m = t[1].length, b = this.options.pedantic ? ae(d, m) : d.replace(this.rules.other.leadingSpaceTab, (M) => ae(M, m)), g = e.split(`
|
|
15426
|
+
`, 1)[0], w = !b.trim(), f = 0;
|
|
15427
|
+
if (this.options.pedantic ? (f = 2, c = b.trimStart()) : w ? f = m + 1 : (f = b.search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, c = b.slice(f), f += m), w && this.rules.other.blankLine.test(g) && (p += g + `
|
|
15428
|
+
`, e = e.substring(g.length + 1), a = true), !a) {
|
|
15429
|
+
let M = this.rules.other.nextBulletRegex(f), v = this.rules.other.hrRegex(f), Z = this.rules.other.fencesBeginRegex(f), le = this.rules.other.headingBeginRegex(f), Pe = this.rules.other.htmlBeginRegex(f), ye = this.rules.other.blockquoteBeginRegex(f);
|
|
15430
|
+
for (;e; ) {
|
|
15431
|
+
let K = e.split(`
|
|
15432
|
+
`, 1)[0], H;
|
|
15433
|
+
if (g = K, this.options.pedantic ? (g = g.replace(this.rules.other.listReplaceNesting, " "), H = g) : H = g.replace(this.rules.other.leadingSpaceTab, (Se) => Se.replace(this.rules.other.tabCharGlobal, " ")), Z.test(g) || le.test(g) || Pe.test(g) || ye.test(g) || M.test(g) || v.test(g))
|
|
15434
|
+
break;
|
|
15435
|
+
if (H.search(this.rules.other.nonSpaceChar) >= f || !g.trim())
|
|
15436
|
+
c += `
|
|
15437
|
+
` + H.slice(f);
|
|
15438
|
+
else {
|
|
15439
|
+
if (w || b.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || Z.test(b) || le.test(b) || v.test(b))
|
|
15440
|
+
break;
|
|
15441
|
+
c += `
|
|
15442
|
+
` + g;
|
|
15443
|
+
}
|
|
15444
|
+
w = !g.trim(), p += K + `
|
|
15445
|
+
`, e = e.substring(K.length + 1), b = H.slice(f);
|
|
15446
|
+
}
|
|
15447
|
+
}
|
|
15448
|
+
r.loose || (i ? r.loose = true : this.rules.other.doubleBlankLine.test(p) && (i = true)), r.items.push({ type: "list_item", raw: p, task: !!this.options.gfm && this.rules.other.listIsTask.test(c), loose: false, text: c, tokens: [] }), r.raw += p;
|
|
15449
|
+
}
|
|
15450
|
+
let u = r.items.at(-1);
|
|
15451
|
+
if (u)
|
|
15452
|
+
u.raw = u.raw.trimEnd(), u.text = u.text.trimEnd();
|
|
15453
|
+
else
|
|
15454
|
+
return;
|
|
15455
|
+
r.raw = r.raw.trimEnd();
|
|
15456
|
+
for (let a of r.items)
|
|
15457
|
+
if (this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []), !r.loose) {
|
|
15458
|
+
let p = a.tokens.filter((d) => d.type === "space"), c = p.length > 0 && p.some((d) => this.rules.other.anyLine.test(d.raw));
|
|
15459
|
+
r.loose = c;
|
|
15460
|
+
}
|
|
15461
|
+
for (let a of r.items) {
|
|
15462
|
+
let p = a.tokens[0];
|
|
15463
|
+
if (a.task && (p?.type === "text" || p?.type === "paragraph")) {
|
|
15464
|
+
a.text = a.text.replace(this.rules.other.listReplaceTask, ""), p.raw = p.raw.replace(this.rules.other.listReplaceTask, ""), p.text = p.text.replace(this.rules.other.listReplaceTask, "");
|
|
15465
|
+
for (let d = this.lexer.inlineQueue.length - 1;d >= 0; d--)
|
|
15466
|
+
if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[d].src)) {
|
|
15467
|
+
this.lexer.inlineQueue[d].src = this.lexer.inlineQueue[d].src.replace(this.rules.other.listReplaceTask, "");
|
|
15468
|
+
break;
|
|
15469
|
+
}
|
|
15470
|
+
let c = this.rules.other.listTaskCheckbox.exec(a.raw);
|
|
15471
|
+
if (c) {
|
|
15472
|
+
let d = { type: "checkbox", raw: c[0] + " ", checked: c[0] !== "[ ]" };
|
|
15473
|
+
a.checked = d.checked, r.loose ? a.tokens[0] && ["paragraph", "text"].includes(a.tokens[0].type) && "tokens" in a.tokens[0] && a.tokens[0].tokens ? (a.tokens[0].raw = d.raw + a.tokens[0].raw, a.tokens[0].text = d.raw + a.tokens[0].text, a.tokens[0].tokens.unshift(d)) : a.tokens.unshift({ type: "paragraph", raw: d.raw, text: d.raw, tokens: [d] }) : a.tokens.unshift(d);
|
|
15474
|
+
}
|
|
15475
|
+
} else
|
|
15476
|
+
a.task && (a.task = false);
|
|
15477
|
+
}
|
|
15478
|
+
if (r.loose)
|
|
15479
|
+
for (let a of r.items) {
|
|
15480
|
+
a.loose = true;
|
|
15481
|
+
for (let p of a.tokens)
|
|
15482
|
+
p.type === "text" && (p.type = "paragraph");
|
|
15483
|
+
}
|
|
15484
|
+
return r;
|
|
15485
|
+
}
|
|
15486
|
+
}
|
|
15487
|
+
html(e) {
|
|
15488
|
+
let t = this.rules.block.html.exec(e);
|
|
15489
|
+
if (t) {
|
|
15490
|
+
let n = ie(t[0]);
|
|
15491
|
+
return { type: "html", block: true, raw: n, pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: n };
|
|
15492
|
+
}
|
|
15493
|
+
}
|
|
15494
|
+
def(e) {
|
|
15495
|
+
let t = this.rules.block.def.exec(e);
|
|
15496
|
+
if (t) {
|
|
15497
|
+
if (!this.rules.other.startAngleBracket.test(t[2]) && oe(t[2], "()") !== -1)
|
|
15498
|
+
return;
|
|
15499
|
+
let n = q(t[1]).replace(this.rules.other.multipleSpaceGlobal, " "), s = t[2] ? t[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", r = t[3] ? t[3].substring(1, t[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t[3];
|
|
15500
|
+
return { type: "def", tag: n, raw: L(t[0], `
|
|
15501
|
+
`), href: s, title: r };
|
|
15502
|
+
}
|
|
15503
|
+
}
|
|
15504
|
+
table(e) {
|
|
15505
|
+
let t = this.rules.block.table.exec(e);
|
|
15506
|
+
if (!t || !this.rules.other.tableDelimiter.test(t[2]))
|
|
15507
|
+
return;
|
|
15508
|
+
let n = se(t[1]), s = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
|
|
15509
|
+
`) : [], o = { type: "table", raw: L(t[0], `
|
|
15510
|
+
`), header: [], align: [], rows: [] };
|
|
15511
|
+
if (n.length === s.length) {
|
|
15512
|
+
for (let i of s)
|
|
15513
|
+
this.rules.other.tableAlignRight.test(i) ? o.align.push("right") : this.rules.other.tableAlignCenter.test(i) ? o.align.push("center") : this.rules.other.tableAlignLeft.test(i) ? o.align.push("left") : o.align.push(null);
|
|
15514
|
+
for (let i = 0;i < n.length; i++)
|
|
15515
|
+
o.header.push({ text: n[i], tokens: this.lexer.inline(n[i]), header: true, align: o.align[i] });
|
|
15516
|
+
for (let i of r)
|
|
15517
|
+
o.rows.push(se(i, o.header.length).map((u, a) => ({ text: u, tokens: this.lexer.inline(u), header: false, align: o.align[a] })));
|
|
15518
|
+
return o;
|
|
15519
|
+
}
|
|
15520
|
+
}
|
|
15521
|
+
lheading(e) {
|
|
15522
|
+
let t = this.rules.block.lheading.exec(e);
|
|
15523
|
+
if (t) {
|
|
15524
|
+
let n = t[1].trim();
|
|
15525
|
+
return { type: "heading", raw: L(t[0], `
|
|
15526
|
+
`), depth: t[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
|
|
15527
|
+
}
|
|
15528
|
+
}
|
|
15529
|
+
paragraph(e) {
|
|
15530
|
+
let t = this.rules.block.paragraph.exec(e);
|
|
15531
|
+
if (t) {
|
|
15532
|
+
let n = t[1].charAt(t[1].length - 1) === `
|
|
15533
|
+
` ? t[1].slice(0, -1) : t[1];
|
|
15534
|
+
return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
|
|
15535
|
+
}
|
|
15536
|
+
}
|
|
15537
|
+
text(e) {
|
|
15538
|
+
let t = this.rules.block.text.exec(e);
|
|
15539
|
+
if (t)
|
|
15540
|
+
return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
|
|
15541
|
+
}
|
|
15542
|
+
escape(e) {
|
|
15543
|
+
let t = this.rules.inline.escape.exec(e);
|
|
15544
|
+
if (t)
|
|
15545
|
+
return { type: "escape", raw: t[0], text: t[1] };
|
|
15546
|
+
}
|
|
15547
|
+
tag(e) {
|
|
15548
|
+
let t = this.rules.inline.tag.exec(e);
|
|
15549
|
+
if (t)
|
|
15550
|
+
return !this.lexer.state.inLink && this.rules.other.startATag.test(t[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t[0] };
|
|
15551
|
+
}
|
|
15552
|
+
link(e) {
|
|
15553
|
+
if (this.lexer.state.linkParenPossible === false)
|
|
15554
|
+
return;
|
|
15555
|
+
let t = this.rules.inline.link.exec(e);
|
|
15556
|
+
if (t) {
|
|
15557
|
+
let n = t[0].charAt(0) === "!" ? 2 : 1;
|
|
15558
|
+
if (!this.options.pedantic && we(e, t[1], n, this.rules))
|
|
15559
|
+
return;
|
|
15560
|
+
let s = t[2].trim();
|
|
15561
|
+
if (!this.options.pedantic && this.rules.other.startAngleBracket.test(s)) {
|
|
15562
|
+
if (!this.rules.other.endAngleBracket.test(s))
|
|
15563
|
+
return;
|
|
15564
|
+
let i = L(s.slice(0, -1), "\\");
|
|
15565
|
+
if ((s.length - i.length) % 2 === 0)
|
|
15566
|
+
return;
|
|
15567
|
+
} else {
|
|
15568
|
+
let i = oe(t[2], "()");
|
|
15569
|
+
if (i === -2)
|
|
15570
|
+
return;
|
|
15571
|
+
if (i > -1) {
|
|
15572
|
+
let a = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + i;
|
|
15573
|
+
t[2] = t[2].substring(0, i), t[0] = t[0].substring(0, a).trim(), t[3] = "";
|
|
15574
|
+
}
|
|
15575
|
+
}
|
|
15576
|
+
let r = t[2], o = "";
|
|
15577
|
+
if (this.options.pedantic) {
|
|
15578
|
+
let i = this.rules.other.pedanticHrefTitle.exec(r);
|
|
15579
|
+
i && (r = i[1], o = i[3]);
|
|
15580
|
+
} else
|
|
15581
|
+
o = t[3] ? t[3].slice(1, -1) : "";
|
|
15582
|
+
return r = r.trim(), this.rules.other.startAngleBracket.test(r) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(s) ? r = r.slice(1) : r = r.slice(1, -1)), Oe(t, { href: r && r.replace(this.rules.inline.anyPunctuation, "$1"), title: o && o.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
|
|
15583
|
+
}
|
|
15584
|
+
}
|
|
15585
|
+
reflink(e, t) {
|
|
15586
|
+
let n;
|
|
15587
|
+
if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
|
|
15588
|
+
let s = n[0].charAt(0) === "!" ? 2 : 1;
|
|
15589
|
+
if (!this.options.pedantic && we(e, n[1], s, this.rules))
|
|
15590
|
+
return;
|
|
15591
|
+
let r = (n[2] || n[1]).replace(this.rules.other.multipleSpaceGlobal, " "), o = t[q(r)];
|
|
15592
|
+
if (!o) {
|
|
15593
|
+
let i = n[0].charAt(0);
|
|
15594
|
+
return { type: "text", raw: i, text: i };
|
|
15595
|
+
}
|
|
15596
|
+
return Oe(n, o, n[0], this.lexer, this.rules);
|
|
15597
|
+
}
|
|
15598
|
+
}
|
|
15599
|
+
emStrong(e, t, n = "") {
|
|
15600
|
+
let s = this.rules.inline.emStrongLDelim.exec(e);
|
|
15601
|
+
if (!s || !s[1] && !s[2] && !s[3] && !s[4] || s[4] && n.match(this.rules.other.unicodeAlphaNumeric))
|
|
15602
|
+
return;
|
|
15603
|
+
if (!(s[1] || s[3] || "") || !n || this.rules.inline.punctuation.exec(n)) {
|
|
15604
|
+
let o = [...s[0]].length - 1, i, u, a = o, p = 0, c = s[0][0], d = n === c, m = c === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
|
|
15605
|
+
for (m.lastIndex = 0, t = t.slice(-1 * e.length + o);(s = m.exec(t)) !== null; ) {
|
|
15606
|
+
if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i)
|
|
15607
|
+
continue;
|
|
15608
|
+
if (u = [...i].length, s[3] || s[4]) {
|
|
15609
|
+
a += u;
|
|
15610
|
+
continue;
|
|
15611
|
+
} else if (s[5] || s[6]) {
|
|
15612
|
+
if (o % 3 && !((o + u) % 3)) {
|
|
15613
|
+
p += u;
|
|
15614
|
+
continue;
|
|
15615
|
+
}
|
|
15616
|
+
if (d)
|
|
15617
|
+
break;
|
|
15618
|
+
}
|
|
15619
|
+
if (a -= u, a > 0)
|
|
15620
|
+
continue;
|
|
15621
|
+
u = Math.min(u, u + a + p);
|
|
15622
|
+
let b = [...s[0]][0].length, g = e.slice(0, o + s.index + b + u);
|
|
15623
|
+
if (Math.min(o, u) % 2) {
|
|
15624
|
+
let f = g.slice(1, -1);
|
|
15625
|
+
return { type: "em", raw: g, text: f, tokens: this.lexer.inlineTokens(f) };
|
|
15626
|
+
}
|
|
15627
|
+
let w = g.slice(2, -2);
|
|
15628
|
+
return { type: "strong", raw: g, text: w, tokens: this.lexer.inlineTokens(w) };
|
|
15629
|
+
}
|
|
15630
|
+
}
|
|
15631
|
+
}
|
|
15632
|
+
codespan(e) {
|
|
15633
|
+
let t = this.rules.inline.code.exec(e);
|
|
15634
|
+
if (t) {
|
|
15635
|
+
let n = t[2].replace(this.rules.other.newLineCharGlobal, " "), s = this.rules.other.nonSpaceChar.test(n), r = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
|
|
15636
|
+
return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15639
|
+
br(e) {
|
|
15640
|
+
let t = this.rules.inline.br.exec(e);
|
|
15641
|
+
if (t)
|
|
15642
|
+
return { type: "br", raw: t[0] };
|
|
15643
|
+
}
|
|
15644
|
+
del(e, t, n = "") {
|
|
15645
|
+
let s = this.rules.inline.delLDelim.exec(e);
|
|
15646
|
+
if (!s)
|
|
15647
|
+
return;
|
|
15648
|
+
if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
|
|
15649
|
+
let o = [...s[0]].length - 1, i, u, a = o, p = this.rules.inline.delRDelim;
|
|
15650
|
+
for (p.lastIndex = 0, t = t.slice(-1 * e.length + o);(s = p.exec(t)) !== null; ) {
|
|
15651
|
+
if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i || (u = [...i].length, u !== o))
|
|
15652
|
+
continue;
|
|
15653
|
+
if (s[3] || s[4]) {
|
|
15654
|
+
a += u;
|
|
15655
|
+
continue;
|
|
15656
|
+
}
|
|
15657
|
+
if (a -= u, a > 0)
|
|
15658
|
+
continue;
|
|
15659
|
+
u = Math.min(u, u + a);
|
|
15660
|
+
let c = [...s[0]][0].length, d = e.slice(0, o + s.index + c + u), m = d.slice(o, -o);
|
|
15661
|
+
return { type: "del", raw: d, text: m, tokens: this.lexer.inlineTokens(m) };
|
|
15662
|
+
}
|
|
15663
|
+
}
|
|
15664
|
+
}
|
|
15665
|
+
autolink(e) {
|
|
15666
|
+
let t = this.rules.inline.autolink.exec(e);
|
|
15667
|
+
if (t) {
|
|
15668
|
+
let n, s;
|
|
15669
|
+
return t[2] === "@" ? (n = t[1], s = "mailto:" + n) : (n = t[1], s = n), { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
|
|
15670
|
+
}
|
|
15671
|
+
}
|
|
15672
|
+
url(e) {
|
|
15673
|
+
let t;
|
|
15674
|
+
if (t = this.rules.inline.url.exec(e)) {
|
|
15675
|
+
let n, s;
|
|
15676
|
+
if (t[2] === "@")
|
|
15677
|
+
n = t[0], s = "mailto:" + n;
|
|
15678
|
+
else {
|
|
15679
|
+
let r;
|
|
15680
|
+
do
|
|
15681
|
+
r = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
|
|
15682
|
+
while (r !== t[0]);
|
|
15683
|
+
n = t[0], t[1] === "www." ? s = "http://" + t[0] : s = t[0];
|
|
15684
|
+
}
|
|
15685
|
+
return { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
|
|
15686
|
+
}
|
|
15687
|
+
}
|
|
15688
|
+
inlineText(e) {
|
|
15689
|
+
let t = this.rules.inline.text.exec(e);
|
|
15690
|
+
if (t) {
|
|
15691
|
+
let n = this.lexer.state.inRawBlock;
|
|
15692
|
+
return { type: "text", raw: t[0], text: n ? t[0] : Te(t[0]), escaped: n };
|
|
15693
|
+
}
|
|
15694
|
+
}
|
|
15695
|
+
}, R = class l {
|
|
15696
|
+
tokens;
|
|
15697
|
+
options;
|
|
15698
|
+
state;
|
|
15699
|
+
inlineQueue;
|
|
15700
|
+
tokenizer;
|
|
15701
|
+
constructor(e) {
|
|
15702
|
+
this.tokens = [], this.tokens.links = Object.create(null), this.options = e || P, this.options.tokenizer = this.options.tokenizer || new y, this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, linkEmitted: false, linkParenPossible: true, top: true };
|
|
15703
|
+
let t = { other: x, block: j.normal, inline: D.normal };
|
|
15704
|
+
this.options.pedantic ? (t.block = j.pedantic, t.inline = D.pedantic) : this.options.gfm && (t.block = j.gfm, this.options.breaks ? t.inline = D.breaks : t.inline = D.gfm), this.tokenizer.rules = t;
|
|
15705
|
+
}
|
|
15706
|
+
static get rules() {
|
|
15707
|
+
return { block: j, inline: D };
|
|
15708
|
+
}
|
|
15709
|
+
static lex(e, t) {
|
|
15710
|
+
return new l(t).lex(e);
|
|
15711
|
+
}
|
|
15712
|
+
static lexInline(e, t) {
|
|
15713
|
+
return new l(t).inlineTokens(e);
|
|
15714
|
+
}
|
|
15715
|
+
lex(e) {
|
|
15716
|
+
e = e.replace(x.carriageReturn, `
|
|
15717
|
+
`), this.blockTokens(e, this.tokens);
|
|
15718
|
+
for (let t = 0;t < this.inlineQueue.length; t++) {
|
|
15719
|
+
let n = this.inlineQueue[t];
|
|
15720
|
+
this.inlineTokens(n.src, n.tokens);
|
|
15721
|
+
}
|
|
15722
|
+
return this.inlineQueue = [], this.tokens;
|
|
15723
|
+
}
|
|
15724
|
+
blockTokens(e, t = [], n = false) {
|
|
15725
|
+
this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(x.tabCharGlobal, " ").replace(x.spaceLine, ""));
|
|
15726
|
+
let s = 1 / 0;
|
|
15727
|
+
for (;e; ) {
|
|
15728
|
+
if (e.length < s)
|
|
15729
|
+
s = e.length;
|
|
15730
|
+
else {
|
|
15731
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
15732
|
+
break;
|
|
15733
|
+
}
|
|
15734
|
+
let r;
|
|
15735
|
+
if (this.options.extensions?.block?.some((i) => (r = i.call({ lexer: this }, e, t)) ? (e = e.substring(r.raw.length), t.push(r), true) : false))
|
|
15736
|
+
continue;
|
|
15737
|
+
if (r = this.tokenizer.space(e)) {
|
|
15738
|
+
e = e.substring(r.raw.length);
|
|
15739
|
+
let i = t.at(-1);
|
|
15740
|
+
r.raw.length === 1 && i !== undefined ? i.raw += `
|
|
15741
|
+
` : t.push(r);
|
|
15742
|
+
continue;
|
|
15743
|
+
}
|
|
15744
|
+
if (r = this.tokenizer.code(e)) {
|
|
15745
|
+
e = e.substring(r.raw.length);
|
|
15746
|
+
let i = t.at(-1);
|
|
15747
|
+
i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
15748
|
+
`) ? "" : `
|
|
15749
|
+
`) + r.raw, i.text += `
|
|
15750
|
+
` + r.text, this.inlineQueue.at(-1).src = i.text) : t.push(r);
|
|
15751
|
+
continue;
|
|
15752
|
+
}
|
|
15753
|
+
if (r = this.tokenizer.fences(e)) {
|
|
15754
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15755
|
+
continue;
|
|
15756
|
+
}
|
|
15757
|
+
if (r = this.tokenizer.heading(e)) {
|
|
15758
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15759
|
+
continue;
|
|
15760
|
+
}
|
|
15761
|
+
if (r = this.tokenizer.hr(e)) {
|
|
15762
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15763
|
+
continue;
|
|
15764
|
+
}
|
|
15765
|
+
if (r = this.tokenizer.blockquote(e)) {
|
|
15766
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15767
|
+
continue;
|
|
15768
|
+
}
|
|
15769
|
+
if (r = this.tokenizer.list(e)) {
|
|
15770
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15771
|
+
continue;
|
|
15772
|
+
}
|
|
15773
|
+
if (r = this.tokenizer.html(e)) {
|
|
15774
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15775
|
+
continue;
|
|
15776
|
+
}
|
|
15777
|
+
if (r = this.tokenizer.def(e)) {
|
|
15778
|
+
e = e.substring(r.raw.length);
|
|
15779
|
+
let i = t.at(-1);
|
|
15780
|
+
i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
15781
|
+
`) ? "" : `
|
|
15782
|
+
`) + r.raw, i.text += `
|
|
15783
|
+
` + r.raw, this.inlineQueue.at(-1).src = i.text) : this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }, t.push(r));
|
|
15784
|
+
continue;
|
|
15785
|
+
}
|
|
15786
|
+
if (r = this.tokenizer.table(e)) {
|
|
15787
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15788
|
+
continue;
|
|
15789
|
+
}
|
|
15790
|
+
if (r = this.tokenizer.lheading(e)) {
|
|
15791
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
15792
|
+
continue;
|
|
15793
|
+
}
|
|
15794
|
+
let o = e;
|
|
15795
|
+
if (this.options.extensions?.startBlock) {
|
|
15796
|
+
let i = 1 / 0, u = e.slice(1), a;
|
|
15797
|
+
this.options.extensions.startBlock.forEach((p) => {
|
|
15798
|
+
a = p.call({ lexer: this }, u), typeof a == "number" && a >= 0 && (i = Math.min(i, a));
|
|
15799
|
+
}), i < 1 / 0 && i >= 0 && (o = e.substring(0, i + 1));
|
|
15800
|
+
}
|
|
15801
|
+
if (this.state.top && (r = this.tokenizer.paragraph(o))) {
|
|
15802
|
+
let i = t.at(-1);
|
|
15803
|
+
n && i?.type === "paragraph" ? (i.raw += (i.raw.endsWith(`
|
|
15804
|
+
`) ? "" : `
|
|
15805
|
+
`) + r.raw, i.text += `
|
|
15806
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r), n = o.length !== e.length, e = e.substring(r.raw.length);
|
|
15807
|
+
continue;
|
|
15808
|
+
}
|
|
15809
|
+
if (r = this.tokenizer.text(e)) {
|
|
15810
|
+
e = e.substring(r.raw.length);
|
|
15811
|
+
let i = t.at(-1);
|
|
15812
|
+
i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
15813
|
+
`) ? "" : `
|
|
15814
|
+
`) + r.raw, i.text += `
|
|
15815
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r);
|
|
15816
|
+
continue;
|
|
15817
|
+
}
|
|
15818
|
+
if (e) {
|
|
15819
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
15820
|
+
break;
|
|
15821
|
+
}
|
|
15822
|
+
}
|
|
15823
|
+
return this.state.top = true, t;
|
|
15824
|
+
}
|
|
15825
|
+
inline(e, t = []) {
|
|
15826
|
+
return this.inlineQueue.push({ src: e, tokens: t }), t;
|
|
15827
|
+
}
|
|
15828
|
+
linkInText(e) {
|
|
15829
|
+
if (!e.includes("["))
|
|
15830
|
+
return false;
|
|
15831
|
+
let t = this.tokenizer.rules.inline.link;
|
|
15832
|
+
for (let n of e.matchAll(this.tokenizer.rules.inline.blockSkip))
|
|
15833
|
+
if (t.test(n[0]) && e.charAt(n.index - 1) !== "!")
|
|
15834
|
+
return true;
|
|
15835
|
+
for (let n of e.matchAll(this.tokenizer.rules.inline.reflinkSearch)) {
|
|
15836
|
+
let s = n[0], r = s.lastIndexOf("[");
|
|
15837
|
+
if (!(s.charAt(0) === "!" || !Object.hasOwn(this.tokens.links, q(s.slice(r + 1, -1)))) && !(r > 1 && this.linkInText(s.slice(1, r - 1))))
|
|
15838
|
+
return true;
|
|
15839
|
+
}
|
|
15840
|
+
return false;
|
|
15841
|
+
}
|
|
15842
|
+
inlineTokens(e, t = []) {
|
|
15843
|
+
this.tokenizer.lexer = this;
|
|
15844
|
+
let n = this.state.linkParenPossible;
|
|
15845
|
+
this.state.linkParenPossible = n && e.includes(")");
|
|
15846
|
+
try {
|
|
15847
|
+
return this.#e(e, t);
|
|
15848
|
+
} finally {
|
|
15849
|
+
this.state.linkParenPossible = n;
|
|
15850
|
+
}
|
|
15851
|
+
}
|
|
15852
|
+
#e(e, t) {
|
|
15853
|
+
let n = e;
|
|
15854
|
+
if (this.tokens.links && e.includes("[")) {
|
|
15855
|
+
let i = this.tokenizer.rules.inline.reflinkSearch, u = (a) => {
|
|
15856
|
+
let p = a.lastIndexOf("[");
|
|
15857
|
+
if (!Object.hasOwn(this.tokens.links, q(a.slice(p + 1, -1))))
|
|
15858
|
+
return a;
|
|
15859
|
+
if (p > 1 && a.charAt(0) !== "!") {
|
|
15860
|
+
let c = a.slice(1, p - 1);
|
|
15861
|
+
if (this.linkInText(c))
|
|
15862
|
+
return "[" + c.replace(i, u) + "][" + "a".repeat(a.length - p - 2) + "]";
|
|
15863
|
+
}
|
|
15864
|
+
return "[" + "a".repeat(a.length - 2) + "]";
|
|
15865
|
+
};
|
|
15866
|
+
n = n.replace(i, u);
|
|
15867
|
+
}
|
|
15868
|
+
n = n.replace(this.tokenizer.rules.inline.anyPunctuation, (i) => "+".repeat(i.length)), n = n.replace(this.tokenizer.rules.inline.blockSkip, (i, u, a) => {
|
|
15869
|
+
let p = a ? a.length : 0;
|
|
15870
|
+
return i.slice(0, p) + "[" + "a".repeat(i.length - p - 2) + "]";
|
|
15871
|
+
}), n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
|
|
15872
|
+
let s = false, r = "", o = 1 / 0;
|
|
15873
|
+
for (;e; ) {
|
|
15874
|
+
if (e.length < o)
|
|
15875
|
+
o = e.length;
|
|
15876
|
+
else {
|
|
15877
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
15878
|
+
break;
|
|
15879
|
+
}
|
|
15880
|
+
s || (r = ""), s = false;
|
|
15881
|
+
let i;
|
|
15882
|
+
if (this.options.extensions?.inline?.some((a) => (i = a.call({ lexer: this }, e, t)) ? (e = e.substring(i.raw.length), t.push(i), true) : false))
|
|
15883
|
+
continue;
|
|
15884
|
+
if (i = this.tokenizer.escape(e)) {
|
|
15885
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15886
|
+
continue;
|
|
15887
|
+
}
|
|
15888
|
+
if (i = this.tokenizer.tag(e)) {
|
|
15889
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15890
|
+
continue;
|
|
15891
|
+
}
|
|
15892
|
+
if (i = this.tokenizer.link(e)) {
|
|
15893
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15894
|
+
continue;
|
|
15895
|
+
}
|
|
15896
|
+
if (i = this.tokenizer.reflink(e, this.tokens.links)) {
|
|
15897
|
+
e = e.substring(i.raw.length);
|
|
15898
|
+
let a = t.at(-1);
|
|
15899
|
+
i.type === "text" && a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
|
|
15900
|
+
continue;
|
|
15901
|
+
}
|
|
15902
|
+
if (i = this.tokenizer.emStrong(e, n, r)) {
|
|
15903
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15904
|
+
continue;
|
|
15905
|
+
}
|
|
15906
|
+
if (i = this.tokenizer.codespan(e)) {
|
|
15907
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15908
|
+
continue;
|
|
15909
|
+
}
|
|
15910
|
+
if (i = this.tokenizer.br(e)) {
|
|
15911
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15912
|
+
continue;
|
|
15913
|
+
}
|
|
15914
|
+
if (i = this.tokenizer.del(e, n, r)) {
|
|
15915
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15916
|
+
continue;
|
|
15917
|
+
}
|
|
15918
|
+
if (i = this.tokenizer.autolink(e)) {
|
|
15919
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15920
|
+
continue;
|
|
15921
|
+
}
|
|
15922
|
+
if (!this.state.inLink && (i = this.tokenizer.url(e))) {
|
|
15923
|
+
e = e.substring(i.raw.length), t.push(i);
|
|
15924
|
+
continue;
|
|
15925
|
+
}
|
|
15926
|
+
let u = e;
|
|
15927
|
+
if (this.options.extensions?.startInline) {
|
|
15928
|
+
let a = 1 / 0, p = e.slice(1), c;
|
|
15929
|
+
this.options.extensions.startInline.forEach((d) => {
|
|
15930
|
+
c = d.call({ lexer: this }, p), typeof c == "number" && c >= 0 && (a = Math.min(a, c));
|
|
15931
|
+
}), a < 1 / 0 && a >= 0 && (u = e.substring(0, a + 1));
|
|
15932
|
+
}
|
|
15933
|
+
if (i = this.tokenizer.inlineText(u)) {
|
|
15934
|
+
e = e.substring(i.raw.length), i.raw.slice(-1) !== "_" && (r = i.raw.slice(-1)), s = true;
|
|
15935
|
+
let a = t.at(-1);
|
|
15936
|
+
a?.type === "text" ? (a.raw += i.raw, a.text += i.text) : t.push(i);
|
|
15937
|
+
continue;
|
|
15938
|
+
}
|
|
15939
|
+
if (e) {
|
|
15940
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
15941
|
+
break;
|
|
15942
|
+
}
|
|
15943
|
+
}
|
|
15944
|
+
return t;
|
|
15945
|
+
}
|
|
15946
|
+
infiniteLoopError(e) {
|
|
15947
|
+
let t = "Infinite loop on byte: " + e;
|
|
15948
|
+
if (this.options.silent)
|
|
15949
|
+
console.error(t);
|
|
15950
|
+
else
|
|
15951
|
+
throw new Error(t);
|
|
15952
|
+
}
|
|
15953
|
+
}, S = class {
|
|
15954
|
+
options;
|
|
15955
|
+
parser;
|
|
15956
|
+
constructor(e) {
|
|
15957
|
+
this.options = e || P;
|
|
15958
|
+
}
|
|
15959
|
+
space(e) {
|
|
15960
|
+
return "";
|
|
15961
|
+
}
|
|
15962
|
+
code({ text: e, lang: t, escaped: n }) {
|
|
15963
|
+
let s = (t || "").match(x.notSpaceStart)?.[0], r = e ? e.replace(x.endingNewline, "") + `
|
|
15964
|
+
` : "";
|
|
15965
|
+
return s ? '<pre><code class="language-' + O(s) + '">' + (n ? r : O(r, true)) + `</code></pre>
|
|
15966
|
+
` : "<pre><code>" + (n ? r : O(r, true)) + `</code></pre>
|
|
15967
|
+
`;
|
|
15968
|
+
}
|
|
15969
|
+
blockquote({ tokens: e }) {
|
|
15970
|
+
return `<blockquote>
|
|
15971
|
+
${this.parser.parse(e)}</blockquote>
|
|
15972
|
+
`;
|
|
15973
|
+
}
|
|
15974
|
+
html({ text: e }) {
|
|
15975
|
+
return e;
|
|
15976
|
+
}
|
|
15977
|
+
def(e) {
|
|
15978
|
+
return "";
|
|
15979
|
+
}
|
|
15980
|
+
heading({ tokens: e, depth: t }) {
|
|
15981
|
+
return `<h${t}>${this.parser.parseInline(e)}</h${t}>
|
|
15982
|
+
`;
|
|
15983
|
+
}
|
|
15984
|
+
hr(e) {
|
|
15985
|
+
return `<hr>
|
|
15986
|
+
`;
|
|
15987
|
+
}
|
|
15988
|
+
list(e) {
|
|
15989
|
+
let { ordered: t, start: n } = e, s = "";
|
|
15990
|
+
for (let i = 0;i < e.items.length; i++) {
|
|
15991
|
+
let u = e.items[i];
|
|
15992
|
+
s += this.listitem(u);
|
|
15993
|
+
}
|
|
15994
|
+
let r = t ? "ol" : "ul", o = t && n !== 1 ? ' start="' + n + '"' : "";
|
|
15995
|
+
return "<" + r + o + `>
|
|
15996
|
+
` + s + "</" + r + `>
|
|
15997
|
+
`;
|
|
15998
|
+
}
|
|
15999
|
+
listitem(e) {
|
|
16000
|
+
return `<li>${this.parser.parse(e.tokens)}</li>
|
|
16001
|
+
`;
|
|
16002
|
+
}
|
|
16003
|
+
checkbox({ checked: e }) {
|
|
16004
|
+
return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
|
|
16005
|
+
}
|
|
16006
|
+
paragraph({ tokens: e }) {
|
|
16007
|
+
return `<p>${this.parser.parseInline(e)}</p>
|
|
16008
|
+
`;
|
|
16009
|
+
}
|
|
16010
|
+
table(e) {
|
|
16011
|
+
let t = "", n = "";
|
|
16012
|
+
for (let r = 0;r < e.header.length; r++)
|
|
16013
|
+
n += this.tablecell(e.header[r]);
|
|
16014
|
+
t += this.tablerow({ text: n });
|
|
16015
|
+
let s = "";
|
|
16016
|
+
for (let r = 0;r < e.rows.length; r++) {
|
|
16017
|
+
let o = e.rows[r];
|
|
16018
|
+
n = "";
|
|
16019
|
+
for (let i = 0;i < o.length; i++)
|
|
16020
|
+
n += this.tablecell(o[i]);
|
|
16021
|
+
s += this.tablerow({ text: n });
|
|
16022
|
+
}
|
|
16023
|
+
return s && (s = `<tbody>${s}</tbody>`), `<table>
|
|
16024
|
+
<thead>
|
|
16025
|
+
` + t + `</thead>
|
|
16026
|
+
` + s + `</table>
|
|
16027
|
+
`;
|
|
16028
|
+
}
|
|
16029
|
+
tablerow({ text: e }) {
|
|
16030
|
+
return `<tr>
|
|
16031
|
+
${e}</tr>
|
|
16032
|
+
`;
|
|
16033
|
+
}
|
|
16034
|
+
tablecell(e) {
|
|
16035
|
+
let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
|
|
16036
|
+
return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
|
|
16037
|
+
`;
|
|
16038
|
+
}
|
|
16039
|
+
strong({ tokens: e }) {
|
|
16040
|
+
return `<strong>${this.parser.parseInline(e)}</strong>`;
|
|
16041
|
+
}
|
|
16042
|
+
em({ tokens: e }) {
|
|
16043
|
+
return `<em>${this.parser.parseInline(e)}</em>`;
|
|
16044
|
+
}
|
|
16045
|
+
codespan({ text: e }) {
|
|
16046
|
+
return `<code>${O(e, true)}</code>`;
|
|
16047
|
+
}
|
|
16048
|
+
br(e) {
|
|
16049
|
+
return "<br>";
|
|
16050
|
+
}
|
|
16051
|
+
del({ tokens: e }) {
|
|
16052
|
+
return `<del>${this.parser.parseInline(e)}</del>`;
|
|
16053
|
+
}
|
|
16054
|
+
link({ href: e, title: t, text: n, tokens: s, autolink: r }) {
|
|
16055
|
+
let o = r ? O(n, true) : this.parser.parseInline(s), i = re(e);
|
|
16056
|
+
if (i === null)
|
|
16057
|
+
return o;
|
|
16058
|
+
e = O(i, r);
|
|
16059
|
+
let u = '<a href="' + e + '"';
|
|
16060
|
+
return t && (u += ' title="' + O(t) + '"'), u += ">" + o + "</a>", u;
|
|
16061
|
+
}
|
|
16062
|
+
image({ href: e, title: t, text: n, tokens: s }) {
|
|
16063
|
+
s && (n = this.parser.parseInline(s, this.parser.textRenderer));
|
|
16064
|
+
let r = re(e);
|
|
16065
|
+
if (r === null)
|
|
16066
|
+
return O(n);
|
|
16067
|
+
e = r;
|
|
16068
|
+
let o = `<img src="${O(e)}" alt="${O(n)}"`;
|
|
16069
|
+
return t && (o += ` title="${O(t)}"`), o += ">", o;
|
|
16070
|
+
}
|
|
16071
|
+
text(e) {
|
|
16072
|
+
return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : ("escaped" in e) && e.escaped ? e.text : O(e.text);
|
|
16073
|
+
}
|
|
16074
|
+
}, z = class {
|
|
16075
|
+
strong({ text: e }) {
|
|
16076
|
+
return e;
|
|
16077
|
+
}
|
|
16078
|
+
em({ text: e }) {
|
|
16079
|
+
return e;
|
|
16080
|
+
}
|
|
16081
|
+
codespan({ text: e }) {
|
|
16082
|
+
return e;
|
|
16083
|
+
}
|
|
16084
|
+
del({ text: e }) {
|
|
16085
|
+
return e;
|
|
16086
|
+
}
|
|
16087
|
+
html({ text: e }) {
|
|
16088
|
+
return e;
|
|
16089
|
+
}
|
|
16090
|
+
text({ text: e }) {
|
|
16091
|
+
return e;
|
|
16092
|
+
}
|
|
16093
|
+
link({ text: e }) {
|
|
16094
|
+
return "" + e;
|
|
16095
|
+
}
|
|
16096
|
+
image({ text: e }) {
|
|
16097
|
+
return "" + e;
|
|
16098
|
+
}
|
|
16099
|
+
br() {
|
|
16100
|
+
return "";
|
|
16101
|
+
}
|
|
16102
|
+
checkbox({ raw: e }) {
|
|
16103
|
+
return e;
|
|
16104
|
+
}
|
|
16105
|
+
}, T = class l {
|
|
16106
|
+
options;
|
|
16107
|
+
renderer;
|
|
16108
|
+
textRenderer;
|
|
16109
|
+
constructor(e) {
|
|
16110
|
+
this.options = e || P, this.options.renderer = this.options.renderer || new S, this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new z;
|
|
16111
|
+
}
|
|
16112
|
+
static parse(e, t) {
|
|
16113
|
+
return new l(t).parse(e);
|
|
16114
|
+
}
|
|
16115
|
+
static parseInline(e, t) {
|
|
16116
|
+
return new l(t).parseInline(e);
|
|
16117
|
+
}
|
|
16118
|
+
parse(e) {
|
|
16119
|
+
this.renderer.parser = this;
|
|
16120
|
+
let t = "";
|
|
16121
|
+
for (let n = 0;n < e.length; n++) {
|
|
16122
|
+
let s = e[n];
|
|
16123
|
+
if (this.options.extensions?.renderers?.[s.type]) {
|
|
16124
|
+
let o = s, i = this.options.extensions.renderers[o.type].call({ parser: this }, o);
|
|
16125
|
+
if (i !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "checkbox", "html", "def", "paragraph", "text"].includes(o.type)) {
|
|
16126
|
+
t += i || "";
|
|
16127
|
+
continue;
|
|
16128
|
+
}
|
|
16129
|
+
}
|
|
16130
|
+
let r = s;
|
|
16131
|
+
switch (r.type) {
|
|
16132
|
+
case "space": {
|
|
16133
|
+
t += this.renderer.space(r);
|
|
16134
|
+
break;
|
|
16135
|
+
}
|
|
16136
|
+
case "hr": {
|
|
16137
|
+
t += this.renderer.hr(r);
|
|
16138
|
+
break;
|
|
16139
|
+
}
|
|
16140
|
+
case "heading": {
|
|
16141
|
+
t += this.renderer.heading(r);
|
|
16142
|
+
break;
|
|
16143
|
+
}
|
|
16144
|
+
case "code": {
|
|
16145
|
+
t += this.renderer.code(r);
|
|
16146
|
+
break;
|
|
16147
|
+
}
|
|
16148
|
+
case "table": {
|
|
16149
|
+
t += this.renderer.table(r);
|
|
16150
|
+
break;
|
|
16151
|
+
}
|
|
16152
|
+
case "blockquote": {
|
|
16153
|
+
t += this.renderer.blockquote(r);
|
|
16154
|
+
break;
|
|
16155
|
+
}
|
|
16156
|
+
case "list": {
|
|
16157
|
+
t += this.renderer.list(r);
|
|
16158
|
+
break;
|
|
16159
|
+
}
|
|
16160
|
+
case "checkbox": {
|
|
16161
|
+
t += this.renderer.checkbox(r);
|
|
16162
|
+
break;
|
|
16163
|
+
}
|
|
16164
|
+
case "html": {
|
|
16165
|
+
t += this.renderer.html(r);
|
|
16166
|
+
break;
|
|
16167
|
+
}
|
|
16168
|
+
case "def": {
|
|
16169
|
+
t += this.renderer.def(r);
|
|
16170
|
+
break;
|
|
16171
|
+
}
|
|
16172
|
+
case "paragraph": {
|
|
16173
|
+
t += this.renderer.paragraph(r);
|
|
16174
|
+
break;
|
|
16175
|
+
}
|
|
16176
|
+
case "text": {
|
|
16177
|
+
t += this.renderer.text(r);
|
|
16178
|
+
break;
|
|
16179
|
+
}
|
|
16180
|
+
default: {
|
|
16181
|
+
let o = 'Token with "' + r.type + '" type was not found.';
|
|
16182
|
+
if (this.options.silent)
|
|
16183
|
+
return console.error(o), "";
|
|
16184
|
+
throw new Error(o);
|
|
16185
|
+
}
|
|
16186
|
+
}
|
|
16187
|
+
}
|
|
16188
|
+
return t;
|
|
16189
|
+
}
|
|
16190
|
+
parseInline(e, t = this.renderer) {
|
|
16191
|
+
this.renderer.parser = this;
|
|
16192
|
+
let n = "";
|
|
16193
|
+
for (let s = 0;s < e.length; s++) {
|
|
16194
|
+
let r = e[s];
|
|
16195
|
+
if (this.options.extensions?.renderers?.[r.type]) {
|
|
16196
|
+
let i = this.options.extensions.renderers[r.type].call({ parser: this }, r);
|
|
16197
|
+
if (i !== false || !["escape", "html", "link", "image", "checkbox", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
|
|
16198
|
+
n += i || "";
|
|
16199
|
+
continue;
|
|
16200
|
+
}
|
|
16201
|
+
}
|
|
16202
|
+
let o = r;
|
|
16203
|
+
switch (o.type) {
|
|
16204
|
+
case "escape": {
|
|
16205
|
+
n += t.text(o);
|
|
16206
|
+
break;
|
|
16207
|
+
}
|
|
16208
|
+
case "html": {
|
|
16209
|
+
n += t.html(o);
|
|
16210
|
+
break;
|
|
16211
|
+
}
|
|
16212
|
+
case "link": {
|
|
16213
|
+
n += t.link(o);
|
|
16214
|
+
break;
|
|
16215
|
+
}
|
|
16216
|
+
case "image": {
|
|
16217
|
+
n += t.image(o);
|
|
16218
|
+
break;
|
|
16219
|
+
}
|
|
16220
|
+
case "checkbox": {
|
|
16221
|
+
n += t.checkbox(o);
|
|
16222
|
+
break;
|
|
16223
|
+
}
|
|
16224
|
+
case "strong": {
|
|
16225
|
+
n += t.strong(o);
|
|
16226
|
+
break;
|
|
16227
|
+
}
|
|
16228
|
+
case "em": {
|
|
16229
|
+
n += t.em(o);
|
|
16230
|
+
break;
|
|
16231
|
+
}
|
|
16232
|
+
case "codespan": {
|
|
16233
|
+
n += t.codespan(o);
|
|
16234
|
+
break;
|
|
16235
|
+
}
|
|
16236
|
+
case "br": {
|
|
16237
|
+
n += t.br(o);
|
|
16238
|
+
break;
|
|
16239
|
+
}
|
|
16240
|
+
case "del": {
|
|
16241
|
+
n += t.del(o);
|
|
16242
|
+
break;
|
|
16243
|
+
}
|
|
16244
|
+
case "text": {
|
|
16245
|
+
n += t.text(o);
|
|
16246
|
+
break;
|
|
16247
|
+
}
|
|
16248
|
+
default: {
|
|
16249
|
+
let i = 'Token with "' + o.type + '" type was not found.';
|
|
16250
|
+
if (this.options.silent)
|
|
16251
|
+
return console.error(i), "";
|
|
16252
|
+
throw new Error(i);
|
|
16253
|
+
}
|
|
16254
|
+
}
|
|
16255
|
+
}
|
|
16256
|
+
return n;
|
|
16257
|
+
}
|
|
16258
|
+
}, _, F = class {
|
|
16259
|
+
defaults = I();
|
|
16260
|
+
options = this.setOptions;
|
|
16261
|
+
parse = this.parseMarkdown(true);
|
|
16262
|
+
parseInline = this.parseMarkdown(false);
|
|
16263
|
+
Parser = T;
|
|
16264
|
+
Renderer = S;
|
|
16265
|
+
TextRenderer = z;
|
|
16266
|
+
Lexer = R;
|
|
16267
|
+
Tokenizer = y;
|
|
16268
|
+
Hooks = _;
|
|
16269
|
+
constructor(...e) {
|
|
16270
|
+
this.use(...e);
|
|
16271
|
+
}
|
|
16272
|
+
walkTokens(e, t) {
|
|
16273
|
+
let n = [];
|
|
16274
|
+
for (let s of e)
|
|
16275
|
+
switch (n = n.concat(t.call(this, s)), s.type) {
|
|
16276
|
+
case "table": {
|
|
16277
|
+
let r = s;
|
|
16278
|
+
for (let o of r.header)
|
|
16279
|
+
n = n.concat(this.walkTokens(o.tokens, t));
|
|
16280
|
+
for (let o of r.rows)
|
|
16281
|
+
for (let i of o)
|
|
16282
|
+
n = n.concat(this.walkTokens(i.tokens, t));
|
|
16283
|
+
break;
|
|
16284
|
+
}
|
|
16285
|
+
case "list": {
|
|
16286
|
+
let r = s;
|
|
16287
|
+
n = n.concat(this.walkTokens(r.items, t));
|
|
16288
|
+
break;
|
|
16289
|
+
}
|
|
16290
|
+
default: {
|
|
16291
|
+
let r = s;
|
|
16292
|
+
this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((o) => {
|
|
16293
|
+
let i = r[o].flat(1 / 0);
|
|
16294
|
+
n = n.concat(this.walkTokens(i, t));
|
|
16295
|
+
}) : r.tokens && (n = n.concat(this.walkTokens(r.tokens, t)));
|
|
16296
|
+
}
|
|
16297
|
+
}
|
|
16298
|
+
return n;
|
|
16299
|
+
}
|
|
16300
|
+
use(...e) {
|
|
16301
|
+
let t = this.defaults.extensions || { renderers: {}, childTokens: {} };
|
|
16302
|
+
return e.forEach((n) => {
|
|
16303
|
+
let s = { ...n };
|
|
16304
|
+
if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
|
|
16305
|
+
if (!r.name)
|
|
16306
|
+
throw new Error("extension name required");
|
|
16307
|
+
if ("renderer" in r) {
|
|
16308
|
+
let o = t.renderers[r.name];
|
|
16309
|
+
o ? t.renderers[r.name] = function(...i) {
|
|
16310
|
+
let u = r.renderer.apply(this, i);
|
|
16311
|
+
return u === false && (u = o.apply(this, i)), u;
|
|
16312
|
+
} : t.renderers[r.name] = r.renderer;
|
|
16313
|
+
}
|
|
16314
|
+
if ("tokenizer" in r) {
|
|
16315
|
+
if (!r.level || r.level !== "block" && r.level !== "inline")
|
|
16316
|
+
throw new Error("extension level must be 'block' or 'inline'");
|
|
16317
|
+
let o = t[r.level];
|
|
16318
|
+
o ? o.unshift(r.tokenizer) : t[r.level] = [r.tokenizer], r.start && (r.level === "block" ? t.startBlock ? t.startBlock.push(r.start) : t.startBlock = [r.start] : r.level === "inline" && (t.startInline ? t.startInline.push(r.start) : t.startInline = [r.start]));
|
|
16319
|
+
}
|
|
16320
|
+
"childTokens" in r && r.childTokens && (t.childTokens[r.name] = r.childTokens);
|
|
16321
|
+
}), s.extensions = t), n.renderer) {
|
|
16322
|
+
let r = this.defaults.renderer || new S(this.defaults);
|
|
16323
|
+
for (let o in n.renderer) {
|
|
16324
|
+
if (!(o in r))
|
|
16325
|
+
throw new Error(`renderer '${o}' does not exist`);
|
|
16326
|
+
if (["options", "parser"].includes(o))
|
|
16327
|
+
continue;
|
|
16328
|
+
let i = o, u = n.renderer[i], a = r[i];
|
|
16329
|
+
r[i] = (...p) => {
|
|
16330
|
+
let c = u.apply(r, p);
|
|
16331
|
+
return c === false && (c = a.apply(r, p)), c || "";
|
|
16332
|
+
};
|
|
16333
|
+
}
|
|
16334
|
+
s.renderer = r;
|
|
16335
|
+
}
|
|
16336
|
+
if (n.tokenizer) {
|
|
16337
|
+
let r = this.defaults.tokenizer || new y(this.defaults);
|
|
16338
|
+
for (let o in n.tokenizer) {
|
|
16339
|
+
if (!(o in r))
|
|
16340
|
+
throw new Error(`tokenizer '${o}' does not exist`);
|
|
16341
|
+
if (["options", "rules", "lexer"].includes(o))
|
|
16342
|
+
continue;
|
|
16343
|
+
let i = o, u = n.tokenizer[i], a = r[i];
|
|
16344
|
+
r[i] = (...p) => {
|
|
16345
|
+
let c = u.apply(r, p);
|
|
16346
|
+
return c === false && (c = a.apply(r, p)), c;
|
|
16347
|
+
};
|
|
16348
|
+
}
|
|
16349
|
+
s.tokenizer = r;
|
|
16350
|
+
}
|
|
16351
|
+
if (n.hooks) {
|
|
16352
|
+
let r = this.defaults.hooks || new _;
|
|
16353
|
+
for (let o in n.hooks) {
|
|
16354
|
+
if (!(o in r))
|
|
16355
|
+
throw new Error(`hook '${o}' does not exist`);
|
|
16356
|
+
if (["options", "block"].includes(o))
|
|
16357
|
+
continue;
|
|
16358
|
+
let i = o, u = n.hooks[i], a = r[i];
|
|
16359
|
+
_.passThroughHooks.has(o) ? r[i] = (p) => {
|
|
16360
|
+
if (this.defaults.async && _.passThroughHooksRespectAsync.has(o))
|
|
16361
|
+
return (async () => {
|
|
16362
|
+
let d = await u.call(r, p);
|
|
16363
|
+
return a.call(r, d);
|
|
16364
|
+
})();
|
|
16365
|
+
let c = u.call(r, p);
|
|
16366
|
+
return a.call(r, c);
|
|
16367
|
+
} : r[i] = (...p) => {
|
|
16368
|
+
if (this.defaults.async)
|
|
16369
|
+
return (async () => {
|
|
16370
|
+
let d = await u.apply(r, p);
|
|
16371
|
+
return d === false && (d = await a.apply(r, p)), d;
|
|
16372
|
+
})();
|
|
16373
|
+
let c = u.apply(r, p);
|
|
16374
|
+
return c === false && (c = a.apply(r, p)), c;
|
|
16375
|
+
};
|
|
16376
|
+
}
|
|
16377
|
+
s.hooks = r;
|
|
16378
|
+
}
|
|
16379
|
+
if (n.walkTokens) {
|
|
16380
|
+
let r = this.defaults.walkTokens, o = n.walkTokens;
|
|
16381
|
+
s.walkTokens = function(i) {
|
|
16382
|
+
let u = [];
|
|
16383
|
+
return u.push(o.call(this, i)), r && (u = u.concat(r.call(this, i))), u;
|
|
16384
|
+
};
|
|
16385
|
+
}
|
|
16386
|
+
this.defaults = { ...this.defaults, ...s };
|
|
16387
|
+
}), this;
|
|
16388
|
+
}
|
|
16389
|
+
setOptions(e) {
|
|
16390
|
+
return this.defaults = { ...this.defaults, ...e }, this;
|
|
16391
|
+
}
|
|
16392
|
+
lexer(e, t) {
|
|
16393
|
+
return R.lex(e, t ?? this.defaults);
|
|
16394
|
+
}
|
|
16395
|
+
parser(e, t) {
|
|
16396
|
+
return T.parse(e, t ?? this.defaults);
|
|
16397
|
+
}
|
|
16398
|
+
parseMarkdown(e) {
|
|
16399
|
+
return (n, s) => {
|
|
16400
|
+
let r = { ...s }, o = { ...this.defaults, ...r }, i = this.onError(!!o.silent, !!o.async);
|
|
16401
|
+
if (this.defaults.async === true && r.async === false)
|
|
16402
|
+
return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
|
|
16403
|
+
if (typeof n > "u" || n === null)
|
|
16404
|
+
return i(new Error("marked(): input parameter is undefined or null"));
|
|
16405
|
+
if (typeof n != "string")
|
|
16406
|
+
return i(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
|
|
16407
|
+
if (o.hooks && (o.hooks.options = o, o.hooks.block = e), o.async)
|
|
16408
|
+
return (async () => {
|
|
16409
|
+
let u = o.hooks ? await o.hooks.preprocess(n) : n, p = await (o.hooks ? await o.hooks.provideLexer(e) : e ? R.lex : R.lexInline)(u, o), c = o.hooks ? await o.hooks.processAllTokens(p) : p;
|
|
16410
|
+
o.walkTokens && await Promise.all(this.walkTokens(c, o.walkTokens));
|
|
16411
|
+
let m = await (o.hooks ? await o.hooks.provideParser(e) : e ? T.parse : T.parseInline)(c, o);
|
|
16412
|
+
return o.hooks ? await o.hooks.postprocess(m) : m;
|
|
16413
|
+
})().catch(i);
|
|
16414
|
+
try {
|
|
16415
|
+
o.hooks && (n = o.hooks.preprocess(n));
|
|
16416
|
+
let a = (o.hooks ? o.hooks.provideLexer(e) : e ? R.lex : R.lexInline)(n, o);
|
|
16417
|
+
o.hooks && (a = o.hooks.processAllTokens(a)), o.walkTokens && this.walkTokens(a, o.walkTokens);
|
|
16418
|
+
let c = (o.hooks ? o.hooks.provideParser(e) : e ? T.parse : T.parseInline)(a, o);
|
|
16419
|
+
return o.hooks && (c = o.hooks.postprocess(c)), c;
|
|
16420
|
+
} catch (u) {
|
|
16421
|
+
return i(u);
|
|
16422
|
+
}
|
|
16423
|
+
};
|
|
16424
|
+
}
|
|
16425
|
+
onError(e, t) {
|
|
16426
|
+
return (n) => {
|
|
16427
|
+
if (n.message += `
|
|
16428
|
+
Please report this to https://github.com/markedjs/marked.`, e) {
|
|
16429
|
+
let s = "<p>An error occurred:</p><pre>" + O(n.message + "", true) + "</pre>";
|
|
16430
|
+
return t ? Promise.resolve(s) : s;
|
|
16431
|
+
}
|
|
16432
|
+
if (t)
|
|
16433
|
+
return Promise.reject(n);
|
|
16434
|
+
throw n;
|
|
16435
|
+
};
|
|
16436
|
+
}
|
|
16437
|
+
}, E, gn, fn, mn, xn, Rn, Tn;
|
|
16438
|
+
var init_marked_esm = __esm(() => {
|
|
16439
|
+
P = I();
|
|
16440
|
+
A = { exec: () => null };
|
|
16441
|
+
_e = ((l = "") => {
|
|
16442
|
+
try {
|
|
16443
|
+
return !!new RegExp("(?<=1)(?<!1)" + l);
|
|
16444
|
+
} catch {
|
|
16445
|
+
return false;
|
|
16446
|
+
}
|
|
16447
|
+
})();
|
|
16448
|
+
x = { codeRemoveIndent: /^(?: {0,3}\t| {1,4})/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, endingSpaceTabChar: /[ \t]$/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, leadingSpaceTab: /^[ \t]+/, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] +\S/, listReplaceTask: /^\[[ xX]\] +/, listTaskCheckbox: /\[[ xX]\]/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, numericCharacterReference: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));/g, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (l) => new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: C((l) => new RegExp(`^ {0,${l}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: C((l) => new RegExp(`^ {0,${l}}((?:-[ ]*){3,}|(?:_[ ]*){3,}|(?:\\*[ ]*){3,})(?:\\n+|$)`)), fencesBeginRegex: C((l) => new RegExp(`^ {0,${l}}(?:\`\`\`|~~~)`)), headingBeginRegex: C((l) => new RegExp(`^ {0,${l}}#`)), htmlBeginRegex: C((l) => new RegExp(`^ {0,${l}}(?:</?(?:${N})(?: +|$|/?>)|<(?:script|pre|style|textarea|!--))`, "i")), blockquoteBeginRegex: C((l) => new RegExp(`^ {0,${l}}>`)) };
|
|
16449
|
+
$e = /^(?:[ \t]*(?:\n|$))+/;
|
|
16450
|
+
Le = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
|
|
16451
|
+
ze = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
|
|
16452
|
+
G = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
|
|
16453
|
+
Ae = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
|
|
16454
|
+
J = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
|
|
16455
|
+
he = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |fences|blockquote|heading|hr|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
|
|
16456
|
+
de = h(he).replace(/bull/g, J).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
|
|
16457
|
+
Ee = h(he).replace(/bull/g, J).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
|
|
16458
|
+
V = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
|
|
16459
|
+
Me = /^[^\n]+/;
|
|
16460
|
+
Y = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
|
|
16461
|
+
Ie = h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Y).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
|
|
16462
|
+
Ce = h(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, J).getRegex();
|
|
16463
|
+
ee = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
|
|
16464
|
+
Be = h("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][a-z0-9-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][a-z0-9-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))", "i").replace("comment", ee).replace("tag", N).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
|
|
16465
|
+
De = ke(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
|
|
16466
|
+
qe = ke(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
|
|
16467
|
+
ve = h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", qe).getRegex();
|
|
16468
|
+
te = { blockquote: ve, code: Le, def: Ie, fences: ze, heading: Ae, hr: G, html: Be, lheading: de, list: Ce, newline: $e, paragraph: De, table: A, text: Me };
|
|
16469
|
+
ue = h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", G).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3}\t)[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", N).getRegex();
|
|
16470
|
+
Ze = { ...te, lheading: Ee, table: ue, paragraph: h(V).replace("hr", G).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", ue).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", N).getRegex() };
|
|
16471
|
+
He = { ...te, html: h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", ee).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: A, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: h(V).replace("hr", G).replace("heading", ` *#{1,6} *[^
|
|
16472
|
+
]`).replace("lheading", de).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
|
|
16473
|
+
Ge = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
|
|
16474
|
+
Ne = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
|
|
16475
|
+
ge = /^( {2,}|\\)\n(?!\s*$)[ \t]*/;
|
|
16476
|
+
Qe = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
|
|
16477
|
+
$ = /[\p{P}\p{S}]/u;
|
|
16478
|
+
B = /[\s\p{P}\p{S}]/u;
|
|
16479
|
+
Q = /[^\s\p{P}\p{S}]/u;
|
|
16480
|
+
je = h(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, B).getRegex();
|
|
16481
|
+
Fe = /[\p{Pi}\p{Ps}"']/u;
|
|
16482
|
+
fe = /(?!~)[\p{P}\p{S}]/u;
|
|
16483
|
+
Ue = /(?!~)[\s\p{P}\p{S}]/u;
|
|
16484
|
+
Ke = /(?:[^\s\p{P}\p{S}]|~)/u;
|
|
16485
|
+
We = h(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", _e ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
|
|
16486
|
+
me = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
|
|
16487
|
+
Xe = h(me, "u").replace(/punct/g, $).getRegex();
|
|
16488
|
+
Je = h(me, "u").replace(/punct/g, fe).getRegex();
|
|
16489
|
+
Ve = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
|
|
16490
|
+
Ye = h(Ve, "u").replace(/openQuote/g, Fe).replace(/punct/g, $).getRegex();
|
|
16491
|
+
et = h(xe, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
|
|
16492
|
+
tt = h(xe, "gu").replace(/notPunctSpace/g, Ke).replace(/punctSpace/g, Ue).replace(/punct/g, fe).getRegex();
|
|
16493
|
+
rt = h(nt, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
|
|
16494
|
+
st = h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
|
|
16495
|
+
ot = h(it, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
|
|
16496
|
+
at = h(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, $).getRegex();
|
|
16497
|
+
ut = h(lt, "gu").replace(/notPunctSpace/g, Q).replace(/punctSpace/g, B).replace(/punct/g, $).getRegex();
|
|
16498
|
+
pt = h(/\\(punct)/, "gu").replace(/punct/g, $).getRegex();
|
|
16499
|
+
ct = h(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
|
|
16500
|
+
ht = h(ee).replace("(?:-->|$)", "-->").getRegex();
|
|
16501
|
+
dt = h("^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", ht).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
|
|
16502
|
+
be = /\[(?:\\[\s\S]|[^\[\]\\])*\]/;
|
|
16503
|
+
U = h(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace("brackets", be).getRegex();
|
|
16504
|
+
kt = h(/^!?\[(label)\]\([ \t\n]*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?[ \t\n]*\)/).replace("label", U).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
|
|
16505
|
+
gt = h(/^!?\[(label)\]\[(ref)\]/).replace("label", U).replace("ref", Y).getRegex();
|
|
16506
|
+
ft = h(/^!?\[(ref)\](?:\[\])?/).replace("ref", Y).getRegex();
|
|
16507
|
+
pe = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/;
|
|
16508
|
+
mt = h(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace("brackets", be).getRegex();
|
|
16509
|
+
xt = h("reflink|nolink(?!\\()", "g").replace("reflink", h(/^!?\[(label)\]\[(ref)\]/).replace("label", mt).replace("ref", pe).getRegex()).replace("nolink", h(/^!?\[(ref)\](?:\[\])?/).replace("ref", pe).getRegex()).getRegex();
|
|
16510
|
+
ce = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
|
|
16511
|
+
bt = /[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/;
|
|
16512
|
+
Rt = h(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g, bt).getRegex();
|
|
16513
|
+
ne = { _backpedal: A, anyPunctuation: pt, autolink: ct, blockSkip: We, br: ge, code: Ne, del: A, delLDelim: A, delRDelim: A, emStrongLDelim: Xe, emStrongRDelimAst: et, emStrongRDelimUnd: st, escape: Ge, link: kt, nolink: ft, punctuation: je, reflink: gt, reflinkSearch: xt, tag: dt, text: Qe, url: A };
|
|
16514
|
+
Tt = { ...ne, emStrongLDelim: Ye, emStrongRDelimAst: rt, emStrongRDelimUnd: ot, link: h(/^!?\[(label)\]\((.*?)\)/).replace("label", U).getRegex(), reflink: h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", U).getRegex() };
|
|
16515
|
+
X = { ...ne, emStrongRDelimAst: tt, emStrongLDelim: Je, delLDelim: at, delRDelim: ut, url: h(/^emailProtocol|^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("emailProtocol", Rt).replace("protocol", ce).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: h(/^(?:[^a-zA-Z0-9](?=emailProtocol)|(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9](?=emailProtocol)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))))/).replace("protocol", ce).replace(/emailProtocol/g, /(?:mailto|xmpp):/).getRegex() };
|
|
16516
|
+
Ot = { ...X, br: h(ge).replace("{2,}", "*").getRegex(), text: h(X.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
|
|
16517
|
+
j = { normal: te, gfm: Ze, pedantic: He };
|
|
16518
|
+
D = { normal: ne, gfm: X, breaks: Ot, pedantic: Tt };
|
|
16519
|
+
wt = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
16520
|
+
_ = class {
|
|
16521
|
+
options;
|
|
16522
|
+
block;
|
|
16523
|
+
constructor(e) {
|
|
16524
|
+
this.options = e || P;
|
|
16525
|
+
}
|
|
16526
|
+
static passThroughHooks = new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
|
|
16527
|
+
static passThroughHooksRespectAsync = new Set(["preprocess", "postprocess", "processAllTokens"]);
|
|
16528
|
+
preprocess(e) {
|
|
16529
|
+
return e;
|
|
16530
|
+
}
|
|
16531
|
+
postprocess(e) {
|
|
16532
|
+
return e;
|
|
16533
|
+
}
|
|
16534
|
+
processAllTokens(e) {
|
|
16535
|
+
return e;
|
|
16536
|
+
}
|
|
16537
|
+
emStrongMask(e) {
|
|
16538
|
+
return e;
|
|
16539
|
+
}
|
|
16540
|
+
provideLexer(e = this.block) {
|
|
16541
|
+
return e ? R.lex : R.lexInline;
|
|
16542
|
+
}
|
|
16543
|
+
provideParser(e = this.block) {
|
|
16544
|
+
return e ? T.parse : T.parseInline;
|
|
16545
|
+
}
|
|
16546
|
+
};
|
|
16547
|
+
E = new F;
|
|
16548
|
+
k.options = k.setOptions = function(l) {
|
|
16549
|
+
return E.setOptions(l), k.defaults = E.defaults, W(k.defaults), k;
|
|
16550
|
+
};
|
|
16551
|
+
k.getDefaults = I;
|
|
16552
|
+
k.defaults = P;
|
|
16553
|
+
k.use = yt;
|
|
16554
|
+
k.walkTokens = function(l, e) {
|
|
16555
|
+
return E.walkTokens(l, e);
|
|
16556
|
+
};
|
|
16557
|
+
k.parseInline = E.parseInline;
|
|
16558
|
+
k.Parser = T;
|
|
16559
|
+
k.parser = T.parse;
|
|
16560
|
+
k.Renderer = S;
|
|
16561
|
+
k.TextRenderer = z;
|
|
16562
|
+
k.Lexer = R;
|
|
16563
|
+
k.lexer = R.lex;
|
|
16564
|
+
k.Tokenizer = y;
|
|
16565
|
+
k.Hooks = _;
|
|
16566
|
+
k.parse = k;
|
|
16567
|
+
gn = k.options;
|
|
16568
|
+
fn = k.setOptions;
|
|
16569
|
+
mn = k.walkTokens;
|
|
16570
|
+
xn = k.parseInline;
|
|
16571
|
+
Rn = T.parse;
|
|
16572
|
+
Tn = R.lex;
|
|
16573
|
+
});
|
|
16574
|
+
|
|
16575
|
+
// packages/core/src/conversation-export-html.ts
|
|
16576
|
+
async function embedImages(items, loadImage) {
|
|
16577
|
+
const embedded = new Map;
|
|
16578
|
+
let used = 0;
|
|
16579
|
+
let skipped = 0;
|
|
16580
|
+
for (const item of items) {
|
|
16581
|
+
if (item.type !== "user" && item.type !== "tool")
|
|
16582
|
+
continue;
|
|
16583
|
+
for (const image of item.images ?? []) {
|
|
16584
|
+
let reason = null;
|
|
16585
|
+
if (loadImage === undefined)
|
|
16586
|
+
reason = "not embedded";
|
|
16587
|
+
else if (used + image.bytes > MAX_EMBEDDED_IMAGE_BYTES)
|
|
16588
|
+
reason = "over the embedding size limit";
|
|
16589
|
+
else {
|
|
16590
|
+
try {
|
|
16591
|
+
const file = await loadImage(image);
|
|
16592
|
+
if (!SAFE_IMAGE_TYPE.test(file.mimeType))
|
|
16593
|
+
reason = "unsupported image type";
|
|
16594
|
+
else if (used + file.bytes.length > MAX_EMBEDDED_IMAGE_BYTES)
|
|
16595
|
+
reason = "over the embedding size limit";
|
|
16596
|
+
else {
|
|
16597
|
+
used += file.bytes.length;
|
|
16598
|
+
const parts = [];
|
|
16599
|
+
for (let at = 0;at < file.bytes.length; at += BASE64_SLICE_BYTES)
|
|
16600
|
+
parts.push(encodeChunk(file.bytes.subarray(at, at + BASE64_SLICE_BYTES)));
|
|
16601
|
+
embedded.set(`${image.entryId}:${image.contentIndex}`, {
|
|
16602
|
+
src: `data:${file.mimeType.toLowerCase()};base64,${parts.join("")}`
|
|
16603
|
+
});
|
|
16604
|
+
}
|
|
16605
|
+
} catch {
|
|
16606
|
+
reason = "image unavailable";
|
|
16607
|
+
}
|
|
16608
|
+
}
|
|
16609
|
+
if (reason !== null) {
|
|
16610
|
+
embedded.set(`${image.entryId}:${image.contentIndex}`, { reason });
|
|
16611
|
+
skipped++;
|
|
16612
|
+
}
|
|
16613
|
+
}
|
|
16614
|
+
}
|
|
16615
|
+
return { embedded, skipped };
|
|
16616
|
+
}
|
|
16617
|
+
function renderImages(images, embedded) {
|
|
16618
|
+
return (images ?? []).map((image) => {
|
|
16619
|
+
const found = embedded.get(`${image.entryId}:${image.contentIndex}`);
|
|
16620
|
+
const label = escapeHtml(imageLabel(image));
|
|
16621
|
+
if (found !== undefined && "src" in found)
|
|
16622
|
+
return `<figure><img src="${found.src}" alt="${escapeHtml(image.name)}"><figcaption>${label}</figcaption></figure>`;
|
|
16623
|
+
const reason = found !== undefined && "reason" in found ? ` \u2014 ${found.reason}` : "";
|
|
16624
|
+
return `<p class="placeholder">[image: ${label}${reason}]</p>`;
|
|
16625
|
+
}).join("");
|
|
16626
|
+
}
|
|
16627
|
+
async function exportHtml(source, options) {
|
|
16628
|
+
const { embedded, skipped } = await embedImages(source.items, options.loadImage);
|
|
16629
|
+
const title = escapeHtml(oneLine(source.title) || FALLBACK_EXPORT_TITLE);
|
|
16630
|
+
const body = [];
|
|
16631
|
+
for (const item of source.items) {
|
|
16632
|
+
if (item.type === "system") {
|
|
16633
|
+
body.push(`<div class="system">${escapeHtml(oneLine(item.text))}</div>`);
|
|
16634
|
+
} else if (item.type === "user") {
|
|
16635
|
+
const text = userText2(item);
|
|
16636
|
+
body.push(`<section class="msg user"><div class="role">User</div>${text === "" ? "" : `<div class="text">${escapeHtml(text)}</div>`}${renderImages(item.images, embedded)}</section>`);
|
|
16637
|
+
} else if (item.type === "assistant") {
|
|
16638
|
+
const thinking = options.includeThinking && item.thinking.trim() !== "" ? `<details class="thinking"><summary>Thinking</summary><div class="text">${escapeHtml(item.thinking.trim())}</div></details>` : "";
|
|
16639
|
+
const text = item.text.trim() === "" ? "" : `<div class="md">${markdown2.parse(item.text.trim(), { async: false })}</div>`;
|
|
16640
|
+
const note = item.note === null ? "" : `<div class="note">${escapeHtml(oneLine(item.note))}</div>`;
|
|
16641
|
+
body.push(`<section class="msg assistant"><div class="role">Assistant</div>${thinking}${text}${note}</section>`);
|
|
16642
|
+
} else {
|
|
16643
|
+
const status = toolStatus(item);
|
|
16644
|
+
const output = toolOutput(item);
|
|
16645
|
+
const heading = [
|
|
16646
|
+
`<b>Tool</b> ${escapeHtml(item.name)}`,
|
|
16647
|
+
item.summary === "" ? "" : `<span class="args">${escapeHtml(oneLine(item.summary))}</span>`,
|
|
16648
|
+
status === "ok" ? "" : `<span class="status">[${status}]</span>`,
|
|
16649
|
+
item.durationMs === null ? "" : `<span class="duration">(${formatDuration(item.durationMs)})</span>`
|
|
16650
|
+
].filter(Boolean).join(" ");
|
|
16651
|
+
body.push(`<details class="tool ${status}"><summary>${heading}</summary>${item.detail === null || item.detail === "" ? "" : `<pre>${escapeHtml(item.detail)}</pre>`}${output === "" ? "" : `<div class="label">${status === "running" ? "Output so far" : "Result"}</div><pre>${escapeHtml(output)}</pre>`}${item.note === null ? "" : `<div class="note">${escapeHtml(oneLine(item.note))}</div>`}${renderImages(item.images, embedded)}</details>`);
|
|
16652
|
+
}
|
|
16653
|
+
}
|
|
16654
|
+
const content = `<!doctype html>
|
|
16655
|
+
<html lang="en">
|
|
16656
|
+
<head>
|
|
16657
|
+
<meta charset="utf-8">
|
|
16658
|
+
<meta http-equiv="Content-Security-Policy" content="${CSP}">
|
|
16659
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
16660
|
+
<title>${title}</title>
|
|
16661
|
+
<style>${STYLE}</style>
|
|
16662
|
+
</head>
|
|
16663
|
+
<body>
|
|
16664
|
+
<main>
|
|
16665
|
+
<h1>${title}</h1>
|
|
16666
|
+
<p class="meta">${escapeHtml(oneLine(source.model))} \xB7 ${escapeHtml(oneLine(source.cwd))} \xB7 ${escapeHtml(source.exportedAt.toISOString())}</p>
|
|
16667
|
+
${body.join(`
|
|
16668
|
+
`)}
|
|
16669
|
+
</main>
|
|
16670
|
+
</body>
|
|
16671
|
+
</html>
|
|
16672
|
+
`;
|
|
16673
|
+
return { content, skippedImages: skipped };
|
|
16674
|
+
}
|
|
16675
|
+
var MAX_EMBEDDED_IMAGE_BYTES, SAFE_IMAGE_TYPE, SAFE_LINK, BASE64_SLICE_BYTES, CSP = "default-src 'none'; img-src data:; style-src 'unsafe-inline'", STYLE = `
|
|
16676
|
+
:root{color-scheme:light dark;--bg:#fff;--fg:#1f2328;--muted:#656d76;--border:#d0d7de;--user:#eef4ff;--code:#f6f8fa}
|
|
16677
|
+
@media(prefers-color-scheme:dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--border:#30363d;--user:#16243a;--code:#161b22}}
|
|
16678
|
+
body{margin:0;background:var(--bg);color:var(--fg);font:15px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif}
|
|
16679
|
+
main{max-width:860px;margin:0 auto;padding:24px 16px 64px}
|
|
16680
|
+
h1{font-size:1.5rem;margin:0 0 4px}
|
|
16681
|
+
.meta{color:var(--muted);font-size:.85rem;margin:0 0 24px}
|
|
16682
|
+
.msg{margin:16px 0;padding:12px 16px;border:1px solid var(--border);border-radius:12px}
|
|
16683
|
+
.msg.user{background:var(--user)}
|
|
16684
|
+
.role{font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
|
|
16685
|
+
.text{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
16686
|
+
.system{text-align:center;color:var(--muted);font-size:.85rem;margin:16px 0}
|
|
16687
|
+
.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}
|
|
16688
|
+
.md pre,pre{background:var(--code);border-radius:8px;padding:10px 12px;overflow:auto;font-size:.85rem;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
16689
|
+
.md code{background:var(--code);border-radius:4px;padding:1px 4px}.md pre code{background:none;padding:0}
|
|
16690
|
+
.md table{border-collapse:collapse}.md th,.md td{border:1px solid var(--border);padding:4px 8px}
|
|
16691
|
+
.md blockquote{margin:0;padding-left:12px;border-left:3px solid var(--border);color:var(--muted)}
|
|
16692
|
+
details{margin:8px 0}summary{cursor:pointer;color:var(--muted)}
|
|
16693
|
+
details.tool{border:1px solid var(--border);border-radius:8px;padding:6px 12px;margin:12px 0}
|
|
16694
|
+
details.tool.error>summary .status{color:#cf222e}
|
|
16695
|
+
.label{font-size:.75rem;color:var(--muted);margin-top:8px}
|
|
16696
|
+
.note{color:var(--muted);font-style:italic;margin-top:6px}
|
|
16697
|
+
figure{margin:8px 0}img{max-width:100%;height:auto;border-radius:8px}figcaption,.placeholder{color:var(--muted);font-size:.8rem}
|
|
16698
|
+
`, escapeHtml = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), markdown2;
|
|
16699
|
+
var init_conversation_export_html = __esm(() => {
|
|
16700
|
+
init_marked_esm();
|
|
16701
|
+
MAX_EMBEDDED_IMAGE_BYTES = 32 * 1024 * 1024;
|
|
16702
|
+
SAFE_IMAGE_TYPE = /^image\/(png|jpeg|webp|gif)$/i;
|
|
16703
|
+
SAFE_LINK = /^(https?:|mailto:)/i;
|
|
16704
|
+
BASE64_SLICE_BYTES = 3 * 16 * 1024;
|
|
16705
|
+
markdown2 = new F({
|
|
16706
|
+
gfm: true,
|
|
16707
|
+
breaks: true,
|
|
16708
|
+
renderer: {
|
|
16709
|
+
html: ({ text }) => escapeHtml(text),
|
|
16710
|
+
link({ href, title, tokens }) {
|
|
16711
|
+
const label = this.parser.parseInline(tokens);
|
|
16712
|
+
if (!SAFE_LINK.test(href.trim()))
|
|
16713
|
+
return label;
|
|
16714
|
+
const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
|
|
16715
|
+
return `<a href="${escapeHtml(href)}"${titleAttr} rel="noopener noreferrer" target="_blank">${label}</a>`;
|
|
16716
|
+
},
|
|
16717
|
+
image({ href, text }) {
|
|
16718
|
+
const label = `[image: ${escapeHtml(text || href)}]`;
|
|
16719
|
+
return SAFE_LINK.test(href.trim()) ? `<a href="${escapeHtml(href)}" rel="noopener noreferrer" target="_blank">${label}</a>` : label;
|
|
16720
|
+
}
|
|
16721
|
+
}
|
|
16722
|
+
});
|
|
16723
|
+
});
|
|
16724
|
+
|
|
16725
|
+
// packages/core/src/conversation-export.ts
|
|
16726
|
+
function copyText(item) {
|
|
16727
|
+
if (item.type === "user")
|
|
16728
|
+
return userText2(item);
|
|
16729
|
+
if (item.type === "assistant")
|
|
16730
|
+
return item.text.trim();
|
|
16731
|
+
return "";
|
|
16732
|
+
}
|
|
16733
|
+
function lastAnswerText(items) {
|
|
16734
|
+
for (let i = items.length - 1;i >= 0; i--) {
|
|
16735
|
+
const item = items[i];
|
|
16736
|
+
if (item.type !== "assistant")
|
|
16737
|
+
continue;
|
|
16738
|
+
const text = copyText(item);
|
|
16739
|
+
if (text !== "")
|
|
16740
|
+
return text;
|
|
16741
|
+
}
|
|
16742
|
+
return null;
|
|
16743
|
+
}
|
|
16744
|
+
function exportFormatFromPath(path) {
|
|
16745
|
+
const extension = /\.(md|html|json)$/i.exec(path)?.[1]?.toLowerCase();
|
|
16746
|
+
return extension === "md" ? "markdown" : extension === "html" ? "html" : extension === "json" ? "json" : null;
|
|
16747
|
+
}
|
|
16748
|
+
function exportFileName(title, format, at) {
|
|
16749
|
+
const cleaned = title.replace(/[\\/:*?"<>|\u0000-\u001f\u007f]/g, "-").replace(/\s+/g, " ").replace(/-{2,}/g, "-");
|
|
16750
|
+
const safe = Array.from(cleaned).slice(0, MAX_FILE_TITLE_CHARS).join("").replace(/^[\s.-]+|[\s.-]+$/g, "") || FALLBACK_EXPORT_TITLE;
|
|
16751
|
+
const pad = (value, width = 2) => String(value).padStart(width, "0");
|
|
16752
|
+
const stamp = `${pad(at.getFullYear(), 4)}${pad(at.getMonth() + 1)}${pad(at.getDate())}-${pad(at.getHours())}${pad(at.getMinutes())}${pad(at.getSeconds())}`;
|
|
16753
|
+
return `${safe}-${stamp}.${EXPORT_EXTENSIONS[format]}`;
|
|
16754
|
+
}
|
|
16755
|
+
async function exportConversation(format, source, options) {
|
|
16756
|
+
if (source.items.length === 0)
|
|
16757
|
+
throw new Error("Nothing to export yet - start a conversation first");
|
|
16758
|
+
const extension = EXPORT_EXTENSIONS[format];
|
|
16759
|
+
const mimeType = MIME_TYPES[format];
|
|
16760
|
+
if (format === "html") {
|
|
16761
|
+
const { content, skippedImages } = await exportHtml(source, options);
|
|
16762
|
+
return { content, mimeType, extension, skippedImages };
|
|
16763
|
+
}
|
|
16764
|
+
const content = format === "markdown" ? exportMarkdown(source, options) : exportJson(source, options);
|
|
16765
|
+
return { content, mimeType, extension, skippedImages: 0 };
|
|
16766
|
+
}
|
|
16767
|
+
function block(content) {
|
|
16768
|
+
let longest = 0;
|
|
16769
|
+
for (const run of content.matchAll(/`+/g))
|
|
16770
|
+
longest = Math.max(longest, run[0].length);
|
|
16771
|
+
const marks = "`".repeat(Math.max(3, longest + 1));
|
|
16772
|
+
return `${marks}
|
|
16773
|
+
${content}
|
|
16774
|
+
${marks}`;
|
|
16775
|
+
}
|
|
16776
|
+
function exportMarkdown(source, options) {
|
|
16777
|
+
const out = [
|
|
16778
|
+
`# ${oneLine(source.title) || FALLBACK_EXPORT_TITLE}`,
|
|
16779
|
+
"",
|
|
16780
|
+
`- **Model:** ${oneLine(source.model)}`,
|
|
16781
|
+
`- **Workspace:** ${oneLine(source.cwd)}`,
|
|
16782
|
+
`- **Exported:** ${source.exportedAt.toISOString()}`,
|
|
16783
|
+
""
|
|
16784
|
+
];
|
|
16785
|
+
let role = null;
|
|
16786
|
+
const heading = (next) => {
|
|
16787
|
+
if (role === next)
|
|
16788
|
+
return;
|
|
16789
|
+
role = next;
|
|
16790
|
+
out.push("---", "", next === "user" ? "## User" : "## Assistant", "");
|
|
16791
|
+
};
|
|
16792
|
+
for (const item of source.items) {
|
|
16793
|
+
if (item.type === "system") {
|
|
16794
|
+
role = null;
|
|
16795
|
+
out.push("---", "", `*${escapeInline(oneLine(item.text))}*`, "");
|
|
16796
|
+
} else if (item.type === "user") {
|
|
16797
|
+
heading("user");
|
|
16798
|
+
const text = userText2(item);
|
|
16799
|
+
if (text !== "")
|
|
16800
|
+
out.push(text, "");
|
|
16801
|
+
for (const image of item.images ?? [])
|
|
16802
|
+
out.push(`> [image] ${escapeInline(imageLabel(image))}`, "");
|
|
16803
|
+
} else if (item.type === "assistant") {
|
|
16804
|
+
heading("assistant");
|
|
16805
|
+
if (options.includeThinking && item.thinking.trim() !== "")
|
|
16806
|
+
out.push("<details>", "<summary>Thinking</summary>", "", item.thinking.trim(), "", "</details>", "");
|
|
16807
|
+
if (item.text.trim() !== "")
|
|
16808
|
+
out.push(item.text.trim(), "");
|
|
16809
|
+
if (item.note !== null)
|
|
16810
|
+
out.push(`> ${escapeInline(oneLine(item.note))}`, "");
|
|
16811
|
+
} else {
|
|
16812
|
+
heading("assistant");
|
|
16813
|
+
out.push(...markdownTool(item));
|
|
16814
|
+
}
|
|
16815
|
+
}
|
|
16816
|
+
return `${out.join(`
|
|
16817
|
+
`).trimEnd()}
|
|
16818
|
+
`;
|
|
16819
|
+
}
|
|
16820
|
+
function markdownTool(item) {
|
|
16821
|
+
const status = toolStatus(item);
|
|
16822
|
+
const label = [
|
|
16823
|
+
`Tool: ${item.name}`,
|
|
16824
|
+
item.summary === "" ? "" : `\xB7 ${oneLine(item.summary)}`,
|
|
16825
|
+
status === "ok" ? "" : `[${status}]`,
|
|
16826
|
+
item.durationMs === null ? "" : `(${formatDuration(item.durationMs)})`
|
|
16827
|
+
].filter(Boolean).join(" ");
|
|
16828
|
+
const lines = ["<details>", `<summary>${escapeInline(label)}</summary>`, ""];
|
|
16829
|
+
if (item.detail !== null && item.detail !== "")
|
|
16830
|
+
lines.push(block(item.detail), "");
|
|
16831
|
+
const output = toolOutput(item);
|
|
16832
|
+
if (output !== "")
|
|
16833
|
+
lines.push(status === "running" ? "Output so far:" : "Result:", "", block(output), "");
|
|
16834
|
+
if (item.note !== null)
|
|
16835
|
+
lines.push(`> ${escapeInline(oneLine(item.note))}`, "");
|
|
16836
|
+
for (const image of item.images ?? [])
|
|
16837
|
+
lines.push(`> [image] ${escapeInline(imageLabel(image))}`, "");
|
|
16838
|
+
lines.push("</details>", "");
|
|
16839
|
+
return lines;
|
|
16840
|
+
}
|
|
16841
|
+
function exportJson(source, options) {
|
|
16842
|
+
const items = source.items.map((item) => {
|
|
16843
|
+
switch (item.type) {
|
|
16844
|
+
case "user":
|
|
16845
|
+
return {
|
|
16846
|
+
type: "user",
|
|
16847
|
+
text: userText2(item),
|
|
16848
|
+
images: (item.images ?? []).map(({ name, mimeType, width, height, bytes }) => ({
|
|
16849
|
+
name,
|
|
16850
|
+
mimeType,
|
|
16851
|
+
width,
|
|
16852
|
+
height,
|
|
16853
|
+
bytes
|
|
16854
|
+
}))
|
|
16855
|
+
};
|
|
16856
|
+
case "assistant":
|
|
16857
|
+
return {
|
|
16858
|
+
type: "assistant",
|
|
16859
|
+
text: item.text,
|
|
16860
|
+
...options.includeThinking && item.thinking.trim() !== "" ? { thinking: item.thinking } : {},
|
|
16861
|
+
stopReason: item.stopReason,
|
|
16862
|
+
note: item.note
|
|
16863
|
+
};
|
|
16864
|
+
case "tool":
|
|
16865
|
+
return {
|
|
16866
|
+
type: "tool",
|
|
16867
|
+
name: item.name,
|
|
16868
|
+
summary: item.summary,
|
|
16869
|
+
detail: item.detail,
|
|
16870
|
+
status: item.phase,
|
|
16871
|
+
isError: item.isError,
|
|
16872
|
+
result: toolOutput(item),
|
|
16873
|
+
durationMs: item.durationMs,
|
|
16874
|
+
note: item.note,
|
|
16875
|
+
images: (item.images ?? []).map(({ name, mimeType, width, height, bytes }) => ({
|
|
16876
|
+
name,
|
|
16877
|
+
mimeType,
|
|
16878
|
+
width,
|
|
16879
|
+
height,
|
|
16880
|
+
bytes
|
|
16881
|
+
}))
|
|
16882
|
+
};
|
|
16883
|
+
default:
|
|
16884
|
+
return { type: "system", text: item.text };
|
|
16885
|
+
}
|
|
16886
|
+
});
|
|
16887
|
+
return `${JSON.stringify({
|
|
16888
|
+
format: "neko-conversation",
|
|
16889
|
+
version: 1,
|
|
16890
|
+
session: {
|
|
16891
|
+
id: source.sessionId,
|
|
16892
|
+
title: source.title,
|
|
16893
|
+
model: source.model,
|
|
16894
|
+
cwd: source.cwd,
|
|
16895
|
+
exportedAt: source.exportedAt.toISOString()
|
|
16896
|
+
},
|
|
16897
|
+
items
|
|
16898
|
+
}, null, 2)}
|
|
16899
|
+
`;
|
|
16900
|
+
}
|
|
16901
|
+
var EXPORT_EXTENSIONS, MIME_TYPES, MAX_FILE_TITLE_CHARS = 60, escapeInline = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
16902
|
+
var init_conversation_export = __esm(() => {
|
|
16903
|
+
init_conversation_export_html();
|
|
16904
|
+
init_conversation_export_html();
|
|
16905
|
+
EXPORT_EXTENSIONS = { markdown: "md", html: "html", json: "json" };
|
|
16906
|
+
MIME_TYPES = {
|
|
16907
|
+
markdown: "text/markdown;charset=utf-8",
|
|
16908
|
+
html: "text/html;charset=utf-8",
|
|
16909
|
+
json: "application/json;charset=utf-8"
|
|
16910
|
+
};
|
|
16911
|
+
});
|
|
16912
|
+
|
|
16913
|
+
// packages/tui/src/clipboard-write.ts
|
|
16914
|
+
import { spawn as spawn2 } from "child_process";
|
|
16915
|
+
import { getNativeClipboard } from "@earendil-works/pi-tui";
|
|
16916
|
+
function runClipboardCommand(command, args, input) {
|
|
16917
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
16918
|
+
const child = spawn2(command, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
|
|
16919
|
+
const timer = setTimeout(() => {
|
|
16920
|
+
child.kill("SIGKILL");
|
|
16921
|
+
resolve(false);
|
|
16922
|
+
}, COMMAND_TIMEOUT_MS);
|
|
16923
|
+
child.on("error", () => {
|
|
16924
|
+
clearTimeout(timer);
|
|
16925
|
+
resolve(false);
|
|
16926
|
+
});
|
|
16927
|
+
child.on("close", (code) => {
|
|
16928
|
+
clearTimeout(timer);
|
|
16929
|
+
resolve(code === 0);
|
|
16930
|
+
});
|
|
16931
|
+
child.stdin.on("error", () => {});
|
|
16932
|
+
child.stdin.end(input);
|
|
16933
|
+
return promise;
|
|
16934
|
+
}
|
|
16935
|
+
async function copyToClipboard(text, deps) {
|
|
16936
|
+
const platform = deps.platform ?? process.platform;
|
|
16937
|
+
const env = deps.env ?? process.env;
|
|
16938
|
+
const native = "native" in deps ? deps.native : getNativeClipboard();
|
|
16939
|
+
const run = deps.run ?? runClipboardCommand;
|
|
16940
|
+
let method = null;
|
|
16941
|
+
if (platform !== "linux" && native?.setText !== undefined) {
|
|
16942
|
+
try {
|
|
16943
|
+
await native.setText(text);
|
|
16944
|
+
method = "native";
|
|
16945
|
+
} catch {}
|
|
16946
|
+
}
|
|
16947
|
+
if (method === null) {
|
|
16948
|
+
const tools = [];
|
|
16949
|
+
if (platform === "darwin")
|
|
16950
|
+
tools.push(["pbcopy", []]);
|
|
16951
|
+
else if (platform === "win32")
|
|
16952
|
+
tools.push([
|
|
16953
|
+
"powershell.exe",
|
|
16954
|
+
[
|
|
16955
|
+
"-NoProfile",
|
|
16956
|
+
"-NonInteractive",
|
|
16957
|
+
"-Command",
|
|
16958
|
+
"$t=[IO.StreamReader]::new([Console]::OpenStandardInput(),[Text.UTF8Encoding]::new($false)).ReadToEnd();Set-Clipboard -Value $t"
|
|
16959
|
+
]
|
|
16960
|
+
]);
|
|
16961
|
+
else {
|
|
16962
|
+
if (env.TERMUX_VERSION)
|
|
16963
|
+
tools.push(["termux-clipboard-set", []]);
|
|
16964
|
+
if (env.WAYLAND_DISPLAY)
|
|
16965
|
+
tools.push(["wl-copy", []]);
|
|
16966
|
+
if (env.DISPLAY)
|
|
16967
|
+
tools.push(["xclip", ["-selection", "clipboard"]], ["xsel", ["--clipboard", "--input"]]);
|
|
16968
|
+
}
|
|
16969
|
+
for (const [command, args] of tools) {
|
|
16970
|
+
if (await run(command, args, text)) {
|
|
16971
|
+
method = "command";
|
|
16972
|
+
break;
|
|
16973
|
+
}
|
|
16974
|
+
}
|
|
16975
|
+
}
|
|
16976
|
+
const remote = Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);
|
|
16977
|
+
let osc52Sent = false;
|
|
16978
|
+
if (method === null || remote) {
|
|
16979
|
+
const encoded = Buffer.from(text).toString("base64");
|
|
16980
|
+
if (encoded.length <= OSC52_MAX_BASE64_LENGTH) {
|
|
16981
|
+
deps.osc52(`\x1B]52;c;${encoded}\x07`);
|
|
16982
|
+
osc52Sent = true;
|
|
16983
|
+
}
|
|
16984
|
+
}
|
|
16985
|
+
if (method === null && !osc52Sent)
|
|
16986
|
+
throw new Error(`Clipboard unavailable: no clipboard tool worked and ${text.length} chars is too large for OSC 52. Use /export to save it to a file.`);
|
|
16987
|
+
return { method: method ?? "osc52", osc52Sent };
|
|
16988
|
+
}
|
|
16989
|
+
async function copyLastAnswer(items, deps) {
|
|
16990
|
+
const text = lastAnswerText(items);
|
|
16991
|
+
if (text === null)
|
|
16992
|
+
return { level: "warning", message: "Nothing to copy yet: no assistant answer in this session." };
|
|
16993
|
+
try {
|
|
16994
|
+
const result = await copyToClipboard(text, deps);
|
|
16995
|
+
return {
|
|
16996
|
+
level: "info",
|
|
16997
|
+
message: result.osc52Sent ? `Sent to terminal clipboard via OSC 52 (${text.length} chars); your terminal must allow it` : `Copied last response (${text.length} chars)`
|
|
16998
|
+
};
|
|
16999
|
+
} catch (error) {
|
|
17000
|
+
return { level: "error", message: error instanceof Error ? error.message : String(error) };
|
|
17001
|
+
}
|
|
17002
|
+
}
|
|
17003
|
+
var OSC52_MAX_BASE64_LENGTH = 1e5, COMMAND_TIMEOUT_MS = 3000;
|
|
17004
|
+
var init_clipboard_write = __esm(() => {
|
|
17005
|
+
init_conversation_export();
|
|
17006
|
+
});
|
|
17007
|
+
|
|
17008
|
+
// packages/tui/src/components/assistant-message.ts
|
|
17009
|
+
import { Container, Markdown, MouseRegion, Spacer, Text as Text2 } from "@earendil-works/pi-tui";
|
|
17010
|
+
var THINKING_COLLAPSED_LABEL = "\u2727 Thinking\u2026 (click to expand)", AssistantMessageComponent;
|
|
17011
|
+
var init_assistant_message = __esm(() => {
|
|
17012
|
+
init_theme();
|
|
17013
|
+
AssistantMessageComponent = class AssistantMessageComponent extends Container {
|
|
17014
|
+
#renderTheme = getActiveThemeMode();
|
|
17015
|
+
#lastContent;
|
|
17016
|
+
#isStreaming = false;
|
|
17017
|
+
#thinkingExpanded = false;
|
|
17018
|
+
#renderWidth = 80;
|
|
17019
|
+
constructor(content, isStreaming = false) {
|
|
17020
|
+
super();
|
|
17021
|
+
if (content !== undefined)
|
|
17022
|
+
this.updateContent(content, isStreaming);
|
|
17023
|
+
}
|
|
17024
|
+
render(width) {
|
|
17025
|
+
if (this.#renderTheme !== getActiveThemeMode()) {
|
|
17026
|
+
this.#renderTheme = getActiveThemeMode();
|
|
17027
|
+
this.#rebuild();
|
|
17028
|
+
}
|
|
17029
|
+
this.#renderWidth = width;
|
|
17030
|
+
return super.render(width);
|
|
17031
|
+
}
|
|
17032
|
+
#highlightWidth() {
|
|
17033
|
+
return Math.max(10, this.#renderWidth - 4);
|
|
14600
17034
|
}
|
|
14601
17035
|
updateContent(content, isStreaming = this.#isStreaming) {
|
|
14602
17036
|
this.#lastContent = content;
|
|
@@ -14685,10 +17119,28 @@ var init_editor = __esm(() => {
|
|
|
14685
17119
|
this.#completionEpoch++;
|
|
14686
17120
|
this.resetEscapeSequence();
|
|
14687
17121
|
super.setText(text);
|
|
17122
|
+
this.#flushHistory();
|
|
17123
|
+
}
|
|
17124
|
+
setHistory(entries) {
|
|
17125
|
+
if (this["historyIndex"] > -1) {
|
|
17126
|
+
this.#pendingHistory = entries;
|
|
17127
|
+
return;
|
|
17128
|
+
}
|
|
17129
|
+
this.#pendingHistory = undefined;
|
|
17130
|
+
const current = this["history"];
|
|
17131
|
+
if (current.length === entries.length && current.every((entry, i) => entry === entries[i]))
|
|
17132
|
+
return;
|
|
17133
|
+
this["history"] = [...entries];
|
|
17134
|
+
}
|
|
17135
|
+
#pendingHistory;
|
|
17136
|
+
#flushHistory() {
|
|
17137
|
+
if (this.#pendingHistory !== undefined && this["historyIndex"] === -1)
|
|
17138
|
+
this.setHistory(this.#pendingHistory);
|
|
14688
17139
|
}
|
|
14689
17140
|
handleInput(data) {
|
|
14690
17141
|
if (isKeyRelease(data))
|
|
14691
17142
|
return;
|
|
17143
|
+
this.#flushHistory();
|
|
14692
17144
|
this.#completionEpoch++;
|
|
14693
17145
|
if (matchesKey3(data, "escape") && this.isShowingAutocomplete()) {
|
|
14694
17146
|
this.resetEscapeSequence();
|
|
@@ -14780,6 +17232,8 @@ var init_labels = __esm(() => {
|
|
|
14780
17232
|
{ name: "help", description: "Show keyboard shortcuts and commands" },
|
|
14781
17233
|
{ name: "version", description: "View versions and check for updates" },
|
|
14782
17234
|
{ name: "compact", description: "Compact context (/compact optional instructions)" },
|
|
17235
|
+
{ name: "copy", description: "Copy the last assistant response" },
|
|
17236
|
+
{ name: "export", description: "Export session (/export path.md|.html|.json [--thinking])" },
|
|
14783
17237
|
{ name: "exit", description: "Exit neko TUI" },
|
|
14784
17238
|
{ name: "new", description: "Create a new session" },
|
|
14785
17239
|
{ name: "sessions", description: "Switch or create a session" },
|
|
@@ -15068,7 +17522,14 @@ var init_history_image = __esm(() => {
|
|
|
15068
17522
|
});
|
|
15069
17523
|
|
|
15070
17524
|
// packages/tui/src/components/login.ts
|
|
15071
|
-
import {
|
|
17525
|
+
import {
|
|
17526
|
+
CURSOR_MARKER as CURSOR_MARKER2,
|
|
17527
|
+
Input,
|
|
17528
|
+
isKeyRelease as isKeyRelease2,
|
|
17529
|
+
matchesKey as matchesKey4,
|
|
17530
|
+
renderFakeCursor,
|
|
17531
|
+
truncateToWidth as truncateToWidth3
|
|
17532
|
+
} from "@earendil-works/pi-tui";
|
|
15072
17533
|
|
|
15073
17534
|
class LoginPanel {
|
|
15074
17535
|
height = 10;
|
|
@@ -15079,22 +17540,28 @@ class LoginPanel {
|
|
|
15079
17540
|
#provider = "deepseek";
|
|
15080
17541
|
#message = "";
|
|
15081
17542
|
#busy = false;
|
|
17543
|
+
#confirmingRemove = false;
|
|
15082
17544
|
#generation = 0;
|
|
17545
|
+
#closeTimer;
|
|
15083
17546
|
#unsubscribe;
|
|
15084
17547
|
#changed;
|
|
15085
17548
|
#closed;
|
|
15086
17549
|
#save;
|
|
15087
17550
|
#remove;
|
|
17551
|
+
#autoCloseMs;
|
|
15088
17552
|
constructor(options) {
|
|
15089
17553
|
this.#changed = options.changed;
|
|
15090
17554
|
this.#closed = options.closed;
|
|
15091
17555
|
this.#save = options.save;
|
|
15092
17556
|
this.#remove = options.remove;
|
|
17557
|
+
this.#autoCloseMs = options.autoCloseMs ?? AUTO_CLOSE_MS;
|
|
15093
17558
|
}
|
|
15094
17559
|
show(state, subscribe) {
|
|
15095
17560
|
this.#generation++;
|
|
17561
|
+
this.#clearCloseTimer();
|
|
15096
17562
|
this.open = true;
|
|
15097
17563
|
this.#busy = false;
|
|
17564
|
+
this.#confirmingRemove = false;
|
|
15098
17565
|
this.#message = "";
|
|
15099
17566
|
this.#input = new Input;
|
|
15100
17567
|
this.#provider = "deepseek";
|
|
@@ -15110,7 +17577,9 @@ class LoginPanel {
|
|
|
15110
17577
|
}
|
|
15111
17578
|
close() {
|
|
15112
17579
|
this.#generation++;
|
|
17580
|
+
this.#clearCloseTimer();
|
|
15113
17581
|
this.open = false;
|
|
17582
|
+
this.#confirmingRemove = false;
|
|
15114
17583
|
this.#input = new Input;
|
|
15115
17584
|
this.#unsubscribe?.();
|
|
15116
17585
|
this.#unsubscribe = undefined;
|
|
@@ -15127,11 +17596,20 @@ class LoginPanel {
|
|
|
15127
17596
|
}
|
|
15128
17597
|
if (this.#busy)
|
|
15129
17598
|
return;
|
|
17599
|
+
const confirming = this.#confirmingRemove;
|
|
17600
|
+
this.#confirmingRemove = false;
|
|
17601
|
+
if (confirming && !matchesKey4(data, "ctrl+r"))
|
|
17602
|
+
this.#message = "";
|
|
15130
17603
|
if (matchesKey4(data, "enter"))
|
|
15131
17604
|
this.#apply(false);
|
|
15132
|
-
else if (matchesKey4(data, "ctrl+r") && this.#status?.savedConfigured)
|
|
15133
|
-
|
|
15134
|
-
|
|
17605
|
+
else if (matchesKey4(data, "ctrl+r") && this.#status?.savedConfigured) {
|
|
17606
|
+
if (confirming)
|
|
17607
|
+
this.#apply(true);
|
|
17608
|
+
else {
|
|
17609
|
+
this.#confirmingRemove = true;
|
|
17610
|
+
this.#message = "Press Ctrl+R again to remove the saved key.";
|
|
17611
|
+
}
|
|
17612
|
+
} else if (matchesKey4(data, "tab") || (matchesKey4(data, "left") || matchesKey4(data, "right")) && this.#input.getValue() === "")
|
|
15135
17613
|
this.#switch();
|
|
15136
17614
|
else {
|
|
15137
17615
|
this.#input.handleInput(data);
|
|
@@ -15146,20 +17624,39 @@ class LoginPanel {
|
|
|
15146
17624
|
#switch() {
|
|
15147
17625
|
const index = CREDENTIAL_PROVIDERS.findIndex((spec) => spec.id === this.#provider);
|
|
15148
17626
|
this.#provider = CREDENTIAL_PROVIDERS[(index + 1) % CREDENTIAL_PROVIDERS.length].id;
|
|
15149
|
-
this.#input = new Input;
|
|
15150
17627
|
this.#message = "";
|
|
15151
17628
|
}
|
|
17629
|
+
#clearCloseTimer() {
|
|
17630
|
+
if (this.#closeTimer !== undefined)
|
|
17631
|
+
clearTimeout(this.#closeTimer);
|
|
17632
|
+
this.#closeTimer = undefined;
|
|
17633
|
+
}
|
|
17634
|
+
#scheduleAutoClose(generation) {
|
|
17635
|
+
this.#clearCloseTimer();
|
|
17636
|
+
this.#closeTimer = setTimeout(() => {
|
|
17637
|
+
this.#closeTimer = undefined;
|
|
17638
|
+
if (generation === this.#generation && this.open)
|
|
17639
|
+
this.close();
|
|
17640
|
+
}, this.#autoCloseMs);
|
|
17641
|
+
}
|
|
15152
17642
|
async#apply(remove) {
|
|
15153
|
-
const key = this.#input.getValue();
|
|
15154
|
-
if (!remove
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
17643
|
+
const key = this.#input.getValue().trim();
|
|
17644
|
+
if (!remove) {
|
|
17645
|
+
if (!key) {
|
|
17646
|
+
this.#message = "Enter an API key.";
|
|
17647
|
+
this.#changed();
|
|
17648
|
+
return;
|
|
17649
|
+
}
|
|
17650
|
+
if (Array.from(key).some((char) => char.charCodeAt(0) < 32)) {
|
|
17651
|
+
this.#message = "Key contains a newline or control character. Remove it and try again.";
|
|
17652
|
+
this.#changed();
|
|
17653
|
+
return;
|
|
17654
|
+
}
|
|
15158
17655
|
}
|
|
15159
17656
|
const generation = this.#generation;
|
|
15160
17657
|
const provider = this.#provider;
|
|
15161
17658
|
this.#busy = true;
|
|
15162
|
-
this.#message = "Saving...";
|
|
17659
|
+
this.#message = remove ? "Removing..." : "Saving...";
|
|
15163
17660
|
this.#changed();
|
|
15164
17661
|
try {
|
|
15165
17662
|
if (remove)
|
|
@@ -15169,10 +17666,11 @@ class LoginPanel {
|
|
|
15169
17666
|
if (generation === this.#generation) {
|
|
15170
17667
|
this.#input = new Input;
|
|
15171
17668
|
this.#message = remove ? "Saved key removed." : "Saved. Used by the next request.";
|
|
17669
|
+
this.#scheduleAutoClose(generation);
|
|
15172
17670
|
}
|
|
15173
|
-
} catch {
|
|
17671
|
+
} catch (error) {
|
|
15174
17672
|
if (generation === this.#generation)
|
|
15175
|
-
this.#message = "Could not update API key. Try again.";
|
|
17673
|
+
this.#message = error instanceof Error ? error.message : "Could not update API key. Try again.";
|
|
15176
17674
|
} finally {
|
|
15177
17675
|
if (generation === this.#generation) {
|
|
15178
17676
|
this.#busy = false;
|
|
@@ -15185,20 +17683,25 @@ class LoginPanel {
|
|
|
15185
17683
|
const spec = credentialProvider(this.#provider);
|
|
15186
17684
|
const tabs = CREDENTIAL_PROVIDERS.map((item) => item.id === this.#provider ? `[${item.id}]` : ` ${item.id} `).join(" ");
|
|
15187
17685
|
const source = state?.source === "keyless" ? "keyless (rate-limited)" : state?.source ?? "Loading...";
|
|
17686
|
+
const keyLength = this.#input.getValue().length;
|
|
17687
|
+
const marker = this.focused ? CURSOR_MARKER2 : "";
|
|
17688
|
+
const keyRow = keyLength > 0 ? `API Key: ********${marker}${this.focused ? renderFakeCursor(" ") : ""} (${keyLength} characters)` : `API Key: ${marker}${this.focused ? `${renderFakeCursor("(")}paste key)` : "(paste key)"}`;
|
|
15188
17689
|
const rows = [
|
|
15189
17690
|
`Provider: ${tabs}`,
|
|
15190
17691
|
`Environment: ${state ? state.environmentConfigured ? "Configured" : "Not configured" : "Loading..."}`,
|
|
15191
17692
|
`Active source: ${source}`,
|
|
15192
|
-
|
|
17693
|
+
keyRow,
|
|
15193
17694
|
this.#message || (spec.keyless ? "Without a key, Tavily runs in rate-limited keyless mode." : "Saved key overrides environment."),
|
|
15194
17695
|
spec.signupUrl
|
|
15195
17696
|
];
|
|
15196
|
-
const
|
|
17697
|
+
const switchHint = keyLength > 0 ? ["Tab", "Switch"] : ["Left/Right/Tab", "Switch"];
|
|
17698
|
+
const help = this.#busy ? shortcutHints(["Esc", "Close"]) : this.#confirmingRemove ? shortcutHints(["Ctrl+R", "Confirm remove"], ["Esc", "Cancel"]) : state?.savedConfigured ? shortcutHints(["Enter", "Save"], ["Ctrl+R", "Remove"], switchHint, ["Esc", "Cancel"]) : shortcutHints(["Enter", "Save"], switchHint, ["Esc", "Cancel"]);
|
|
15197
17699
|
while (rows.length < this.height - 1)
|
|
15198
17700
|
rows.push("");
|
|
15199
17701
|
return [...rows.slice(0, Math.max(0, this.height - 1)), help].map((line) => theme.panel(` ${truncateToWidth3(line, Math.max(1, width - 2), "...", true)} `));
|
|
15200
17702
|
}
|
|
15201
17703
|
}
|
|
17704
|
+
var AUTO_CLOSE_MS = 800;
|
|
15202
17705
|
var init_login = __esm(() => {
|
|
15203
17706
|
init_src();
|
|
15204
17707
|
init_theme();
|
|
@@ -15535,6 +18038,17 @@ class ThemedTruncatedText {
|
|
|
15535
18038
|
return new TruncatedText(this.#content(), this.#paddingX, this.#paddingY).render(width);
|
|
15536
18039
|
}
|
|
15537
18040
|
}
|
|
18041
|
+
|
|
18042
|
+
class ThemedWrappedText {
|
|
18043
|
+
#content;
|
|
18044
|
+
constructor(content) {
|
|
18045
|
+
this.#content = content;
|
|
18046
|
+
}
|
|
18047
|
+
invalidate() {}
|
|
18048
|
+
render(width) {
|
|
18049
|
+
return new Text4(this.#content(), 1, 0).render(width);
|
|
18050
|
+
}
|
|
18051
|
+
}
|
|
15538
18052
|
var ThemedText;
|
|
15539
18053
|
var init_themed_text = __esm(() => {
|
|
15540
18054
|
ThemedText = class ThemedText extends Text4 {
|
|
@@ -15556,6 +18070,103 @@ var init_themed_text = __esm(() => {
|
|
|
15556
18070
|
};
|
|
15557
18071
|
});
|
|
15558
18072
|
|
|
18073
|
+
// packages/tui/src/components/diff-view.ts
|
|
18074
|
+
function parseDiffLine(line, format = "edit") {
|
|
18075
|
+
if (format === "write") {
|
|
18076
|
+
return line.startsWith("+ ") ? { prefix: "+", lineNum: "", content: line.slice(2) } : null;
|
|
18077
|
+
}
|
|
18078
|
+
const match = /^([+\- ])( *\d+) (.*)$/.exec(line);
|
|
18079
|
+
if (match === null)
|
|
18080
|
+
return null;
|
|
18081
|
+
const first = match[1];
|
|
18082
|
+
const prefix = first === "+" || first === "-" ? first : " ";
|
|
18083
|
+
return { prefix, lineNum: match[2] ?? "", content: match[3] ?? "" };
|
|
18084
|
+
}
|
|
18085
|
+
function parseDiffLines(diff, format = "edit") {
|
|
18086
|
+
return diff.split(`
|
|
18087
|
+
`).map((line) => {
|
|
18088
|
+
const parsed = parseDiffLine(line, format);
|
|
18089
|
+
if (parsed === null)
|
|
18090
|
+
return { kind: "raw", text: line };
|
|
18091
|
+
const kind = parsed.prefix === "+" ? "add" : parsed.prefix === "-" ? "del" : "context";
|
|
18092
|
+
return { kind, lineNum: parsed.lineNum, content: parsed.content };
|
|
18093
|
+
});
|
|
18094
|
+
}
|
|
18095
|
+
function diffTargetPath(name, summary, detail) {
|
|
18096
|
+
if (name === "edit") {
|
|
18097
|
+
const path = summary.replace(/ \(\d+ edits?\)$/, "");
|
|
18098
|
+
return path === "" ? undefined : path;
|
|
18099
|
+
}
|
|
18100
|
+
if (name === "write") {
|
|
18101
|
+
if (detail !== null) {
|
|
18102
|
+
const first = detail.split(`
|
|
18103
|
+
`, 1)[0] ?? "";
|
|
18104
|
+
if (first !== "")
|
|
18105
|
+
return first;
|
|
18106
|
+
}
|
|
18107
|
+
return summary === "" ? undefined : summary;
|
|
18108
|
+
}
|
|
18109
|
+
return;
|
|
18110
|
+
}
|
|
18111
|
+
function highlightDocuments(parsed, lang) {
|
|
18112
|
+
const newContents = [];
|
|
18113
|
+
const oldContents = [];
|
|
18114
|
+
for (const line of parsed) {
|
|
18115
|
+
if (line.kind === "raw")
|
|
18116
|
+
continue;
|
|
18117
|
+
if (line.kind !== "del")
|
|
18118
|
+
newContents.push(line.content);
|
|
18119
|
+
if (line.kind !== "add")
|
|
18120
|
+
oldContents.push(line.content);
|
|
18121
|
+
}
|
|
18122
|
+
const newLines = highlightCodeToSegments(newContents.join(`
|
|
18123
|
+
`), lang);
|
|
18124
|
+
const oldLines = highlightCodeToSegments(oldContents.join(`
|
|
18125
|
+
`), lang);
|
|
18126
|
+
if (newLines === null || oldLines === null)
|
|
18127
|
+
return null;
|
|
18128
|
+
return { newLines, oldLines };
|
|
18129
|
+
}
|
|
18130
|
+
function styleSegments(segments) {
|
|
18131
|
+
return segments.map((s) => s.slot === "plain" ? theme.codeFg(s.text) : theme[s.slot](s.text)).join("");
|
|
18132
|
+
}
|
|
18133
|
+
function paintChangedLine(kind, gutter, content) {
|
|
18134
|
+
const bg = diffBackgroundAnsi(kind === "add" ? "added" : "removed");
|
|
18135
|
+
return `${bg}${theme.dim(gutter)}${bg}${content}\x1B[49m`;
|
|
18136
|
+
}
|
|
18137
|
+
function highlightDiffLines(diff, lang, format = "edit") {
|
|
18138
|
+
const parsed = parseDiffLines(diff, format);
|
|
18139
|
+
const documents = highlightDocuments(parsed, lang);
|
|
18140
|
+
if (documents === null)
|
|
18141
|
+
return highlightCodeToAnsiLines(diff, "diff");
|
|
18142
|
+
const rendered = [];
|
|
18143
|
+
let newIndex = 0;
|
|
18144
|
+
let oldIndex = 0;
|
|
18145
|
+
for (const line of parsed) {
|
|
18146
|
+
if (line.kind === "raw") {
|
|
18147
|
+
rendered.push(theme.dim(line.text));
|
|
18148
|
+
continue;
|
|
18149
|
+
}
|
|
18150
|
+
const sign = line.kind === "add" ? "+" : line.kind === "del" ? "-" : " ";
|
|
18151
|
+
const gutter = `${sign}${line.lineNum} `;
|
|
18152
|
+
if (line.kind === "del") {
|
|
18153
|
+
rendered.push(paintChangedLine("del", gutter, styleSegments(documents.oldLines[oldIndex++] ?? [])));
|
|
18154
|
+
continue;
|
|
18155
|
+
}
|
|
18156
|
+
if (line.kind === "add") {
|
|
18157
|
+
rendered.push(paintChangedLine("add", gutter, styleSegments(documents.newLines[newIndex++] ?? [])));
|
|
18158
|
+
continue;
|
|
18159
|
+
}
|
|
18160
|
+
rendered.push(`${theme.dim(gutter)}${styleSegments(documents.newLines[newIndex++] ?? [])}`);
|
|
18161
|
+
oldIndex++;
|
|
18162
|
+
}
|
|
18163
|
+
return rendered;
|
|
18164
|
+
}
|
|
18165
|
+
var init_diff_view = __esm(() => {
|
|
18166
|
+
init_slots();
|
|
18167
|
+
init_syntax();
|
|
18168
|
+
});
|
|
18169
|
+
|
|
15559
18170
|
// packages/tui/src/components/tool-execution.ts
|
|
15560
18171
|
import { Box, Container as Container3, MouseRegion as MouseRegion2, Text as Text5 } from "@earendil-works/pi-tui";
|
|
15561
18172
|
function currentToolFrame() {
|
|
@@ -15586,15 +18197,23 @@ class ToolSpinnerTicker {
|
|
|
15586
18197
|
this.#timer = undefined;
|
|
15587
18198
|
}
|
|
15588
18199
|
}
|
|
18200
|
+
function diffCountSuffix(state) {
|
|
18201
|
+
if (state.diffAdded === null)
|
|
18202
|
+
return "";
|
|
18203
|
+
const removed = state.diffRemoved !== null && state.diffRemoved > 0 ? `/-${state.diffRemoved}` : "";
|
|
18204
|
+
return ` (+${state.diffAdded}${removed})`;
|
|
18205
|
+
}
|
|
15589
18206
|
function clipLines(text, maxLines) {
|
|
15590
18207
|
const lines = text.split(`
|
|
15591
18208
|
`);
|
|
15592
18209
|
return { visible: lines.slice(0, maxLines).join(`
|
|
15593
18210
|
`), rest: Math.max(0, lines.length - maxLines) };
|
|
15594
18211
|
}
|
|
15595
|
-
var SPINNER_FRAMES, spinnerFrame = 0, ToolExecutionComponent;
|
|
18212
|
+
var SPINNER_FRAMES, spinnerFrame = 0, DIFF_MAX_LINES = 50, ToolExecutionComponent;
|
|
15596
18213
|
var init_tool_execution = __esm(() => {
|
|
15597
18214
|
init_theme();
|
|
18215
|
+
init_syntax();
|
|
18216
|
+
init_diff_view();
|
|
15598
18217
|
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
15599
18218
|
ToolExecutionComponent = class ToolExecutionComponent extends Container3 {
|
|
15600
18219
|
#renderTheme = getActiveThemeMode();
|
|
@@ -15648,16 +18267,38 @@ var init_tool_execution = __esm(() => {
|
|
|
15648
18267
|
}
|
|
15649
18268
|
rebuild() {
|
|
15650
18269
|
const state = this.#state;
|
|
15651
|
-
const parts = [
|
|
18270
|
+
const parts = [
|
|
18271
|
+
`${theme.toolTitle(`\u26A1 ${state.name}`)}`,
|
|
18272
|
+
theme.dim(state.summary + diffCountSuffix(state)),
|
|
18273
|
+
this.#statusLine(state.phase)
|
|
18274
|
+
];
|
|
15652
18275
|
let text = parts.join(" ");
|
|
15653
|
-
if (this.#expanded
|
|
15654
|
-
const detail =
|
|
15655
|
-
|
|
18276
|
+
if (this.#expanded) {
|
|
18277
|
+
const detail = state.detail;
|
|
18278
|
+
if (detail !== null && !(state.diff !== null && state.name === "write" && !state.diffTruncated)) {
|
|
18279
|
+
const clipped = clipLines(detail, 20);
|
|
18280
|
+
text += `
|
|
15656
18281
|
${theme.dim("---- Arguments ----")}
|
|
15657
|
-
${
|
|
15658
|
-
|
|
18282
|
+
${clipped.visible}`;
|
|
18283
|
+
if (clipped.rest > 0)
|
|
18284
|
+
text += `
|
|
18285
|
+
${theme.dim(`... ${clipped.rest} more lines`)}`;
|
|
18286
|
+
}
|
|
18287
|
+
if (state.diff !== null) {
|
|
18288
|
+
const clipped = clipLines(state.diff, DIFF_MAX_LINES);
|
|
18289
|
+
const lang = languageForPath(diffTargetPath(state.name, state.summary, state.detail));
|
|
18290
|
+
const format = state.name === "write" ? "write" : "edit";
|
|
15659
18291
|
text += `
|
|
15660
|
-
${theme.dim(
|
|
18292
|
+
${theme.dim("---- Diff ----")}
|
|
18293
|
+
${highlightDiffLines(clipped.visible, lang, format).join(`
|
|
18294
|
+
`)}`;
|
|
18295
|
+
if (state.diffTruncated)
|
|
18296
|
+
text += `
|
|
18297
|
+
${theme.dim("\u2026 Diff preview truncated (line or byte limit)")}`;
|
|
18298
|
+
if (clipped.rest > 0)
|
|
18299
|
+
text += `
|
|
18300
|
+
${theme.dim(`\u2026 +${clipped.rest} more lines`)}`;
|
|
18301
|
+
}
|
|
15661
18302
|
}
|
|
15662
18303
|
const body = state.phase === "running" ? state.output : state.result;
|
|
15663
18304
|
if (!this.#expanded && body !== null && body !== "") {
|
|
@@ -15844,6 +18485,90 @@ function followTerminalTheme(ui, apply) {
|
|
|
15844
18485
|
}
|
|
15845
18486
|
var THEME_QUERY_TIMEOUT_MS = 100;
|
|
15846
18487
|
|
|
18488
|
+
// packages/tui/src/export-command.ts
|
|
18489
|
+
import { open as open2, unlink as unlink2 } from "fs/promises";
|
|
18490
|
+
import { homedir as homedir6 } from "os";
|
|
18491
|
+
import { resolve as resolve4 } from "path";
|
|
18492
|
+
function parseExportArgs(input) {
|
|
18493
|
+
const words = [];
|
|
18494
|
+
let word = "";
|
|
18495
|
+
let quote = "";
|
|
18496
|
+
let quoted = false;
|
|
18497
|
+
let active = false;
|
|
18498
|
+
for (const c of input) {
|
|
18499
|
+
if (quote !== "") {
|
|
18500
|
+
if (c === quote)
|
|
18501
|
+
quote = "";
|
|
18502
|
+
else
|
|
18503
|
+
word += c;
|
|
18504
|
+
} else if (c === '"' || c === "'") {
|
|
18505
|
+
quote = c;
|
|
18506
|
+
quoted = true;
|
|
18507
|
+
active = true;
|
|
18508
|
+
} else if (/\s/.test(c)) {
|
|
18509
|
+
if (active)
|
|
18510
|
+
words.push({ text: word, quoted });
|
|
18511
|
+
word = "";
|
|
18512
|
+
quoted = false;
|
|
18513
|
+
active = false;
|
|
18514
|
+
} else {
|
|
18515
|
+
word += c;
|
|
18516
|
+
active = true;
|
|
18517
|
+
}
|
|
18518
|
+
}
|
|
18519
|
+
if (quote !== "")
|
|
18520
|
+
throw new Error(`Unterminated quote. ${EXPORT_USAGE}`);
|
|
18521
|
+
if (active)
|
|
18522
|
+
words.push({ text: word, quoted });
|
|
18523
|
+
let includeThinking = false;
|
|
18524
|
+
let path;
|
|
18525
|
+
for (const { text, quoted: wasQuoted } of words) {
|
|
18526
|
+
if (!wasQuoted && text === "--thinking")
|
|
18527
|
+
includeThinking = true;
|
|
18528
|
+
else if (!wasQuoted && text.startsWith("--"))
|
|
18529
|
+
throw new Error(`Unknown option ${text}. ${EXPORT_USAGE}`);
|
|
18530
|
+
else if (path === undefined && text !== "")
|
|
18531
|
+
path = text;
|
|
18532
|
+
else
|
|
18533
|
+
throw new Error(EXPORT_USAGE);
|
|
18534
|
+
}
|
|
18535
|
+
return { path, includeThinking };
|
|
18536
|
+
}
|
|
18537
|
+
async function exportToFile(input) {
|
|
18538
|
+
const format = input.path === undefined ? "markdown" : exportFormatFromPath(input.path);
|
|
18539
|
+
if (format === null)
|
|
18540
|
+
throw new Error("Unsupported export format: use a .md, .html or .json path");
|
|
18541
|
+
const target = resolve4(input.cwd, input.path === undefined ? exportFileName(input.source.title, format, input.source.exportedAt) : input.path.startsWith("~/") ? homedir6() + input.path.slice(1) : input.path);
|
|
18542
|
+
let handle;
|
|
18543
|
+
try {
|
|
18544
|
+
handle = await open2(target, "wx");
|
|
18545
|
+
} catch (error) {
|
|
18546
|
+
const code = error.code;
|
|
18547
|
+
if (code === "EEXIST")
|
|
18548
|
+
throw new Error(`File already exists: ${target}. Choose another path.`);
|
|
18549
|
+
if (code === "ENOENT")
|
|
18550
|
+
throw new Error(`Directory does not exist: ${target}`);
|
|
18551
|
+
throw error;
|
|
18552
|
+
}
|
|
18553
|
+
try {
|
|
18554
|
+
const result = await exportConversation(format, input.source, {
|
|
18555
|
+
includeThinking: input.includeThinking,
|
|
18556
|
+
...input.loadImage ? { loadImage: input.loadImage } : {}
|
|
18557
|
+
});
|
|
18558
|
+
await handle.writeFile(result.content, "utf8");
|
|
18559
|
+
return { path: target, skippedImages: result.skippedImages };
|
|
18560
|
+
} catch (error) {
|
|
18561
|
+
await unlink2(target).catch(() => {});
|
|
18562
|
+
throw error;
|
|
18563
|
+
} finally {
|
|
18564
|
+
await handle.close().catch(() => {});
|
|
18565
|
+
}
|
|
18566
|
+
}
|
|
18567
|
+
var EXPORT_USAGE = "Usage: /export [path.md|path.html|path.json] [--thinking]";
|
|
18568
|
+
var init_export_command = __esm(() => {
|
|
18569
|
+
init_conversation_export();
|
|
18570
|
+
});
|
|
18571
|
+
|
|
15847
18572
|
// packages/core/src/file-mentions.ts
|
|
15848
18573
|
function mentionAt(text, cursor) {
|
|
15849
18574
|
const before = text.slice(0, cursor);
|
|
@@ -15908,7 +18633,7 @@ function fileCompletion(commands, root, notice, search) {
|
|
|
15908
18633
|
var init_file_completion = () => {};
|
|
15909
18634
|
|
|
15910
18635
|
// packages/gateway/src/unix-link.ts
|
|
15911
|
-
import { lstat as lstat2, mkdir as mkdir4, unlink as
|
|
18636
|
+
import { lstat as lstat2, mkdir as mkdir4, unlink as unlink3 } from "fs/promises";
|
|
15912
18637
|
import { connect, createServer } from "net";
|
|
15913
18638
|
import { dirname as dirname7 } from "path";
|
|
15914
18639
|
import { webSocketLink as webSocketLink2 } from "@earendil-works/chord";
|
|
@@ -16051,7 +18776,7 @@ function createUnixListener(options) {
|
|
|
16051
18776
|
});
|
|
16052
18777
|
if (active)
|
|
16053
18778
|
throw new Error("Gateway already running at this socket");
|
|
16054
|
-
await
|
|
18779
|
+
await unlink3(options.path);
|
|
16055
18780
|
} catch (error) {
|
|
16056
18781
|
if (error.code !== "ENOENT")
|
|
16057
18782
|
throw error;
|
|
@@ -16081,7 +18806,7 @@ function createUnixListener(options) {
|
|
|
16081
18806
|
await new Promise((resolve) => previous.close(() => resolve()));
|
|
16082
18807
|
if (bound) {
|
|
16083
18808
|
bound = false;
|
|
16084
|
-
await
|
|
18809
|
+
await unlink3(options.path).catch(() => {});
|
|
16085
18810
|
}
|
|
16086
18811
|
}
|
|
16087
18812
|
};
|
|
@@ -16311,6 +19036,7 @@ import {
|
|
|
16311
19036
|
opaque,
|
|
16312
19037
|
resource
|
|
16313
19038
|
} from "@earendil-works/chord";
|
|
19039
|
+
import { UsageDoc as UsageDoc3 } from "@earendil-works/pi-durable";
|
|
16314
19040
|
import { Type as Type5 } from "typebox";
|
|
16315
19041
|
async function openReader(runtime, childId, parentId, context, through, historyUsage) {
|
|
16316
19042
|
const child = await runtime.harness.conversation(childId, context);
|
|
@@ -16373,7 +19099,7 @@ async function openReader(runtime, childId, parentId, context, through, historyU
|
|
|
16373
19099
|
return () => {};
|
|
16374
19100
|
const stop = native.subscribe(() => fn(null));
|
|
16375
19101
|
const stopApprovals = runtime.harness.subscribeCommits(({ changes }) => {
|
|
16376
|
-
if (changes.some((c) => c.type === "document" &&
|
|
19102
|
+
if (changes.some((c) => c.type === "document" && ["app.neko.approvals", "app.neko.delegations", "app.neko.subagents"].includes(c.record.kind) && c.conversationId === parentId))
|
|
16377
19103
|
fn(null);
|
|
16378
19104
|
});
|
|
16379
19105
|
return () => {
|
|
@@ -16384,7 +19110,12 @@ async function openReader(runtime, childId, parentId, context, through, historyU
|
|
|
16384
19110
|
async refresh() {
|
|
16385
19111
|
const page = await pageAt();
|
|
16386
19112
|
const approvals = through === undefined ? (await runtime.approvals.list(parentId, context)).filter((a) => a.childId === childId) : [];
|
|
16387
|
-
|
|
19113
|
+
const currentUsage = await runtime.harness.snapshot(UsageDoc3, childId, context);
|
|
19114
|
+
const rounds = (await listDelegations(runtime.harness, parentId, context)).filter((r) => r.childId === childId).map(({ usageStart, usageEnd: _end, ...round }) => ({
|
|
19115
|
+
...round,
|
|
19116
|
+
roundUsage: round.roundUsage ?? (through === undefined && usageStart && currentUsage ? subagentUsageTotals(subtractSubagentUsage(currentUsage, usageStart)) : null)
|
|
19117
|
+
}));
|
|
19118
|
+
revision = remember({ ...project(page.entries), rounds, approvals, historyBefore: page.next });
|
|
16388
19119
|
return revision;
|
|
16389
19120
|
},
|
|
16390
19121
|
async chunk(input) {
|
|
@@ -16436,7 +19167,7 @@ function installSubagentHost(host, runtime, context) {
|
|
|
16436
19167
|
reader: resource({
|
|
16437
19168
|
rev: 1,
|
|
16438
19169
|
async open() {
|
|
16439
|
-
const entry = (await listDelegations(runtime.harness, input.parentId, context)).find((d) => d.taskId === input.
|
|
19170
|
+
const entry = (await listDelegations(runtime.harness, input.parentId, context)).find((d) => input.agentId.startsWith("round-") ? d.taskId === Number(input.agentId.slice(6)) : (d.agentId ?? agentIdFor(d.childId)) === input.agentId);
|
|
16440
19171
|
if (!entry)
|
|
16441
19172
|
throw new ChordError("gone", "Subagent unavailable");
|
|
16442
19173
|
const r = await openReader(runtime, entry.childId, input.parentId, context, entry.historyThrough, entry.historyUsage);
|
|
@@ -16466,13 +19197,13 @@ function installSubagentHost(host, runtime, context) {
|
|
|
16466
19197
|
throw new ChordError("forbidden", "Attachment expired");
|
|
16467
19198
|
if (!await runtime.getConversation(Number(input.sessionId)))
|
|
16468
19199
|
throw new ChordError("gone", "Session unavailable");
|
|
16469
|
-
const entry = (await listDelegations(runtime.harness, Number(input.sessionId), context)).find((d) => d.taskId === input.taskId);
|
|
19200
|
+
const entry = (await listDelegations(runtime.harness, Number(input.sessionId), context)).find((d) => input.agentId !== undefined ? (d.agentId ?? agentIdFor(d.childId)) === input.agentId : d.taskId === input.taskId);
|
|
16470
19201
|
if (!entry)
|
|
16471
19202
|
throw new ChordError("forbidden", "Subagent does not belong to this session");
|
|
16472
19203
|
return entry;
|
|
16473
19204
|
};
|
|
16474
19205
|
const { target } = self.resources({ target: resource({ rev: 1, deps: [owner], open: check }) });
|
|
16475
|
-
const shared = self.get(ChildProjection, { parentId: Number(input.sessionId),
|
|
19206
|
+
const shared = self.get(ChildProjection, { parentId: Number(input.sessionId), agentId: input.agentId ?? `round-${input.taskId}` }, { principal: hostPrincipal });
|
|
16476
19207
|
const { authorizedRevision } = self.state({ authorizedRevision: cell(Type5.Integer(), 0) });
|
|
16477
19208
|
self.listen({
|
|
16478
19209
|
authorizedView: listener(shared.revision, async (value, ctx) => {
|
|
@@ -16501,14 +19232,26 @@ function installSubagentHost(host, runtime, context) {
|
|
|
16501
19232
|
const entry = await check();
|
|
16502
19233
|
if (entry.historyThrough !== undefined)
|
|
16503
19234
|
throw new ChordError("forbidden", "Fork history is read-only");
|
|
16504
|
-
|
|
19235
|
+
const approval = (await runtime.approvals.list(Number(input.sessionId), context)).find((a) => a.id === id && a.childId === entry.childId);
|
|
19236
|
+
if (!approval)
|
|
19237
|
+
throw new ChordError("forbidden", "Approval does not belong to this agent");
|
|
19238
|
+
return runtime.approvals.decide(Number(input.sessionId), approval.delegationTaskId, id, version, decision, context);
|
|
16505
19239
|
},
|
|
16506
|
-
stop: async () => {
|
|
19240
|
+
stop: async (request) => {
|
|
16507
19241
|
const entry = await check();
|
|
16508
19242
|
if (entry.historyThrough !== undefined)
|
|
16509
19243
|
throw new ChordError("forbidden", "Fork history is read-only");
|
|
16510
|
-
|
|
16511
|
-
|
|
19244
|
+
const taskId = request?.taskId ?? input.taskId;
|
|
19245
|
+
if (taskId === undefined)
|
|
19246
|
+
throw new ChordError("invalid", "Select the exact active round to stop");
|
|
19247
|
+
const valid = await runtime.harness.commit(async (tx) => {
|
|
19248
|
+
const identity = (await tx.doc(SubagentsDoc, Number(input.sessionId))).items.find((a) => a.childId === entry.childId);
|
|
19249
|
+
return identity?.activeRoundId === taskId;
|
|
19250
|
+
}, context);
|
|
19251
|
+
if (!valid)
|
|
19252
|
+
return null;
|
|
19253
|
+
await runtime.harness.abortTask(taskId, context);
|
|
19254
|
+
await runtime.harness.waitForTask(taskId, context);
|
|
16512
19255
|
return null;
|
|
16513
19256
|
}
|
|
16514
19257
|
};
|
|
@@ -16522,7 +19265,7 @@ var init_subagent_host = __esm(() => {
|
|
|
16522
19265
|
init_session_host();
|
|
16523
19266
|
ChildProjection = local("neko.subagent-projection", {
|
|
16524
19267
|
version: 1,
|
|
16525
|
-
input: Type5.Object({ parentId: Type5.Integer(),
|
|
19268
|
+
input: Type5.Object({ parentId: Type5.Integer(), agentId: Type5.String() }),
|
|
16526
19269
|
members: {
|
|
16527
19270
|
revision: Type5.Integer(),
|
|
16528
19271
|
reader: opaque("neko.subagent-reader@1")
|
|
@@ -16531,7 +19274,7 @@ var init_subagent_host = __esm(() => {
|
|
|
16531
19274
|
});
|
|
16532
19275
|
|
|
16533
19276
|
// packages/gateway/src/session-host.ts
|
|
16534
|
-
import { open as
|
|
19277
|
+
import { open as open3 } from "fs/promises";
|
|
16535
19278
|
import { basename as basename5, extname } from "path";
|
|
16536
19279
|
import {
|
|
16537
19280
|
ChordError as ChordError2,
|
|
@@ -16543,7 +19286,7 @@ import {
|
|
|
16543
19286
|
resource as resource2
|
|
16544
19287
|
} from "@earendil-works/chord";
|
|
16545
19288
|
import { withAbortSignal as withAbortSignal3 } from "@earendil-works/chord/context";
|
|
16546
|
-
import { UsageDoc as
|
|
19289
|
+
import { UsageDoc as UsageDoc4 } from "@earendil-works/pi-durable";
|
|
16547
19290
|
import { Type as Type6 } from "typebox";
|
|
16548
19291
|
async function openProjection(runtime, session, context) {
|
|
16549
19292
|
const view = await session.viewState();
|
|
@@ -16560,7 +19303,7 @@ async function openProjection(runtime, session, context) {
|
|
|
16560
19303
|
const stopMetadata = runtime.onDirectoryChange(() => changed?.(null));
|
|
16561
19304
|
let childIds = new Set;
|
|
16562
19305
|
const stopChildren = runtime.harness.subscribeCommits(({ changes }) => {
|
|
16563
|
-
if (changes.some((change) => change.type === "document" && (["app.neko.delegations", "app.neko.approvals"].includes(change.record.kind) && change.conversationId === session.id || change.record.kind === "pi.usage" && change.conversationId !== undefined && childIds.has(change.conversationId))))
|
|
19306
|
+
if (changes.some((change) => change.type === "document" && (["app.neko.delegations", "app.neko.approvals", "app.neko.subagents"].includes(change.record.kind) && change.conversationId === session.id || change.record.kind === "pi.usage" && change.conversationId !== undefined && childIds.has(change.conversationId))))
|
|
16564
19307
|
changed?.(null);
|
|
16565
19308
|
});
|
|
16566
19309
|
return {
|
|
@@ -16592,15 +19335,19 @@ async function openProjection(runtime, session, context) {
|
|
|
16592
19335
|
entry.approvalCount = entry.historyThrough === undefined ? approvals.filter((a) => a.delegationTaskId === entry.taskId && a.status === "pending").length : 0;
|
|
16593
19336
|
childIds = new Set(subagents.filter((entry) => entry.historyThrough === undefined).map((entry) => entry.childId));
|
|
16594
19337
|
let aggregate = await session.usage();
|
|
16595
|
-
for (const child of subagents.filter((entry) => entry.historyThrough === undefined))
|
|
16596
|
-
aggregate = mergeUsage(aggregate, await runtime.harness.snapshot(
|
|
19338
|
+
for (const child of new Map(subagents.filter((entry) => entry.historyThrough === undefined).map((r) => [r.childId, r])).values())
|
|
19339
|
+
aggregate = mergeUsage(aggregate, await runtime.harness.snapshot(UsageDoc4, child.childId, context) ?? {
|
|
16597
19340
|
models: {},
|
|
16598
19341
|
tools: {}
|
|
16599
19342
|
});
|
|
16600
19343
|
const u = totalUsage(aggregate);
|
|
16601
19344
|
return {
|
|
16602
19345
|
...projected,
|
|
16603
|
-
|
|
19346
|
+
agents: summarizeSubagents(subagents, (await runtime.harness.snapshot(SubagentsDoc, session.id, context))?.items),
|
|
19347
|
+
subagents: subagents.map(({ usageStart: _start, usageEnd: _end, ...entry }) => ({
|
|
19348
|
+
...entry,
|
|
19349
|
+
report: entry.report?.slice(0, 512) ?? null
|
|
19350
|
+
})),
|
|
16604
19351
|
taskUsage: {
|
|
16605
19352
|
input: u.input,
|
|
16606
19353
|
output: u.output,
|
|
@@ -16708,7 +19455,7 @@ function serveSessions(host, runtime, context) {
|
|
|
16708
19455
|
const model = runtime.listModels().find((m) => m.provider === agent.model?.provider && m.modelId === agent.model?.modelId);
|
|
16709
19456
|
if (!model?.input.includes("image"))
|
|
16710
19457
|
throw new Error("Current model does not support images");
|
|
16711
|
-
const handle = await
|
|
19458
|
+
const handle = await open3(target, "r");
|
|
16712
19459
|
let id;
|
|
16713
19460
|
try {
|
|
16714
19461
|
const info = await handle.stat();
|
|
@@ -16944,7 +19691,7 @@ var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, cl
|
|
|
16944
19691
|
}
|
|
16945
19692
|
}
|
|
16946
19693
|
return { b, r };
|
|
16947
|
-
}, _a, fl, revfl, _b, fd, revfd, rev,
|
|
19694
|
+
}, _a, fl, revfl, _b, fd, revfd, rev, x2, i, hMap = function(cd, mb, r) {
|
|
16948
19695
|
var s = cd.length;
|
|
16949
19696
|
var i = 0;
|
|
16950
19697
|
var l = new u16(mb);
|
|
@@ -17148,7 +19895,7 @@ var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, cl
|
|
|
17148
19895
|
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
17149
19896
|
} while (!final);
|
|
17150
19897
|
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
17151
|
-
},
|
|
19898
|
+
}, et2, b2 = function(d, b) {
|
|
17152
19899
|
return d[b] | d[b + 1] << 8;
|
|
17153
19900
|
}, b4 = function(d, b) {
|
|
17154
19901
|
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
@@ -17214,10 +19961,10 @@ var init_esm = __esm(() => {
|
|
|
17214
19961
|
revfd = _b.r;
|
|
17215
19962
|
rev = new u16(32768);
|
|
17216
19963
|
for (i = 0;i < 32768; ++i) {
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17220
|
-
rev[i] = ((
|
|
19964
|
+
x2 = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
19965
|
+
x2 = (x2 & 52428) >> 2 | (x2 & 13107) << 2;
|
|
19966
|
+
x2 = (x2 & 61680) >> 4 | (x2 & 3855) << 4;
|
|
19967
|
+
rev[i] = ((x2 & 65280) >> 8 | (x2 & 255) << 8) >> 1;
|
|
17221
19968
|
}
|
|
17222
19969
|
flt = new u8(288);
|
|
17223
19970
|
for (i = 0;i < 144; ++i)
|
|
@@ -17249,10 +19996,10 @@ var init_esm = __esm(() => {
|
|
|
17249
19996
|
"stream finishing",
|
|
17250
19997
|
"invalid zip data"
|
|
17251
19998
|
];
|
|
17252
|
-
|
|
19999
|
+
et2 = /* @__PURE__ */ new u8(0);
|
|
17253
20000
|
td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder;
|
|
17254
20001
|
try {
|
|
17255
|
-
td.decode(
|
|
20002
|
+
td.decode(et2, { stream: true });
|
|
17256
20003
|
tds = 1;
|
|
17257
20004
|
} catch (e) {}
|
|
17258
20005
|
});
|
|
@@ -17260,10 +20007,10 @@ var init_esm = __esm(() => {
|
|
|
17260
20007
|
// packages/gateway/src/skill-market.ts
|
|
17261
20008
|
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
17262
20009
|
import { mkdir as mkdir5, readdir as readdir2, rename as rename3, rm as rm4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
|
|
17263
|
-
import { homedir as
|
|
20010
|
+
import { homedir as homedir7 } from "os";
|
|
17264
20011
|
import { dirname as dirname8, join as join9 } from "path";
|
|
17265
20012
|
function createSkillMarketClient(options) {
|
|
17266
|
-
const home = options.home ??
|
|
20013
|
+
const home = options.home ?? homedir7();
|
|
17267
20014
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
17268
20015
|
const now = options.now ?? Date.now;
|
|
17269
20016
|
let base;
|
|
@@ -17991,7 +20738,7 @@ var init_src2 = __esm(() => {
|
|
|
17991
20738
|
});
|
|
17992
20739
|
|
|
17993
20740
|
// packages/tui/src/gateway.ts
|
|
17994
|
-
import { spawn as
|
|
20741
|
+
import { spawn as spawn3 } from "child_process";
|
|
17995
20742
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
17996
20743
|
import { basename as basename7, dirname as dirname11, join as join12 } from "path";
|
|
17997
20744
|
async function connectToGateway(options = {}) {
|
|
@@ -18032,7 +20779,7 @@ async function connectToGateway(options = {}) {
|
|
|
18032
20779
|
}
|
|
18033
20780
|
async function spawnAndConnect(plan) {
|
|
18034
20781
|
const command = gatewayCommand(gatewayArgs(plan));
|
|
18035
|
-
const child =
|
|
20782
|
+
const child = spawn3(command.binary, command.args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
18036
20783
|
const outputTail = captureOutput(child);
|
|
18037
20784
|
let spawnError;
|
|
18038
20785
|
child.on("error", (error) => {
|
|
@@ -18206,6 +20953,7 @@ function helpLines(platform = process.platform) {
|
|
|
18206
20953
|
["Alt+Enter", "Queue while running"],
|
|
18207
20954
|
["Esc", "Stop a running task or blocking compaction"],
|
|
18208
20955
|
["Esc Esc", "Clear draft when idle (press twice quickly)"],
|
|
20956
|
+
["Up / Down", "Browse previous inputs in this session"],
|
|
18209
20957
|
["Ctrl+C", "Stop while running; exit when idle"],
|
|
18210
20958
|
["Ctrl+S", "Open sessions"],
|
|
18211
20959
|
[platform === "win32" ? "Alt+V" : "Ctrl+V", "Paste clipboard image or text"],
|
|
@@ -18229,8 +20977,8 @@ function helpLines(platform = process.platform) {
|
|
|
18229
20977
|
["Enter", "Confirm selected approval option"],
|
|
18230
20978
|
["PgUp / PgDn", "Scroll full approval command"],
|
|
18231
20979
|
["[/]", "Select another pending approval"],
|
|
18232
|
-
["S", "Stop
|
|
18233
|
-
["Click", "Open
|
|
20980
|
+
["S", "Stop current round; keep agent context (Enter confirms)"],
|
|
20981
|
+
["Click", "Open round card or status-bar Agents entry"]
|
|
18234
20982
|
]);
|
|
18235
20983
|
section("Skills", [
|
|
18236
20984
|
["U", "Install for user"],
|
|
@@ -18314,8 +21062,8 @@ var init_help_ui = __esm(() => {
|
|
|
18314
21062
|
// packages/tui/src/image-input.ts
|
|
18315
21063
|
import { execFile as execFile2 } from "child_process";
|
|
18316
21064
|
import { readFile as readFile8, stat as stat5 } from "fs/promises";
|
|
18317
|
-
import { homedir as
|
|
18318
|
-
import { basename as basename8, resolve as
|
|
21065
|
+
import { homedir as homedir8 } from "os";
|
|
21066
|
+
import { basename as basename8, resolve as resolve5 } from "path";
|
|
18319
21067
|
import { promisify as promisify2 } from "util";
|
|
18320
21068
|
import { isKeyRelease as isKeyRelease4, isKeyRepeat as isKeyRepeat2, matchesKey as matchesKey7 } from "@earendil-works/pi-tui";
|
|
18321
21069
|
function imagePaths(text, platform = process.platform) {
|
|
@@ -18349,7 +21097,7 @@ function imagePaths(text, platform = process.platform) {
|
|
|
18349
21097
|
return paths.length && paths.every((p) => /\.(png|jpe?g|webp)$/i.test(p)) ? paths : null;
|
|
18350
21098
|
}
|
|
18351
21099
|
async function readImageFile(path, cwd) {
|
|
18352
|
-
const full =
|
|
21100
|
+
const full = resolve5(cwd, path.startsWith("~/") ? homedir8() + path.slice(1) : path);
|
|
18353
21101
|
const info = await stat5(full);
|
|
18354
21102
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
18355
21103
|
throw new Error("Image must be a file no larger than 20 MiB");
|
|
@@ -18707,7 +21455,7 @@ import { matchesKey as matchesKey9 } from "@earendil-works/pi-tui";
|
|
|
18707
21455
|
|
|
18708
21456
|
class SubagentDetail {
|
|
18709
21457
|
get help() {
|
|
18710
|
-
const canStop = this.entry?.historyThrough === undefined && (this.entry?.status === "running" || this.entry?.status === "queued");
|
|
21458
|
+
const canStop = this.identity ? this.identity.activeRoundId !== null && this.identity.historyThrough === undefined : this.entry?.historyThrough === undefined && (this.entry?.status === "running" || this.entry?.status === "queued");
|
|
18711
21459
|
return shortcutHints(["\u2190", "Main"], ["\u2191\u2193/Wheel", "Scroll"], ["E", "Expand"], ...canStop ? [["S", "Stop"]] : []);
|
|
18712
21460
|
}
|
|
18713
21461
|
#view;
|
|
@@ -18729,6 +21477,9 @@ class SubagentDetail {
|
|
|
18729
21477
|
#panel;
|
|
18730
21478
|
#active = false;
|
|
18731
21479
|
entry;
|
|
21480
|
+
identity;
|
|
21481
|
+
#targetRound;
|
|
21482
|
+
#locating = false;
|
|
18732
21483
|
#epoch = 0;
|
|
18733
21484
|
constructor(client, taskId, panel, changed) {
|
|
18734
21485
|
this.#service = client.subagent(taskId);
|
|
@@ -18755,10 +21506,35 @@ class SubagentDetail {
|
|
|
18755
21506
|
if (this.#before === undefined)
|
|
18756
21507
|
this.#before = view.historyBefore;
|
|
18757
21508
|
this.#entries = new Map(mergeTranscriptItems([...this.#entries.values()], view.items).map((item) => [item.key, item]));
|
|
21509
|
+
this.#loadTarget();
|
|
18758
21510
|
this.#changed();
|
|
18759
21511
|
});
|
|
18760
21512
|
return this;
|
|
18761
21513
|
}
|
|
21514
|
+
locate(taskId) {
|
|
21515
|
+
this.#targetRound = taskId;
|
|
21516
|
+
this.#loadTarget();
|
|
21517
|
+
this.#changed();
|
|
21518
|
+
}
|
|
21519
|
+
async#loadTarget() {
|
|
21520
|
+
if (this.#locating || !this.#active || this.#targetRound === undefined)
|
|
21521
|
+
return;
|
|
21522
|
+
const entryId = this.#view?.rounds?.find((r) => r.taskId === this.#targetRound)?.inputEntryId;
|
|
21523
|
+
if (entryId === undefined)
|
|
21524
|
+
return;
|
|
21525
|
+
this.#locating = true;
|
|
21526
|
+
try {
|
|
21527
|
+
while (this.#active && !this.#entries.has(`e${entryId}`) && this.#before != null && !this.#loading) {
|
|
21528
|
+
const before = this.#before;
|
|
21529
|
+
await this.history();
|
|
21530
|
+
if (before === this.#before)
|
|
21531
|
+
break;
|
|
21532
|
+
}
|
|
21533
|
+
} finally {
|
|
21534
|
+
this.#locating = false;
|
|
21535
|
+
this.#changed();
|
|
21536
|
+
}
|
|
21537
|
+
}
|
|
18762
21538
|
close() {
|
|
18763
21539
|
this.#epoch++;
|
|
18764
21540
|
this.#active = false;
|
|
@@ -18811,14 +21587,15 @@ class SubagentDetail {
|
|
|
18811
21587
|
if (component instanceof AssistantMessageComponent)
|
|
18812
21588
|
component.setThinkingExpanded(this.#expanded);
|
|
18813
21589
|
}
|
|
18814
|
-
} else if (data.toLowerCase() === "s" && this.entry?.historyThrough === undefined && (this.entry?.status === "running" || this.entry?.status === "queued"))
|
|
21590
|
+
} else if (data.toLowerCase() === "s" && this.entry?.historyThrough === undefined && (this.identity?.activeRoundId != null || !this.identity && (this.entry?.status === "running" || this.entry?.status === "queued"))) {
|
|
21591
|
+
const stopTaskId = this.identity?.activeRoundId ?? this.entry?.taskId;
|
|
18815
21592
|
this.#panel.showDetail({
|
|
18816
21593
|
help: shortcutHints(["Enter", "Stop"], ["Esc", "Back"]),
|
|
18817
21594
|
lines: () => [theme.warning("Stop this task? Existing changes will be kept.")],
|
|
18818
21595
|
handleKey: (key) => {
|
|
18819
21596
|
if (!matchesKey9(key, "enter"))
|
|
18820
21597
|
return false;
|
|
18821
|
-
this.#service.stop(null).catch((e) => {
|
|
21598
|
+
this.#service.stop(stopTaskId === undefined ? null : { taskId: stopTaskId }).catch((e) => {
|
|
18822
21599
|
this.#error = String(e);
|
|
18823
21600
|
}).finally(() => {
|
|
18824
21601
|
this.#panel.popDetail();
|
|
@@ -18827,7 +21604,7 @@ class SubagentDetail {
|
|
|
18827
21604
|
return true;
|
|
18828
21605
|
}
|
|
18829
21606
|
});
|
|
18830
|
-
else
|
|
21607
|
+
} else
|
|
18831
21608
|
return false;
|
|
18832
21609
|
return true;
|
|
18833
21610
|
}
|
|
@@ -18851,14 +21628,25 @@ class SubagentDetail {
|
|
|
18851
21628
|
this.#pageSize = Math.max(1, height - 1);
|
|
18852
21629
|
const entry = this.entry;
|
|
18853
21630
|
const rows = entry ? [
|
|
18854
|
-
theme.accent(`${entry.role} \xB7 ${entry.title}`),
|
|
18855
|
-
theme.dim(`${entry.historyThrough !== undefined ? "Snapshot \xB7 " : ""}${labels2[entry.status]} \xB7 ${Math.max(0, Math.round(((entry.endedAt ?? Date.now()) - entry.createdAt) / 1000))}s`),
|
|
21631
|
+
theme.accent(`${entry.role} \xB7 ${this.identity?.title ?? entry.title}`),
|
|
21632
|
+
theme.dim(`${entry.historyThrough !== undefined ? "Snapshot \xB7 " : ""}${this.identity ? this.identity.status === "idle" ? "Idle" : this.identity.status === "queued" ? "Queued" : "Running" : labels2[entry.status]} \xB7 ${Math.max(0, Math.round(((entry.endedAt ?? Date.now()) - entry.createdAt) / 1000))}s`),
|
|
18856
21633
|
""
|
|
18857
21634
|
] : [];
|
|
18858
21635
|
if (this.#view)
|
|
18859
|
-
rows.push(theme.dim(`In ${this.#view.usage.input} \xB7 Out ${this.#view.usage.output} \xB7 $${this.#view.usage.cost.toFixed(4)}`), "");
|
|
21636
|
+
rows.push(theme.dim(`Total In ${this.#view.usage.input} \xB7 Out ${this.#view.usage.output} \xB7 $${this.#view.usage.cost.toFixed(4)}`), "");
|
|
18860
21637
|
const imageRows = [];
|
|
21638
|
+
let targetOffset;
|
|
18861
21639
|
for (const item of [...this.#entries.values()].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))) {
|
|
21640
|
+
if (item.type === "user") {
|
|
21641
|
+
const round = this.#view?.rounds?.find((r) => r.inputEntryId === item.id || r.taskId === item.subagentRoundId);
|
|
21642
|
+
if (round?.taskId === this.#targetRound)
|
|
21643
|
+
targetOffset = rows.length;
|
|
21644
|
+
if (round) {
|
|
21645
|
+
rows.push(theme.accent(`Task ${round.round ?? ""} \xB7 ${round.title} \xB7 ${labels2[round.status]}`));
|
|
21646
|
+
const u = round.roundUsage;
|
|
21647
|
+
rows.push(theme.dim(u ? `Round In ${u.input} \xB7 Out ${u.output} \xB7 Cache ${u.cacheRead}/${u.cacheWrite} \xB7 $${u.cost.toFixed(4)}` : "Round usage not recorded"));
|
|
21648
|
+
}
|
|
21649
|
+
}
|
|
18862
21650
|
rows.push(...this.#component(item).render(width));
|
|
18863
21651
|
if (item.type === "tool") {
|
|
18864
21652
|
for (const approval of this.#view?.approvals ?? [])
|
|
@@ -18904,6 +21692,11 @@ class SubagentDetail {
|
|
|
18904
21692
|
this.#offset += Math.max(0, this.#maxOffset - this.#prependOffset);
|
|
18905
21693
|
this.#prependOffset = undefined;
|
|
18906
21694
|
}
|
|
21695
|
+
if (targetOffset !== undefined) {
|
|
21696
|
+
this.#offset = targetOffset;
|
|
21697
|
+
this.#follow = false;
|
|
21698
|
+
this.#targetRound = undefined;
|
|
21699
|
+
}
|
|
18907
21700
|
this.#offset = this.#follow ? this.#maxOffset : Math.min(this.#offset, this.#maxOffset);
|
|
18908
21701
|
for (const image of imageRows) {
|
|
18909
21702
|
image.image.setVisible(this.#active && image.start < this.#offset + height && image.end > this.#offset);
|
|
@@ -18912,11 +21705,11 @@ class SubagentDetail {
|
|
|
18912
21705
|
return rows.slice(this.#offset, this.#offset + height);
|
|
18913
21706
|
}
|
|
18914
21707
|
}
|
|
18915
|
-
var labels2, subagentItems = (entries) =>
|
|
18916
|
-
value:
|
|
21708
|
+
var labels2, subagentItems = (entries, summaries = summarizeSubagents(entries)) => summaries.map((d) => ({
|
|
21709
|
+
value: d.agentId,
|
|
18917
21710
|
label: `${d.role} \xB7 ${d.title}`,
|
|
18918
|
-
description: `${d.historyThrough !== undefined ? "Snapshot \xB7 " : ""}${
|
|
18919
|
-
rightLabel: d.approvalCount ? `Approval ${d.approvalCount}` :
|
|
21711
|
+
description: `${d.historyThrough !== undefined ? "Snapshot \xB7 " : ""}${d.taskTitle} \xB7 ${d.roundCount} rounds`,
|
|
21712
|
+
rightLabel: d.approvalCount ? `Approval ${d.approvalCount}` : d.status === "idle" ? "Idle" : d.status === "queued" ? "Queued" : "Running"
|
|
18920
21713
|
}));
|
|
18921
21714
|
var init_subagents_ui = __esm(() => {
|
|
18922
21715
|
init_src();
|
|
@@ -19052,20 +21845,6 @@ var init_version_ui = __esm(() => {
|
|
|
19052
21845
|
init_application_version();
|
|
19053
21846
|
});
|
|
19054
21847
|
|
|
19055
|
-
// packages/core/src/session-display.ts
|
|
19056
|
-
function relativeTime(at, now, language = "en") {
|
|
19057
|
-
const minutes = Math.floor(Math.max(0, now - at) / 60000);
|
|
19058
|
-
if (minutes < 1)
|
|
19059
|
-
return language === "zh" ? "\u521A\u521A" : "now";
|
|
19060
|
-
const hours = Math.floor(minutes / 60), days = Math.floor(hours / 24);
|
|
19061
|
-
if (days >= 30)
|
|
19062
|
-
return new Date(at).toLocaleDateString(language === "zh" ? "zh-CN" : "en-GB");
|
|
19063
|
-
const value = days || hours || minutes;
|
|
19064
|
-
const unit = days ? ["\u5929", "d"] : hours ? ["\u5C0F\u65F6", "h"] : ["\u5206\u949F", "m"];
|
|
19065
|
-
return language === "zh" ? `${value} ${unit[0]}\u524D` : `${value}${unit[1]}`;
|
|
19066
|
-
}
|
|
19067
|
-
var sessionName = (session, empty = "New session") => session.title || session.firstPromptPreview || empty, messageTime = (session) => session.lastMessageAt ?? session.createdAt, byMessage = (a, b) => messageTime(b) - messageTime(a) || Number(b.id) - Number(a.id), byVisited = (a, b) => b.lastUsedAt - a.lastUsedAt || Number(b.id) - Number(a.id);
|
|
19068
|
-
|
|
19069
21848
|
// packages/tui/src/workspace.ts
|
|
19070
21849
|
function workspaceSessions(sessions, cwd) {
|
|
19071
21850
|
return sessions.filter((s) => s.workspaceRoot === cwd).sort(byMessage);
|
|
@@ -19117,6 +21896,7 @@ class NekoTuiApp {
|
|
|
19117
21896
|
#noticeTimer;
|
|
19118
21897
|
#compactionTimer;
|
|
19119
21898
|
#editor;
|
|
21899
|
+
#historyItems;
|
|
19120
21900
|
#footer = new StatusFooter;
|
|
19121
21901
|
#welcome = new WelcomeScreen;
|
|
19122
21902
|
#welcomeAttached = false;
|
|
@@ -19455,6 +22235,14 @@ class NekoTuiApp {
|
|
|
19455
22235
|
this.#manage(() => this.archiveSession());
|
|
19456
22236
|
return;
|
|
19457
22237
|
}
|
|
22238
|
+
if (trimmed === "/copy") {
|
|
22239
|
+
this.#copyLastAnswer();
|
|
22240
|
+
return;
|
|
22241
|
+
}
|
|
22242
|
+
if (trimmed === "/export" || trimmed.startsWith("/export ")) {
|
|
22243
|
+
this.#exportSession(trimmed.slice("/export".length));
|
|
22244
|
+
return;
|
|
22245
|
+
}
|
|
19458
22246
|
const chat = this.#chat;
|
|
19459
22247
|
if (chat === undefined)
|
|
19460
22248
|
return;
|
|
@@ -19555,6 +22343,44 @@ class NekoTuiApp {
|
|
|
19555
22343
|
this.#ui.requestRender();
|
|
19556
22344
|
}
|
|
19557
22345
|
}
|
|
22346
|
+
async#copyLastAnswer() {
|
|
22347
|
+
const outcome = await copyLastAnswer(this.#lastView?.items ?? [], {
|
|
22348
|
+
osc52: (sequence) => this.#terminal.write(sequence)
|
|
22349
|
+
});
|
|
22350
|
+
this.addNotice(outcome.message, outcome.level);
|
|
22351
|
+
}
|
|
22352
|
+
async#exportSession(argumentText) {
|
|
22353
|
+
const view = this.#lastView;
|
|
22354
|
+
const chat = this.#chat;
|
|
22355
|
+
const sessionId = this.#sessionId;
|
|
22356
|
+
if (view === undefined || chat === undefined) {
|
|
22357
|
+
this.addNotice("No session is open.", "warning");
|
|
22358
|
+
return;
|
|
22359
|
+
}
|
|
22360
|
+
let args;
|
|
22361
|
+
try {
|
|
22362
|
+
args = parseExportArgs(argumentText);
|
|
22363
|
+
} catch (error) {
|
|
22364
|
+
this.addNotice(messageOf(error), "warning", { wrap: true });
|
|
22365
|
+
return;
|
|
22366
|
+
}
|
|
22367
|
+
const summary = this.#gateway.client.directory.state.value?.sessions.find((s) => s.id === sessionId);
|
|
22368
|
+
const title = summary ? sessionName(summary, "") : "";
|
|
22369
|
+
this.addNotice("Exporting...");
|
|
22370
|
+
try {
|
|
22371
|
+
const { path, skippedImages } = await exportToFile({
|
|
22372
|
+
...args,
|
|
22373
|
+
cwd: this.#options.cwd ?? process.cwd(),
|
|
22374
|
+
source: { sessionId, title, model: view.model, cwd: view.cwd, exportedAt: new Date, items: view.items },
|
|
22375
|
+
loadImage: (image) => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset }))
|
|
22376
|
+
});
|
|
22377
|
+
const other = sessionId !== this.#sessionId ? ` (session ${title || sessionId})` : "";
|
|
22378
|
+
const skipped = skippedImages > 0 ? `; ${skippedImages} image(s) not embedded` : "";
|
|
22379
|
+
this.addNotice(`Exported${other} to ${path}${skipped}`, "info", { wrap: true, ttlMs: 20000 });
|
|
22380
|
+
} catch (error) {
|
|
22381
|
+
this.addNotice(`Export failed: ${messageOf(error)}`, "error", { wrap: true, ttlMs: 20000 });
|
|
22382
|
+
}
|
|
22383
|
+
}
|
|
19558
22384
|
abort() {
|
|
19559
22385
|
const chat = this.#chat;
|
|
19560
22386
|
if (chat === undefined)
|
|
@@ -19585,6 +22411,8 @@ class NekoTuiApp {
|
|
|
19585
22411
|
this.#sessionId = id;
|
|
19586
22412
|
this.#refreshSkills(handle);
|
|
19587
22413
|
this.#editor.setText(this.#texts.get(id) ?? "");
|
|
22414
|
+
this.#editor.setHistory([]);
|
|
22415
|
+
this.#historyItems = undefined;
|
|
19588
22416
|
this.#resetTranscript();
|
|
19589
22417
|
const view = handle.view;
|
|
19590
22418
|
if (view.value !== undefined)
|
|
@@ -19753,19 +22581,25 @@ class NekoTuiApp {
|
|
|
19753
22581
|
this.#agentsPanel = true;
|
|
19754
22582
|
this.#panel.pointerSelection = true;
|
|
19755
22583
|
this.#panel.agentNavigation = true;
|
|
19756
|
-
this.#panel.show("Agents", async () => subagentItems(this.#lastView?.subagents ?? []), async (value) => this.#agentDetail(
|
|
22584
|
+
this.#panel.show("Agents", async () => subagentItems(this.#lastView?.subagents ?? [], this.#lastView?.agents), async (value) => this.#agentDetail(value));
|
|
19757
22585
|
this.#ui.setFocus(this.#panel);
|
|
19758
22586
|
if (taskId !== undefined)
|
|
19759
22587
|
this.#panel.showDetail(this.#agentDetail(taskId));
|
|
19760
22588
|
}
|
|
19761
|
-
#agentDetail(
|
|
19762
|
-
|
|
22589
|
+
#agentDetail(target) {
|
|
22590
|
+
const round = typeof target === "number" ? this.#lastView?.subagents?.find((r) => r.taskId === target) : undefined;
|
|
22591
|
+
const id = typeof target === "string" ? target : round?.agentId ?? `agent-${round?.childId}`;
|
|
22592
|
+
let detail = this.#agentDetails.get(id);
|
|
19763
22593
|
if (!detail) {
|
|
19764
|
-
detail = new SubagentDetail(this.#gateway.client,
|
|
19765
|
-
this.#agentDetails.set(
|
|
22594
|
+
detail = new SubagentDetail(this.#gateway.client, id, this.#panel, () => this.#ui.requestRender());
|
|
22595
|
+
this.#agentDetails.set(id, detail);
|
|
19766
22596
|
}
|
|
19767
|
-
detail.
|
|
19768
|
-
|
|
22597
|
+
detail.identity = this.#lastView?.agents?.find((a) => a.agentId === id);
|
|
22598
|
+
detail.entry = this.#lastView?.subagents?.find((r) => r.taskId === (detail.identity?.activeRoundId ?? detail.identity?.lastRoundId));
|
|
22599
|
+
detail.open();
|
|
22600
|
+
if (typeof target === "number")
|
|
22601
|
+
detail.locate(target);
|
|
22602
|
+
return detail;
|
|
19769
22603
|
}
|
|
19770
22604
|
#closeOverlay() {
|
|
19771
22605
|
if (this.#panel.open)
|
|
@@ -19774,14 +22608,15 @@ class NekoTuiApp {
|
|
|
19774
22608
|
this.#login.close();
|
|
19775
22609
|
this.#ui.setFocus(this.#editor);
|
|
19776
22610
|
}
|
|
19777
|
-
addNotice(text, level = "info") {
|
|
22611
|
+
addNotice(text, level = "info", options = {}) {
|
|
19778
22612
|
clearTimeout(this.#noticeTimer);
|
|
19779
22613
|
this.#noticeTimer = setTimeout(() => {
|
|
19780
22614
|
this.#notices.clear();
|
|
19781
22615
|
this.#ui.requestRender();
|
|
19782
|
-
}, 5000);
|
|
22616
|
+
}, options.ttlMs ?? 5000);
|
|
19783
22617
|
this.#notices.clear();
|
|
19784
|
-
|
|
22618
|
+
const content = () => formatNotice(text, level);
|
|
22619
|
+
this.#notices.addChild(options.wrap ? new ThemedWrappedText(content) : new ThemedTruncatedText(content, 1, 0));
|
|
19785
22620
|
this.#ui.requestRender();
|
|
19786
22621
|
}
|
|
19787
22622
|
scheduleApply() {
|
|
@@ -19805,16 +22640,22 @@ class NekoTuiApp {
|
|
|
19805
22640
|
}
|
|
19806
22641
|
applyView(view) {
|
|
19807
22642
|
this.#lastView = view;
|
|
22643
|
+
if (this.#historyItems !== view.items) {
|
|
22644
|
+
this.#historyItems = view.items;
|
|
22645
|
+
this.#editor.setHistory(promptHistory(view.items));
|
|
22646
|
+
}
|
|
19808
22647
|
if (this.#chat)
|
|
19809
22648
|
this.#approval.update(view.subagents ?? []);
|
|
19810
22649
|
else
|
|
19811
22650
|
this.#approval.close();
|
|
19812
22651
|
if (this.#agentsPanel)
|
|
19813
|
-
this.#panel.update(subagentItems(view.subagents ?? []));
|
|
19814
|
-
for (const
|
|
19815
|
-
const detail = this.#agentDetails.get(
|
|
19816
|
-
if (detail)
|
|
19817
|
-
detail.
|
|
22652
|
+
this.#panel.update(subagentItems(view.subagents ?? [], view.agents));
|
|
22653
|
+
for (const identity of view.agents ?? []) {
|
|
22654
|
+
const detail = this.#agentDetails.get(identity.agentId);
|
|
22655
|
+
if (detail) {
|
|
22656
|
+
detail.identity = identity;
|
|
22657
|
+
detail.entry = view.subagents?.find((r) => r.taskId === (identity.activeRoundId ?? identity.lastRoundId));
|
|
22658
|
+
}
|
|
19818
22659
|
}
|
|
19819
22660
|
const imageModel = `${this.#sessionId}:${view.agent.model?.provider}/${view.agent.model?.modelId}`;
|
|
19820
22661
|
if (this.#imageWarningModel !== imageModel && view.items.some((i) => (i.type === "user" || i.type === "tool") && i.images?.length)) {
|
|
@@ -19932,7 +22773,11 @@ class NekoTuiApp {
|
|
|
19932
22773
|
summary: item.summary,
|
|
19933
22774
|
detail: item.detail,
|
|
19934
22775
|
phase: item.phase,
|
|
19935
|
-
output: item.output
|
|
22776
|
+
output: item.output,
|
|
22777
|
+
diff: item.diff,
|
|
22778
|
+
diffAdded: item.diffAdded,
|
|
22779
|
+
diffRemoved: item.diffRemoved,
|
|
22780
|
+
diffTruncated: item.diffTruncated
|
|
19936
22781
|
});
|
|
19937
22782
|
component.sync(item);
|
|
19938
22783
|
this.#items.set(item.key, { kind: "tool", component });
|
|
@@ -20014,7 +22859,7 @@ class NekoTuiApp {
|
|
|
20014
22859
|
#syncFooter(view) {
|
|
20015
22860
|
const usage = view.taskUsage ?? view.usage;
|
|
20016
22861
|
this.#footer.setStats({
|
|
20017
|
-
subagentCount: view.
|
|
22862
|
+
subagentCount: view.agents?.length ?? 0,
|
|
20018
22863
|
approvalCount: view.subagents?.reduce((n, d) => n + (d.approvalCount ?? 0), 0) ?? 0,
|
|
20019
22864
|
model: view.model,
|
|
20020
22865
|
thinkingLevel: view.agent.thinkingLevel,
|
|
@@ -20085,7 +22930,11 @@ function streamingCardState(call) {
|
|
|
20085
22930
|
output: call.output,
|
|
20086
22931
|
result: null,
|
|
20087
22932
|
durationMs: null,
|
|
20088
|
-
note: null
|
|
22933
|
+
note: null,
|
|
22934
|
+
diff: call.diff,
|
|
22935
|
+
diffAdded: call.diffAdded,
|
|
22936
|
+
diffRemoved: call.diffRemoved,
|
|
22937
|
+
diffTruncated: call.diffTruncated
|
|
20089
22938
|
};
|
|
20090
22939
|
}
|
|
20091
22940
|
function messageOf(error) {
|
|
@@ -20131,7 +22980,9 @@ var EXIT_COMMANDS, SESSIONS_COMMANDS, NEW_SESSION_VALUE = "__new__";
|
|
|
20131
22980
|
var init_tui = __esm(() => {
|
|
20132
22981
|
init_src();
|
|
20133
22982
|
init_application_updates();
|
|
22983
|
+
init_input_history();
|
|
20134
22984
|
init_approval_dock();
|
|
22985
|
+
init_clipboard_write();
|
|
20135
22986
|
init_assistant_message();
|
|
20136
22987
|
init_editor();
|
|
20137
22988
|
init_footer();
|
|
@@ -20143,6 +22994,7 @@ var init_tui = __esm(() => {
|
|
|
20143
22994
|
init_tool_execution();
|
|
20144
22995
|
init_user_message();
|
|
20145
22996
|
init_welcome();
|
|
22997
|
+
init_export_command();
|
|
20146
22998
|
init_file_completion();
|
|
20147
22999
|
init_gateway2();
|
|
20148
23000
|
init_help_ui();
|
|
@@ -20268,7 +23120,7 @@ function openBrowser(url) {
|
|
|
20268
23120
|
var init_open_browser = () => {};
|
|
20269
23121
|
|
|
20270
23122
|
// packages/web/src/gateway-spawn.ts
|
|
20271
|
-
import { spawn as
|
|
23123
|
+
import { spawn as spawn4 } from "child_process";
|
|
20272
23124
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
20273
23125
|
import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
|
|
20274
23126
|
import { dirname as dirname12, join as join13 } from "path";
|
|
@@ -20370,7 +23222,7 @@ function spawnGatewayProcess(options, socketPath, serverId) {
|
|
|
20370
23222
|
...options.model !== undefined ? ["--model", `${options.model.provider}/${options.model.modelId}`] : []
|
|
20371
23223
|
];
|
|
20372
23224
|
const command = gatewayCommand(args);
|
|
20373
|
-
return
|
|
23225
|
+
return spawn4(command.binary, command.args, { env: process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
20374
23226
|
}
|
|
20375
23227
|
function pipeChildLogs(child, onLog) {
|
|
20376
23228
|
if (onLog === undefined)
|
|
@@ -20460,10 +23312,10 @@ var init_gateway_spawn = __esm(() => {
|
|
|
20460
23312
|
import { createReadStream } from "fs";
|
|
20461
23313
|
import { stat as stat6 } from "fs/promises";
|
|
20462
23314
|
import { createServer as createServer2 } from "http";
|
|
20463
|
-
import { dirname as dirname13, extname as extname2, resolve as
|
|
23315
|
+
import { dirname as dirname13, extname as extname2, resolve as resolve6, sep as sep2 } from "path";
|
|
20464
23316
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
20465
23317
|
async function startWebServer(options = {}) {
|
|
20466
|
-
const staticDir =
|
|
23318
|
+
const staticDir = resolve6(options.staticDir ?? DEFAULT_STATIC_DIR);
|
|
20467
23319
|
const workspaceRoot = normalizeWorkspace(options.gateway?.cwd ?? process.cwd());
|
|
20468
23320
|
const gateway = await ensureNekoGateway({
|
|
20469
23321
|
...options.gateway ?? {},
|
|
@@ -20542,7 +23394,7 @@ async function handleHttp(request, response, info) {
|
|
|
20542
23394
|
}
|
|
20543
23395
|
async function serveStatic(pathname, method, response, staticDir) {
|
|
20544
23396
|
const cleanPath = decodeURIComponent(pathname);
|
|
20545
|
-
const candidate =
|
|
23397
|
+
const candidate = resolve6(staticDir, `.${cleanPath}`);
|
|
20546
23398
|
if (candidate !== staticDir && !candidate.startsWith(staticDir + sep2)) {
|
|
20547
23399
|
response.writeHead(403);
|
|
20548
23400
|
response.end();
|
|
@@ -20553,13 +23405,13 @@ async function serveStatic(pathname, method, response, staticDir) {
|
|
|
20553
23405
|
return;
|
|
20554
23406
|
});
|
|
20555
23407
|
if (stats?.isDirectory()) {
|
|
20556
|
-
file =
|
|
23408
|
+
file = resolve6(file, "index.html");
|
|
20557
23409
|
stats = await stat6(file).catch(() => {
|
|
20558
23410
|
return;
|
|
20559
23411
|
});
|
|
20560
23412
|
}
|
|
20561
23413
|
if (stats === undefined && extname2(candidate) === "") {
|
|
20562
|
-
file =
|
|
23414
|
+
file = resolve6(staticDir, "index.html");
|
|
20563
23415
|
stats = await stat6(file).catch(() => {
|
|
20564
23416
|
return;
|
|
20565
23417
|
});
|