@matyah00/openpi 0.1.2
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/README.md +117 -0
- package/agents/agent-chain.yaml +113 -0
- package/agents/backend.md +13 -0
- package/agents/basher.md +27 -0
- package/agents/builder.md +14 -0
- package/agents/code-searcher.md +27 -0
- package/agents/context-pruner.md +29 -0
- package/agents/directory-lister.md +25 -0
- package/agents/documenter.md +13 -0
- package/agents/editor.md +27 -0
- package/agents/file-picker.md +27 -0
- package/agents/frontend.md +14 -0
- package/agents/glob-matcher.md +25 -0
- package/agents/librarian.md +27 -0
- package/agents/loop-controller.md +41 -0
- package/agents/pi-pi/agent-expert.md +97 -0
- package/agents/pi-pi/cli-expert.md +41 -0
- package/agents/pi-pi/config-expert.md +63 -0
- package/agents/pi-pi/ext-expert.md +43 -0
- package/agents/pi-pi/keybinding-expert.md +134 -0
- package/agents/pi-pi/pi-orchestrator.md +57 -0
- package/agents/pi-pi/prompt-expert.md +70 -0
- package/agents/pi-pi/skill-expert.md +42 -0
- package/agents/pi-pi/theme-expert.md +40 -0
- package/agents/pi-pi/tui-expert.md +85 -0
- package/agents/plan-reviewer.md +22 -0
- package/agents/planner.md +14 -0
- package/agents/problem-architect.md +55 -0
- package/agents/red-team.md +13 -0
- package/agents/reviewer.md +14 -0
- package/agents/rule-verifier.md +35 -0
- package/agents/scout.md +14 -0
- package/agents/security-auditor.md +35 -0
- package/agents/ship-guard.md +34 -0
- package/agents/spec-reviewer.md +41 -0
- package/agents/teams.yaml +73 -0
- package/agents/tester.md +27 -0
- package/agents/thinker.md +26 -0
- package/agents/worker.md +27 -0
- package/damage-control-rules.yaml +277 -0
- package/extensions/agent-chain.ts +293 -0
- package/extensions/agent-team.ts +312 -0
- package/extensions/audit-tools.ts +260 -0
- package/extensions/commands.ts +169 -0
- package/extensions/damage-control-continue.ts +243 -0
- package/extensions/lib/packagePaths.ts +13 -0
- package/extensions/minimal.ts +34 -0
- package/extensions/openpi.ts +255 -0
- package/extensions/pure-focus.ts +24 -0
- package/extensions/purpose-gate.ts +84 -0
- package/extensions/search-tools.ts +277 -0
- package/extensions/state-tools.ts +276 -0
- package/extensions/system-select.ts +120 -0
- package/extensions/theme-cycler.ts +181 -0
- package/extensions/themeMap.ts +145 -0
- package/extensions/tool-counter-widget.ts +68 -0
- package/extensions/tool-counter.ts +102 -0
- package/extensions/workflow.ts +642 -0
- package/package.json +60 -0
- package/prompts/blueprint.md +66 -0
- package/prompts/clarify.md +26 -0
- package/prompts/compress.md +23 -0
- package/prompts/debate.md +23 -0
- package/prompts/deep.md +36 -0
- package/prompts/deps.md +24 -0
- package/prompts/explore.md +22 -0
- package/prompts/ghost-test.md +22 -0
- package/prompts/goal.md +26 -0
- package/prompts/parallel.md +42 -0
- package/prompts/plan-team.md +31 -0
- package/prompts/prime.md +17 -0
- package/prompts/review.md +23 -0
- package/prompts/sentinel.md +29 -0
- package/prompts/ship.md +30 -0
- package/prompts/snapshot.md +26 -0
- package/prompts/spec.md +58 -0
- package/prompts/test.md +13 -0
- package/prompts/validate.md +19 -0
- package/skills/bowser/SKILL.md +114 -0
- package/skills/env-scanner/SKILL.md +25 -0
- package/skills/security-guard/SKILL.md +24 -0
- package/skills/session-continuity/SKILL.md +20 -0
- package/skills/spec-driven/SKILL.md +25 -0
- package/skills/test-first/SKILL.md +23 -0
- package/skills/ultrathink/SKILL.md +27 -0
- package/themes/catppuccin-mocha.json +86 -0
- package/themes/cyberpunk.json +81 -0
- package/themes/dracula.json +81 -0
- package/themes/everforest.json +82 -0
- package/themes/gruvbox.json +80 -0
- package/themes/midnight-ocean.json +76 -0
- package/themes/nord.json +84 -0
- package/themes/ocean-breeze.json +83 -0
- package/themes/rose-pine.json +82 -0
- package/themes/synthwave.json +82 -0
- package/themes/tokyo-night.json +83 -0
- package/tsconfig.json +15 -0
- package/types/pi-shims.d.ts +102 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* themeMap.ts — Per-extension default theme assignments
|
|
3
|
+
*
|
|
4
|
+
* Themes live in .pi/themes/ and are mapped by extension filename (no extension).
|
|
5
|
+
* Each extension calls applyExtensionTheme(import.meta.url, ctx) in its session_start
|
|
6
|
+
* hook to automatically load its designated theme on boot.
|
|
7
|
+
*
|
|
8
|
+
* Available themes (.pi/themes/):
|
|
9
|
+
* catppuccin-mocha · cyberpunk · dracula · everforest · gruvbox
|
|
10
|
+
* midnight-ocean · nord · ocean-breeze · rose-pine
|
|
11
|
+
* synthwave · tokyo-night
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
15
|
+
import { basename } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
|
|
18
|
+
// ── Theme assignments ──────────────────────────────────────────────────────
|
|
19
|
+
//
|
|
20
|
+
// Key = extension filename without extension (matches extensions/<key>.ts)
|
|
21
|
+
// Value = theme name from .pi/themes/<value>.json
|
|
22
|
+
//
|
|
23
|
+
export const THEME_MAP: Record<string, string> = {
|
|
24
|
+
"agent-chain": "midnight-ocean", // deep sequential pipeline
|
|
25
|
+
"agent-team": "dracula", // rich orchestration palette
|
|
26
|
+
"coms": "ocean-breeze", // peer-to-peer messaging, cross-boundary
|
|
27
|
+
"coms-net": "ocean-breeze", // peer-to-peer messaging, cross-boundary
|
|
28
|
+
"cross-agent": "ocean-breeze", // cross-boundary, connecting
|
|
29
|
+
"damage-control": "gruvbox", // grounded, earthy safety
|
|
30
|
+
"minimal": "synthwave", // synthwave by default now!
|
|
31
|
+
"pi-pi": "rose-pine", // warm creative meta-agent
|
|
32
|
+
"pure-focus": "everforest", // calm, distraction-free
|
|
33
|
+
"purpose-gate": "tokyo-night", // intentional, sharp focus
|
|
34
|
+
"session-replay": "catppuccin-mocha", // soft, reflective history
|
|
35
|
+
"subagent-widget": "cyberpunk", // multi-agent futuristic
|
|
36
|
+
"system-select": "catppuccin-mocha", // soft selection UI
|
|
37
|
+
"theme-cycler": "synthwave", // neon, it's a theme tool
|
|
38
|
+
"tilldone": "everforest", // task-focused calm
|
|
39
|
+
"tool-counter": "synthwave", // techy metrics
|
|
40
|
+
"tool-counter-widget":"synthwave", // same family
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/** Derive the extension name (e.g. "minimal") from its import.meta.url. */
|
|
46
|
+
function extensionName(fileUrl: string): string {
|
|
47
|
+
const filePath = fileUrl.startsWith("file://") ? fileURLToPath(fileUrl) : fileUrl;
|
|
48
|
+
return basename(filePath).replace(/\.[^.]+$/, "");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Theme ──────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Apply the mapped theme for an extension on session boot.
|
|
55
|
+
*
|
|
56
|
+
* @param fileUrl Pass `import.meta.url` from the calling extension file.
|
|
57
|
+
* @param ctx The ExtensionContext from the session_start handler.
|
|
58
|
+
* @returns true if the theme was applied successfully, false otherwise.
|
|
59
|
+
*/
|
|
60
|
+
export function applyExtensionTheme(fileUrl: string, ctx: ExtensionContext): boolean {
|
|
61
|
+
if (!ctx.hasUI) return false;
|
|
62
|
+
|
|
63
|
+
const name = extensionName(fileUrl);
|
|
64
|
+
|
|
65
|
+
// If there are multiple extensions stacked in 'ipi', they each fire session_start
|
|
66
|
+
// and try to apply their own mapped theme. The LAST one to fire wins.
|
|
67
|
+
// Since system-select is last in the ipi alias array, it was setting 'catppuccin-mocha'.
|
|
68
|
+
|
|
69
|
+
// We want to skip theme application for all secondary extensions if they are stacked,
|
|
70
|
+
// so the primary extension (first in the array) dictates the theme.
|
|
71
|
+
const primaryExt = primaryExtensionName();
|
|
72
|
+
if (primaryExt && primaryExt !== name) {
|
|
73
|
+
return true; // Pretend we succeeded, but don't overwrite the primary theme
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let themeName = THEME_MAP[name];
|
|
77
|
+
|
|
78
|
+
if (!themeName) {
|
|
79
|
+
themeName = "synthwave";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result = ctx.ui.setTheme(themeName);
|
|
83
|
+
|
|
84
|
+
if (!result.success && themeName !== "synthwave") {
|
|
85
|
+
return ctx.ui.setTheme("synthwave").success;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return result.success;
|
|
89
|
+
}
|
|
90
|
+
// ── Title ──────────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Read process.argv to find the first -e / --extension flag value.
|
|
94
|
+
*
|
|
95
|
+
* When Pi is launched as:
|
|
96
|
+
* pi -e extensions/subagent-widget.ts -e extensions/pure-focus.ts
|
|
97
|
+
*
|
|
98
|
+
* process.argv contains those paths verbatim. Every stacked extension calls
|
|
99
|
+
* this and gets the same answer ("subagent-widget"), so all setTitle calls
|
|
100
|
+
* are idempotent — no shared state or deduplication needed.
|
|
101
|
+
*
|
|
102
|
+
* Returns null if no -e flag is present (e.g. plain `pi` with no extensions).
|
|
103
|
+
*/
|
|
104
|
+
function primaryExtensionName(): string | null {
|
|
105
|
+
const argv = process.argv;
|
|
106
|
+
for (let i = 0; i < argv.length - 1; i++) {
|
|
107
|
+
if (argv[i] === "-e" || argv[i] === "--extension") {
|
|
108
|
+
return basename(argv[i + 1]).replace(/\.[^.]+$/, "");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set the terminal title to "π - <first-extension-name>" on session boot.
|
|
116
|
+
* Reads the title from process.argv so all stacked extensions agree on the
|
|
117
|
+
* same value — no coordination or shared state required.
|
|
118
|
+
*
|
|
119
|
+
* Deferred 150 ms to fire after Pi's own startup title-set.
|
|
120
|
+
*/
|
|
121
|
+
function applyExtensionTitle(ctx: ExtensionContext): void {
|
|
122
|
+
if (!ctx.hasUI) return;
|
|
123
|
+
const name = primaryExtensionName();
|
|
124
|
+
if (!name) return;
|
|
125
|
+
setTimeout(() => ctx.ui.setTitle(`π - ${name}`), 150);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── Combined default ───────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Apply both the mapped theme AND the terminal title for an extension.
|
|
132
|
+
* Drop-in replacement for applyExtensionTheme — call this in every session_start.
|
|
133
|
+
*
|
|
134
|
+
* Usage:
|
|
135
|
+
* import { applyExtensionDefaults } from "./themeMap.ts";
|
|
136
|
+
*
|
|
137
|
+
* pi.on("session_start", async (_event, ctx) => {
|
|
138
|
+
* applyExtensionDefaults(import.meta.url, ctx);
|
|
139
|
+
* // ... rest of handler
|
|
140
|
+
* });
|
|
141
|
+
*/
|
|
142
|
+
export function applyExtensionDefaults(fileUrl: string, ctx: ExtensionContext): void {
|
|
143
|
+
applyExtensionTheme(fileUrl, ctx);
|
|
144
|
+
applyExtensionTitle(ctx);
|
|
145
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Counter Widget — Tool call counts in a widget above the editor
|
|
3
|
+
*
|
|
4
|
+
* Shows a persistent, live-updating widget with per-tool background colors.
|
|
5
|
+
* Format: Tools (N): [Bash 3] [Read 7] [Write 2]
|
|
6
|
+
*
|
|
7
|
+
* Usage: pi -e extensions/tool-counter-widget.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
11
|
+
import { Box, Text } from "@mariozechner/pi-tui";
|
|
12
|
+
import { applyExtensionDefaults } from "./themeMap.ts";
|
|
13
|
+
|
|
14
|
+
const palette = [
|
|
15
|
+
[12, 40, 80], // deep navy
|
|
16
|
+
[50, 20, 70], // dark purple
|
|
17
|
+
[10, 55, 45], // dark teal
|
|
18
|
+
[70, 30, 10], // dark rust
|
|
19
|
+
[55, 15, 40], // dark plum
|
|
20
|
+
[15, 50, 65], // dark ocean
|
|
21
|
+
[45, 45, 15], // dark olive
|
|
22
|
+
[65, 18, 25], // dark wine
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function bg(rgb: number[], s: string): string {
|
|
26
|
+
return `\x1b[48;2;${rgb[0]};${rgb[1]};${rgb[2]}m${s}\x1b[49m`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function (pi: ExtensionAPI) {
|
|
30
|
+
const counts: Record<string, number> = {};
|
|
31
|
+
const toolColors: Record<string, number[]> = {};
|
|
32
|
+
let total = 0;
|
|
33
|
+
let colorIdx = 0;
|
|
34
|
+
|
|
35
|
+
pi.on("tool_execution_end", async (event) => {
|
|
36
|
+
if (!(event.toolName in toolColors)) {
|
|
37
|
+
toolColors[event.toolName] = palette[colorIdx % palette.length];
|
|
38
|
+
colorIdx++;
|
|
39
|
+
}
|
|
40
|
+
counts[event.toolName] = (counts[event.toolName] || 0) + 1;
|
|
41
|
+
total++;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
45
|
+
applyExtensionDefaults(import.meta.url, ctx);
|
|
46
|
+
ctx.ui.setWidget("tool-counter", (_tui, theme) => {
|
|
47
|
+
const text = new Text("", 1, 1);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
render(width: number): string[] {
|
|
51
|
+
const entries = Object.entries(counts);
|
|
52
|
+
const parts = entries.map(([name, count]) => {
|
|
53
|
+
const rgb = toolColors[name];
|
|
54
|
+
return bg(rgb, `\x1b[38;2;220;220;220m ${name} ${count} \x1b[39m`);
|
|
55
|
+
});
|
|
56
|
+
text.setText(
|
|
57
|
+
theme.fg("accent", `Tools (${total}):`) +
|
|
58
|
+
(entries.length > 0 ? " " + parts.join(" ") : "")
|
|
59
|
+
);
|
|
60
|
+
return text.render(width);
|
|
61
|
+
},
|
|
62
|
+
invalidate() {
|
|
63
|
+
text.invalidate();
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Counter — Rich two-line custom footer
|
|
3
|
+
*
|
|
4
|
+
* Line 1: model + context meter on left, tokens in/out + cost on right
|
|
5
|
+
* Line 2: cwd (branch) on left, tool call tally on right
|
|
6
|
+
*
|
|
7
|
+
* Demonstrates: setFooter, footerData.getGitBranch(), onBranchChange(),
|
|
8
|
+
* session branch traversal for token/cost accumulation.
|
|
9
|
+
*
|
|
10
|
+
* Usage: pi -e extensions/tool-counter.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
14
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
15
|
+
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
16
|
+
import { basename } from "node:path";
|
|
17
|
+
import { applyExtensionDefaults } from "./themeMap.ts";
|
|
18
|
+
|
|
19
|
+
export default function (pi: ExtensionAPI) {
|
|
20
|
+
const counts: Record<string, number> = {};
|
|
21
|
+
|
|
22
|
+
pi.on("tool_execution_end", async (event) => {
|
|
23
|
+
counts[event.toolName] = (counts[event.toolName] || 0) + 1;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
27
|
+
applyExtensionDefaults(import.meta.url, ctx);
|
|
28
|
+
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
29
|
+
const unsub = footerData.onBranchChange(() => tui.requestRender());
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
dispose: unsub,
|
|
33
|
+
invalidate() {},
|
|
34
|
+
render(width: number): string[] {
|
|
35
|
+
// --- Line 1: cwd + branch (left), tokens + cost (right) ---
|
|
36
|
+
let tokIn = 0;
|
|
37
|
+
let tokOut = 0;
|
|
38
|
+
let cost = 0;
|
|
39
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
40
|
+
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
41
|
+
const m = entry.message as AssistantMessage;
|
|
42
|
+
tokIn += m.usage.input;
|
|
43
|
+
tokOut += m.usage.output;
|
|
44
|
+
cost += m.usage.cost.total;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const fmt = (n: number) => n < 1000 ? `${n}` : `${(n / 1000).toFixed(1)}k`;
|
|
49
|
+
const dir = basename(ctx.cwd);
|
|
50
|
+
const branch = footerData.getGitBranch();
|
|
51
|
+
|
|
52
|
+
// --- Line 1: model + context meter (left), tokens + cost (right) ---
|
|
53
|
+
const usage = ctx.getContextUsage();
|
|
54
|
+
const pct = usage ? usage.percent : 0;
|
|
55
|
+
const filled = Math.round(pct / 10) || 1;
|
|
56
|
+
const bar = "#".repeat(filled) + "-".repeat(10 - filled);
|
|
57
|
+
const model = ctx.model?.id || "no-model";
|
|
58
|
+
|
|
59
|
+
const l1Left =
|
|
60
|
+
theme.fg("dim", ` ${model} `) +
|
|
61
|
+
theme.fg("warning", "[") +
|
|
62
|
+
theme.fg("success", "#".repeat(filled)) +
|
|
63
|
+
theme.fg("dim", "-".repeat(10 - filled)) +
|
|
64
|
+
theme.fg("warning", "]") +
|
|
65
|
+
theme.fg("dim", " ") +
|
|
66
|
+
theme.fg("accent", `${Math.round(pct)}%`);
|
|
67
|
+
|
|
68
|
+
const l1Right =
|
|
69
|
+
theme.fg("success", `${fmt(tokIn)}`) +
|
|
70
|
+
theme.fg("dim", " in ") +
|
|
71
|
+
theme.fg("accent", `${fmt(tokOut)}`) +
|
|
72
|
+
theme.fg("dim", " out ") +
|
|
73
|
+
theme.fg("warning", `$${cost.toFixed(4)}`) +
|
|
74
|
+
theme.fg("dim", " ");
|
|
75
|
+
|
|
76
|
+
const pad1 = " ".repeat(Math.max(1, width - visibleWidth(l1Left) - visibleWidth(l1Right)));
|
|
77
|
+
const line1 = truncateToWidth(l1Left + pad1 + l1Right, width, "");
|
|
78
|
+
|
|
79
|
+
// --- Line 2: cwd + branch (left), tool tally (right) ---
|
|
80
|
+
const l2Left =
|
|
81
|
+
theme.fg("dim", ` ${dir}`) +
|
|
82
|
+
(branch
|
|
83
|
+
? theme.fg("dim", " ") + theme.fg("warning", "(") + theme.fg("success", branch) + theme.fg("warning", ")")
|
|
84
|
+
: "");
|
|
85
|
+
|
|
86
|
+
const entries = Object.entries(counts);
|
|
87
|
+
const l2Right = entries.length === 0
|
|
88
|
+
? theme.fg("dim", "waiting for tools ")
|
|
89
|
+
: entries.map(
|
|
90
|
+
([name, count]) =>
|
|
91
|
+
theme.fg("accent", name) + theme.fg("dim", " ") + theme.fg("success", `${count}`)
|
|
92
|
+
).join(theme.fg("warning", " | ")) + theme.fg("dim", " ");
|
|
93
|
+
|
|
94
|
+
const pad2 = " ".repeat(Math.max(1, width - visibleWidth(l2Left) - visibleWidth(l2Right)));
|
|
95
|
+
const line2 = truncateToWidth(l2Left + pad2 + l2Right, width, "");
|
|
96
|
+
|
|
97
|
+
return [line1, line2];
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|