pi-goosedump 0.12.72 → 0.13.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 +385 -23
- package/package.json +2 -2
package/dist/index.ts
CHANGED
|
@@ -1871,6 +1871,367 @@ import {
|
|
|
1871
1871
|
truncateHead
|
|
1872
1872
|
} from "@earendil-works/pi-coding-agent";
|
|
1873
1873
|
import { Type as Type3 } from "typebox";
|
|
1874
|
+
|
|
1875
|
+
// src/tui-render-utils.ts
|
|
1876
|
+
import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
1877
|
+
var SUMMARY_PREFIX = "↳";
|
|
1878
|
+
var EXPAND_HINT = " • Ctrl+O to expand";
|
|
1879
|
+
function renderToolLabel(theme, label) {
|
|
1880
|
+
const boldFn = typeof theme.bold === "function" ? theme.bold.bind(theme) : (text) => text;
|
|
1881
|
+
return theme.fg("toolTitle", boldFn(label));
|
|
1882
|
+
}
|
|
1883
|
+
function appendExpandHint(text, hidden) {
|
|
1884
|
+
return hidden ? `${text}${EXPAND_HINT}` : text;
|
|
1885
|
+
}
|
|
1886
|
+
function summaryLine(summary, options = {}) {
|
|
1887
|
+
const prefix = options.theme ? options.theme.fg(options.style ?? "dim", SUMMARY_PREFIX) : SUMMARY_PREFIX;
|
|
1888
|
+
return appendExpandHint(`${prefix} ${summary}`, Boolean(options.hidden));
|
|
1889
|
+
}
|
|
1890
|
+
function isRendererExpanded(options, context, defaultExpanded = false) {
|
|
1891
|
+
return context?.expanded ?? options?.expanded ?? defaultExpanded;
|
|
1892
|
+
}
|
|
1893
|
+
function resolveRenderResultContext(options, rest, defaultExpanded = false) {
|
|
1894
|
+
const context = rest[0] ?? options ?? {};
|
|
1895
|
+
return {
|
|
1896
|
+
isPartial: context.isPartial ?? options?.isPartial ?? false,
|
|
1897
|
+
isError: context.isError ?? false,
|
|
1898
|
+
expanded: isRendererExpanded(options, context, defaultExpanded),
|
|
1899
|
+
width: context.width ?? options?.width,
|
|
1900
|
+
cwd: context.cwd ?? process.cwd(),
|
|
1901
|
+
context
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
function normalizeWidth(width, fallback = 80) {
|
|
1905
|
+
return typeof width === "number" && Number.isFinite(width) && width > 0 ? Math.floor(width) : fallback;
|
|
1906
|
+
}
|
|
1907
|
+
function clampLineToWidth(line, width) {
|
|
1908
|
+
if (width === undefined || width === null)
|
|
1909
|
+
return line;
|
|
1910
|
+
const normalized = normalizeWidth(width);
|
|
1911
|
+
return visibleWidth(line) <= normalized ? line : truncateToWidth(line, normalized);
|
|
1912
|
+
}
|
|
1913
|
+
function clampLinesToWidth(lines, width) {
|
|
1914
|
+
if (width === undefined || width === null)
|
|
1915
|
+
return lines;
|
|
1916
|
+
return lines.map((line) => clampLineToWidth(line, width));
|
|
1917
|
+
}
|
|
1918
|
+
function renderPendingResult(pendingLabel, width, theme) {
|
|
1919
|
+
return new Text(clampLinesToWidth([summaryLine(pendingLabel, { theme, style: "muted" })], width).join(`
|
|
1920
|
+
`), 0, 0);
|
|
1921
|
+
}
|
|
1922
|
+
function renderErrorResult(textContent, options) {
|
|
1923
|
+
const firstLine = textContent.split(`
|
|
1924
|
+
`)[0] || (options.fallback ?? "Error");
|
|
1925
|
+
const body = options.expanded && textContent ? textContent : firstLine;
|
|
1926
|
+
return new Text(clampLinesToWidth(summaryLine(body, { theme: options.theme, style: "error" }).split(`
|
|
1927
|
+
`), options.width).join(`
|
|
1928
|
+
`), 0, 0);
|
|
1929
|
+
}
|
|
1930
|
+
function upsertTextComponent(lastComponent, text) {
|
|
1931
|
+
const component = lastComponent instanceof Text ? lastComponent : new Text("", 0, 0);
|
|
1932
|
+
component.setText(text);
|
|
1933
|
+
return component;
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
// src/tool-renderers.ts
|
|
1937
|
+
function renderGooseRememberCall(args, theme, ...rest) {
|
|
1938
|
+
const context = rest[0] ?? {};
|
|
1939
|
+
const target = args?.session ? `${args?.provider ?? "pi"}:${args.session}` : "current session";
|
|
1940
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_remember")} ${theme.fg("accent", target)}`, context.width);
|
|
1941
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
1942
|
+
}
|
|
1943
|
+
function renderGooseRememberResult(result, options, theme, ...rest) {
|
|
1944
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
1945
|
+
if (isPartial)
|
|
1946
|
+
return renderPendingResult("pending goose_remember", width, theme);
|
|
1947
|
+
const content = result.content?.[0]?.text ?? "";
|
|
1948
|
+
if (isError || result.isError) {
|
|
1949
|
+
return renderErrorResult(content, {
|
|
1950
|
+
expanded,
|
|
1951
|
+
width,
|
|
1952
|
+
fallback: "goose_remember failed",
|
|
1953
|
+
theme
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
const style = content.includes("dropped") ? "warning" : content.includes("disabled") ? "dim" : "success";
|
|
1957
|
+
const summary = summaryLine(content.split(`
|
|
1958
|
+
`)[0] || "memory learning completed", {
|
|
1959
|
+
theme,
|
|
1960
|
+
style
|
|
1961
|
+
});
|
|
1962
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summary, width));
|
|
1963
|
+
}
|
|
1964
|
+
function renderGooseRecallCall(args, theme, ...rest) {
|
|
1965
|
+
const context = rest[0] ?? {};
|
|
1966
|
+
const query = typeof args?.query === "string" ? `"${args.query}"` : '""';
|
|
1967
|
+
const flags = [
|
|
1968
|
+
args?.type && `type=${args.type}`,
|
|
1969
|
+
args?.limit !== undefined && args.limit !== 5 && `limit=${args.limit}`,
|
|
1970
|
+
args?.allProjects && "all-projects",
|
|
1971
|
+
args?.history && "history"
|
|
1972
|
+
].filter(Boolean);
|
|
1973
|
+
const flagsBadge = flags.length > 0 ? theme.fg("dim", ` [${flags.join(", ")}]`) : "";
|
|
1974
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_recall")} ${theme.fg("accent", query)}${flagsBadge}`, context.width);
|
|
1975
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
1976
|
+
}
|
|
1977
|
+
function renderGooseRecallResult(result, options, theme, ...rest) {
|
|
1978
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
1979
|
+
if (isPartial)
|
|
1980
|
+
return renderPendingResult("pending goose_recall", width, theme);
|
|
1981
|
+
const content = result.content?.[0]?.text ?? "";
|
|
1982
|
+
if (isError || result.isError) {
|
|
1983
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_recall failed", theme });
|
|
1984
|
+
}
|
|
1985
|
+
if (content.startsWith("No durable memory") || content.startsWith("Durable memory is disabled") || content.startsWith("Memory recall dropped")) {
|
|
1986
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style: "dim" }), width));
|
|
1987
|
+
}
|
|
1988
|
+
const matchCount = (content.match(/\[mem_[^\]]+\]/g) || []).length;
|
|
1989
|
+
const count = matchCount > 0 ? matchCount : content.split(`
|
|
1990
|
+
`).filter((l) => l.trim().startsWith("-")).length;
|
|
1991
|
+
const unit = count === 1 ? "memory" : "memories";
|
|
1992
|
+
const summary = summaryLine(`${count} ${unit} recalled`, {
|
|
1993
|
+
hidden: !expanded,
|
|
1994
|
+
theme,
|
|
1995
|
+
style: "success"
|
|
1996
|
+
});
|
|
1997
|
+
const body = expanded ? `${summary}
|
|
1998
|
+
|
|
1999
|
+
${content}` : summary;
|
|
2000
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2001
|
+
`), width).join(`
|
|
2002
|
+
`));
|
|
2003
|
+
}
|
|
2004
|
+
function renderGooseForgetCall(args, theme, ...rest) {
|
|
2005
|
+
const context = rest[0] ?? {};
|
|
2006
|
+
const target = args?.target ? String(args.target) : '""';
|
|
2007
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_forget")} ${theme.fg("accent", target)}`, context.width);
|
|
2008
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2009
|
+
}
|
|
2010
|
+
function renderGooseForgetResult(result, options, theme, ...rest) {
|
|
2011
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2012
|
+
if (isPartial)
|
|
2013
|
+
return renderPendingResult("pending goose_forget", width, theme);
|
|
2014
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2015
|
+
if (isError || result.isError) {
|
|
2016
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_forget failed", theme });
|
|
2017
|
+
}
|
|
2018
|
+
const isFailure = content.toLowerCase().includes("error");
|
|
2019
|
+
const summary = summaryLine(content, { theme, style: isFailure ? "error" : "success" });
|
|
2020
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summary, width));
|
|
2021
|
+
}
|
|
2022
|
+
function renderGooseMemoryStatusCall(_args, theme, ...rest) {
|
|
2023
|
+
const context = rest[0] ?? {};
|
|
2024
|
+
const text = clampLineToWidth(renderToolLabel(theme, "goose_memory_status"), context.width);
|
|
2025
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2026
|
+
}
|
|
2027
|
+
function renderGooseMemoryStatusResult(result, options, theme, ...rest) {
|
|
2028
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2029
|
+
if (isPartial)
|
|
2030
|
+
return renderPendingResult("pending goose_memory_status", width, theme);
|
|
2031
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2032
|
+
if (isError || result.isError) {
|
|
2033
|
+
return renderErrorResult(content, {
|
|
2034
|
+
expanded,
|
|
2035
|
+
width,
|
|
2036
|
+
fallback: "goose_memory_status failed",
|
|
2037
|
+
theme
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
if (content.startsWith("Durable memory is disabled")) {
|
|
2041
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style: "dim" }), width));
|
|
2042
|
+
}
|
|
2043
|
+
let summaryText = "durable memory status";
|
|
2044
|
+
try {
|
|
2045
|
+
const parsed = JSON.parse(content);
|
|
2046
|
+
if (typeof parsed.entries === "number") {
|
|
2047
|
+
summaryText = `${parsed.entries} ${parsed.entries === 1 ? "entry" : "entries"} in durable memory`;
|
|
2048
|
+
}
|
|
2049
|
+
} catch {
|
|
2050
|
+
const firstLine = content.split(`
|
|
2051
|
+
`)[0];
|
|
2052
|
+
if (firstLine)
|
|
2053
|
+
summaryText = firstLine;
|
|
2054
|
+
}
|
|
2055
|
+
const summary = summaryLine(summaryText, { hidden: !expanded, theme, style: "success" });
|
|
2056
|
+
const body = expanded ? `${summary}
|
|
2057
|
+
|
|
2058
|
+
${content}` : summary;
|
|
2059
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2060
|
+
`), width).join(`
|
|
2061
|
+
`));
|
|
2062
|
+
}
|
|
2063
|
+
function renderGooseSearchCall(args, theme, ...rest) {
|
|
2064
|
+
const context = rest[0] ?? {};
|
|
2065
|
+
const query = typeof args?.query === "string" ? `"${args.query}"` : '""';
|
|
2066
|
+
const target = args?.session ? theme.fg("dim", ` in ${args.provider ?? "pi"}:${args.session}`) : "";
|
|
2067
|
+
const flags = [
|
|
2068
|
+
args?.scope && args.scope !== "lineage" && `scope=${args.scope}`,
|
|
2069
|
+
args?.page && args.page > 1 && `page=${args.page}`
|
|
2070
|
+
].filter(Boolean);
|
|
2071
|
+
const flagsBadge = flags.length > 0 ? theme.fg("dim", ` [${flags.join(", ")}]`) : "";
|
|
2072
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_search")} ${theme.fg("accent", query)}${target}${flagsBadge}`, context.width);
|
|
2073
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2074
|
+
}
|
|
2075
|
+
function renderGooseSearchResult(result, options, theme, ...rest) {
|
|
2076
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2077
|
+
if (isPartial)
|
|
2078
|
+
return renderPendingResult("pending goose_search", width, theme);
|
|
2079
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2080
|
+
if (isError || result.isError) {
|
|
2081
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_search failed", theme });
|
|
2082
|
+
}
|
|
2083
|
+
if (content.startsWith("No results")) {
|
|
2084
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style: "dim" }), width));
|
|
2085
|
+
}
|
|
2086
|
+
const hitCount = (content.match(/\[#[^\]]+\]/g) || []).length;
|
|
2087
|
+
const count = hitCount > 0 ? hitCount : content.split(`
|
|
2088
|
+
`).filter((l) => l.trim().length > 0).length;
|
|
2089
|
+
const unit = count === 1 ? "result" : "results";
|
|
2090
|
+
const pageMatch = content.match(/\(page (\d+)\)/);
|
|
2091
|
+
const pageSuffix = pageMatch ? ` (page ${pageMatch[1]})` : "";
|
|
2092
|
+
const summary = summaryLine(`${count} ${unit}${pageSuffix}`, {
|
|
2093
|
+
hidden: !expanded,
|
|
2094
|
+
theme,
|
|
2095
|
+
style: "success"
|
|
2096
|
+
});
|
|
2097
|
+
const body = expanded ? `${summary}
|
|
2098
|
+
|
|
2099
|
+
${content}` : summary;
|
|
2100
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2101
|
+
`), width).join(`
|
|
2102
|
+
`));
|
|
2103
|
+
}
|
|
2104
|
+
function renderGooseGetCall(args, theme, ...rest) {
|
|
2105
|
+
const context = rest[0] ?? {};
|
|
2106
|
+
const ids = Array.isArray(args?.ids) ? args.ids : [];
|
|
2107
|
+
const idsDisplay = ids.length <= 3 ? ids.join(", ") : `${ids.slice(0, 3).join(", ")}… (${ids.length})`;
|
|
2108
|
+
const target = args?.session ? theme.fg("dim", ` in ${args.provider ?? "pi"}:${args.session}`) : "";
|
|
2109
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_get")} ${theme.fg("accent", `[${idsDisplay}]`)}${target}`, context.width);
|
|
2110
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2111
|
+
}
|
|
2112
|
+
function renderGooseGetResult(result, options, theme, ...rest) {
|
|
2113
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2114
|
+
if (isPartial)
|
|
2115
|
+
return renderPendingResult("pending goose_get", width, theme);
|
|
2116
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2117
|
+
if (isError || result.isError) {
|
|
2118
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_get failed", theme });
|
|
2119
|
+
}
|
|
2120
|
+
if (content.startsWith("No entries found")) {
|
|
2121
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine("no entries found", { theme, style: "dim" }), width));
|
|
2122
|
+
}
|
|
2123
|
+
const entryCount = (content.match(/\[#[^\]]+\]/g) || []).length;
|
|
2124
|
+
const count = entryCount > 0 ? entryCount : Array.isArray(options) ? options.length : 1;
|
|
2125
|
+
const unit = count === 1 ? "entry" : "entries";
|
|
2126
|
+
const summary = summaryLine(`${count} ${unit} retrieved`, {
|
|
2127
|
+
hidden: !expanded,
|
|
2128
|
+
theme,
|
|
2129
|
+
style: "success"
|
|
2130
|
+
});
|
|
2131
|
+
const body = expanded ? `${summary}
|
|
2132
|
+
|
|
2133
|
+
${content}` : summary;
|
|
2134
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2135
|
+
`), width).join(`
|
|
2136
|
+
`));
|
|
2137
|
+
}
|
|
2138
|
+
function renderGooseGrepCall(args, theme, ...rest) {
|
|
2139
|
+
const context = rest[0] ?? {};
|
|
2140
|
+
const pattern = typeof args?.pattern === "string" ? `/${args.pattern}/` : "//";
|
|
2141
|
+
const target = args?.session ? theme.fg("dim", ` in ${args.provider ?? "pi"}:${args.session}`) : "";
|
|
2142
|
+
const flags = [args?.scope && args.scope !== "lineage" && `scope=${args.scope}`].filter(Boolean);
|
|
2143
|
+
const flagsBadge = flags.length > 0 ? theme.fg("dim", ` [${flags.join(", ")}]`) : "";
|
|
2144
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_grep")} ${theme.fg("accent", pattern)}${target}${flagsBadge}`, context.width);
|
|
2145
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2146
|
+
}
|
|
2147
|
+
function renderGooseGrepResult(result, options, theme, ...rest) {
|
|
2148
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2149
|
+
if (isPartial)
|
|
2150
|
+
return renderPendingResult("pending goose_grep", width, theme);
|
|
2151
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2152
|
+
if (isError || result.isError) {
|
|
2153
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_grep failed", theme });
|
|
2154
|
+
}
|
|
2155
|
+
if (content.startsWith("No matches")) {
|
|
2156
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style: "dim" }), width));
|
|
2157
|
+
}
|
|
2158
|
+
const matchCount = (content.match(/\[#[^\]]+\]/g) || []).length;
|
|
2159
|
+
const count = matchCount > 0 ? matchCount : content.split(`
|
|
2160
|
+
`).filter((l) => l.trim().length > 0).length;
|
|
2161
|
+
const unit = count === 1 ? "match" : "matches";
|
|
2162
|
+
const summary = summaryLine(`${count} ${unit}`, { hidden: !expanded, theme, style: "success" });
|
|
2163
|
+
const body = expanded ? `${summary}
|
|
2164
|
+
|
|
2165
|
+
${content}` : summary;
|
|
2166
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2167
|
+
`), width).join(`
|
|
2168
|
+
`));
|
|
2169
|
+
}
|
|
2170
|
+
function renderGooseCompactCall(args, theme, ...rest) {
|
|
2171
|
+
const context = rest[0] ?? {};
|
|
2172
|
+
const flags = args?.keep ? [theme.fg("dim", `keep=${args.keep}`)] : [];
|
|
2173
|
+
const flagsBadge = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
2174
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_compact")}${flagsBadge}`, context.width);
|
|
2175
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2176
|
+
}
|
|
2177
|
+
function renderGooseCompactResult(result, options, theme, ...rest) {
|
|
2178
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2179
|
+
if (isPartial)
|
|
2180
|
+
return renderPendingResult("pending goose_compact", width, theme);
|
|
2181
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2182
|
+
if (isError || result.isError) {
|
|
2183
|
+
return renderErrorResult(content, { expanded, width, fallback: "goose_compact failed", theme });
|
|
2184
|
+
}
|
|
2185
|
+
const style = content.includes("already in progress") ? "warning" : content.includes("Nothing to compact") ? "dim" : "success";
|
|
2186
|
+
const summary = summaryLine(content.split(`
|
|
2187
|
+
`)[0] || "compaction completed", { theme, style });
|
|
2188
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summary, width));
|
|
2189
|
+
}
|
|
2190
|
+
function renderGooseSessionsCall(args, theme, ...rest) {
|
|
2191
|
+
const context = rest[0] ?? {};
|
|
2192
|
+
const action = args?.action ?? "list";
|
|
2193
|
+
const target = args?.session ? `${args?.provider ?? "pi"}:${args.session}` : `(${args?.provider ?? "pi"})`;
|
|
2194
|
+
const text = clampLineToWidth(`${renderToolLabel(theme, "goose_sessions")} ${theme.fg("accent", action)} ${theme.fg("dim", target)}`, context.width);
|
|
2195
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
2196
|
+
}
|
|
2197
|
+
function renderGooseSessionsResult(result, options, theme, ...rest) {
|
|
2198
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
2199
|
+
if (isPartial)
|
|
2200
|
+
return renderPendingResult("pending goose_sessions", width, theme);
|
|
2201
|
+
const content = result.content?.[0]?.text ?? "";
|
|
2202
|
+
if (isError || result.isError) {
|
|
2203
|
+
return renderErrorResult(content, {
|
|
2204
|
+
expanded,
|
|
2205
|
+
width,
|
|
2206
|
+
fallback: "goose_sessions failed",
|
|
2207
|
+
theme
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
if (content.startsWith("No ")) {
|
|
2211
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style: "dim" }), width));
|
|
2212
|
+
}
|
|
2213
|
+
if (content.startsWith("Deleted session") || content.startsWith("Cannot delete")) {
|
|
2214
|
+
const style = content.startsWith("Cannot delete") ? "warning" : "success";
|
|
2215
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLineToWidth(summaryLine(content, { theme, style }), width));
|
|
2216
|
+
}
|
|
2217
|
+
const sessionCount = (content.match(/^- /gm) || []).length;
|
|
2218
|
+
const count = sessionCount > 0 ? sessionCount : content.split(`
|
|
2219
|
+
`).filter((l) => l.trim().startsWith("-")).length;
|
|
2220
|
+
const unit = count === 1 ? "session" : "sessions";
|
|
2221
|
+
const summary = summaryLine(`${count} ${unit} found`, {
|
|
2222
|
+
hidden: !expanded,
|
|
2223
|
+
theme,
|
|
2224
|
+
style: "success"
|
|
2225
|
+
});
|
|
2226
|
+
const body = expanded ? `${summary}
|
|
2227
|
+
|
|
2228
|
+
${content}` : summary;
|
|
2229
|
+
return upsertTextComponent(rest[0]?.lastComponent, clampLinesToWidth(body.split(`
|
|
2230
|
+
`), width).join(`
|
|
2231
|
+
`));
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
// src/tools.ts
|
|
1874
2235
|
function memoryDisabledResult() {
|
|
1875
2236
|
return textResult(MEMORY_DISABLED_MESSAGE);
|
|
1876
2237
|
}
|
|
@@ -1945,7 +2306,7 @@ function gooseToolMeta(name) {
|
|
|
1945
2306
|
promptGuidelines: [...policy.guidelines]
|
|
1946
2307
|
};
|
|
1947
2308
|
}
|
|
1948
|
-
function defineGooseTool(name, parameters, handler) {
|
|
2309
|
+
function defineGooseTool(name, parameters, handler, renderers) {
|
|
1949
2310
|
return defineTool({
|
|
1950
2311
|
...gooseToolMeta(name),
|
|
1951
2312
|
parameters,
|
|
@@ -1955,7 +2316,9 @@ function defineGooseTool(name, parameters, handler) {
|
|
|
1955
2316
|
} catch (err) {
|
|
1956
2317
|
return goosedumpErrorResult(err);
|
|
1957
2318
|
}
|
|
1958
|
-
}
|
|
2319
|
+
},
|
|
2320
|
+
...renderers?.renderCall ? { renderCall: renderers.renderCall } : {},
|
|
2321
|
+
...renderers?.renderResult ? { renderResult: renderers.renderResult } : {}
|
|
1959
2322
|
});
|
|
1960
2323
|
}
|
|
1961
2324
|
function registerGooseTools(pi, deps) {
|
|
@@ -1973,7 +2336,7 @@ function registerGooseTools(pi, deps) {
|
|
|
1973
2336
|
}
|
|
1974
2337
|
});
|
|
1975
2338
|
return textResult(accepted ? `Memory learning started for ${resolved.target}.` : `Memory learning dropped for ${resolved.target}: another inference task is active.`);
|
|
1976
|
-
}));
|
|
2339
|
+
}, { renderCall: renderGooseRememberCall, renderResult: renderGooseRememberResult }));
|
|
1977
2340
|
pi.registerTool(defineGooseTool("goose_recall", Type3.Object({
|
|
1978
2341
|
query: Type3.String({ description: PARAM_DESCRIPTIONS.memoryQuery }),
|
|
1979
2342
|
type: Type3.Optional(Type3.Union(GOOSE_MEMORY_TYPES.map((type) => Type3.Literal(type)), { description: PARAM_DESCRIPTIONS.memoryType })),
|
|
@@ -2010,7 +2373,7 @@ function registerGooseTools(pi, deps) {
|
|
|
2010
2373
|
if (hits.length === 0)
|
|
2011
2374
|
return textResult(`No durable memory for "${params.query}"`);
|
|
2012
2375
|
return textResult(formatMemoryHits(hits));
|
|
2013
|
-
}));
|
|
2376
|
+
}, { renderCall: renderGooseRecallCall, renderResult: renderGooseRecallResult }));
|
|
2014
2377
|
pi.registerTool(defineGooseTool("goose_forget", Type3.Object({
|
|
2015
2378
|
target: Type3.String({
|
|
2016
2379
|
description: PARAM_DESCRIPTIONS.forgetTarget
|
|
@@ -2024,13 +2387,13 @@ function registerGooseTools(pi, deps) {
|
|
|
2024
2387
|
}
|
|
2025
2388
|
const res = await goosedumpMemoryForget(params.target.trim(), signal, nativeExecutablePath);
|
|
2026
2389
|
return textResult(res);
|
|
2027
|
-
}));
|
|
2390
|
+
}, { renderCall: renderGooseForgetCall, renderResult: renderGooseForgetResult }));
|
|
2028
2391
|
pi.registerTool(defineGooseTool("goose_memory_status", Type3.Object({}), async (_params, signal, ctx) => {
|
|
2029
2392
|
const disabled = requireMemoryEnabled(ctx);
|
|
2030
2393
|
if (disabled)
|
|
2031
2394
|
return disabled;
|
|
2032
2395
|
return textResult(await goosedumpMemoryStatus(signal, nativeExecutablePath));
|
|
2033
|
-
}));
|
|
2396
|
+
}, { renderCall: renderGooseMemoryStatusCall, renderResult: renderGooseMemoryStatusResult }));
|
|
2034
2397
|
pi.registerTool(defineGooseTool("goose_search", Type3.Object({
|
|
2035
2398
|
query: Type3.String({ description: PARAM_DESCRIPTIONS.searchQuery }),
|
|
2036
2399
|
...historyBranchParams(),
|
|
@@ -2052,7 +2415,7 @@ function registerGooseTools(pi, deps) {
|
|
|
2052
2415
|
return textResult(`Results for "${params.query}" (page ${page}):
|
|
2053
2416
|
|
|
2054
2417
|
${text}`);
|
|
2055
|
-
}));
|
|
2418
|
+
}, { renderCall: renderGooseSearchCall, renderResult: renderGooseSearchResult }));
|
|
2056
2419
|
pi.registerTool(defineGooseTool("goose_get", Type3.Object({
|
|
2057
2420
|
ids: Type3.Array(Type3.String(), {
|
|
2058
2421
|
minItems: 1,
|
|
@@ -2068,7 +2431,7 @@ ${text}`);
|
|
|
2068
2431
|
return textResult("No entries found for the given IDs.");
|
|
2069
2432
|
}
|
|
2070
2433
|
return boundedHistoryResult(formatMessagesFull(messages));
|
|
2071
|
-
}));
|
|
2434
|
+
}, { renderCall: renderGooseGetCall, renderResult: renderGooseGetResult }));
|
|
2072
2435
|
pi.registerTool(defineGooseTool("goose_grep", Type3.Object({
|
|
2073
2436
|
pattern: Type3.String({ description: PARAM_DESCRIPTIONS.pattern }),
|
|
2074
2437
|
...historyBranchParams()
|
|
@@ -2081,7 +2444,7 @@ ${text}`);
|
|
|
2081
2444
|
return textResult(`No matches for "${params.pattern}"`);
|
|
2082
2445
|
}
|
|
2083
2446
|
return boundedHistoryResult(formatMessagesCompact(messages));
|
|
2084
|
-
}));
|
|
2447
|
+
}, { renderCall: renderGooseGrepCall, renderResult: renderGooseGrepResult }));
|
|
2085
2448
|
pi.registerTool(defineGooseTool("goose_compact", Type3.Object({
|
|
2086
2449
|
keep: Type3.Optional(Type3.Integer({
|
|
2087
2450
|
minimum: 1,
|
|
@@ -2096,7 +2459,7 @@ ${text}`);
|
|
|
2096
2459
|
return textResult("Nothing to compact (session too small).");
|
|
2097
2460
|
}
|
|
2098
2461
|
return textResult(compactStartedMessage(keep, result === "queued"));
|
|
2099
|
-
}));
|
|
2462
|
+
}, { renderCall: renderGooseCompactCall, renderResult: renderGooseCompactResult }));
|
|
2100
2463
|
pi.registerTool(defineGooseTool("goose_sessions", Type3.Object({
|
|
2101
2464
|
action: Type3.Optional(Type3.Union([Type3.Literal("list"), Type3.Literal("delete")], {
|
|
2102
2465
|
default: "list",
|
|
@@ -2141,7 +2504,7 @@ ${text}`);
|
|
|
2141
2504
|
|
|
2142
2505
|
${lines.join(`
|
|
2143
2506
|
`)}`);
|
|
2144
|
-
}));
|
|
2507
|
+
}, { renderCall: renderGooseSessionsCall, renderResult: renderGooseSessionsResult }));
|
|
2145
2508
|
}
|
|
2146
2509
|
|
|
2147
2510
|
// src/tui.ts
|
|
@@ -2151,8 +2514,8 @@ import {
|
|
|
2151
2514
|
Key,
|
|
2152
2515
|
decodeKittyPrintable,
|
|
2153
2516
|
matchesKey,
|
|
2154
|
-
truncateToWidth,
|
|
2155
|
-
visibleWidth,
|
|
2517
|
+
truncateToWidth as truncateToWidth2,
|
|
2518
|
+
visibleWidth as visibleWidth2,
|
|
2156
2519
|
wrapTextWithAnsi
|
|
2157
2520
|
} from "@earendil-works/pi-tui";
|
|
2158
2521
|
import { existsSync as existsSync3 } from "node:fs";
|
|
@@ -2234,8 +2597,8 @@ class NumberInputSubmenu {
|
|
|
2234
2597
|
}
|
|
2235
2598
|
}
|
|
2236
2599
|
function makeRow(content, innerW, border) {
|
|
2237
|
-
const line =
|
|
2238
|
-
const pad = Math.max(0, innerW -
|
|
2600
|
+
const line = truncateToWidth2(content, innerW);
|
|
2601
|
+
const pad = Math.max(0, innerW - visibleWidth2(line));
|
|
2239
2602
|
return `${border} ${line}${" ".repeat(pad)} ${border}`;
|
|
2240
2603
|
}
|
|
2241
2604
|
function overlayColors(theme) {
|
|
@@ -2254,7 +2617,7 @@ function overlayInnerWidth(width) {
|
|
|
2254
2617
|
}
|
|
2255
2618
|
function overlayHeader(colors, width, title) {
|
|
2256
2619
|
const styled = colors.accent(` ${title} `);
|
|
2257
|
-
const fill = colors.borderFg("─".repeat(Math.max(0, width - 4 -
|
|
2620
|
+
const fill = colors.borderFg("─".repeat(Math.max(0, width - 4 - visibleWidth2(styled))));
|
|
2258
2621
|
return `${colors.borderFg("╭─")}${styled}${fill}${colors.borderFg("─╮")}`;
|
|
2259
2622
|
}
|
|
2260
2623
|
function overlayFooter(colors, width) {
|
|
@@ -2386,8 +2749,8 @@ async function runSettingsEditor(ctx) {
|
|
|
2386
2749
|
const { accent, bold, dim, muted, text } = colors;
|
|
2387
2750
|
const innerW = overlayInnerWidth(width);
|
|
2388
2751
|
const pad = (value, cellWidth) => {
|
|
2389
|
-
const clipped =
|
|
2390
|
-
return `${clipped}${" ".repeat(Math.max(0, cellWidth -
|
|
2752
|
+
const clipped = truncateToWidth2(value, cellWidth);
|
|
2753
|
+
return `${clipped}${" ".repeat(Math.max(0, cellWidth - visibleWidth2(clipped)))}`;
|
|
2391
2754
|
};
|
|
2392
2755
|
const tabLabel = (label, active) => active ? accent(bold(`[${label}]`)) : muted(label);
|
|
2393
2756
|
const tabs = `${tabLabel("Settings", tab === "settings")} ${tabLabel("Help", tab === "help")}`;
|
|
@@ -2395,11 +2758,11 @@ async function runSettingsEditor(ctx) {
|
|
|
2395
2758
|
if (editor) {
|
|
2396
2759
|
content.push(...editor.render(innerW));
|
|
2397
2760
|
} else if (tab === "help") {
|
|
2398
|
-
const shortcutWidth = Math.max(
|
|
2761
|
+
const shortcutWidth = Math.max(visibleWidth2("Shortcut"), ...helpRows.map(([shortcut]) => visibleWidth2(shortcut)));
|
|
2399
2762
|
const descriptionWidth = Math.max(1, innerW - shortcutWidth - 4);
|
|
2400
|
-
content.push(dim(` ${pad("Shortcut", shortcutWidth)} Description`), ...helpRows.map(([shortcut, description]) => ` ${accent(pad(shortcut, shortcutWidth))} ${text(
|
|
2763
|
+
content.push(dim(` ${pad("Shortcut", shortcutWidth)} Description`), ...helpRows.map(([shortcut, description]) => ` ${accent(pad(shortcut, shortcutWidth))} ${text(truncateToWidth2(description, descriptionWidth))}`));
|
|
2401
2764
|
} else {
|
|
2402
|
-
const labelWidth = Math.max(...specs.map(({ key }) =>
|
|
2765
|
+
const labelWidth = Math.max(...specs.map(({ key }) => visibleWidth2(settingLabel(key))));
|
|
2403
2766
|
for (const [index, entry] of specs.entries()) {
|
|
2404
2767
|
const selected = index === selectedSetting;
|
|
2405
2768
|
const inherited = projectSettings[entry.key] === undefined;
|
|
@@ -2537,7 +2900,7 @@ async function runSearchPanel(ctx, query, executablePath) {
|
|
|
2537
2900
|
}
|
|
2538
2901
|
return {
|
|
2539
2902
|
render(width) {
|
|
2540
|
-
const header = overlayHeader(colors, width, `Goosedump search: ${
|
|
2903
|
+
const header = overlayHeader(colors, width, `Goosedump search: ${truncateToWidth2(query, 44)}`);
|
|
2541
2904
|
if (error) {
|
|
2542
2905
|
return [header, ...overlayError(colors, width, error), overlayFooter(colors, width)];
|
|
2543
2906
|
}
|
|
@@ -3006,7 +3369,6 @@ ${renderToolRoutingPolicy()}`
|
|
|
3006
3369
|
compaction.updateStatus(ctx);
|
|
3007
3370
|
};
|
|
3008
3371
|
registerGooseCommand("goose-settings", "Edit goosedump settings", openSettingsEditor);
|
|
3009
|
-
registerGooseCommand("goosedump-settings", "Edit goosedump settings", openSettingsEditor);
|
|
3010
3372
|
registerGooseCommand("goose-compact", "Compact the current session now; optionally keep the last N user turns", async (args, ctx) => {
|
|
3011
3373
|
let keep = null;
|
|
3012
3374
|
if (args.trim()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Pi extension for goosedump session search, durable memory, session management, and compaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compaction",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"ci:test": "npm test"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@jarkkojs/goosedump": "^0.
|
|
40
|
+
"@jarkkojs/goosedump": "^0.13.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": "^0.84.2",
|