@sayknow-cli/coding-agent 0.6.4 → 0.6.5
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 +25 -1
- package/README.md +2 -2
- package/dist/types/config/keybindings.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +7 -3
- package/dist/types/i18n/messages/en.d.ts +16 -0
- package/dist/types/modes/components/session-selector.d.ts +7 -3
- package/dist/types/modes/components/sessions-dashboard.d.ts +2 -1
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/components/user-message.d.ts +3 -1
- package/dist/types/modes/components/welcome.d.ts +49 -6
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +5 -0
- package/dist/types/modes/interactive-mode.d.ts +7 -1
- package/dist/types/modes/theme/defaults/index.d.ts +342 -0
- package/dist/types/modes/theme/theme.d.ts +5 -1
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/session/session-manager.d.ts +9 -0
- package/dist/types/session/session-stars.d.ts +15 -0
- package/dist/types/tui/output-block.d.ts +12 -1
- package/dist/types/tui/utils.d.ts +1 -3
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +8 -0
- package/src/cli/session-picker.ts +4 -0
- package/src/config/keybindings.ts +1 -1
- package/src/config/settings-schema.ts +4 -3
- package/src/i18n/messages/de.messages.ts +4 -1
- package/src/i18n/messages/de.settings.ts +2 -0
- package/src/i18n/messages/de.ts +16 -0
- package/src/i18n/messages/en.ts +16 -0
- package/src/i18n/messages/es.messages.ts +4 -1
- package/src/i18n/messages/es.settings.ts +2 -0
- package/src/i18n/messages/es.ts +16 -0
- package/src/i18n/messages/fr.messages.ts +4 -1
- package/src/i18n/messages/fr.settings.ts +2 -0
- package/src/i18n/messages/fr.ts +16 -0
- package/src/i18n/messages/ja.messages.ts +4 -1
- package/src/i18n/messages/ja.settings.ts +2 -0
- package/src/i18n/messages/ja.ts +16 -0
- package/src/i18n/messages/ko.messages.ts +4 -1
- package/src/i18n/messages/ko.settings.ts +2 -0
- package/src/i18n/messages/ko.ts +16 -0
- package/src/i18n/messages/zh.messages.ts +2 -1
- package/src/i18n/messages/zh.settings.ts +2 -0
- package/src/i18n/messages/zh.ts +16 -0
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/lsp/render.ts +0 -1
- package/src/modes/components/session-selector.ts +71 -21
- package/src/modes/components/sessions-dashboard.ts +8 -5
- package/src/modes/components/settings-selector.ts +1 -0
- package/src/modes/components/status-line/presets.ts +5 -5
- package/src/modes/components/status-line/separators.ts +4 -0
- package/src/modes/components/tool-execution.ts +6 -19
- package/src/modes/components/tool-status-header.ts +103 -12
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/components/user-message.ts +25 -15
- package/src/modes/components/welcome.ts +374 -478
- package/src/modes/controllers/command-controller.ts +56 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +91 -10
- package/src/modes/interactive-mode.ts +101 -12
- package/src/modes/theme/defaults/glow-octopus.json +114 -0
- package/src/modes/theme/defaults/index.ts +6 -0
- package/src/modes/theme/defaults/ink-octopus.json +114 -0
- package/src/modes/theme/defaults/violet-octopus.json +114 -0
- package/src/modes/theme/theme.ts +18 -2
- package/src/modes/types.ts +1 -1
- package/src/prompts/system/title-system.md +1 -1
- package/src/sdk/protocol/operation-inventory.generated.json +40 -0
- package/src/session/agent-session.ts +12 -0
- package/src/session/internal/managed-session-scope.ts +10 -0
- package/src/session/session-manager.ts +26 -1
- package/src/session/session-stars.ts +104 -0
- package/src/slash-commands/builtin-registry.ts +104 -4
- package/src/tools/debug.ts +0 -1
- package/src/tools/fetch.ts +0 -1
- package/src/tui/output-block.ts +29 -61
- package/src/tui/utils.ts +1 -8
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
|
@@ -14,9 +14,10 @@ interface UserMessageItem {
|
|
|
14
14
|
*/
|
|
15
15
|
class UserMessageList implements Component {
|
|
16
16
|
#selectedIndex: number = 0;
|
|
17
|
+
#selectionInFlight = false;
|
|
17
18
|
onSelect?: (entryId: string) => void;
|
|
18
19
|
onCancel?: () => void;
|
|
19
|
-
#
|
|
20
|
+
#availableRows = Number.POSITIVE_INFINITY;
|
|
20
21
|
|
|
21
22
|
constructor(private readonly messages: UserMessageItem[]) {
|
|
22
23
|
// Store messages in chronological order (oldest to newest)
|
|
@@ -24,6 +25,10 @@ class UserMessageList implements Component {
|
|
|
24
25
|
this.#selectedIndex = Math.max(0, this.messages.length - 1);
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
setAvailableRows(rows: number): void {
|
|
29
|
+
this.#availableRows = Math.max(3, rows);
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
invalidate(): void {
|
|
28
33
|
// No cached state to invalidate currently
|
|
29
34
|
}
|
|
@@ -36,12 +41,15 @@ class UserMessageList implements Component {
|
|
|
36
41
|
return lines;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
//
|
|
44
|
+
// Each entry uses two content rows plus a separator. Leave one row for
|
|
45
|
+
// the scroll position whenever the full history does not fit.
|
|
46
|
+
const needsScrollIndicator = this.messages.length * 3 > this.#availableRows;
|
|
47
|
+
const maxVisible = Math.max(1, Math.floor((this.#availableRows - (needsScrollIndicator ? 1 : 0)) / 3));
|
|
40
48
|
const startIndex = Math.max(
|
|
41
49
|
0,
|
|
42
|
-
Math.min(this.#selectedIndex - Math.floor(
|
|
50
|
+
Math.min(this.#selectedIndex - Math.floor(maxVisible / 2), this.messages.length - maxVisible),
|
|
43
51
|
);
|
|
44
|
-
const endIndex = Math.min(startIndex +
|
|
52
|
+
const endIndex = Math.min(startIndex + maxVisible, this.messages.length);
|
|
45
53
|
|
|
46
54
|
// Render visible messages (2 lines per message + blank line)
|
|
47
55
|
for (let i = startIndex; i < endIndex; i++) {
|
|
@@ -77,6 +85,7 @@ class UserMessageList implements Component {
|
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
handleInput(keyData: string): void {
|
|
88
|
+
if (this.#selectionInFlight) return;
|
|
80
89
|
// Up arrow - go to previous (older) message, wrap to bottom when at top
|
|
81
90
|
if (matchesKey(keyData, "up")) {
|
|
82
91
|
this.#selectedIndex = this.#selectedIndex === 0 ? this.messages.length - 1 : this.#selectedIndex - 1;
|
|
@@ -89,6 +98,7 @@ class UserMessageList implements Component {
|
|
|
89
98
|
else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
|
|
90
99
|
const selected = this.messages[this.#selectedIndex];
|
|
91
100
|
if (selected && this.onSelect) {
|
|
101
|
+
this.#selectionInFlight = true;
|
|
92
102
|
this.onSelect(selected.id);
|
|
93
103
|
}
|
|
94
104
|
}
|
|
@@ -102,21 +112,43 @@ class UserMessageList implements Component {
|
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
/**
|
|
105
|
-
* Component that renders a
|
|
115
|
+
* Component that renders a prompt selector for creating a new session
|
|
106
116
|
*/
|
|
107
117
|
export class UserMessageSelectorComponent extends Container {
|
|
108
118
|
#messageList: UserMessageList;
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
#header: Container;
|
|
120
|
+
#footer: Container;
|
|
121
|
+
|
|
122
|
+
constructor(
|
|
123
|
+
messages: UserMessageItem[],
|
|
124
|
+
onSelect: (entryId: string) => void,
|
|
125
|
+
onCancel: () => void,
|
|
126
|
+
private readonly getViewportRows: () => number,
|
|
127
|
+
) {
|
|
111
128
|
super();
|
|
112
129
|
|
|
113
130
|
// Add header
|
|
114
|
-
this
|
|
115
|
-
this.addChild(new
|
|
116
|
-
this.addChild(new Text(theme.
|
|
117
|
-
this.addChild(
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
this.#header = new Container();
|
|
132
|
+
this.#header.addChild(new Spacer(1));
|
|
133
|
+
this.#header.addChild(new Text(theme.bold("Fork from Prompt"), 1, 0));
|
|
134
|
+
this.#header.addChild(
|
|
135
|
+
new Text(
|
|
136
|
+
theme.fg(
|
|
137
|
+
"muted",
|
|
138
|
+
"Creates a new session with history before the prompt; shared files stay in the same cwd.",
|
|
139
|
+
),
|
|
140
|
+
1,
|
|
141
|
+
0,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
this.#header.addChild(
|
|
145
|
+
new Text(theme.fg("muted", "The selected prompt is restored for editing, not submitted."), 1, 0),
|
|
146
|
+
);
|
|
147
|
+
this.#header.addChild(new Text(theme.fg("muted", "↑/↓ move · Enter select · Esc cancel"), 1, 0));
|
|
148
|
+
this.#header.addChild(new Spacer(1));
|
|
149
|
+
this.#header.addChild(new DynamicBorder());
|
|
150
|
+
this.#header.addChild(new Spacer(1));
|
|
151
|
+
this.addChild(this.#header);
|
|
120
152
|
|
|
121
153
|
// Create message list
|
|
122
154
|
this.#messageList = new UserMessageList(messages);
|
|
@@ -126,8 +158,10 @@ export class UserMessageSelectorComponent extends Container {
|
|
|
126
158
|
this.addChild(this.#messageList);
|
|
127
159
|
|
|
128
160
|
// Add bottom border
|
|
129
|
-
this
|
|
130
|
-
this.addChild(new
|
|
161
|
+
this.#footer = new Container();
|
|
162
|
+
this.#footer.addChild(new Spacer(1));
|
|
163
|
+
this.#footer.addChild(new DynamicBorder());
|
|
164
|
+
this.addChild(this.#footer);
|
|
131
165
|
|
|
132
166
|
// Auto-cancel if no messages
|
|
133
167
|
if (messages.length === 0) {
|
|
@@ -135,6 +169,14 @@ export class UserMessageSelectorComponent extends Container {
|
|
|
135
169
|
}
|
|
136
170
|
}
|
|
137
171
|
|
|
172
|
+
render(width: number): string[] {
|
|
173
|
+
const chromeRows = this.#header.render(width).length + this.#footer.render(width).length;
|
|
174
|
+
// Reserve the pinned status/composer rows outside the overlay. Recompute
|
|
175
|
+
// against current terminal rows and wrapped header height on every render.
|
|
176
|
+
this.#messageList.setAvailableRows(this.getViewportRows() - chromeRows - 2);
|
|
177
|
+
return super.render(width);
|
|
178
|
+
}
|
|
179
|
+
|
|
138
180
|
getMessageList(): UserMessageList {
|
|
139
181
|
return this.#messageList;
|
|
140
182
|
}
|
|
@@ -14,8 +14,13 @@ const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
|
14
14
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
15
15
|
const OSC133_ZONE_FINAL = "\x1b]133;C\x07";
|
|
16
16
|
|
|
17
|
+
/** Columns taken by the rail glyph plus the gap before the prompt text. */
|
|
18
|
+
const RAIL_WIDTH = 2;
|
|
19
|
+
|
|
17
20
|
/**
|
|
18
|
-
* Component that renders a user message
|
|
21
|
+
* Component that renders a user message: the prompt sits on the transcript
|
|
22
|
+
* background behind an accent rail instead of inside a filled bubble, so the
|
|
23
|
+
* user's turns read as margin notes rather than cards.
|
|
19
24
|
*/
|
|
20
25
|
export class UserMessageComponent extends Container {
|
|
21
26
|
#viewportAnchorSource?: ViewportAnchorSource;
|
|
@@ -23,14 +28,15 @@ export class UserMessageComponent extends Container {
|
|
|
23
28
|
constructor(text: string, synthetic = false, viewportAnchorId?: string) {
|
|
24
29
|
super();
|
|
25
30
|
if (viewportAnchorId) this.#viewportAnchorSource = { id: viewportAnchorId };
|
|
26
|
-
const bgColor = (value: string) => theme.bg("userMessageBg", value);
|
|
27
31
|
const color = synthetic
|
|
28
32
|
? (value: string) => theme.fg("dim", value)
|
|
29
33
|
: (value: string) => theme.fg("userMessageText", value);
|
|
34
|
+
// Resolved per render so a /theme switch recolors prompts already in the transcript.
|
|
35
|
+
const rail = () => theme.fg(synthetic ? "dim" : "accent", theme.rail.user);
|
|
30
36
|
this.addChild(new Spacer(1));
|
|
31
|
-
|
|
32
|
-
this.addChild(new Text(
|
|
33
|
-
const prompt = new PromptZoneMarkdown(text,
|
|
37
|
+
// A replayed prompt is not something the user just typed; say so once, quietly.
|
|
38
|
+
if (synthetic) this.addChild(new Text(`${rail()} ${theme.fg("dim", "replay")}`, 0, 0));
|
|
39
|
+
const prompt = new PromptZoneMarkdown(text, color, rail);
|
|
34
40
|
this.addChild(prompt);
|
|
35
41
|
if (this.#viewportAnchorSource) this.setViewportAnchorSource(prompt, this.#viewportAnchorSource);
|
|
36
42
|
}
|
|
@@ -38,31 +44,35 @@ export class UserMessageComponent extends Container {
|
|
|
38
44
|
|
|
39
45
|
class PromptZoneMarkdown implements Component {
|
|
40
46
|
#markdown: Markdown;
|
|
47
|
+
#rail: () => string;
|
|
41
48
|
|
|
42
|
-
constructor(text: string,
|
|
43
|
-
this.#markdown = new Markdown(text,
|
|
44
|
-
|
|
45
|
-
color,
|
|
46
|
-
});
|
|
49
|
+
constructor(text: string, color: (value: string) => string, rail: () => string) {
|
|
50
|
+
this.#markdown = new Markdown(text, 0, 0, getMarkdownTheme(), { color });
|
|
51
|
+
this.#rail = rail;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
invalidate(): void {
|
|
50
55
|
this.#markdown.invalidate();
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
#
|
|
58
|
+
#withRailAndPromptZone(lines: string[]): string[] {
|
|
54
59
|
if (lines.length === 0) return lines;
|
|
55
|
-
const
|
|
60
|
+
const rail = this.#rail();
|
|
61
|
+
const zoned = lines.map(line => `${rail} ${line}`);
|
|
56
62
|
zoned[0] = OSC133_ZONE_START + zoned[0];
|
|
57
63
|
zoned[zoned.length - 1] = `${zoned[zoned.length - 1]}${OSC133_ZONE_END}${OSC133_ZONE_FINAL}`;
|
|
58
64
|
return zoned;
|
|
59
65
|
}
|
|
60
66
|
|
|
67
|
+
#innerWidth(width: number): number {
|
|
68
|
+
return Math.max(1, width - RAIL_WIDTH);
|
|
69
|
+
}
|
|
70
|
+
|
|
61
71
|
renderWithViewportAnchorSource(width: number, source: ViewportAnchorSource): ViewportAnchorRender {
|
|
62
|
-
const rendered = this.#markdown.renderWithViewportAnchorSource(width, source);
|
|
63
|
-
return { lines: this.#
|
|
72
|
+
const rendered = this.#markdown.renderWithViewportAnchorSource(this.#innerWidth(width), source);
|
|
73
|
+
return { lines: this.#withRailAndPromptZone(rendered.lines), anchors: rendered.anchors };
|
|
64
74
|
}
|
|
65
75
|
render(width: number): string[] {
|
|
66
|
-
return this.#
|
|
76
|
+
return this.#withRailAndPromptZone(this.#markdown.render(this.#innerWidth(width)));
|
|
67
77
|
}
|
|
68
78
|
}
|