@thoth-agents/pi-thoth-theme 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.ts +202 -24
- package/package.json +2 -2
package/dist/index.ts
CHANGED
|
@@ -1745,43 +1745,71 @@ function decorateEditor(editor, deps) {
|
|
|
1745
1745
|
import { truncateToWidth as truncateToWidth7, visibleWidth as visibleWidth6 } from "@earendil-works/pi-tui";
|
|
1746
1746
|
function createWorkingState(requestRender) {
|
|
1747
1747
|
let startedAt;
|
|
1748
|
+
let pendingBackground = 0;
|
|
1748
1749
|
let ticker;
|
|
1749
1750
|
let disposed = false;
|
|
1750
1751
|
function stop() {
|
|
1751
1752
|
if (ticker !== void 0) clearInterval(ticker);
|
|
1752
1753
|
ticker = void 0;
|
|
1753
|
-
|
|
1754
|
+
}
|
|
1755
|
+
function syncTicker() {
|
|
1756
|
+
if (startedAt === void 0 && pendingBackground === 0) {
|
|
1757
|
+
stop();
|
|
1758
|
+
} else if (ticker === void 0) {
|
|
1759
|
+
ticker = setInterval(requestRender, 50);
|
|
1760
|
+
ticker.unref?.();
|
|
1761
|
+
}
|
|
1762
|
+
requestRender();
|
|
1754
1763
|
}
|
|
1755
1764
|
return {
|
|
1756
1765
|
get isWorking() {
|
|
1757
|
-
return startedAt !== void 0;
|
|
1766
|
+
return startedAt !== void 0 || pendingBackground > 0;
|
|
1758
1767
|
},
|
|
1759
1768
|
start() {
|
|
1760
1769
|
if (disposed) return;
|
|
1761
|
-
stop();
|
|
1762
1770
|
startedAt = Date.now();
|
|
1763
|
-
|
|
1764
|
-
ticker.unref?.();
|
|
1765
|
-
requestRender();
|
|
1771
|
+
syncTicker();
|
|
1766
1772
|
},
|
|
1767
1773
|
end() {
|
|
1768
1774
|
if (disposed) return;
|
|
1769
|
-
|
|
1770
|
-
|
|
1775
|
+
startedAt = void 0;
|
|
1776
|
+
syncTicker();
|
|
1777
|
+
},
|
|
1778
|
+
setPendingBackground(count) {
|
|
1779
|
+
if (disposed || pendingBackground === count) return;
|
|
1780
|
+
pendingBackground = count;
|
|
1781
|
+
syncTicker();
|
|
1771
1782
|
},
|
|
1772
1783
|
status(indicator, width, styleMuted = (text) => text, frame, mode = "nerd") {
|
|
1773
1784
|
const ready = `${icon("ready", mode)} ready`;
|
|
1774
1785
|
const separator2 = icon("separator", mode);
|
|
1786
|
+
const now = frame?.now ?? Date.now();
|
|
1787
|
+
const fallback = () => {
|
|
1788
|
+
if (pendingBackground === 0)
|
|
1789
|
+
return styleMuted(truncateToWidth7(ready, width, ""));
|
|
1790
|
+
const glyphs = frames("workingFrames", mode);
|
|
1791
|
+
const glyph = glyphs[Math.floor(now / 200) % glyphs.length];
|
|
1792
|
+
const label2 = renderWorkingIndicator(
|
|
1793
|
+
`${glyph} working${icon("ellipsis", mode)}`,
|
|
1794
|
+
frame ?? createBreathingFrame(now),
|
|
1795
|
+
styleMuted,
|
|
1796
|
+
glyphs
|
|
1797
|
+
);
|
|
1798
|
+
return truncateToWidth7(
|
|
1799
|
+
`${label2}${styleMuted(` ${separator2} ${pendingBackground} bg`)}`,
|
|
1800
|
+
width,
|
|
1801
|
+
""
|
|
1802
|
+
);
|
|
1803
|
+
};
|
|
1775
1804
|
if (!indicator || typeof indicator !== "object" || !("renderInBorder" in indicator) || typeof indicator.renderInBorder !== "function") {
|
|
1776
|
-
return
|
|
1805
|
+
return fallback();
|
|
1777
1806
|
}
|
|
1778
1807
|
const working = "kind" in indicator && indicator.kind === "working";
|
|
1779
|
-
const now = frame?.now ?? Date.now();
|
|
1780
1808
|
const elapsed = working && startedAt !== void 0 ? ` ${separator2} ${formatDuration(Math.floor((now - startedAt) / 1e3) * 1e3)}` : "";
|
|
1781
1809
|
const nativeWidth = Math.max(1, width - visibleWidth6(elapsed));
|
|
1782
1810
|
const native = indicator.renderInBorder(nativeWidth);
|
|
1783
1811
|
if (typeof native !== "string" || visibleWidth6(native) === 0) {
|
|
1784
|
-
return
|
|
1812
|
+
return fallback();
|
|
1785
1813
|
}
|
|
1786
1814
|
const fitted = truncateToWidth7(native, nativeWidth, "");
|
|
1787
1815
|
const label = working && startedAt !== void 0 ? renderWorkingIndicator(
|
|
@@ -1798,11 +1826,107 @@ function createWorkingState(requestRender) {
|
|
|
1798
1826
|
},
|
|
1799
1827
|
dispose() {
|
|
1800
1828
|
disposed = true;
|
|
1829
|
+
startedAt = void 0;
|
|
1830
|
+
pendingBackground = 0;
|
|
1801
1831
|
stop();
|
|
1802
1832
|
}
|
|
1803
1833
|
};
|
|
1804
1834
|
}
|
|
1805
1835
|
|
|
1836
|
+
// src/status-line/orca-child-hold.ts
|
|
1837
|
+
var memoryKey = /* @__PURE__ */ Symbol.for("@thoth-agents/pi-thoth-theme/orca-child-holds");
|
|
1838
|
+
function createOrcaChildHold(events) {
|
|
1839
|
+
const processState = globalThis;
|
|
1840
|
+
processState[memoryKey] ??= /* @__PURE__ */ new Map();
|
|
1841
|
+
const sessions = processState[memoryKey];
|
|
1842
|
+
let announced = /* @__PURE__ */ new Set();
|
|
1843
|
+
let subagents = [];
|
|
1844
|
+
let background = [];
|
|
1845
|
+
let timer;
|
|
1846
|
+
let disposed = false;
|
|
1847
|
+
function reconcile(prefix, tasks) {
|
|
1848
|
+
const live = /* @__PURE__ */ new Set();
|
|
1849
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1850
|
+
for (const task of tasks) {
|
|
1851
|
+
if (disposed) return;
|
|
1852
|
+
const id = `${prefix}${task.id}`;
|
|
1853
|
+
if (!byId.has(id)) byId.set(id, task);
|
|
1854
|
+
if (!task.live) continue;
|
|
1855
|
+
live.add(id);
|
|
1856
|
+
if (announced.has(id)) continue;
|
|
1857
|
+
announced.add(id);
|
|
1858
|
+
events.emit("task:subagent:lifecycle", {
|
|
1859
|
+
id,
|
|
1860
|
+
status: "started",
|
|
1861
|
+
agent: task.agent,
|
|
1862
|
+
...task.description ? { description: task.description } : {}
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
for (const id of announced) {
|
|
1866
|
+
if (disposed) return;
|
|
1867
|
+
if (!id.startsWith(prefix) || live.has(id)) continue;
|
|
1868
|
+
announced.delete(id);
|
|
1869
|
+
const status = byId.get(id)?.status;
|
|
1870
|
+
events.emit("task:subagent:lifecycle", {
|
|
1871
|
+
id,
|
|
1872
|
+
status: status === "failed" || status === "timed_out" ? "failed" : status === "cancelled" || status === "interrupted" ? "aborted" : "completed"
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
return {
|
|
1877
|
+
startSession(sessionId) {
|
|
1878
|
+
if (disposed) return;
|
|
1879
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1880
|
+
announced = sessions.get(sessionId) ?? /* @__PURE__ */ new Set();
|
|
1881
|
+
sessions.set(sessionId, announced);
|
|
1882
|
+
subagents = [];
|
|
1883
|
+
background = [];
|
|
1884
|
+
timer = setTimeout(() => {
|
|
1885
|
+
timer = void 0;
|
|
1886
|
+
if (disposed) return;
|
|
1887
|
+
reconcile("thoth:subagent:", subagents);
|
|
1888
|
+
reconcile("thoth:bg:", background);
|
|
1889
|
+
}, 0);
|
|
1890
|
+
timer.unref?.();
|
|
1891
|
+
},
|
|
1892
|
+
updateSubagents(data) {
|
|
1893
|
+
if (disposed) return;
|
|
1894
|
+
subagents = [
|
|
1895
|
+
...data.tasks.map((task) => ({
|
|
1896
|
+
id: task.id,
|
|
1897
|
+
live: task.mode === "background" && (task.status === "queued" || task.status === "running" || task.status === "stopping"),
|
|
1898
|
+
status: task.status,
|
|
1899
|
+
agent: task.agent,
|
|
1900
|
+
description: task.displayName
|
|
1901
|
+
})),
|
|
1902
|
+
...data.history.map((task) => ({
|
|
1903
|
+
id: task.id,
|
|
1904
|
+
live: false,
|
|
1905
|
+
status: task.status,
|
|
1906
|
+
agent: task.agent
|
|
1907
|
+
}))
|
|
1908
|
+
];
|
|
1909
|
+
if (timer === void 0) reconcile("thoth:subagent:", subagents);
|
|
1910
|
+
},
|
|
1911
|
+
updateBackground(data) {
|
|
1912
|
+
if (disposed) return;
|
|
1913
|
+
background = data.tasks.map((task) => ({
|
|
1914
|
+
id: task.id,
|
|
1915
|
+
live: task.status === "running",
|
|
1916
|
+
status: task.status,
|
|
1917
|
+
agent: task.kind === "command_watch" ? "watch" : "process",
|
|
1918
|
+
description: task.name
|
|
1919
|
+
}));
|
|
1920
|
+
if (timer === void 0) reconcile("thoth:bg:", background);
|
|
1921
|
+
},
|
|
1922
|
+
dispose() {
|
|
1923
|
+
disposed = true;
|
|
1924
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1925
|
+
timer = void 0;
|
|
1926
|
+
}
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1806
1930
|
// src/status-line/throughput.ts
|
|
1807
1931
|
function createThroughputTracker() {
|
|
1808
1932
|
let pending;
|
|
@@ -1946,6 +2070,7 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
1946
2070
|
requestRender();
|
|
1947
2071
|
};
|
|
1948
2072
|
const working = createWorkingState(invalidateRender);
|
|
2073
|
+
const orcaChildHold = createOrcaChildHold(pi.events);
|
|
1949
2074
|
const editorDecorations = /* @__PURE__ */ new Set();
|
|
1950
2075
|
const refreshSession = () => {
|
|
1951
2076
|
if (disposed) return;
|
|
@@ -1953,7 +2078,12 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
1953
2078
|
invalidateRender();
|
|
1954
2079
|
};
|
|
1955
2080
|
let offSubagentUsage;
|
|
2081
|
+
let offBackgroundWork = [];
|
|
1956
2082
|
unsubs.push(() => offSubagentUsage?.());
|
|
2083
|
+
unsubs.push(() => {
|
|
2084
|
+
for (const off of offBackgroundWork) off();
|
|
2085
|
+
offBackgroundWork = [];
|
|
2086
|
+
});
|
|
1957
2087
|
if (footerData?.onBranchChange) {
|
|
1958
2088
|
unsubs.push(footerData.onBranchChange(invalidateRender));
|
|
1959
2089
|
}
|
|
@@ -1974,7 +2104,50 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
1974
2104
|
data: {}
|
|
1975
2105
|
});
|
|
1976
2106
|
};
|
|
2107
|
+
const subscribeAndRequestBackgroundWork = () => {
|
|
2108
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
2109
|
+
for (const off of offBackgroundWork) off();
|
|
2110
|
+
orcaChildHold.startSession(sessionId);
|
|
2111
|
+
let subagentPending = 0;
|
|
2112
|
+
let backgroundPending = 0;
|
|
2113
|
+
if (inputBoxEnabled) working.setPendingBackground(0);
|
|
2114
|
+
offBackgroundWork = [
|
|
2115
|
+
subscribe(pi.events, SUBAGENTS_STATE_CHANNEL, {
|
|
2116
|
+
sessionId,
|
|
2117
|
+
onSnapshot: ({ data }) => {
|
|
2118
|
+
if (disposed) return;
|
|
2119
|
+
orcaChildHold.updateSubagents(data);
|
|
2120
|
+
subagentPending = data.tasks.filter(
|
|
2121
|
+
(task) => task.mode === "background" && (task.status === "queued" || task.status === "running" || task.status === "stopping")
|
|
2122
|
+
).length;
|
|
2123
|
+
if (inputBoxEnabled)
|
|
2124
|
+
working.setPendingBackground(subagentPending + backgroundPending);
|
|
2125
|
+
}
|
|
2126
|
+
}),
|
|
2127
|
+
subscribe(pi.events, BACKGROUND_STATE_CHANNEL, {
|
|
2128
|
+
sessionId,
|
|
2129
|
+
onSnapshot: ({ data }) => {
|
|
2130
|
+
if (disposed) return;
|
|
2131
|
+
orcaChildHold.updateBackground(data);
|
|
2132
|
+
backgroundPending = data.counts.running;
|
|
2133
|
+
if (inputBoxEnabled)
|
|
2134
|
+
working.setPendingBackground(subagentPending + backgroundPending);
|
|
2135
|
+
}
|
|
2136
|
+
})
|
|
2137
|
+
];
|
|
2138
|
+
for (const channel of [
|
|
2139
|
+
SUBAGENTS_STATE_REQUEST,
|
|
2140
|
+
BACKGROUND_STATE_REQUEST
|
|
2141
|
+
]) {
|
|
2142
|
+
request(pi.events, channel, {
|
|
2143
|
+
source: "@thoth-agents/pi-thoth-theme",
|
|
2144
|
+
sessionId,
|
|
2145
|
+
data: {}
|
|
2146
|
+
});
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
1977
2149
|
if (pi?.on) {
|
|
2150
|
+
unsubs.push(pi.on("session_shutdown", dispose));
|
|
1978
2151
|
unsubs.push(
|
|
1979
2152
|
pi.on("session_start", () => {
|
|
1980
2153
|
if (disposed) return;
|
|
@@ -1983,6 +2156,7 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
1983
2156
|
if (inputBoxEnabled) working.end();
|
|
1984
2157
|
refreshSession();
|
|
1985
2158
|
subscribeAndRequestSubagentUsage();
|
|
2159
|
+
subscribeAndRequestBackgroundWork();
|
|
1986
2160
|
})
|
|
1987
2161
|
);
|
|
1988
2162
|
if (inputBoxEnabled) {
|
|
@@ -2008,6 +2182,22 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
2008
2182
|
unsubs.push(pi.on("thinking_level_select", invalidateRender));
|
|
2009
2183
|
}
|
|
2010
2184
|
subscribeAndRequestSubagentUsage();
|
|
2185
|
+
subscribeAndRequestBackgroundWork();
|
|
2186
|
+
function dispose() {
|
|
2187
|
+
if (disposed) return;
|
|
2188
|
+
disposed = true;
|
|
2189
|
+
working.dispose();
|
|
2190
|
+
orcaChildHold.dispose();
|
|
2191
|
+
for (const decoration of editorDecorations) decoration.dispose();
|
|
2192
|
+
editorDecorations.clear();
|
|
2193
|
+
for (const unsub of unsubs) {
|
|
2194
|
+
try {
|
|
2195
|
+
unsub();
|
|
2196
|
+
} catch {
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
unsubs.length = 0;
|
|
2200
|
+
}
|
|
2011
2201
|
return {
|
|
2012
2202
|
getStatusSnapshot,
|
|
2013
2203
|
render(width) {
|
|
@@ -2041,19 +2231,7 @@ function registerStatusLine(pi, ctx, config) {
|
|
|
2041
2231
|
return cachedLines;
|
|
2042
2232
|
},
|
|
2043
2233
|
invalidate: invalidateRender,
|
|
2044
|
-
dispose
|
|
2045
|
-
disposed = true;
|
|
2046
|
-
working.dispose();
|
|
2047
|
-
for (const decoration of editorDecorations) decoration.dispose();
|
|
2048
|
-
editorDecorations.clear();
|
|
2049
|
-
for (const unsub of unsubs) {
|
|
2050
|
-
try {
|
|
2051
|
-
unsub();
|
|
2052
|
-
} catch {
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
unsubs.length = 0;
|
|
2056
|
-
}
|
|
2234
|
+
dispose
|
|
2057
2235
|
};
|
|
2058
2236
|
});
|
|
2059
2237
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thoth-agents/pi-thoth-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Modular Thoth theme, status line, tool styling, and welcome header for Pi.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@earendil-works/pi-tui": "1.0.2",
|
|
51
51
|
"@earendil-works/pi-ai": "1.0.2",
|
|
52
52
|
"@rolldown/binding-wasm32-wasi": "^1.2.4",
|
|
53
|
-
"@thoth-agents/pi-core": "^0.
|
|
53
|
+
"@thoth-agents/pi-core": "^0.5.0"
|
|
54
54
|
},
|
|
55
55
|
"upstream": {
|
|
56
56
|
"repository": "https://github.com/QuangThai/pi-omp-theme",
|