pantheon-opencode 1.5.0 → 1.5.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/CHANGELOG.md +27 -0
- package/README.md +63 -2
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/pyproject.toml +2 -1
- package/scripts/doctor.mjs +228 -2
- package/scripts/install/state.mjs +27 -2
- package/scripts/sync-tui.mjs +11 -5
- package/scripts/zenodo-artifact.mjs +77 -4
- package/src/agents/mnemosyne.md +11 -1
- package/src/agents/zeus.md +1 -0
- package/src/mcp/memory_mcp_server.py +81 -27
- package/src/plugins/pantheon-hooks.ts +1 -1
- package/src/plugins/tui/dist/tui.d.ts +19 -24
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +22 -81
- package/src/plugins/tui/package-lock.json +5 -2
- package/src/plugins/tui/package.json +4 -1
- package/src/plugins/tui/src/index.tsx +54 -151
- package/src/mcp/toon_codec.py +0 -489
|
@@ -978,8 +978,6 @@ export type DelegationEntry = {
|
|
|
978
978
|
updatedAt: number | null
|
|
979
979
|
timedOut: boolean
|
|
980
980
|
description: string
|
|
981
|
-
/** True while the panel is waiting for pantheon_delegation_read. */
|
|
982
|
-
read?: boolean
|
|
983
981
|
// NOTE: the nested/tree view is BACKLOG. `session.children` returns direct
|
|
984
982
|
// children only, so no real grandchild rows exist yet; the parentTaskID /
|
|
985
983
|
// childCount fields + tree-connector helpers were removed as dead code.
|
|
@@ -1365,13 +1363,7 @@ export function delegationElapsed(entry: DelegationEntry, now: number): string {
|
|
|
1365
1363
|
|
|
1366
1364
|
/** The activity labels shown by the animated row. Keeping this pure makes the
|
|
1367
1365
|
* state machine testable without booting OpenCode's renderer. */
|
|
1368
|
-
export type DelegationActivity =
|
|
1369
|
-
| 'delegating'
|
|
1370
|
-
| 'working'
|
|
1371
|
-
| 'reading'
|
|
1372
|
-
| 'completed'
|
|
1373
|
-
| 'error'
|
|
1374
|
-
| 'cancelled'
|
|
1366
|
+
export type DelegationActivity = 'delegating' | 'working' | 'completed' | 'error' | 'cancelled'
|
|
1375
1367
|
|
|
1376
1368
|
export function delegationActivity(entry: DelegationEntry): DelegationActivity {
|
|
1377
1369
|
if (entry.state === 'completed') return 'completed'
|
|
@@ -1382,7 +1374,6 @@ export function delegationActivity(entry: DelegationEntry): DelegationActivity {
|
|
|
1382
1374
|
)
|
|
1383
1375
|
return 'error'
|
|
1384
1376
|
if (entry.state === 'cancelled') return 'cancelled'
|
|
1385
|
-
if (entry.read) return 'reading'
|
|
1386
1377
|
if (entry.alias.startsWith('live-') && entry.taskID === undefined) return 'delegating'
|
|
1387
1378
|
return 'working'
|
|
1388
1379
|
}
|
|
@@ -1394,8 +1385,6 @@ export function delegationActivityLabel(entry: DelegationEntry): string {
|
|
|
1394
1385
|
return 'DELEGATING'
|
|
1395
1386
|
case 'working':
|
|
1396
1387
|
return 'WORKING'
|
|
1397
|
-
case 'reading':
|
|
1398
|
-
return 'READING RESULT'
|
|
1399
1388
|
case 'completed':
|
|
1400
1389
|
return entry.timedOut ? 'DONE (TIMED OUT)' : 'DONE'
|
|
1401
1390
|
case 'error':
|
|
@@ -1560,8 +1549,7 @@ export function mergeChildDelegationSources(
|
|
|
1560
1549
|
const incoming = toDelegationEntry(liveEntry)
|
|
1561
1550
|
// A native task() live part never carries a report alias — it is a
|
|
1562
1551
|
// children-only row by definition whether it lands on a new row or
|
|
1563
|
-
// upgrades an existing
|
|
1564
|
-
// children-only one. pantheon_delegate pending parts keep source 'live'.
|
|
1552
|
+
// upgrades an existing children-only one.
|
|
1565
1553
|
const isNativeLive = liveEntry.tool === 'task' && liveEntry.alias === null
|
|
1566
1554
|
if (isNativeLive) {
|
|
1567
1555
|
// Native task() rows carry no report alias — keep the per-call
|
|
@@ -1589,12 +1577,12 @@ export function mergeChildDelegationSources(
|
|
|
1589
1577
|
if (existing === undefined) continue
|
|
1590
1578
|
// Any terminal state is authoritative — a child session that went idle
|
|
1591
1579
|
// correctly derives 'completed' via childStatusToState before the MD
|
|
1592
|
-
// report is written. The live tool-part channel stays 'running'
|
|
1593
|
-
//
|
|
1594
|
-
//
|
|
1580
|
+
// report is written. The live tool-part channel stays 'running' for the
|
|
1581
|
+
// whole call, so allowing it to overwrite a terminal state would flip
|
|
1582
|
+
// completed → running (the bug this fixes).
|
|
1595
1583
|
//
|
|
1596
1584
|
// When the existing entry IS terminal, we still absorb live metadata
|
|
1597
|
-
// (alias, agent
|
|
1585
|
+
// (alias, agent) but preserve the terminal state.
|
|
1598
1586
|
if (existing.state !== 'running') {
|
|
1599
1587
|
if (liveEntry.alias !== null && existing.alias !== incoming.alias) {
|
|
1600
1588
|
existing.alias = incoming.alias
|
|
@@ -1602,9 +1590,6 @@ export function mergeChildDelegationSources(
|
|
|
1602
1590
|
if (incoming.agent !== 'agent' && existing.agent !== incoming.agent) {
|
|
1603
1591
|
existing.agent = incoming.agent
|
|
1604
1592
|
}
|
|
1605
|
-
if (incoming.read && !existing.read) {
|
|
1606
|
-
existing.read = true
|
|
1607
|
-
}
|
|
1608
1593
|
continue
|
|
1609
1594
|
}
|
|
1610
1595
|
result[index] = {
|
|
@@ -1617,10 +1602,8 @@ export function mergeChildDelegationSources(
|
|
|
1617
1602
|
state: incoming.state,
|
|
1618
1603
|
startedAt: Math.min(existing.startedAt, incoming.startedAt),
|
|
1619
1604
|
updatedAt: incoming.updatedAt,
|
|
1620
|
-
read: incoming.read,
|
|
1621
1605
|
// A native task() live upgrade must not flip a children-only row to
|
|
1622
|
-
// 'live' (that would drop the children-only provenance)
|
|
1623
|
-
// upgrades still take source 'live'.
|
|
1606
|
+
// 'live' (that would drop the children-only provenance).
|
|
1624
1607
|
source: isNativeLive ? existing.source : 'live',
|
|
1625
1608
|
}
|
|
1626
1609
|
}
|
|
@@ -1630,12 +1613,11 @@ export function mergeChildDelegationSources(
|
|
|
1630
1613
|
}
|
|
1631
1614
|
|
|
1632
1615
|
/* ─── Live tool-call lifecycle (agent-sidebar pattern) ─────
|
|
1633
|
-
*
|
|
1616
|
+
* Refresh trigger for jobs born while opencode is open. The TUI event bus
|
|
1634
1617
|
* (api.event.on) delivers `message.part.updated` for every part change;
|
|
1635
|
-
* we only care about tool parts whose `tool` is
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
* (blocking until terminal → closes the entry). Shape-adapted from the
|
|
1618
|
+
* we only care about tool parts whose `tool` is the native `task` subagent
|
|
1619
|
+
* tool (parentID === caller mechanism — its rows render `nat:`); the panel
|
|
1620
|
+
* rows themselves come from the children channel. Shape-adapted from the
|
|
1639
1621
|
* SDK v2 ToolPart but duck-typed so the pure helpers are testable without
|
|
1640
1622
|
* the SDK. */
|
|
1641
1623
|
|
|
@@ -1655,27 +1637,25 @@ export type DelegationToolPart = {
|
|
|
1655
1637
|
}
|
|
1656
1638
|
}
|
|
1657
1639
|
|
|
1658
|
-
/** One live delegation tracked in-memory, keyed by the
|
|
1640
|
+
/** One live delegation tracked in-memory, keyed by the task callID. */
|
|
1659
1641
|
export type LiveDelegationEntry = {
|
|
1660
|
-
/** Tool call id of the
|
|
1642
|
+
/** Tool call id of the task part (stable across events). */
|
|
1661
1643
|
callID: string
|
|
1662
1644
|
/** Part id (for message.part.removed cleanup). */
|
|
1663
1645
|
partID: string
|
|
1664
1646
|
/** Parent session the delegation was launched from. */
|
|
1665
1647
|
sessionID: string
|
|
1666
|
-
tool: '
|
|
1667
|
-
/** Agent name (from the
|
|
1648
|
+
tool: 'task'
|
|
1649
|
+
/** Agent name (from the task input args). */
|
|
1668
1650
|
agent: string
|
|
1669
1651
|
description: string
|
|
1670
|
-
/** Known
|
|
1652
|
+
/** Known once the task completes and its output carries a marker. */
|
|
1671
1653
|
alias: string | null
|
|
1672
|
-
/** Child session id (parsed from the
|
|
1654
|
+
/** Child session id (parsed from the task output, when present). */
|
|
1673
1655
|
taskID: string | null
|
|
1674
1656
|
state: 'running' | 'completed' | 'error' | 'cancelled'
|
|
1675
1657
|
startedAt: number
|
|
1676
1658
|
updatedAt: number | null
|
|
1677
|
-
/** True once a pantheon_delegation_read for this job has been observed. */
|
|
1678
|
-
read: boolean
|
|
1679
1659
|
}
|
|
1680
1660
|
|
|
1681
1661
|
/** Result of parsing one tool part into lifecycle-relevant fields. */
|
|
@@ -1683,9 +1663,9 @@ export type ParsedDelegationToolPart = {
|
|
|
1683
1663
|
callID: string
|
|
1684
1664
|
partID: string
|
|
1685
1665
|
sessionID: string
|
|
1686
|
-
tool: '
|
|
1687
|
-
/**
|
|
1688
|
-
agent: string
|
|
1666
|
+
tool: 'task'
|
|
1667
|
+
/** Agent name from the task input args ('agent' fallback when absent). */
|
|
1668
|
+
agent: string
|
|
1689
1669
|
description: string
|
|
1690
1670
|
status: 'pending' | 'running' | 'completed' | 'error'
|
|
1691
1671
|
alias: string | null
|
|
@@ -1694,29 +1674,21 @@ export type ParsedDelegationToolPart = {
|
|
|
1694
1674
|
endAt: number | null
|
|
1695
1675
|
}
|
|
1696
1676
|
|
|
1697
|
-
/** Alias in the
|
|
1677
|
+
/** Alias in the task output: "Delegated to apollo: [apo-1] (task …)". */
|
|
1698
1678
|
const DELEGATE_ALIAS_PATTERN = /\[([a-z]{2,8}-\d+)\]/i
|
|
1699
|
-
/** Child task id in the
|
|
1679
|
+
/** Child task id in the task output: "(task ses_child_9)". */
|
|
1700
1680
|
const DELEGATE_TASKID_PATTERN = /\(task\s+([a-z0-9_]+)\)/i
|
|
1701
|
-
/** Plain alias, as passed to pantheon_delegation_read input.id: "apo-1". */
|
|
1702
|
-
const READ_ALIAS_PATTERN = /^[a-z]{2,8}-\d+$/i
|
|
1703
1681
|
|
|
1704
1682
|
/** Extract the tool name + args from a `message.part.updated` part and
|
|
1705
1683
|
* reduce it to what the panel needs. Returns null for anything that is
|
|
1706
|
-
* not
|
|
1707
|
-
*
|
|
1708
|
-
* or is missing its callID. */
|
|
1684
|
+
* not the native `task` subagent tool (parentID === caller mechanism —
|
|
1685
|
+
* its children render `nat:`), or is missing its callID. */
|
|
1709
1686
|
export function parseDelegationToolPart(
|
|
1710
1687
|
part: DelegationToolPart,
|
|
1711
1688
|
now = Date.now(),
|
|
1712
1689
|
): ParsedDelegationToolPart | null {
|
|
1713
1690
|
if (part.type !== 'tool') return null
|
|
1714
|
-
if (
|
|
1715
|
-
part.tool !== 'pantheon_delegate' &&
|
|
1716
|
-
part.tool !== 'pantheon_delegation_read' &&
|
|
1717
|
-
part.tool !== 'task'
|
|
1718
|
-
)
|
|
1719
|
-
return null
|
|
1691
|
+
if (part.tool !== 'task') return null
|
|
1720
1692
|
const callID = part.callID
|
|
1721
1693
|
if (callID === undefined || callID === '') return null
|
|
1722
1694
|
const sessionID = part.sessionID ?? ''
|
|
@@ -1728,29 +1700,6 @@ export function parseDelegationToolPart(
|
|
|
1728
1700
|
const startedAt = state.time?.start ?? now
|
|
1729
1701
|
const endAt = state.time?.end ?? null
|
|
1730
1702
|
|
|
1731
|
-
if (part.tool === 'pantheon_delegation_read') {
|
|
1732
|
-
const target = typeof input.id === 'string' ? input.id : null
|
|
1733
|
-
let alias: string | null = null
|
|
1734
|
-
let taskID: string | null = null
|
|
1735
|
-
if (target !== null) {
|
|
1736
|
-
if (READ_ALIAS_PATTERN.test(target)) alias = target
|
|
1737
|
-
else if (target.startsWith('ses_')) taskID = target // raw child session id
|
|
1738
|
-
}
|
|
1739
|
-
return {
|
|
1740
|
-
callID,
|
|
1741
|
-
partID: part.id ?? '',
|
|
1742
|
-
sessionID,
|
|
1743
|
-
tool: 'pantheon_delegation_read',
|
|
1744
|
-
agent: null,
|
|
1745
|
-
description: '',
|
|
1746
|
-
status,
|
|
1747
|
-
alias,
|
|
1748
|
-
taskID,
|
|
1749
|
-
startedAt,
|
|
1750
|
-
endAt,
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
1703
|
const agent =
|
|
1755
1704
|
typeof input.agent === 'string'
|
|
1756
1705
|
? input.agent
|
|
@@ -1763,9 +1712,9 @@ export function parseDelegationToolPart(
|
|
|
1763
1712
|
: typeof input.prompt === 'string'
|
|
1764
1713
|
? (input.prompt as string).slice(0, 120)
|
|
1765
1714
|
: ''
|
|
1766
|
-
// The alias/taskID only exist once the
|
|
1767
|
-
// returned in its output); a running/pending part has neither.
|
|
1768
|
-
// `task`
|
|
1715
|
+
// The alias/taskID only exist once the task COMPLETES (they are
|
|
1716
|
+
// returned in its output); a running/pending part has neither. A native
|
|
1717
|
+
// `task` part never carries a report alias — the children channel supplies
|
|
1769
1718
|
// the child session id and the row's identity.
|
|
1770
1719
|
let alias: string | null = null
|
|
1771
1720
|
let taskID: string | null = null
|
|
@@ -1778,7 +1727,7 @@ export function parseDelegationToolPart(
|
|
|
1778
1727
|
callID,
|
|
1779
1728
|
partID: part.id ?? '',
|
|
1780
1729
|
sessionID,
|
|
1781
|
-
tool:
|
|
1730
|
+
tool: 'task',
|
|
1782
1731
|
agent,
|
|
1783
1732
|
description,
|
|
1784
1733
|
status,
|
|
@@ -1789,20 +1738,6 @@ export function parseDelegationToolPart(
|
|
|
1789
1738
|
}
|
|
1790
1739
|
}
|
|
1791
1740
|
|
|
1792
|
-
/** Find a live entry by alias or taskID (read parts resolve by id). */
|
|
1793
|
-
function findLiveByTarget(
|
|
1794
|
-
map: Map<string, LiveDelegationEntry>,
|
|
1795
|
-
alias: string | null,
|
|
1796
|
-
taskID: string | null,
|
|
1797
|
-
): LiveDelegationEntry | undefined {
|
|
1798
|
-
if (alias === null && taskID === null) return undefined
|
|
1799
|
-
for (const entry of map.values()) {
|
|
1800
|
-
if (alias !== null && entry.alias === alias) return entry
|
|
1801
|
-
if (taskID !== null && entry.taskID === taskID) return entry
|
|
1802
|
-
}
|
|
1803
|
-
return undefined
|
|
1804
|
-
}
|
|
1805
|
-
|
|
1806
1741
|
/** Apply one tool part to the live map. Returns true when the map changed.
|
|
1807
1742
|
* Pure w.r.t. I/O — only mutates `map`. */
|
|
1808
1743
|
export function reduceDelegationToolPart(
|
|
@@ -1813,34 +1748,11 @@ export function reduceDelegationToolPart(
|
|
|
1813
1748
|
const parsed = parseDelegationToolPart(part, now)
|
|
1814
1749
|
if (parsed === null) return false
|
|
1815
1750
|
|
|
1816
|
-
//
|
|
1817
|
-
//
|
|
1818
|
-
//
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
if (target === undefined) return false
|
|
1822
|
-
let changed = false
|
|
1823
|
-
if (!target.read) {
|
|
1824
|
-
target.read = true
|
|
1825
|
-
changed = true
|
|
1826
|
-
}
|
|
1827
|
-
if (parsed.status === 'completed' && target.state === 'running') {
|
|
1828
|
-
target.state = 'completed'
|
|
1829
|
-
target.updatedAt = parsed.endAt ?? now
|
|
1830
|
-
changed = true
|
|
1831
|
-
} else if (parsed.status === 'error' && target.state === 'running') {
|
|
1832
|
-
target.state = 'error'
|
|
1833
|
-
target.updatedAt = parsed.endAt ?? now
|
|
1834
|
-
changed = true
|
|
1835
|
-
}
|
|
1836
|
-
return changed
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
// Delegate tool (pantheon_delegate AND native task): pending/running →
|
|
1840
|
-
// job launched (running). A COMPLETED delegate tool only means the job was
|
|
1841
|
-
// registered — it stays running and we pick up alias + taskID from the
|
|
1842
|
-
// output. Native `task` parts never yield a report alias, so their rows
|
|
1843
|
-
// stay identity-less until the children channel resolves them.
|
|
1751
|
+
// Task tool: pending/running → job launched (running). A COMPLETED task
|
|
1752
|
+
// only means the call returned — the child session keeps running, and we
|
|
1753
|
+
// pick up alias + taskID from the output when present. Native `task` parts
|
|
1754
|
+
// never yield a report alias, so their rows stay identity-less until the
|
|
1755
|
+
// children channel resolves them.
|
|
1844
1756
|
const existing = map.get(parsed.callID)
|
|
1845
1757
|
if (parsed.status === 'error') {
|
|
1846
1758
|
if (existing !== undefined && existing.state === 'error' && existing.updatedAt === parsed.endAt)
|
|
@@ -1850,14 +1762,13 @@ export function reduceDelegationToolPart(
|
|
|
1850
1762
|
partID: parsed.partID,
|
|
1851
1763
|
sessionID: parsed.sessionID,
|
|
1852
1764
|
tool: parsed.tool,
|
|
1853
|
-
agent: parsed.agent
|
|
1765
|
+
agent: parsed.agent,
|
|
1854
1766
|
description: parsed.description,
|
|
1855
1767
|
alias: existing?.alias ?? null,
|
|
1856
1768
|
taskID: existing?.taskID ?? null,
|
|
1857
1769
|
state: 'error',
|
|
1858
1770
|
startedAt: existing?.startedAt ?? parsed.startedAt,
|
|
1859
1771
|
updatedAt: parsed.endAt ?? now,
|
|
1860
|
-
read: existing?.read ?? false,
|
|
1861
1772
|
})
|
|
1862
1773
|
return true
|
|
1863
1774
|
}
|
|
@@ -1867,14 +1778,13 @@ export function reduceDelegationToolPart(
|
|
|
1867
1778
|
partID: parsed.partID,
|
|
1868
1779
|
sessionID: parsed.sessionID,
|
|
1869
1780
|
tool: parsed.tool,
|
|
1870
|
-
agent: parsed.agent
|
|
1781
|
+
agent: parsed.agent,
|
|
1871
1782
|
description: parsed.description,
|
|
1872
1783
|
alias: parsed.alias,
|
|
1873
1784
|
taskID: parsed.taskID,
|
|
1874
1785
|
state: 'running',
|
|
1875
1786
|
startedAt: parsed.startedAt,
|
|
1876
1787
|
updatedAt: null,
|
|
1877
|
-
read: false,
|
|
1878
1788
|
})
|
|
1879
1789
|
return true
|
|
1880
1790
|
}
|
|
@@ -1919,14 +1829,14 @@ export function removeDelegationEntry(
|
|
|
1919
1829
|
return false
|
|
1920
1830
|
}
|
|
1921
1831
|
|
|
1922
|
-
/** Collect
|
|
1832
|
+
/** Collect native task tool parts from a session's messages.
|
|
1923
1833
|
* Messages may carry their parts inline (duck-typed `msg.parts`); when
|
|
1924
1834
|
* they don't, the optional `getParts(messageID)` callback is used (the TUI
|
|
1925
1835
|
* SDK exposes `api.state.part(messageID)`). The native `task` tool spawns a
|
|
1926
|
-
* child session with parentID = caller
|
|
1927
|
-
*
|
|
1928
|
-
*
|
|
1929
|
-
*
|
|
1836
|
+
* child session with parentID = caller, so its parts feed the live-map as
|
|
1837
|
+
* the refresh signal (rows come from the children channel). Pure w.r.t.
|
|
1838
|
+
* I/O — used by the mount re-scan to re-seed the live map after
|
|
1839
|
+
* compaction/attach. */
|
|
1930
1840
|
export function collectDelegationToolParts(
|
|
1931
1841
|
messages: readonly { id?: string; parts?: unknown[] }[] | undefined,
|
|
1932
1842
|
getParts?: (messageID: string) => readonly unknown[] | undefined,
|
|
@@ -1942,12 +1852,7 @@ export function collectDelegationToolParts(
|
|
|
1942
1852
|
if (!parts) continue
|
|
1943
1853
|
for (const raw of parts) {
|
|
1944
1854
|
const part = raw as DelegationToolPart
|
|
1945
|
-
if (
|
|
1946
|
-
part?.type === 'tool' &&
|
|
1947
|
-
(part.tool === 'pantheon_delegate' ||
|
|
1948
|
-
part.tool === 'pantheon_delegation_read' ||
|
|
1949
|
-
part.tool === 'task')
|
|
1950
|
-
) {
|
|
1855
|
+
if (part?.type === 'tool' && part.tool === 'task') {
|
|
1951
1856
|
out.push(part)
|
|
1952
1857
|
}
|
|
1953
1858
|
}
|
|
@@ -1972,7 +1877,7 @@ export function seedLiveDelegationMap(
|
|
|
1972
1877
|
}
|
|
1973
1878
|
|
|
1974
1879
|
/** Convert a live entry into the shared display shape. Alias falls back to
|
|
1975
|
-
* a `live-<callID>` prefix while the
|
|
1880
|
+
* a `live-<callID>` prefix while the task call has not completed yet. */
|
|
1976
1881
|
export function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry {
|
|
1977
1882
|
return {
|
|
1978
1883
|
alias: live.alias ?? `live-${live.callID.slice(0, 8)}`,
|
|
@@ -1984,7 +1889,6 @@ export function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry {
|
|
|
1984
1889
|
updatedAt: live.updatedAt,
|
|
1985
1890
|
timedOut: false,
|
|
1986
1891
|
description: live.description,
|
|
1987
|
-
read: live.read,
|
|
1988
1892
|
source: 'live',
|
|
1989
1893
|
}
|
|
1990
1894
|
}
|
|
@@ -2049,7 +1953,7 @@ export function filterDelegationsToSession(
|
|
|
2049
1953
|
|
|
2050
1954
|
/* ─── Children channel (primary source, delegations-sidebar pattern) ────
|
|
2051
1955
|
* `api.client.session.children` returns the child sessions of the current
|
|
2052
|
-
* session — every
|
|
1956
|
+
* session — every native task() call spawns one (parentID = caller). The
|
|
2053
1957
|
* pure helpers here turn those children + the md reports into the display
|
|
2054
1958
|
* list, and navigate to a child session on click. */
|
|
2055
1959
|
|
|
@@ -2384,7 +2288,7 @@ export function ceilingDelegationList(
|
|
|
2384
2288
|
return { visible, hidden: hiddenActive + hiddenTerminal, hiddenActive, hiddenTerminal }
|
|
2385
2289
|
}
|
|
2386
2290
|
|
|
2387
|
-
/** Split a display list into native task() rows vs
|
|
2291
|
+
/** Split a display list into native task() rows vs pantheon report rows.
|
|
2388
2292
|
* Native = source 'children-only' (no delegate report); everything else counts
|
|
2389
2293
|
* as pantheon. Pure — powers the hooks.log line. */
|
|
2390
2294
|
export function countDelegationSources(entries: readonly DelegationEntry[]): {
|
|
@@ -2417,8 +2321,8 @@ export function formatPanelLogLine(
|
|
|
2417
2321
|
* report still renders: description from its title, agent from the child
|
|
2418
2322
|
* itself (fallback 'agent'), state derived from its status, startedAt from
|
|
2419
2323
|
* time.created. A report-less child is a NATIVE task() child (every
|
|
2420
|
-
* child of the current session —
|
|
2421
|
-
*
|
|
2324
|
+
* child of the current session — the native `task()` tool — carries
|
|
2325
|
+
* parentID = caller), so it gets source 'children-only', a
|
|
2422
2326
|
* per-child alias 'native-<last4 of the child id>' (one identity per native
|
|
2423
2327
|
* row) instead of a report alias. The 'task nativa' description fallback
|
|
2424
2328
|
* keeps the row non-empty when the child carries no title.
|
|
@@ -2821,7 +2725,7 @@ function View(props: {
|
|
|
2821
2725
|
|
|
2822
2726
|
// ── Delegations: session.children (PRIMARY) + md reports (enrichment) ──
|
|
2823
2727
|
// The panel's source of truth is the SDK child-session API
|
|
2824
|
-
// (`api.client.session.children`) — every
|
|
2728
|
+
// (`api.client.session.children`) — every native task() call spawns a child
|
|
2825
2729
|
// session with parentID = this session, so children ARE the delegation
|
|
2826
2730
|
// list (delegations-sidebar pattern). The md channel
|
|
2827
2731
|
// (.pantheon/delegations) enriches each child with alias/agent/description
|
|
@@ -3168,16 +3072,15 @@ const tui: TuiPlugin = (api, _options, _meta) => {
|
|
|
3168
3072
|
// Vendored feature (MIT): AI subscription usage gauges.
|
|
3169
3073
|
void setupUsageBar(api) // async init — never blocks sidebar registration
|
|
3170
3074
|
|
|
3171
|
-
// ── Live delegation store (
|
|
3075
|
+
// ── Live delegation store (tool-part tracker, kept as a REFRESH
|
|
3172
3076
|
// TRIGGER) ──
|
|
3173
3077
|
// The Delegations panel's PRIMARY source is `api.client.session.children`
|
|
3174
3078
|
// (delegations-sidebar pattern) — `message.part.updated` may not fire for
|
|
3175
|
-
//
|
|
3176
|
-
// lifecycle below still tracks
|
|
3177
|
-
//
|
|
3178
|
-
//
|
|
3179
|
-
//
|
|
3180
|
-
// keeps the panel working (never crash).
|
|
3079
|
+
// the native task tool on runtime 1.18.13 (the "(0)" symptom). The
|
|
3080
|
+
// tool-part lifecycle below still tracks `task` parts and bumps a version
|
|
3081
|
+
// signal the View subscribes to: when part events DO arrive, the panel
|
|
3082
|
+
// re-fetches children. Fail-open: if the events API is unavailable nothing
|
|
3083
|
+
// subscribes and the 1s safety poll keeps the panel working (never crash).
|
|
3181
3084
|
const [liveVersion, setLiveVersion] = createSignal(0)
|
|
3182
3085
|
const liveStore: LiveDelegationStore = {
|
|
3183
3086
|
map: new Map<string, LiveDelegationEntry>(),
|