killeros 1.5.8 → 2.0.1
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 +17 -130
- package/Killeros.ts +1 -25
- package/README.md +130 -209
- package/killeros/bounded-text.ts +25 -0
- package/killeros/commands.ts +8 -238
- package/killeros/display.ts +6 -2
- package/killeros/footer.ts +35 -5
- package/killeros/goals.ts +53 -25
- package/killeros/hooks.ts +1 -1
- package/killeros/limits.ts +1 -0
- package/killeros/personal-instructions.ts +3 -1
- package/killeros/question.ts +144 -97
- package/killeros/shell-ui.ts +230 -54
- package/killeros/variants.ts +6 -2
- package/package.json +1 -6
- package/themes/killeros.json +4 -3
- package/killeros/subagent-lifecycle.ts +0 -761
- package/killeros/subagent-persistence.ts +0 -572
- package/killeros/subagent-process.ts +0 -626
- package/killeros/subagent-ui.ts +0 -245
- package/killeros/subagents.ts +0 -3257
- package/subagent-lifecycle.ts +0 -1
- package/subagent-process.ts +0 -1
- package/subagent-ui.ts +0 -1
- package/subagents.ts +0 -1
package/killeros/shell-ui.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import {
|
|
4
4
|
CustomEditor,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import {
|
|
13
13
|
Container,
|
|
14
|
+
CURSOR_MARKER,
|
|
14
15
|
Text,
|
|
15
16
|
truncateToWidth,
|
|
16
17
|
visibleWidth,
|
|
@@ -18,16 +19,14 @@ import {
|
|
|
18
19
|
type EditorTheme,
|
|
19
20
|
type TUI,
|
|
20
21
|
} from "@earendil-works/pi-tui";
|
|
22
|
+
import { availableCommandNames } from "./commands.ts";
|
|
21
23
|
import { formatCwd, padRight } from "./display.ts";
|
|
22
24
|
import { reportError } from "./errors.ts";
|
|
23
25
|
import { formatModel } from "./footer.ts";
|
|
24
26
|
import { LEVEL_COLORS, type ThinkingLevel } from "./variants.ts";
|
|
25
27
|
|
|
26
|
-
const COMMAND_BLUE_RGB = "120;169;255";
|
|
27
28
|
const COMPACT_HEADER_MAX_WIDTH = 52;
|
|
28
29
|
|
|
29
|
-
const commandBlue = (text: string): string => `\x1B[38;2;${COMMAND_BLUE_RGB}m${text}\x1B[39m`;
|
|
30
|
-
|
|
31
30
|
function readPackageVersion(path: string | URL): string | undefined {
|
|
32
31
|
try {
|
|
33
32
|
const value = JSON.parse(readFileSync(path, "utf8")) as { version?: unknown };
|
|
@@ -45,20 +44,27 @@ const STARTUP_TIPS = [
|
|
|
45
44
|
"Type / to browse every command available in this session.",
|
|
46
45
|
] as const;
|
|
47
46
|
|
|
48
|
-
function resolveGitBranch(cwd: string): string | undefined {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
export function resolveGitBranch(cwd: string): Promise<string | undefined> {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
execFile(
|
|
50
|
+
"git",
|
|
51
|
+
["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"],
|
|
52
|
+
{
|
|
53
|
+
encoding: "utf8",
|
|
54
|
+
maxBuffer: 64 * 1024,
|
|
55
|
+
timeout: 500,
|
|
56
|
+
windowsHide: true,
|
|
57
|
+
},
|
|
58
|
+
(error, stdout) => {
|
|
59
|
+
if (error) {
|
|
60
|
+
resolve(undefined);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const branch = stdout.trim();
|
|
64
|
+
resolve(branch ? branch === "HEAD" ? "detached" : branch : undefined);
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
});
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
function shuffledTips(): string[] {
|
|
@@ -78,14 +84,21 @@ function compactBoxLine(content: string, width: number, theme: Theme): string {
|
|
|
78
84
|
class PiStartupHeader {
|
|
79
85
|
private readonly pi: ExtensionAPI;
|
|
80
86
|
private readonly ctx: ExtensionContext;
|
|
81
|
-
private readonly branch: string | undefined;
|
|
82
87
|
private readonly tip: string;
|
|
88
|
+
private readonly tui: TUI;
|
|
89
|
+
private branch: string | undefined;
|
|
90
|
+
private disposed = false;
|
|
83
91
|
|
|
84
|
-
constructor(pi: ExtensionAPI, ctx: ExtensionContext, tip: string) {
|
|
92
|
+
constructor(pi: ExtensionAPI, ctx: ExtensionContext, tip: string, tui: TUI) {
|
|
85
93
|
this.pi = pi;
|
|
86
94
|
this.ctx = ctx;
|
|
87
|
-
this.branch = resolveGitBranch(ctx.cwd);
|
|
88
95
|
this.tip = tip;
|
|
96
|
+
this.tui = tui;
|
|
97
|
+
void resolveGitBranch(ctx.cwd).then((branch) => {
|
|
98
|
+
if (this.disposed) return;
|
|
99
|
+
this.branch = branch;
|
|
100
|
+
this.tui.requestRender();
|
|
101
|
+
});
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
private tipLines(width: number, theme: Theme): string[] {
|
|
@@ -113,7 +126,7 @@ class PiStartupHeader {
|
|
|
113
126
|
const repository = this.branch
|
|
114
127
|
? `${directory} ${theme.fg("dim", `· ${this.branch}`)}`
|
|
115
128
|
: directory;
|
|
116
|
-
const modelCommand =
|
|
129
|
+
const modelCommand = theme.fg("mdLink", "/model");
|
|
117
130
|
const agentWidth = Math.max(0, innerWidth - visibleWidth(modelCommand) - 1);
|
|
118
131
|
const agentCommand = `${truncateToWidth(agent, agentWidth, "…")} ${modelCommand}`;
|
|
119
132
|
const border = (left: string, right: string): string => theme.fg("dim", `${left}${"─".repeat(panelWidth - 2)}${right}`);
|
|
@@ -131,10 +144,119 @@ class PiStartupHeader {
|
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
invalidate(): void {}
|
|
134
|
-
dispose(): void {
|
|
147
|
+
dispose(): void {
|
|
148
|
+
this.disposed = true;
|
|
149
|
+
}
|
|
135
150
|
}
|
|
136
151
|
|
|
137
152
|
const ANSI_REGEX = /\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
153
|
+
const ANSI_SEQUENCE_AT_START = /^\x1b\[[0-?]*[ -/]*[@-~]/u;
|
|
154
|
+
const COMMAND_TOKEN_PATTERN = /(^|[ \t])(\/[A-Za-z0-9:_-]*)/gu;
|
|
155
|
+
|
|
156
|
+
function controlSequenceAt(text: string, index: number): string | undefined {
|
|
157
|
+
if (text.startsWith(CURSOR_MARKER, index)) return CURSOR_MARKER;
|
|
158
|
+
return text.slice(index).match(ANSI_SEQUENCE_AT_START)?.[0];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface CommandToken {
|
|
162
|
+
text: string;
|
|
163
|
+
start: number;
|
|
164
|
+
end: number;
|
|
165
|
+
valid: boolean;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
interface EditorVisualLine {
|
|
169
|
+
logicalLine: number;
|
|
170
|
+
startCol: number;
|
|
171
|
+
length: number;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function commandTokens(text: string, normalizedNames: readonly string[]): CommandToken[] {
|
|
175
|
+
return [...text.matchAll(COMMAND_TOKEN_PATTERN)].map((match) => {
|
|
176
|
+
const token = match[2] ?? "";
|
|
177
|
+
const prefix = token.slice(1).toLocaleLowerCase();
|
|
178
|
+
const start = (match.index ?? 0) + (match[1]?.length ?? 0);
|
|
179
|
+
return {
|
|
180
|
+
text: token,
|
|
181
|
+
start,
|
|
182
|
+
end: start + token.length,
|
|
183
|
+
valid: normalizedNames.some((name) => name.startsWith(prefix)),
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function highlightTextRanges(
|
|
189
|
+
text: string,
|
|
190
|
+
ranges: Array<{ start: number; end: number }>,
|
|
191
|
+
color: (value: string) => string,
|
|
192
|
+
): string {
|
|
193
|
+
if (ranges.length === 0) return text;
|
|
194
|
+
|
|
195
|
+
let output = "";
|
|
196
|
+
let buffer = "";
|
|
197
|
+
let bufferHighlighted: boolean | undefined;
|
|
198
|
+
let plainIndex = 0;
|
|
199
|
+
const flush = (): void => {
|
|
200
|
+
if (!buffer) return;
|
|
201
|
+
output += bufferHighlighted ? color(buffer) : buffer;
|
|
202
|
+
buffer = "";
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
for (let index = 0; index < text.length;) {
|
|
206
|
+
const control = controlSequenceAt(text, index);
|
|
207
|
+
if (control) {
|
|
208
|
+
flush();
|
|
209
|
+
output += control;
|
|
210
|
+
index += control.length;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const highlighted = ranges.some((range) => plainIndex >= range.start && plainIndex < range.end);
|
|
215
|
+
if (bufferHighlighted !== highlighted) {
|
|
216
|
+
flush();
|
|
217
|
+
bufferHighlighted = highlighted;
|
|
218
|
+
}
|
|
219
|
+
buffer += text[index];
|
|
220
|
+
plainIndex += 1;
|
|
221
|
+
index += 1;
|
|
222
|
+
}
|
|
223
|
+
flush();
|
|
224
|
+
return output;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function highlightEditorLines(
|
|
228
|
+
lines: string[],
|
|
229
|
+
sourceLines: string[],
|
|
230
|
+
visualLines: EditorVisualLine[],
|
|
231
|
+
scrollOffset: number,
|
|
232
|
+
commandNames: ReadonlySet<string>,
|
|
233
|
+
color: (value: string) => string,
|
|
234
|
+
): { lines: string[]; bottomBorderIndex: number } {
|
|
235
|
+
let bottomBorderIndex = -1;
|
|
236
|
+
for (let index = lines.length - 1; index >= 1; index -= 1) {
|
|
237
|
+
if (isBorderLine(lines[index] ?? "")) {
|
|
238
|
+
bottomBorderIndex = index;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (bottomBorderIndex < 0) bottomBorderIndex = lines.length - 1;
|
|
243
|
+
|
|
244
|
+
const normalizedNames = [...commandNames].map((name) => name.toLocaleLowerCase());
|
|
245
|
+
for (let index = 1; index < bottomBorderIndex; index += 1) {
|
|
246
|
+
const visualLine = visualLines[scrollOffset + index - 1];
|
|
247
|
+
if (!visualLine) continue;
|
|
248
|
+
const visibleStart = visualLine.startCol;
|
|
249
|
+
const visibleEnd = visibleStart + visualLine.length;
|
|
250
|
+
const ranges = commandTokens(sourceLines[visualLine.logicalLine] ?? "", normalizedNames)
|
|
251
|
+
.filter((token) => token.valid && token.start < visibleEnd && token.end > visibleStart)
|
|
252
|
+
.map((token) => ({
|
|
253
|
+
start: Math.max(token.start, visibleStart) - visibleStart,
|
|
254
|
+
end: Math.min(token.end, visibleEnd) - visibleStart,
|
|
255
|
+
}));
|
|
256
|
+
lines[index] = highlightTextRanges(lines[index] ?? "", ranges, color);
|
|
257
|
+
}
|
|
258
|
+
return { lines, bottomBorderIndex };
|
|
259
|
+
}
|
|
138
260
|
|
|
139
261
|
function stripAnsi(text: string): string {
|
|
140
262
|
return text.replace(ANSI_REGEX, "").trim();
|
|
@@ -145,12 +267,27 @@ function isBorderLine(line: string): boolean {
|
|
|
145
267
|
return /^[─━═]+$/.test(unstyled) || /^───\s*[↓↑]/.test(unstyled) || /^─{3,}/.test(unstyled);
|
|
146
268
|
}
|
|
147
269
|
|
|
270
|
+
function isScrolledTopBorder(line: string): boolean {
|
|
271
|
+
const unstyled = stripAnsi(line);
|
|
272
|
+
return unstyled.includes("↑") || unstyled.includes(".");
|
|
273
|
+
}
|
|
274
|
+
|
|
148
275
|
class PiCodeEditor extends CustomEditor {
|
|
149
276
|
private readonly appKeybindings: KeybindingsManager;
|
|
150
|
-
|
|
151
|
-
|
|
277
|
+
private readonly runtimeTheme: Theme;
|
|
278
|
+
private readonly getCommandNames: () => ReadonlySet<string>;
|
|
279
|
+
|
|
280
|
+
constructor(
|
|
281
|
+
tui: TUI,
|
|
282
|
+
theme: EditorTheme,
|
|
283
|
+
appKeybindings: KeybindingsManager,
|
|
284
|
+
runtimeTheme: Theme,
|
|
285
|
+
getCommandNames: () => ReadonlySet<string>,
|
|
286
|
+
) {
|
|
152
287
|
super(tui, theme, appKeybindings);
|
|
153
288
|
this.appKeybindings = appKeybindings;
|
|
289
|
+
this.runtimeTheme = runtimeTheme;
|
|
290
|
+
this.getCommandNames = getCommandNames;
|
|
154
291
|
}
|
|
155
292
|
|
|
156
293
|
override handleInput(data: string): void {
|
|
@@ -167,25 +304,42 @@ class PiCodeEditor extends CustomEditor {
|
|
|
167
304
|
super.handleInput(data);
|
|
168
305
|
}
|
|
169
306
|
|
|
307
|
+
private renderWithCommandHighlighting(
|
|
308
|
+
width: number,
|
|
309
|
+
color: (value: string) => string,
|
|
310
|
+
): { lines: string[]; bottomBorderIndex: number } {
|
|
311
|
+
const lines = super.render(width);
|
|
312
|
+
const internals = this as unknown as {
|
|
313
|
+
lastWidth: number;
|
|
314
|
+
scrollOffset: number;
|
|
315
|
+
buildVisualLineMap: (layoutWidth: number) => EditorVisualLine[];
|
|
316
|
+
};
|
|
317
|
+
return highlightEditorLines(
|
|
318
|
+
lines,
|
|
319
|
+
this.getLines(),
|
|
320
|
+
internals.buildVisualLineMap(internals.lastWidth),
|
|
321
|
+
internals.scrollOffset,
|
|
322
|
+
this.getCommandNames(),
|
|
323
|
+
color,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
170
327
|
override render(width: number): string[] {
|
|
171
|
-
if (width
|
|
328
|
+
if (width <= 0) return [];
|
|
329
|
+
const colorCommand = (value: string): string => this.runtimeTheme.fg("mdLink", value);
|
|
330
|
+
if (width < 4) {
|
|
331
|
+
return this.renderWithCommandHighlighting(width, colorCommand)
|
|
332
|
+
.lines.map((line) => truncateToWidth(line, width, ""));
|
|
333
|
+
}
|
|
172
334
|
const innerWidth = width - 2;
|
|
173
|
-
const
|
|
335
|
+
const highlighted = this.renderWithCommandHighlighting(innerWidth, colorCommand);
|
|
336
|
+
const { lines, bottomBorderIndex } = highlighted;
|
|
174
337
|
if (lines.length < 2) return lines.map((line) => truncateToWidth(line, width, ""));
|
|
175
338
|
|
|
176
|
-
const gray = (text: string): string =>
|
|
177
|
-
let bottomBorderIndex = -1;
|
|
178
|
-
for (let index = lines.length - 1; index >= 1; index -= 1) {
|
|
179
|
-
if (isBorderLine(lines[index] ?? "")) {
|
|
180
|
-
bottomBorderIndex = index;
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (bottomBorderIndex < 0) bottomBorderIndex = lines.length - 1;
|
|
185
|
-
|
|
339
|
+
const gray = (text: string): string => this.runtimeTheme.fg("dim", text);
|
|
186
340
|
const framed: string[] = [];
|
|
187
341
|
const top = stripAnsi(lines[0] ?? "");
|
|
188
|
-
const isScrolledHeader =
|
|
342
|
+
const isScrolledHeader = isScrolledTopBorder(lines[0] ?? "");
|
|
189
343
|
if (isScrolledHeader) {
|
|
190
344
|
const count = top.match(/↑\s*(\d+)/)?.[1] ?? "";
|
|
191
345
|
const indicator = `${gray("─── ↑ ")}${count}${gray(" more ")}${gray("─".repeat(Math.max(0, width - 12 - count.length)))}`;
|
|
@@ -219,34 +373,50 @@ const ACTIVITY_WORDS = ["Brewing", "Pondering", "Tinkering", "Wrangling", "Noodl
|
|
|
219
373
|
|
|
220
374
|
export function registerShellUi(pi: ExtensionAPI): void {
|
|
221
375
|
let activeHeader: PiStartupHeader | undefined;
|
|
222
|
-
let
|
|
376
|
+
let activityDeck: string[] = [];
|
|
377
|
+
let lastActivityWord: string | undefined;
|
|
378
|
+
let activityTimer: ReturnType<typeof setInterval> | undefined;
|
|
223
379
|
let tipDeck: string[] = [];
|
|
224
380
|
const nextStartupTip = (): string => {
|
|
225
381
|
if (tipDeck.length === 0) tipDeck = shuffledTips();
|
|
226
382
|
return tipDeck.pop() ?? STARTUP_TIPS[0];
|
|
227
383
|
};
|
|
384
|
+
const refillActivityDeck = (): void => {
|
|
385
|
+
activityDeck = [...ACTIVITY_WORDS];
|
|
386
|
+
for (let index = activityDeck.length - 1; index > 0; index -= 1) {
|
|
387
|
+
const swapIndex = Math.floor(Math.random() * (index + 1));
|
|
388
|
+
[activityDeck[index], activityDeck[swapIndex]] = [activityDeck[swapIndex]!, activityDeck[index]!];
|
|
389
|
+
}
|
|
390
|
+
if (activityDeck.length > 1 && activityDeck.at(-1) === lastActivityWord) {
|
|
391
|
+
[activityDeck[0], activityDeck[activityDeck.length - 1]] = [activityDeck.at(-1)!, activityDeck[0]!];
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
const nextActivityWord = (): string => {
|
|
395
|
+
if (activityDeck.length === 0) refillActivityDeck();
|
|
396
|
+
const word = activityDeck.pop() ?? ACTIVITY_WORDS[0];
|
|
397
|
+
lastActivityWord = word;
|
|
398
|
+
return word;
|
|
399
|
+
};
|
|
400
|
+
const clearActivityTimer = (): void => {
|
|
401
|
+
if (activityTimer) clearInterval(activityTimer);
|
|
402
|
+
activityTimer = undefined;
|
|
403
|
+
};
|
|
228
404
|
|
|
229
405
|
pi.on("session_start", (_event, ctx) => {
|
|
230
406
|
if (ctx.mode !== "tui") return;
|
|
231
407
|
try {
|
|
232
408
|
ctx.ui.setTheme("killeros");
|
|
233
409
|
const startupTip = nextStartupTip();
|
|
234
|
-
ctx.ui.setHeader(() => {
|
|
410
|
+
ctx.ui.setHeader((tui) => {
|
|
235
411
|
activeHeader?.dispose();
|
|
236
|
-
activeHeader = new PiStartupHeader(pi, ctx, startupTip);
|
|
412
|
+
activeHeader = new PiStartupHeader(pi, ctx, startupTip, tui);
|
|
237
413
|
return activeHeader;
|
|
238
414
|
});
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
ctx.ui.theme.fg("dim", "✻"),
|
|
242
|
-
ctx.ui.theme.fg("muted", "✻"),
|
|
243
|
-
ctx.ui.theme.fg("accent", "✻"),
|
|
244
|
-
ctx.ui.theme.fg("muted", "✻"),
|
|
245
|
-
],
|
|
246
|
-
intervalMs: 180,
|
|
247
|
-
});
|
|
415
|
+
clearActivityTimer();
|
|
416
|
+
ctx.ui.setWorkingIndicator({ frames: [ctx.ui.theme.fg("accent", "✻")] });
|
|
248
417
|
ctx.ui.setHiddenThinkingLabel("└ Thinking…");
|
|
249
|
-
ctx.ui.setEditorComponent((tui,
|
|
418
|
+
ctx.ui.setEditorComponent((tui, editorTheme, keybindings) =>
|
|
419
|
+
new PiCodeEditor(tui, editorTheme, keybindings, ctx.ui.theme, () => availableCommandNames(pi)));
|
|
250
420
|
} catch (error) {
|
|
251
421
|
reportError(ctx, "Killeros UI failed to initialize", error);
|
|
252
422
|
}
|
|
@@ -254,17 +424,23 @@ export function registerShellUi(pi: ExtensionAPI): void {
|
|
|
254
424
|
|
|
255
425
|
pi.on("agent_start", (_event, ctx) => {
|
|
256
426
|
if (ctx.mode !== "tui") return;
|
|
257
|
-
|
|
258
|
-
|
|
427
|
+
clearActivityTimer();
|
|
428
|
+
const updateWorkingWord = (): void => ctx.ui.setWorkingMessage(`${nextActivityWord()}…`);
|
|
429
|
+
updateWorkingWord();
|
|
430
|
+
activityTimer = setInterval(updateWorkingWord, 2_500);
|
|
431
|
+
activityTimer.unref?.();
|
|
259
432
|
});
|
|
260
433
|
|
|
261
434
|
pi.on("agent_end", (_event, ctx) => {
|
|
435
|
+
clearActivityTimer();
|
|
262
436
|
if (ctx.mode === "tui") ctx.ui.setWorkingMessage();
|
|
263
437
|
});
|
|
264
438
|
|
|
265
439
|
pi.on("session_shutdown", () => {
|
|
440
|
+
clearActivityTimer();
|
|
266
441
|
activeHeader?.dispose();
|
|
267
442
|
activeHeader = undefined;
|
|
268
|
-
|
|
443
|
+
activityDeck = [];
|
|
444
|
+
lastActivityWord = undefined;
|
|
269
445
|
});
|
|
270
446
|
}
|
package/killeros/variants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DynamicBorder, type ExtensionAPI, type ExtensionContext, type ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import { DynamicBorder, keyHint, type ExtensionAPI, type ExtensionContext, type ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Container, SelectList, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
3
3
|
|
|
4
4
|
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
@@ -119,7 +119,11 @@ export function registerVariants(pi: ExtensionAPI): void {
|
|
|
119
119
|
selectList.onCancel = () => done(null);
|
|
120
120
|
container.addChild(selectList);
|
|
121
121
|
container.addChild(new Text("", 0, 0));
|
|
122
|
-
container.addChild(new Text(
|
|
122
|
+
container.addChild(new Text(
|
|
123
|
+
theme.fg("dim", `${keyHint("tui.select.up", "up")} • ${keyHint("tui.select.down", "down")} • ${keyHint("tui.select.confirm", "select")} • ${keyHint("tui.select.cancel", "cancel")}`),
|
|
124
|
+
1,
|
|
125
|
+
0,
|
|
126
|
+
));
|
|
123
127
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
124
128
|
return {
|
|
125
129
|
render: (width) => container.render(width).map((line) => truncateToWidth(line, width, "")),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "killeros",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A production-hardened TUI and workflow extension for the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -22,10 +22,6 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"Killeros.ts",
|
|
24
24
|
"killeros/*.ts",
|
|
25
|
-
"subagents.ts",
|
|
26
|
-
"subagent-lifecycle.ts",
|
|
27
|
-
"subagent-process.ts",
|
|
28
|
-
"subagent-ui.ts",
|
|
29
25
|
"themes/killeros.json",
|
|
30
26
|
"README.md",
|
|
31
27
|
"CHANGELOG.md"
|
|
@@ -49,7 +45,6 @@
|
|
|
49
45
|
"@earendil-works/pi-ai": ">=0.82.1",
|
|
50
46
|
"@earendil-works/pi-coding-agent": ">=0.82.1",
|
|
51
47
|
"@earendil-works/pi-tui": ">=0.82.1",
|
|
52
|
-
"pi-web-access": ">=0.17.1",
|
|
53
48
|
"typebox": ">=1.1.38 <2"
|
|
54
49
|
},
|
|
55
50
|
"devDependencies": {
|
package/themes/killeros.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"vars": {
|
|
5
5
|
"coral": "#d77757",
|
|
6
6
|
"coralBright": "#e58b6d",
|
|
7
|
+
"commandBlue": "#78a9ff",
|
|
7
8
|
"canvas": "#0a0a0a",
|
|
8
9
|
"surface": "#121212",
|
|
9
10
|
"surfaceRaised": "#1a1a1a",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"toolOutput": "muted",
|
|
44
45
|
|
|
45
46
|
"mdHeading": "coralBright",
|
|
46
|
-
"mdLink": "
|
|
47
|
+
"mdLink": "commandBlue",
|
|
47
48
|
"mdLinkUrl": "dim",
|
|
48
49
|
"mdCode": "coralBright",
|
|
49
50
|
"mdCodeBlock": "text",
|
|
@@ -68,8 +69,8 @@
|
|
|
68
69
|
"syntaxPunctuation": "muted",
|
|
69
70
|
|
|
70
71
|
"thinkingOff": "dim",
|
|
71
|
-
"thinkingMinimal": "#
|
|
72
|
-
"thinkingLow": "#
|
|
72
|
+
"thinkingMinimal": "#927f74",
|
|
73
|
+
"thinkingLow": "#a27b6a",
|
|
73
74
|
"thinkingMedium": "#b27762",
|
|
74
75
|
"thinkingHigh": "coral",
|
|
75
76
|
"thinkingXhigh": "#d58272",
|