@preapexis/pi-kit 1.0.0 → 1.0.7
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/.github/workflows/publish.yml +30 -30
- package/LICENSE +15 -15
- package/README.md +373 -370
- package/extensions/brand-ui.ts +107 -107
- package/extensions/sound-cues.ts +88 -88
- package/extensions/update.ts +245 -245
- package/extensions/usage-tracker.ts +154 -154
- package/package.json +6 -2
- package/prompts/init.md +98 -98
- package/settings.json +4 -4
- package/skills/component-implementation/SKILL.md +80 -80
- package/skills/frontend-onboarding/SKILL.md +76 -76
- package/skills/frontend-quality/SKILL.md +85 -85
- package/skills/safe-coding/SKILL.md +48 -48
- package/themes/latte-review.json +77 -77
- package/themes/neon-guardian.json +77 -77
- package/themes/safe-dark.json +75 -75
- package/themes/tokyo-midnight.json +77 -77
package/extensions/brand-ui.ts
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
type EventContext = Parameters<Parameters<ExtensionAPI["on"]>[1]>[1];
|
|
4
|
-
|
|
5
|
-
const PREAPEXIS_ART = [
|
|
6
|
-
"██████╗ ██████╗ ███████╗ █████╗ ██████╗ ███████╗██╗ ██╗██╗███████╗",
|
|
7
|
-
"██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔════╝╚██╗██╔╝██║██╔════╝",
|
|
8
|
-
"██████╔╝██████╔╝█████╗ ███████║██████╔╝█████╗ ╚███╔╝ ██║███████╗",
|
|
9
|
-
"██╔═══╝ ██╔══██╗██╔══╝ ██╔══██║██╔═══╝ ██╔══╝ ██╔██╗ ██║╚════██║",
|
|
10
|
-
"██║ ██║ ██║███████╗██║ ██║██║ ███████╗██╔╝ ██╗██║███████║",
|
|
11
|
-
"╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝"
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
const COMPACT_HEADER = "π PreApeXis π";
|
|
15
|
-
|
|
16
|
-
const RAINBOW = [
|
|
17
|
-
[255, 90, 90],
|
|
18
|
-
[255, 170, 70],
|
|
19
|
-
[255, 230, 90],
|
|
20
|
-
[90, 220, 130],
|
|
21
|
-
[90, 190, 255],
|
|
22
|
-
[180, 130, 255]
|
|
23
|
-
] as const;
|
|
24
|
-
|
|
25
|
-
function rgb(text: string, r: number, g: number, b: number): string {
|
|
26
|
-
return `\x1b[1;38;2;${r};${g};${b}m${text}\x1b[0m`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function rainbowText(text: string): string {
|
|
30
|
-
let colorIndex = 0;
|
|
31
|
-
|
|
32
|
-
return [...text]
|
|
33
|
-
.map((char) => {
|
|
34
|
-
if (char === " ") return char;
|
|
35
|
-
|
|
36
|
-
const [r, g, b] = RAINBOW[colorIndex % RAINBOW.length];
|
|
37
|
-
colorIndex += 1;
|
|
38
|
-
|
|
39
|
-
return rgb(char, r, g, b);
|
|
40
|
-
})
|
|
41
|
-
.join("");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function rainbowPi(): string {
|
|
45
|
-
return rainbowText("π");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export default function (pi: ExtensionAPI): void {
|
|
49
|
-
function applyBrandUI(ctx: EventContext): void {
|
|
50
|
-
if (!ctx.hasUI || ctx.mode !== "tui") return;
|
|
51
|
-
|
|
52
|
-
ctx.ui.setTitle("PreApeXis");
|
|
53
|
-
|
|
54
|
-
ctx.ui.setHeader((_tui, theme) => ({
|
|
55
|
-
render(width: number): string[] {
|
|
56
|
-
if (width < 90) {
|
|
57
|
-
return [
|
|
58
|
-
rainbowText(COMPACT_HEADER),
|
|
59
|
-
theme.fg("dim", "safe changes · clear plans")
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return [
|
|
64
|
-
...PREAPEXIS_ART.map((line) => rainbowText(line)),
|
|
65
|
-
theme.fg("dim", "safe changes · clear plans")
|
|
66
|
-
];
|
|
67
|
-
},
|
|
68
|
-
invalidate() {}
|
|
69
|
-
}));
|
|
70
|
-
|
|
71
|
-
ctx.ui.setWorkingMessage("Thinking");
|
|
72
|
-
|
|
73
|
-
ctx.ui.setWorkingIndicator({
|
|
74
|
-
frames: [
|
|
75
|
-
rainbowPi(),
|
|
76
|
-
`${rainbowPi()}·`,
|
|
77
|
-
`${rainbowPi()}··`,
|
|
78
|
-
`${rainbowPi()}···`
|
|
79
|
-
],
|
|
80
|
-
intervalMs: 300
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
85
|
-
applyBrandUI(ctx);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
pi.registerCommand("brand", {
|
|
89
|
-
description: "Re-apply PreApeXis brand UI",
|
|
90
|
-
handler: async (_args, ctx) => {
|
|
91
|
-
applyBrandUI(ctx);
|
|
92
|
-
ctx.ui.notify("PreApeXis brand UI applied.", "info");
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
pi.registerCommand("brand-reset", {
|
|
97
|
-
description: "Restore default Pi header and working indicator",
|
|
98
|
-
handler: async (_args, ctx) => {
|
|
99
|
-
if (!ctx.hasUI) return;
|
|
100
|
-
|
|
101
|
-
ctx.ui.setHeader(undefined);
|
|
102
|
-
ctx.ui.setWorkingMessage();
|
|
103
|
-
ctx.ui.setWorkingIndicator();
|
|
104
|
-
ctx.ui.notify("Default Pi UI restored.", "info");
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
type EventContext = Parameters<Parameters<ExtensionAPI["on"]>[1]>[1];
|
|
4
|
+
|
|
5
|
+
const PREAPEXIS_ART = [
|
|
6
|
+
"██████╗ ██████╗ ███████╗ █████╗ ██████╗ ███████╗██╗ ██╗██╗███████╗",
|
|
7
|
+
"██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔════╝╚██╗██╔╝██║██╔════╝",
|
|
8
|
+
"██████╔╝██████╔╝█████╗ ███████║██████╔╝█████╗ ╚███╔╝ ██║███████╗",
|
|
9
|
+
"██╔═══╝ ██╔══██╗██╔══╝ ██╔══██║██╔═══╝ ██╔══╝ ██╔██╗ ██║╚════██║",
|
|
10
|
+
"██║ ██║ ██║███████╗██║ ██║██║ ███████╗██╔╝ ██╗██║███████║",
|
|
11
|
+
"╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝"
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const COMPACT_HEADER = "π PreApeXis π";
|
|
15
|
+
|
|
16
|
+
const RAINBOW = [
|
|
17
|
+
[255, 90, 90],
|
|
18
|
+
[255, 170, 70],
|
|
19
|
+
[255, 230, 90],
|
|
20
|
+
[90, 220, 130],
|
|
21
|
+
[90, 190, 255],
|
|
22
|
+
[180, 130, 255]
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
function rgb(text: string, r: number, g: number, b: number): string {
|
|
26
|
+
return `\x1b[1;38;2;${r};${g};${b}m${text}\x1b[0m`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function rainbowText(text: string): string {
|
|
30
|
+
let colorIndex = 0;
|
|
31
|
+
|
|
32
|
+
return [...text]
|
|
33
|
+
.map((char) => {
|
|
34
|
+
if (char === " ") return char;
|
|
35
|
+
|
|
36
|
+
const [r, g, b] = RAINBOW[colorIndex % RAINBOW.length];
|
|
37
|
+
colorIndex += 1;
|
|
38
|
+
|
|
39
|
+
return rgb(char, r, g, b);
|
|
40
|
+
})
|
|
41
|
+
.join("");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function rainbowPi(): string {
|
|
45
|
+
return rainbowText("π");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function (pi: ExtensionAPI): void {
|
|
49
|
+
function applyBrandUI(ctx: EventContext): void {
|
|
50
|
+
if (!ctx.hasUI || ctx.mode !== "tui") return;
|
|
51
|
+
|
|
52
|
+
ctx.ui.setTitle("PreApeXis");
|
|
53
|
+
|
|
54
|
+
ctx.ui.setHeader((_tui, theme) => ({
|
|
55
|
+
render(width: number): string[] {
|
|
56
|
+
if (width < 90) {
|
|
57
|
+
return [
|
|
58
|
+
rainbowText(COMPACT_HEADER),
|
|
59
|
+
theme.fg("dim", "safe changes · clear plans")
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return [
|
|
64
|
+
...PREAPEXIS_ART.map((line) => rainbowText(line)),
|
|
65
|
+
theme.fg("dim", "safe changes · clear plans")
|
|
66
|
+
];
|
|
67
|
+
},
|
|
68
|
+
invalidate() {}
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
ctx.ui.setWorkingMessage("Thinking");
|
|
72
|
+
|
|
73
|
+
ctx.ui.setWorkingIndicator({
|
|
74
|
+
frames: [
|
|
75
|
+
rainbowPi(),
|
|
76
|
+
`${rainbowPi()}·`,
|
|
77
|
+
`${rainbowPi()}··`,
|
|
78
|
+
`${rainbowPi()}···`
|
|
79
|
+
],
|
|
80
|
+
intervalMs: 300
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
85
|
+
applyBrandUI(ctx);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
pi.registerCommand("brand", {
|
|
89
|
+
description: "Re-apply PreApeXis brand UI",
|
|
90
|
+
handler: async (_args, ctx) => {
|
|
91
|
+
applyBrandUI(ctx);
|
|
92
|
+
ctx.ui.notify("PreApeXis brand UI applied.", "info");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
pi.registerCommand("brand-reset", {
|
|
97
|
+
description: "Restore default Pi header and working indicator",
|
|
98
|
+
handler: async (_args, ctx) => {
|
|
99
|
+
if (!ctx.hasUI) return;
|
|
100
|
+
|
|
101
|
+
ctx.ui.setHeader(undefined);
|
|
102
|
+
ctx.ui.setWorkingMessage();
|
|
103
|
+
ctx.ui.setWorkingIndicator();
|
|
104
|
+
ctx.ui.notify("Default Pi UI restored.", "info");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
package/extensions/sound-cues.ts
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
type EventContext = Parameters<Parameters<ExtensionAPI["on"]>[1]>[1];
|
|
4
|
-
|
|
5
|
-
type SoundName = "start" | "done" | "need-input" | "error";
|
|
6
|
-
|
|
7
|
-
export default function (pi: ExtensionAPI): void {
|
|
8
|
-
let enabled = true;
|
|
9
|
-
|
|
10
|
-
function bell(count = 1): void {
|
|
11
|
-
if (!enabled) return;
|
|
12
|
-
|
|
13
|
-
for (let i = 0; i < count; i += 1) {
|
|
14
|
-
setTimeout(() => {
|
|
15
|
-
process.stdout.write("\u0007");
|
|
16
|
-
}, i * 150);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function play(sound: SoundName): void {
|
|
21
|
-
if (sound === "start") bell(1);
|
|
22
|
-
if (sound === "done") bell(2);
|
|
23
|
-
if (sound === "need-input") bell(3);
|
|
24
|
-
if (sound === "error") bell(4);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
pi.on("before_agent_start", async () => {
|
|
28
|
-
play("start");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
pi.on("agent_end", async () => {
|
|
32
|
-
play("done");
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
pi.on("tool_call", async (event) => {
|
|
36
|
-
if (event.toolName === "bash") {
|
|
37
|
-
const command = String(event.input.command ?? "");
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
/\bnpm\s+install\b/i.test(command) ||
|
|
41
|
-
/\bnpm\s+update\b/i.test(command) ||
|
|
42
|
-
/\bgit\s+reset\s+--hard\b/i.test(command)
|
|
43
|
-
) {
|
|
44
|
-
play("need-input");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
pi.on("tool_result", async (event) => {
|
|
50
|
-
const maybeResult = event as {
|
|
51
|
-
result?: {
|
|
52
|
-
code?: number;
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
typeof maybeResult.result?.code === "number" &&
|
|
58
|
-
maybeResult.result.code !== 0
|
|
59
|
-
) {
|
|
60
|
-
play("error");
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
pi.registerCommand("sound-on", {
|
|
65
|
-
description: "Enable PreApeXis sound cues",
|
|
66
|
-
handler: async (_args, ctx: EventContext) => {
|
|
67
|
-
enabled = true;
|
|
68
|
-
play("done");
|
|
69
|
-
ctx.ui.notify("Sound cues enabled.", "info");
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
pi.registerCommand("sound-off", {
|
|
74
|
-
description: "Disable PreApeXis sound cues",
|
|
75
|
-
handler: async (_args, ctx: EventContext) => {
|
|
76
|
-
enabled = false;
|
|
77
|
-
ctx.ui.notify("Sound cues disabled.", "info");
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
pi.registerCommand("sound-test", {
|
|
82
|
-
description: "Test PreApeXis sound cues",
|
|
83
|
-
handler: async (_args, ctx: EventContext) => {
|
|
84
|
-
play("need-input");
|
|
85
|
-
ctx.ui.notify("Sound test played.", "info");
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
type EventContext = Parameters<Parameters<ExtensionAPI["on"]>[1]>[1];
|
|
4
|
+
|
|
5
|
+
type SoundName = "start" | "done" | "need-input" | "error";
|
|
6
|
+
|
|
7
|
+
export default function (pi: ExtensionAPI): void {
|
|
8
|
+
let enabled = true;
|
|
9
|
+
|
|
10
|
+
function bell(count = 1): void {
|
|
11
|
+
if (!enabled) return;
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < count; i += 1) {
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
process.stdout.write("\u0007");
|
|
16
|
+
}, i * 150);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function play(sound: SoundName): void {
|
|
21
|
+
if (sound === "start") bell(1);
|
|
22
|
+
if (sound === "done") bell(2);
|
|
23
|
+
if (sound === "need-input") bell(3);
|
|
24
|
+
if (sound === "error") bell(4);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pi.on("before_agent_start", async () => {
|
|
28
|
+
play("start");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
pi.on("agent_end", async () => {
|
|
32
|
+
play("done");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
pi.on("tool_call", async (event) => {
|
|
36
|
+
if (event.toolName === "bash") {
|
|
37
|
+
const command = String(event.input.command ?? "");
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
/\bnpm\s+install\b/i.test(command) ||
|
|
41
|
+
/\bnpm\s+update\b/i.test(command) ||
|
|
42
|
+
/\bgit\s+reset\s+--hard\b/i.test(command)
|
|
43
|
+
) {
|
|
44
|
+
play("need-input");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
pi.on("tool_result", async (event) => {
|
|
50
|
+
const maybeResult = event as {
|
|
51
|
+
result?: {
|
|
52
|
+
code?: number;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
typeof maybeResult.result?.code === "number" &&
|
|
58
|
+
maybeResult.result.code !== 0
|
|
59
|
+
) {
|
|
60
|
+
play("error");
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
pi.registerCommand("sound-on", {
|
|
65
|
+
description: "Enable PreApeXis sound cues",
|
|
66
|
+
handler: async (_args, ctx: EventContext) => {
|
|
67
|
+
enabled = true;
|
|
68
|
+
play("done");
|
|
69
|
+
ctx.ui.notify("Sound cues enabled.", "info");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pi.registerCommand("sound-off", {
|
|
74
|
+
description: "Disable PreApeXis sound cues",
|
|
75
|
+
handler: async (_args, ctx: EventContext) => {
|
|
76
|
+
enabled = false;
|
|
77
|
+
ctx.ui.notify("Sound cues disabled.", "info");
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
pi.registerCommand("sound-test", {
|
|
82
|
+
description: "Test PreApeXis sound cues",
|
|
83
|
+
handler: async (_args, ctx: EventContext) => {
|
|
84
|
+
play("need-input");
|
|
85
|
+
ctx.ui.notify("Sound test played.", "info");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|