gsd-pi 2.74.0-dev.ffbcc03 → 2.75.0-dev.063e5a3
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/resources/extensions/gsd/auto/phases.js +51 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +3 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -3
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +5 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +50 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -0
- package/dist/resources/extensions/gsd/guided-flow.js +7 -5
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +10 -0
- package/dist/resources/extensions/gsd/preferences.js +5 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/package.json +2 -2
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +61 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts +8 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +27 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +92 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +12 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +36 -15
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -2
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/tui.ts +9 -1
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/phases.ts +70 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +3 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +5 -3
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +5 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +57 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -0
- package/src/resources/extensions/gsd/guided-flow.ts +3 -1
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +10 -0
- package/src/resources/extensions/gsd/preferences.ts +6 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/preferences.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +57 -2
- /package/dist/web/standalone/.next/static/{kn6xzWKYnogsxp2b6RpDD → j7IBD35UgrL2b298GLK3V}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{kn6xzWKYnogsxp2b6RpDD → j7IBD35UgrL2b298GLK3V}/_ssgManifest.js +0 -0
package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Container, Markdown, Text } from "@gsd/pi-tui";
|
|
2
2
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
|
+
import { renderChatFrame } from "./chat-frame.js";
|
|
3
4
|
import { editorKey } from "./keybinding-hints.js";
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* Renders a compaction notice in the shared chat-frame style (top rule,
|
|
7
|
+
* `• compaction` header, `│ ` body margin) with purple border/label so it
|
|
8
|
+
* visually matches the other framed messages (user / assistant / tool
|
|
9
|
+
* execution) while standing apart from the conversation flow.
|
|
7
10
|
*/
|
|
8
|
-
export class CompactionSummaryMessageComponent extends
|
|
11
|
+
export class CompactionSummaryMessageComponent extends Container {
|
|
9
12
|
constructor(message, markdownTheme = getMarkdownTheme()) {
|
|
10
|
-
super(
|
|
13
|
+
super();
|
|
11
14
|
this.expanded = false;
|
|
12
15
|
this.message = message;
|
|
13
16
|
this.markdownTheme = markdownTheme;
|
|
14
|
-
this.
|
|
17
|
+
this.rebuild();
|
|
15
18
|
}
|
|
16
19
|
setExpanded(expanded) {
|
|
17
|
-
this.expanded
|
|
18
|
-
|
|
20
|
+
if (this.expanded !== expanded) {
|
|
21
|
+
this.expanded = expanded;
|
|
22
|
+
this.rebuild();
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
invalidate() {
|
|
21
26
|
super.invalidate();
|
|
22
|
-
this.
|
|
27
|
+
this.rebuild();
|
|
23
28
|
}
|
|
24
|
-
|
|
29
|
+
rebuild() {
|
|
25
30
|
this.clear();
|
|
26
31
|
const tokenStr = this.message.tokensBefore.toLocaleString();
|
|
27
|
-
const label = theme.fg("customMessageLabel", theme.bold("[compaction]"));
|
|
28
|
-
this.addChild(new Text(label, 0, 0));
|
|
29
|
-
this.addChild(new Spacer(1));
|
|
30
32
|
if (this.expanded) {
|
|
31
33
|
const header = `**Compacted from ${tokenStr} tokens**\n\n`;
|
|
32
34
|
this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
|
|
@@ -39,5 +41,17 @@ export class CompactionSummaryMessageComponent extends Box {
|
|
|
39
41
|
theme.fg("customMessageText", " to expand)"), 0, 0));
|
|
40
42
|
}
|
|
41
43
|
}
|
|
44
|
+
render(width) {
|
|
45
|
+
const frameWidth = Math.max(20, width);
|
|
46
|
+
const contentWidth = Math.max(1, frameWidth - 4);
|
|
47
|
+
const lines = super.render(contentWidth);
|
|
48
|
+
const framed = renderChatFrame(lines, frameWidth, {
|
|
49
|
+
label: "compaction",
|
|
50
|
+
tone: "compaction",
|
|
51
|
+
timestampFormat: "date-time-iso",
|
|
52
|
+
showTimestamp: false,
|
|
53
|
+
});
|
|
54
|
+
return framed.length > 0 ? ["", ...framed] : framed;
|
|
55
|
+
}
|
|
42
56
|
}
|
|
43
57
|
//# sourceMappingURL=compaction-summary-message.js.map
|
package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,IAAI,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,OAAO,iCAAkC,SAAQ,SAAS;IAK/D,YACC,OAAiC,EACjC,gBAA+B,gBAAgB,EAAE;QAEjD,KAAK,EAAE,CAAC;QARD,aAAQ,GAAG,KAAK,CAAC;QASxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;IAChB,CAAC;IAED,WAAW,CAAC,QAAiB;QAC5B,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACzB,IAAI,CAAC,OAAO,EAAE,CAAC;QAChB,CAAC;IACF,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;IAChB,CAAC;IAEO,OAAO;QACd,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QAE5D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,oBAAoB,QAAQ,eAAe,CAAC;YAC3D,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CACP,mBAAmB,EACnB,kBAAkB,QAAQ,WAAW,CACrC;gBACA,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;gBACzC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IACF,CAAC;IAEQ,MAAM,CAAC,KAAa;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE;YACjD,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,YAAY;YAClB,eAAe,EAAE,eAAe;YAChC,aAAa,EAAE,KAAK;SACpB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACrD,CAAC;CACD","sourcesContent":["import { Container, Markdown, type MarkdownTheme, Text } from \"@gsd/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { renderChatFrame } from \"./chat-frame.js\";\nimport { editorKey } from \"./keybinding-hints.js\";\n\n/**\n * Renders a compaction notice in the shared chat-frame style (top rule,\n * `• compaction` header, `│ ` body margin) with purple border/label so it\n * visually matches the other framed messages (user / assistant / tool\n * execution) while standing apart from the conversation flow.\n */\nexport class CompactionSummaryMessageComponent extends Container {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(\n\t\tmessage: CompactionSummaryMessage,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t) {\n\t\tsuper();\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.rebuild();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this.expanded !== expanded) {\n\t\t\tthis.expanded = expanded;\n\t\t\tthis.rebuild();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.clear();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"customMessageText\",\n\t\t\t\t\t\t`Compacted from ${tokenStr} tokens (`,\n\t\t\t\t\t) +\n\t\t\t\t\t\ttheme.fg(\"dim\", editorKey(\"expandTools\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst frameWidth = Math.max(20, width);\n\t\tconst contentWidth = Math.max(1, frameWidth - 4);\n\t\tconst lines = super.render(contentWidth);\n\t\tconst framed = renderChatFrame(lines, frameWidth, {\n\t\t\tlabel: \"compaction\",\n\t\t\ttone: \"compaction\",\n\t\t\ttimestampFormat: \"date-time-iso\",\n\t\t\tshowTimestamp: false,\n\t\t});\n\t\treturn framed.length > 0 ? [\"\", ...framed] : framed;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { test, describe } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import stripAnsi from "strip-ansi";
|
|
4
|
+
import { renderChatFrame } from "../chat-frame.js";
|
|
5
|
+
import { initTheme } from "../../theme/theme.js";
|
|
6
|
+
|
|
7
|
+
initTheme("dark", false);
|
|
8
|
+
|
|
9
|
+
// Regression tests for the "compaction" tone added to renderChatFrame.
|
|
10
|
+
// The compaction notice shares the same visual frame as user / assistant
|
|
11
|
+
// messages (top rule, `• label` header, `│ ` body prefix) but uses the
|
|
12
|
+
// purple `customMessageLabel` color key so it is visually distinct from
|
|
13
|
+
// conversation turns.
|
|
14
|
+
|
|
15
|
+
describe("renderChatFrame — compaction tone", () => {
|
|
16
|
+
test("produces a top rule, `• compaction` header row, and a │ body margin", () => {
|
|
17
|
+
const lines = renderChatFrame(
|
|
18
|
+
["Compacted from 1,224,262 tokens (ctrl+o to expand)"],
|
|
19
|
+
60,
|
|
20
|
+
{
|
|
21
|
+
label: "compaction",
|
|
22
|
+
tone: "compaction",
|
|
23
|
+
timestampFormat: "date-time-iso",
|
|
24
|
+
showTimestamp: false,
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Structure: top rule, header, body line(s)
|
|
29
|
+
assert.ok(lines.length >= 3, `expected at least 3 frame lines, got ${lines.length}`);
|
|
30
|
+
|
|
31
|
+
const plain = lines.map((line) => stripAnsi(line));
|
|
32
|
+
|
|
33
|
+
// Top rule is a solid horizontal bar
|
|
34
|
+
assert.match(plain[0], /^─+$/, "first line should be the solid top rule");
|
|
35
|
+
|
|
36
|
+
// Header row contains `• compaction`
|
|
37
|
+
assert.ok(
|
|
38
|
+
plain[1].includes("• compaction"),
|
|
39
|
+
`expected header to contain "• compaction", got ${JSON.stringify(plain[1])}`,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Body line(s) start with `│ `
|
|
43
|
+
assert.ok(
|
|
44
|
+
plain[2].startsWith("│ "),
|
|
45
|
+
`expected body line to start with "│ ", got ${JSON.stringify(plain[2])}`,
|
|
46
|
+
);
|
|
47
|
+
assert.ok(
|
|
48
|
+
plain[2].includes("Compacted from 1,224,262 tokens"),
|
|
49
|
+
"body line should include the original content",
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("does not render a right-aligned timestamp when showTimestamp is false", () => {
|
|
54
|
+
const lines = renderChatFrame(["body"], 60, {
|
|
55
|
+
label: "compaction",
|
|
56
|
+
tone: "compaction",
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
timestampFormat: "date-time-iso",
|
|
59
|
+
showTimestamp: false,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const header = stripAnsi(lines[1]);
|
|
63
|
+
// No four-digit year should appear anywhere in the header row
|
|
64
|
+
assert.ok(
|
|
65
|
+
!/\b20\d{2}\b/.test(header),
|
|
66
|
+
`timestamp should be suppressed when showTimestamp=false, got ${JSON.stringify(header)}`,
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("emits ANSI color codes distinct from the assistant tone", () => {
|
|
71
|
+
const assistantFrame = renderChatFrame(["body"], 60, {
|
|
72
|
+
label: "claude",
|
|
73
|
+
tone: "assistant",
|
|
74
|
+
timestampFormat: "date-time-iso",
|
|
75
|
+
showTimestamp: false,
|
|
76
|
+
}).join("\n");
|
|
77
|
+
|
|
78
|
+
const compactionFrame = renderChatFrame(["body"], 60, {
|
|
79
|
+
label: "compaction",
|
|
80
|
+
tone: "compaction",
|
|
81
|
+
timestampFormat: "date-time-iso",
|
|
82
|
+
showTimestamp: false,
|
|
83
|
+
}).join("\n");
|
|
84
|
+
|
|
85
|
+
// Both frames carry ANSI; the compaction frame should not be identical
|
|
86
|
+
// to the assistant frame (different color mappings).
|
|
87
|
+
assert.ok(
|
|
88
|
+
assistantFrame !== compactionFrame,
|
|
89
|
+
"compaction tone must produce a different styled output than assistant tone",
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -2,7 +2,7 @@ import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
|
2
2
|
import { theme } from "../theme/theme.js";
|
|
3
3
|
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
4
4
|
|
|
5
|
-
type FrameTone = "assistant" | "user";
|
|
5
|
+
type FrameTone = "assistant" | "user" | "compaction";
|
|
6
6
|
|
|
7
7
|
function trimOuterBlankLines(lines: string[]): string[] {
|
|
8
8
|
let start = 0;
|
|
@@ -25,8 +25,14 @@ export function renderChatFrame(
|
|
|
25
25
|
): string[] {
|
|
26
26
|
const outerWidth = Math.max(20, width);
|
|
27
27
|
const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
|
|
28
|
-
const borderColor =
|
|
29
|
-
|
|
28
|
+
const borderColor =
|
|
29
|
+
opts.tone === "user"
|
|
30
|
+
? "borderAccent"
|
|
31
|
+
: opts.tone === "compaction"
|
|
32
|
+
? "customMessageLabel"
|
|
33
|
+
: "border";
|
|
34
|
+
const borderMuted =
|
|
35
|
+
opts.tone === "compaction" ? "customMessageLabel" : "borderMuted";
|
|
30
36
|
const border = (s: string) => theme.fg(borderColor, s);
|
|
31
37
|
const leftRaw = `• ${opts.label}`;
|
|
32
38
|
const rightRaw =
|
|
@@ -41,7 +47,9 @@ export function renderChatFrame(
|
|
|
41
47
|
const leftStyled =
|
|
42
48
|
opts.tone === "user"
|
|
43
49
|
? theme.fg("accent", theme.bold(left))
|
|
44
|
-
:
|
|
50
|
+
: opts.tone === "compaction"
|
|
51
|
+
? theme.fg("customMessageLabel", theme.bold(left))
|
|
52
|
+
: theme.fg("muted", theme.bold(left));
|
|
45
53
|
const rightStyled = rightRaw ? theme.fg("dim", rightRaw) : "";
|
|
46
54
|
const gap =
|
|
47
55
|
rightRaw.length > 0
|
package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts
CHANGED
|
@@ -1,41 +1,46 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Container, Markdown, type MarkdownTheme, Text } from "@gsd/pi-tui";
|
|
2
2
|
import type { CompactionSummaryMessage } from "../../../core/messages.js";
|
|
3
3
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
4
|
+
import { renderChatFrame } from "./chat-frame.js";
|
|
4
5
|
import { editorKey } from "./keybinding-hints.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* Renders a compaction notice in the shared chat-frame style (top rule,
|
|
9
|
+
* `• compaction` header, `│ ` body margin) with purple border/label so it
|
|
10
|
+
* visually matches the other framed messages (user / assistant / tool
|
|
11
|
+
* execution) while standing apart from the conversation flow.
|
|
9
12
|
*/
|
|
10
|
-
export class CompactionSummaryMessageComponent extends
|
|
13
|
+
export class CompactionSummaryMessageComponent extends Container {
|
|
11
14
|
private expanded = false;
|
|
12
15
|
private message: CompactionSummaryMessage;
|
|
13
16
|
private markdownTheme: MarkdownTheme;
|
|
14
17
|
|
|
15
|
-
constructor(
|
|
16
|
-
|
|
18
|
+
constructor(
|
|
19
|
+
message: CompactionSummaryMessage,
|
|
20
|
+
markdownTheme: MarkdownTheme = getMarkdownTheme(),
|
|
21
|
+
) {
|
|
22
|
+
super();
|
|
17
23
|
this.message = message;
|
|
18
24
|
this.markdownTheme = markdownTheme;
|
|
19
|
-
this.
|
|
25
|
+
this.rebuild();
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
setExpanded(expanded: boolean): void {
|
|
23
|
-
this.expanded
|
|
24
|
-
|
|
29
|
+
if (this.expanded !== expanded) {
|
|
30
|
+
this.expanded = expanded;
|
|
31
|
+
this.rebuild();
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
override invalidate(): void {
|
|
28
36
|
super.invalidate();
|
|
29
|
-
this.
|
|
37
|
+
this.rebuild();
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
private
|
|
40
|
+
private rebuild(): void {
|
|
33
41
|
this.clear();
|
|
34
42
|
|
|
35
43
|
const tokenStr = this.message.tokensBefore.toLocaleString();
|
|
36
|
-
const label = theme.fg("customMessageLabel", theme.bold("[compaction]"));
|
|
37
|
-
this.addChild(new Text(label, 0, 0));
|
|
38
|
-
this.addChild(new Spacer(1));
|
|
39
44
|
|
|
40
45
|
if (this.expanded) {
|
|
41
46
|
const header = `**Compacted from ${tokenStr} tokens**\n\n`;
|
|
@@ -47,7 +52,10 @@ export class CompactionSummaryMessageComponent extends Box {
|
|
|
47
52
|
} else {
|
|
48
53
|
this.addChild(
|
|
49
54
|
new Text(
|
|
50
|
-
theme.fg(
|
|
55
|
+
theme.fg(
|
|
56
|
+
"customMessageText",
|
|
57
|
+
`Compacted from ${tokenStr} tokens (`,
|
|
58
|
+
) +
|
|
51
59
|
theme.fg("dim", editorKey("expandTools")) +
|
|
52
60
|
theme.fg("customMessageText", " to expand)"),
|
|
53
61
|
0,
|
|
@@ -56,4 +64,17 @@ export class CompactionSummaryMessageComponent extends Box {
|
|
|
56
64
|
);
|
|
57
65
|
}
|
|
58
66
|
}
|
|
67
|
+
|
|
68
|
+
override render(width: number): string[] {
|
|
69
|
+
const frameWidth = Math.max(20, width);
|
|
70
|
+
const contentWidth = Math.max(1, frameWidth - 4);
|
|
71
|
+
const lines = super.render(contentWidth);
|
|
72
|
+
const framed = renderChatFrame(lines, frameWidth, {
|
|
73
|
+
label: "compaction",
|
|
74
|
+
tone: "compaction",
|
|
75
|
+
timestampFormat: "date-time-iso",
|
|
76
|
+
showTimestamp: false,
|
|
77
|
+
});
|
|
78
|
+
return framed.length > 0 ? ["", ...framed] : framed;
|
|
79
|
+
}
|
|
59
80
|
}
|