killeros 1.0.1 → 1.1.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/CHANGELOG.md +20 -0
- package/Killeros.ts +123 -206
- package/README.md +7 -3
- package/package.json +7 -2
- package/themes/killeros.json +85 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to KillerOS are documented here.
|
|
4
|
+
|
|
5
|
+
## [1.1.0] - 2026-07-31
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Compact startup card with model, reasoning level, working directory, context remaining, and detected package capabilities.
|
|
10
|
+
- Packaged KillerOS theme with coral accents and one neutral tool-call surface across pending, success, and error states.
|
|
11
|
+
- Single-glyph Spark activity indicator with a restrained color pulse.
|
|
12
|
+
- Claude-adjacent activity word bank that advances between agent runs.
|
|
13
|
+
- Static `└ Thinking…` label for hidden reasoning blocks.
|
|
14
|
+
- Responsive header tests across terminal widths from 1 to 100 columns.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Replaced the animated startup illustration and rotating tips with the compact operational card.
|
|
19
|
+
- Standardized product branding on mixed-case `KillerOS` and the `› KillerOS` lockup.
|
|
20
|
+
- Reduced saturated semantic color usage while preserving status text and diff distinctions.
|
package/Killeros.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import os from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
2
4
|
import {
|
|
3
5
|
CustomEditor,
|
|
4
6
|
DynamicBorder,
|
|
@@ -28,30 +30,25 @@ import {
|
|
|
28
30
|
import { Type } from "typebox";
|
|
29
31
|
|
|
30
32
|
const BRAND_RGB = "215;119;87";
|
|
31
|
-
const LEFT_PANEL_WIDTH = 42;
|
|
32
|
-
const LOGO_CELL = "███";
|
|
33
|
-
const LOGO_ANIMATION_INTERVAL_MS = 120;
|
|
34
|
-
const TIP_ROTATION_INTERVAL_MS = 5_000;
|
|
35
33
|
const FOOTER_REFRESH_INTERVAL_MS = 1_000;
|
|
34
|
+
const COMPACT_HEADER_MAX_WIDTH = 76;
|
|
36
35
|
|
|
37
36
|
const brand = (text: string): string => `\x1B[38;2;${BRAND_RGB}m${text}\x1B[39m`;
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const LOGO_FRAME_COUNT = ORCA_WIDTH + 3;
|
|
50
|
-
|
|
51
|
-
function extractProvider(model: ExtensionContext["model"]): string {
|
|
52
|
-
return model?.provider ?? "";
|
|
38
|
+
function readPackageMetadata(path: string | URL): { name?: string; version?: string } {
|
|
39
|
+
try {
|
|
40
|
+
const value = JSON.parse(readFileSync(path, "utf8")) as { name?: unknown; version?: unknown };
|
|
41
|
+
return {
|
|
42
|
+
name: typeof value.name === "string" ? value.name : undefined,
|
|
43
|
+
version: typeof value.version === "string" ? value.version : undefined,
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
53
48
|
}
|
|
54
49
|
|
|
50
|
+
const KILLEROS_VERSION = readPackageMetadata(new URL("./package.json", import.meta.url)).version;
|
|
51
|
+
|
|
55
52
|
function formatCwd(cwd: string): string {
|
|
56
53
|
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
57
54
|
if (!home) return cwd;
|
|
@@ -64,226 +61,125 @@ function formatCwd(cwd: string): string {
|
|
|
64
61
|
: cwd;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
function center(text: string, width: number): string {
|
|
68
|
-
if (width <= 0) return "";
|
|
69
|
-
const textWidth = visibleWidth(text);
|
|
70
|
-
if (textWidth >= width) return truncateToWidth(text, width, "");
|
|
71
|
-
return `${" ".repeat(Math.floor((width - textWidth) / 2))}${text}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
64
|
function padRight(text: string, width: number): string {
|
|
75
65
|
if (width <= 0) return "";
|
|
76
66
|
const clipped = truncateToWidth(text, width, "");
|
|
77
67
|
return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
|
|
78
68
|
}
|
|
79
69
|
|
|
80
|
-
|
|
70
|
+
interface CapabilitySourceInfo {
|
|
71
|
+
path?: string;
|
|
72
|
+
source?: string;
|
|
73
|
+
baseDir?: string;
|
|
74
|
+
}
|
|
81
75
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
case "white": return `\x1B[97m${LOGO_CELL}\x1B[39m`;
|
|
86
|
-
case "brand": return brand(LOGO_CELL);
|
|
87
|
-
default: return " ".repeat(LOGO_CELL.length);
|
|
88
|
-
}
|
|
76
|
+
interface CompactCapability {
|
|
77
|
+
label: string;
|
|
78
|
+
version?: string;
|
|
89
79
|
}
|
|
90
80
|
|
|
91
|
-
function
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (cell === "g") return colorCell("body");
|
|
97
|
-
if (cell === "w") return colorCell("white");
|
|
98
|
-
if (cell === "b") return colorCell(eyeColor);
|
|
99
|
-
return colorCell("panel");
|
|
100
|
-
}).join(""));
|
|
81
|
+
function capabilityLabel(packageName: string): string {
|
|
82
|
+
const name = packageName.replace(/^npm:/, "").split("/").at(-1) ?? packageName;
|
|
83
|
+
if (name === "pi-mcp-adapter") return "MCP adapter";
|
|
84
|
+
if (name === "pi-web-access") return "Web access";
|
|
85
|
+
return name.replace(/^pi-/, "").replace(/[-_]+/g, " ").replace(/^\w/, (letter) => letter.toUpperCase());
|
|
101
86
|
}
|
|
102
87
|
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
88
|
+
function collectCompactCapabilities(pi: Pick<ExtensionAPI, "getCommands" | "getAllTools">): CompactCapability[] {
|
|
89
|
+
const sources: CapabilitySourceInfo[] = [];
|
|
90
|
+
try {
|
|
91
|
+
for (const command of pi.getCommands()) {
|
|
92
|
+
if (command.source === "extension" && command.sourceInfo.source !== "inline") sources.push(command.sourceInfo);
|
|
93
|
+
}
|
|
94
|
+
} catch {}
|
|
95
|
+
try {
|
|
96
|
+
for (const tool of pi.getAllTools()) {
|
|
97
|
+
if (tool.sourceInfo.source !== "builtin" && tool.sourceInfo.source !== "sdk") sources.push(tool.sourceInfo);
|
|
98
|
+
}
|
|
99
|
+
} catch {}
|
|
100
|
+
|
|
101
|
+
const capabilities = new Map<string, CompactCapability>();
|
|
102
|
+
for (const source of sources) {
|
|
103
|
+
const directories = [source.baseDir, source.path ? dirname(source.path) : undefined]
|
|
104
|
+
.filter((directory): directory is string => Boolean(directory));
|
|
105
|
+
let metadata: { name?: string; version?: string } = {};
|
|
106
|
+
for (const directory of new Set(directories)) {
|
|
107
|
+
metadata = readPackageMetadata(join(directory, "package.json"));
|
|
108
|
+
if (metadata.name) break;
|
|
109
|
+
}
|
|
110
|
+
const packageName = metadata.name ?? (source.source?.startsWith("npm:") ? source.source.slice(4) : undefined);
|
|
111
|
+
if (!packageName || packageName === "killeros") continue;
|
|
112
|
+
capabilities.set(packageName, { label: capabilityLabel(packageName), version: metadata.version });
|
|
113
113
|
}
|
|
114
|
-
|
|
115
|
-
const before = Math.min(3, fill);
|
|
116
|
-
const after = fill - before;
|
|
117
|
-
return `${brand(left)}${brand("─".repeat(before))} ${clippedLabel} ${brand("─".repeat(after))}${brand(right)}`;
|
|
114
|
+
return [...capabilities.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
118
115
|
}
|
|
119
116
|
|
|
120
|
-
function
|
|
117
|
+
function alignEdges(left: string, right: string, width: number): string {
|
|
121
118
|
if (width <= 0) return "";
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
const clippedRight = truncateToWidth(right, width, "");
|
|
120
|
+
const leftWidth = Math.max(0, width - visibleWidth(clippedRight) - 1);
|
|
121
|
+
const clippedLeft = truncateToWidth(left, leftWidth, "…");
|
|
122
|
+
const gap = " ".repeat(Math.max(1, width - visibleWidth(clippedLeft) - visibleWidth(clippedRight)));
|
|
123
|
+
return truncateToWidth(`${clippedLeft}${gap}${clippedRight}`, width, "");
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const TIP_SETS = [
|
|
131
|
-
[
|
|
132
|
-
"",
|
|
133
|
-
"Shortcuts & Commands",
|
|
134
|
-
"/variants — model reasoning",
|
|
135
|
-
"/compact — compress context",
|
|
136
|
-
"/model — choose a model",
|
|
137
|
-
"────────────────────────",
|
|
138
|
-
"Keybindings",
|
|
139
|
-
"Shift+Enter — new line",
|
|
140
|
-
"Esc — cancel generation",
|
|
141
|
-
"Ctrl+C — interrupt agent",
|
|
142
|
-
],
|
|
143
|
-
[
|
|
144
|
-
"",
|
|
145
|
-
"Session",
|
|
146
|
-
"/new — start a session",
|
|
147
|
-
"/name — name this session",
|
|
148
|
-
"/session — usage and stats",
|
|
149
|
-
"────────────────────────",
|
|
150
|
-
"Workflow",
|
|
151
|
-
"Give Pi a goal and constraints",
|
|
152
|
-
"Ask it to run the relevant tests",
|
|
153
|
-
"Review changes before committing",
|
|
154
|
-
],
|
|
155
|
-
[
|
|
156
|
-
"",
|
|
157
|
-
"Useful Commands",
|
|
158
|
-
"/copy — copy last response",
|
|
159
|
-
"/tree — navigate branches",
|
|
160
|
-
"/reload — reload resources",
|
|
161
|
-
"────────────────────────",
|
|
162
|
-
"Extension locations",
|
|
163
|
-
"Global: ~/.pi/agent/extensions",
|
|
164
|
-
"Project: .pi/extensions",
|
|
165
|
-
"Reload after making changes",
|
|
166
|
-
],
|
|
167
|
-
[
|
|
168
|
-
"",
|
|
169
|
-
"Navigation",
|
|
170
|
-
"Up/Down — command history",
|
|
171
|
-
"Tab — autocomplete",
|
|
172
|
-
"Ctrl+L — clear the screen",
|
|
173
|
-
"────────────────────────",
|
|
174
|
-
"Good defaults",
|
|
175
|
-
"Keep edits scoped",
|
|
176
|
-
"Test after refactoring",
|
|
177
|
-
"Verify output before committing",
|
|
178
|
-
],
|
|
179
|
-
] as const;
|
|
180
|
-
|
|
181
|
-
function getTipLines(index: number, theme: Theme): string[] {
|
|
182
|
-
const selected = TIP_SETS[index % TIP_SETS.length] ?? TIP_SETS[0];
|
|
183
|
-
return selected.map((line, lineIndex) => {
|
|
184
|
-
if (lineIndex === 1 || lineIndex === 6) return brand(theme.bold(line));
|
|
185
|
-
if (line.startsWith("─")) return brand(line);
|
|
186
|
-
if (line.startsWith("/")) {
|
|
187
|
-
const [command, ...rest] = line.split(" ");
|
|
188
|
-
return `${theme.fg("accent", command ?? "")}${theme.fg("dim", ` ${rest.join(" ")}`)}`;
|
|
189
|
-
}
|
|
190
|
-
return theme.fg(lineIndex > 6 ? "muted" : "dim", line);
|
|
191
|
-
});
|
|
126
|
+
function compactBoxLine(content: string, width: number, theme: Theme): string {
|
|
127
|
+
if (width < 4) return truncateToWidth(content, width, "");
|
|
128
|
+
return `${theme.fg("dim", "│")} ${padRight(content, width - 4)} ${theme.fg("dim", "│")}`;
|
|
192
129
|
}
|
|
193
130
|
|
|
194
131
|
class PiStartupHeader {
|
|
195
132
|
private readonly pi: ExtensionAPI;
|
|
196
133
|
private readonly ctx: ExtensionContext;
|
|
197
|
-
private readonly
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
private animationTimer?: ReturnType<typeof setInterval>;
|
|
201
|
-
private tipTimer?: ReturnType<typeof setInterval>;
|
|
202
|
-
private disposed = false;
|
|
203
|
-
|
|
204
|
-
constructor(
|
|
205
|
-
pi: ExtensionAPI,
|
|
206
|
-
ctx: ExtensionContext,
|
|
207
|
-
tui: TUI,
|
|
208
|
-
) {
|
|
134
|
+
private readonly capabilities: CompactCapability[];
|
|
135
|
+
|
|
136
|
+
constructor(pi: ExtensionAPI, ctx: ExtensionContext) {
|
|
209
137
|
this.pi = pi;
|
|
210
138
|
this.ctx = ctx;
|
|
211
|
-
this.
|
|
212
|
-
this.animationTimer = setInterval(() => {
|
|
213
|
-
if (this.disposed) return;
|
|
214
|
-
if (this.frame >= LOGO_FRAME_COUNT - 1) {
|
|
215
|
-
this.stopAnimation();
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
this.frame += 1;
|
|
219
|
-
this.tui.requestRender();
|
|
220
|
-
if (this.frame >= LOGO_FRAME_COUNT - 1) this.stopAnimation();
|
|
221
|
-
}, LOGO_ANIMATION_INTERVAL_MS);
|
|
222
|
-
this.animationTimer.unref?.();
|
|
223
|
-
|
|
224
|
-
this.tipTimer = setInterval(() => {
|
|
225
|
-
if (this.disposed) return;
|
|
226
|
-
this.tipIndex = (this.tipIndex + 1) % TIP_SETS.length;
|
|
227
|
-
this.tui.requestRender();
|
|
228
|
-
}, TIP_ROTATION_INTERVAL_MS);
|
|
229
|
-
this.tipTimer.unref?.();
|
|
139
|
+
this.capabilities = collectCompactCapabilities(pi);
|
|
230
140
|
}
|
|
231
141
|
|
|
232
|
-
private
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
142
|
+
private contextText(theme: Theme): string {
|
|
143
|
+
const usage = this.ctx.getContextUsage();
|
|
144
|
+
if (!usage || usage.tokens === null) return theme.fg("dim", "context —");
|
|
145
|
+
const windowSize = usage.contextWindow > 0 ? usage.contextWindow : 128_000;
|
|
146
|
+
const percent = Math.max(0, Math.min(100, Math.round((1 - usage.tokens / windowSize) * 100)));
|
|
147
|
+
return theme.fg(percent < 20 ? "error" : percent <= 50 ? "warning" : "success", `${percent}% context`);
|
|
236
148
|
}
|
|
237
149
|
|
|
238
150
|
render(width: number): string[] {
|
|
239
151
|
if (width <= 0) return [];
|
|
240
152
|
const theme = this.ctx.ui.theme;
|
|
241
|
-
if (width <
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
const
|
|
247
|
-
const model =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const modelText = leftWidth < 34 ? `${model} (${effort})` : `${model} with ${effort} effort`;
|
|
258
|
-
const leftLines = [
|
|
259
|
-
...logoLines,
|
|
260
|
-
center(theme.bold("Let's build something great"), leftWidth),
|
|
261
|
-
center(theme.fg("muted", truncateToWidth(modelText, leftWidth, "…")), leftWidth),
|
|
262
|
-
center(theme.fg("dim", truncateToWidth(cwd, leftWidth, "…")), leftWidth),
|
|
153
|
+
if (width < 28) return [truncateToWidth(brand(theme.bold("KillerOS")), width, "")];
|
|
154
|
+
|
|
155
|
+
const panelWidth = Math.min(width, COMPACT_HEADER_MAX_WIDTH);
|
|
156
|
+
const innerWidth = panelWidth - 4;
|
|
157
|
+
const version = KILLEROS_VERSION ? theme.fg("dim", ` ${KILLEROS_VERSION}`) : "";
|
|
158
|
+
const identity = `${brand(theme.bold("› KillerOS"))}${version}`;
|
|
159
|
+
const model = this.ctx.model?.id ?? "default model";
|
|
160
|
+
const agent = `${model} · ${this.pi.getThinkingLevel()}`;
|
|
161
|
+
const directory = formatCwd(this.ctx.cwd);
|
|
162
|
+
const border = (left: string, right: string): string => theme.fg("dim", `${left}${"─".repeat(panelWidth - 2)}${right}`);
|
|
163
|
+
const lines = [
|
|
164
|
+
border("╭", "╮"),
|
|
165
|
+
compactBoxLine(alignEdges(identity, theme.fg("success", "READY"), innerWidth), panelWidth, theme),
|
|
166
|
+
compactBoxLine("", panelWidth, theme),
|
|
167
|
+
compactBoxLine(alignEdges(agent, theme.fg("dim", "/model"), innerWidth), panelWidth, theme),
|
|
168
|
+
compactBoxLine(alignEdges(directory, this.contextText(theme), innerWidth), panelWidth, theme),
|
|
263
169
|
];
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
lines.push(boxedLine(content, width));
|
|
170
|
+
if (this.capabilities.length > 0) {
|
|
171
|
+
lines.push(compactBoxLine(theme.fg("dim", "─".repeat(innerWidth)), panelWidth, theme));
|
|
172
|
+
const capabilityText = this.capabilities
|
|
173
|
+
.map((capability) => `${capability.label}${capability.version ? ` ${capability.version}` : ""}`)
|
|
174
|
+
.join(" · ");
|
|
175
|
+
lines.push(compactBoxLine(theme.fg("dim", capabilityText), panelWidth, theme));
|
|
271
176
|
}
|
|
272
|
-
lines.push(
|
|
273
|
-
return lines
|
|
177
|
+
lines.push(border("╰", "╯"));
|
|
178
|
+
return lines;
|
|
274
179
|
}
|
|
275
180
|
|
|
276
181
|
invalidate(): void {}
|
|
277
|
-
|
|
278
|
-
dispose(): void {
|
|
279
|
-
if (this.disposed) return;
|
|
280
|
-
this.disposed = true;
|
|
281
|
-
this.stopAnimation();
|
|
282
|
-
if (this.tipTimer) {
|
|
283
|
-
clearInterval(this.tipTimer);
|
|
284
|
-
this.tipTimer = undefined;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
182
|
+
dispose(): void {}
|
|
287
183
|
}
|
|
288
184
|
|
|
289
185
|
const ANSI_REGEX = /\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
@@ -372,30 +268,51 @@ function reportError(ctx: ExtensionContext, area: string, error: unknown): void
|
|
|
372
268
|
ctx.ui.notify(`${area}: ${message}`, "error");
|
|
373
269
|
}
|
|
374
270
|
|
|
271
|
+
const ACTIVITY_WORDS = ["Brewing", "Pondering", "Tinkering", "Wrangling", "Noodling", "Cooking"] as const;
|
|
272
|
+
|
|
375
273
|
function registerShellUi(pi: ExtensionAPI): void {
|
|
376
274
|
let activeHeader: PiStartupHeader | undefined;
|
|
275
|
+
let activityWordIndex = 0;
|
|
377
276
|
|
|
378
277
|
pi.on("session_start", (_event, ctx) => {
|
|
379
278
|
if (ctx.mode !== "tui") return;
|
|
380
279
|
try {
|
|
381
|
-
ctx.ui.
|
|
280
|
+
ctx.ui.setTheme("killeros");
|
|
281
|
+
ctx.ui.setHeader(() => {
|
|
382
282
|
activeHeader?.dispose();
|
|
383
|
-
activeHeader = new PiStartupHeader(pi, ctx
|
|
283
|
+
activeHeader = new PiStartupHeader(pi, ctx);
|
|
384
284
|
return activeHeader;
|
|
385
285
|
});
|
|
386
286
|
ctx.ui.setWorkingIndicator({
|
|
387
|
-
frames: [
|
|
388
|
-
|
|
287
|
+
frames: [
|
|
288
|
+
ctx.ui.theme.fg("dim", "✻"),
|
|
289
|
+
ctx.ui.theme.fg("muted", "✻"),
|
|
290
|
+
ctx.ui.theme.fg("accent", "✻"),
|
|
291
|
+
ctx.ui.theme.fg("muted", "✻"),
|
|
292
|
+
],
|
|
293
|
+
intervalMs: 180,
|
|
389
294
|
});
|
|
295
|
+
ctx.ui.setHiddenThinkingLabel("└ Thinking…");
|
|
390
296
|
ctx.ui.setEditorComponent((tui, theme, keybindings) => new PiCodeEditor(tui, theme, keybindings));
|
|
391
297
|
} catch (error) {
|
|
392
298
|
reportError(ctx, "Killeros UI failed to initialize", error);
|
|
393
299
|
}
|
|
394
300
|
});
|
|
395
301
|
|
|
302
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
303
|
+
if (ctx.mode !== "tui") return;
|
|
304
|
+
ctx.ui.setWorkingMessage(`${ACTIVITY_WORDS[activityWordIndex]}…`);
|
|
305
|
+
activityWordIndex = (activityWordIndex + 1) % ACTIVITY_WORDS.length;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
pi.on("agent_end", (_event, ctx) => {
|
|
309
|
+
if (ctx.mode === "tui") ctx.ui.setWorkingMessage();
|
|
310
|
+
});
|
|
311
|
+
|
|
396
312
|
pi.on("session_shutdown", () => {
|
|
397
313
|
activeHeader?.dispose();
|
|
398
314
|
activeHeader = undefined;
|
|
315
|
+
activityWordIndex = 0;
|
|
399
316
|
});
|
|
400
317
|
}
|
|
401
318
|
|
package/README.md
CHANGED
|
@@ -29,14 +29,16 @@ pi install git:github.com/KyrosHendrix/pi-KillerOS
|
|
|
29
29
|
Pin an install to a release:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
pi install git:github.com/KyrosHendrix/pi-KillerOS@v1.
|
|
32
|
+
pi install git:github.com/KyrosHendrix/pi-KillerOS@v1.1.0
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
36
36
|
|
|
37
37
|
## Features
|
|
38
38
|
|
|
39
|
-
-
|
|
39
|
+
- Compact KillerOS startup card with model, directory, context, and loaded capability state
|
|
40
|
+
- Cohesive dark theme with coral accents and neutral tool-call containers across pending, success, and error states
|
|
41
|
+
- Coral Spark activity indicator with Claude-adjacent verbs that advance between agent runs and a quiet hidden-thinking label
|
|
40
42
|
- Framed multiline editor with Shift+Enter support
|
|
41
43
|
- Footer with model, reasoning, context remaining, Git branch, elapsed time, and cost
|
|
42
44
|
- `/variants` selector and direct reasoning-level arguments
|
|
@@ -58,6 +60,8 @@ Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh
|
|
|
58
60
|
|
|
59
61
|
## Configuration
|
|
60
62
|
|
|
63
|
+
KillerOS activates its packaged `killeros` theme when a TUI session starts. Tool-call backgrounds stay neutral across pending, successful, and failed states; restrained text and icons preserve status visibility.
|
|
64
|
+
|
|
61
65
|
KillerOS displays provider costs in USD.
|
|
62
66
|
|
|
63
67
|
Set a custom footer shortcut hint with:
|
|
@@ -83,7 +87,7 @@ npm ci
|
|
|
83
87
|
npm run check
|
|
84
88
|
npm test
|
|
85
89
|
npm pack --dry-run
|
|
86
|
-
pi -e . --mode rpc
|
|
90
|
+
pi -ne -e . --mode rpc
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
The package manifest lists Pi’s built-in modules as peer dependencies, so npm does not bundle a second copy.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "killeros",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A production-hardened TUI and workflow extension for the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"Killeros.ts",
|
|
24
|
-
"
|
|
24
|
+
"themes/killeros.json",
|
|
25
|
+
"README.md",
|
|
26
|
+
"CHANGELOG.md"
|
|
25
27
|
],
|
|
26
28
|
"engines": {
|
|
27
29
|
"node": ">=22.19.0"
|
|
@@ -33,6 +35,9 @@
|
|
|
33
35
|
"pi": {
|
|
34
36
|
"extensions": [
|
|
35
37
|
"./Killeros.ts"
|
|
38
|
+
],
|
|
39
|
+
"themes": [
|
|
40
|
+
"./themes/killeros.json"
|
|
36
41
|
]
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "killeros",
|
|
4
|
+
"vars": {
|
|
5
|
+
"coral": "#d77757",
|
|
6
|
+
"coralBright": "#e58b6d",
|
|
7
|
+
"canvas": "#090b0e",
|
|
8
|
+
"surface": "#101419",
|
|
9
|
+
"surfaceRaised": "#151a20",
|
|
10
|
+
"line": "#39424b",
|
|
11
|
+
"lineMuted": "#2b333b",
|
|
12
|
+
"text": "#dce1e5",
|
|
13
|
+
"muted": "#8f99a3",
|
|
14
|
+
"dim": "#606b75",
|
|
15
|
+
"success": "#8fa88b",
|
|
16
|
+
"error": "#c8786c",
|
|
17
|
+
"warning": "#bda36c",
|
|
18
|
+
"pink": "#b98aa5"
|
|
19
|
+
},
|
|
20
|
+
"colors": {
|
|
21
|
+
"accent": "coral",
|
|
22
|
+
"border": "line",
|
|
23
|
+
"borderAccent": "coral",
|
|
24
|
+
"borderMuted": "lineMuted",
|
|
25
|
+
"success": "success",
|
|
26
|
+
"error": "error",
|
|
27
|
+
"warning": "warning",
|
|
28
|
+
"muted": "muted",
|
|
29
|
+
"dim": "dim",
|
|
30
|
+
"text": "text",
|
|
31
|
+
"thinkingText": "muted",
|
|
32
|
+
|
|
33
|
+
"selectedBg": "surfaceRaised",
|
|
34
|
+
"userMessageBg": "surface",
|
|
35
|
+
"userMessageText": "text",
|
|
36
|
+
"customMessageBg": "surface",
|
|
37
|
+
"customMessageText": "text",
|
|
38
|
+
"customMessageLabel": "coralBright",
|
|
39
|
+
"toolPendingBg": "surface",
|
|
40
|
+
"toolSuccessBg": "surface",
|
|
41
|
+
"toolErrorBg": "surface",
|
|
42
|
+
"toolTitle": "coralBright",
|
|
43
|
+
"toolOutput": "muted",
|
|
44
|
+
|
|
45
|
+
"mdHeading": "coralBright",
|
|
46
|
+
"mdLink": "coralBright",
|
|
47
|
+
"mdLinkUrl": "dim",
|
|
48
|
+
"mdCode": "coralBright",
|
|
49
|
+
"mdCodeBlock": "text",
|
|
50
|
+
"mdCodeBlockBorder": "lineMuted",
|
|
51
|
+
"mdQuote": "muted",
|
|
52
|
+
"mdQuoteBorder": "line",
|
|
53
|
+
"mdHr": "line",
|
|
54
|
+
"mdListBullet": "coral",
|
|
55
|
+
|
|
56
|
+
"toolDiffAdded": "success",
|
|
57
|
+
"toolDiffRemoved": "error",
|
|
58
|
+
"toolDiffContext": "muted",
|
|
59
|
+
|
|
60
|
+
"syntaxComment": "dim",
|
|
61
|
+
"syntaxKeyword": "coralBright",
|
|
62
|
+
"syntaxFunction": "#c9a48d",
|
|
63
|
+
"syntaxVariable": "#b7c0c8",
|
|
64
|
+
"syntaxString": "#a9b78d",
|
|
65
|
+
"syntaxNumber": "#c5a77a",
|
|
66
|
+
"syntaxType": "#a3afb8",
|
|
67
|
+
"syntaxOperator": "muted",
|
|
68
|
+
"syntaxPunctuation": "muted",
|
|
69
|
+
|
|
70
|
+
"thinkingOff": "dim",
|
|
71
|
+
"thinkingMinimal": "#78685f",
|
|
72
|
+
"thinkingLow": "#98705f",
|
|
73
|
+
"thinkingMedium": "#b27762",
|
|
74
|
+
"thinkingHigh": "coral",
|
|
75
|
+
"thinkingXhigh": "#d58272",
|
|
76
|
+
"thinkingMax": "pink",
|
|
77
|
+
|
|
78
|
+
"bashMode": "warning"
|
|
79
|
+
},
|
|
80
|
+
"export": {
|
|
81
|
+
"pageBg": "#090b0e",
|
|
82
|
+
"cardBg": "#101419",
|
|
83
|
+
"infoBg": "#151a20"
|
|
84
|
+
}
|
|
85
|
+
}
|