oh-pi 0.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.
Files changed (65) hide show
  1. package/README.md +180 -0
  2. package/dist/bin/oh-pi.d.ts +2 -0
  3. package/dist/bin/oh-pi.js +3 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +62 -0
  6. package/dist/tui/agents-select.d.ts +1 -0
  7. package/dist/tui/agents-select.js +18 -0
  8. package/dist/tui/confirm-apply.d.ts +3 -0
  9. package/dist/tui/confirm-apply.js +90 -0
  10. package/dist/tui/extension-select.d.ts +1 -0
  11. package/dist/tui/extension-select.js +17 -0
  12. package/dist/tui/keybinding-select.d.ts +1 -0
  13. package/dist/tui/keybinding-select.js +16 -0
  14. package/dist/tui/mode-select.d.ts +3 -0
  15. package/dist/tui/mode-select.js +16 -0
  16. package/dist/tui/preset-select.d.ts +5 -0
  17. package/dist/tui/preset-select.js +81 -0
  18. package/dist/tui/provider-setup.d.ts +2 -0
  19. package/dist/tui/provider-setup.js +68 -0
  20. package/dist/tui/theme-select.d.ts +1 -0
  21. package/dist/tui/theme-select.js +16 -0
  22. package/dist/tui/welcome.d.ts +2 -0
  23. package/dist/tui/welcome.js +25 -0
  24. package/dist/types.d.ts +31 -0
  25. package/dist/types.js +41 -0
  26. package/dist/utils/detect.d.ts +11 -0
  27. package/dist/utils/detect.js +56 -0
  28. package/dist/utils/install.d.ts +5 -0
  29. package/dist/utils/install.js +130 -0
  30. package/package.json +54 -0
  31. package/pi-package/agents/colony-operator.md +32 -0
  32. package/pi-package/agents/data-ai-engineer.md +24 -0
  33. package/pi-package/agents/fullstack-developer.md +24 -0
  34. package/pi-package/agents/general-developer.md +22 -0
  35. package/pi-package/agents/security-researcher.md +29 -0
  36. package/pi-package/extensions/ant-colony/README.md +117 -0
  37. package/pi-package/extensions/ant-colony/concurrency.ts +115 -0
  38. package/pi-package/extensions/ant-colony/index.ts +338 -0
  39. package/pi-package/extensions/ant-colony/nest.ts +196 -0
  40. package/pi-package/extensions/ant-colony/queen.ts +356 -0
  41. package/pi-package/extensions/ant-colony/spawner.ts +328 -0
  42. package/pi-package/extensions/ant-colony/types.ts +117 -0
  43. package/pi-package/extensions/auto-session-name.ts +29 -0
  44. package/pi-package/extensions/git-guard.ts +45 -0
  45. package/pi-package/extensions/safe-guard.ts +46 -0
  46. package/pi-package/prompts/commit.md +18 -0
  47. package/pi-package/prompts/document.md +14 -0
  48. package/pi-package/prompts/explain.md +13 -0
  49. package/pi-package/prompts/fix.md +11 -0
  50. package/pi-package/prompts/optimize.md +14 -0
  51. package/pi-package/prompts/pr.md +24 -0
  52. package/pi-package/prompts/refactor.md +14 -0
  53. package/pi-package/prompts/review.md +18 -0
  54. package/pi-package/prompts/security.md +16 -0
  55. package/pi-package/prompts/test.md +12 -0
  56. package/pi-package/skills/ant-colony/SKILL.md +59 -0
  57. package/pi-package/skills/debug-helper/SKILL.md +43 -0
  58. package/pi-package/skills/git-workflow/SKILL.md +48 -0
  59. package/pi-package/skills/quick-setup/SKILL.md +44 -0
  60. package/pi-package/themes/catppuccin-mocha.json +31 -0
  61. package/pi-package/themes/cyberpunk.json +66 -0
  62. package/pi-package/themes/gruvbox-dark.json +29 -0
  63. package/pi-package/themes/nord.json +29 -0
  64. package/pi-package/themes/oh-p-dark.json +69 -0
  65. package/pi-package/themes/tokyo-night.json +29 -0
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # oh-pi!
2
+
3
+ > One-click setup for [pi-coding-agent](https://github.com/badlogic/pi-mono). Like oh-my-zsh for pi.
4
+
5
+ ```bash
6
+ npx oh-pi
7
+ ```
8
+
9
+ ## What it does
10
+
11
+ oh-pi! is a modern interactive TUI that configures pi-coding-agent in minutes:
12
+
13
+ - **API Key Setup** — Multi-provider configuration with validation (Anthropic, OpenAI, Google, Groq, OpenRouter, xAI, Mistral)
14
+ - **Preset Profiles** — Pre-made configs for different roles (Developer, Security, Data/AI, Colony Operator, Minimal)
15
+ - **Custom Themes** — 6 beautiful themes (oh-pi Dark, Cyberpunk, Nord, Catppuccin, Tokyo Night, Gruvbox)
16
+ - **Prompt Templates** — 10 ready-to-use templates (/review, /fix, /commit, /test, /security, etc.)
17
+ - **Extensions** — Safety guards, git checkpoints, auto session naming, ant colony swarm
18
+ - **Skills** — Debug helper, git workflow, quick project setup, ant colony orchestration
19
+ - **Keybindings** — Default, Vim, or Emacs schemes
20
+ - **AGENTS.md** — Role-specific project guidelines
21
+ - **🐜 Ant Colony** — Autonomous multi-agent swarm with adaptive concurrency
22
+
23
+ ## Quick Start
24
+
25
+ ```bash
26
+ # Run the configurator
27
+ npx oh-pi
28
+
29
+ # Then start coding
30
+ pi
31
+ ```
32
+
33
+ ## Setup Modes
34
+
35
+ ### 🚀 Quick Setup (3 steps)
36
+ 1. Pick your API provider(s)
37
+ 2. Enter API key(s)
38
+ 3. Done — sensible defaults applied
39
+
40
+ ### 📦 Preset
41
+ Choose a pre-made profile:
42
+
43
+ | Preset | Theme | Thinking | Focus |
44
+ |--------|-------|----------|-------|
45
+ | 🟢 Starter | oh-pi Dark | medium | Basic safety + git |
46
+ | 🔵 Pro Developer | Catppuccin | high | Full toolchain |
47
+ | 🟣 Security Researcher | Cyberpunk | high | Audit + pentesting |
48
+ | 🟠 Data & AI Engineer | Tokyo Night | medium | MLOps + pipelines |
49
+ | 🔴 Minimal | Pi Default | off | Core only |
50
+ | ⚫ Full Power | oh-pi Dark | high | Everything + ant colony |
51
+
52
+ ### 🎛️ Custom
53
+ Pick every option yourself: providers, theme, keybindings, extensions, skills, AGENTS.md template.
54
+
55
+ ## 🐜 Ant Colony
56
+
57
+ Autonomous multi-agent swarm built as a pi extension. Modeled after real ant colony behavior.
58
+
59
+ ### How it works
60
+
61
+ ```
62
+ Goal → 🔍 Scouts explore → 📋 Task pool generated → ⚒️ Workers execute in parallel → 🛡️ Soldiers review → ✅ Done
63
+ ```
64
+
65
+ - **Scouts** (haiku) — Fast codebase recon, identify targets
66
+ - **Workers** (sonnet) — Execute tasks, can spawn sub-tasks
67
+ - **Soldiers** (sonnet) — Review quality, request fixes if needed
68
+
69
+ ### Key features
70
+
71
+ - **Auto-trigger** — LLM automatically deploys colony for complex multi-file tasks
72
+ - **Adaptive concurrency** — Starts at 1, explores throughput ceiling, stabilizes at optimal
73
+ - **429 backoff** — Rate limits trigger exponential backoff (15s→30s→60s) + concurrency halving
74
+ - **Pheromone communication** — Ants share discoveries via file-based pheromone trails (10min half-life)
75
+ - **File locking** — One ant per file, blocked tasks auto-resume when locks release
76
+
77
+ ### Usage
78
+
79
+ ```bash
80
+ # LLM auto-triggers for complex tasks
81
+ "Refactor the auth system from sessions to JWT"
82
+
83
+ # Manual command
84
+ /colony migrate the entire project from CJS to ESM
85
+
86
+ # Shortcut
87
+ Ctrl+Alt+A
88
+ ```
89
+
90
+ ## What Gets Installed
91
+
92
+ ```
93
+ ~/.pi/agent/
94
+ ├── auth.json # API keys (0600 permissions)
95
+ ├── settings.json # Model, theme, thinking level
96
+ ├── keybindings.json # Vim/Emacs shortcuts (if selected)
97
+ ├── AGENTS.md # Project guidelines for the AI
98
+ ├── extensions/ # Safety guards, git tools, ant colony
99
+ ├── prompts/ # /review, /fix, /commit, /test, etc.
100
+ ├── skills/ # debug-helper, git-workflow, ant-colony
101
+ └── themes/ # Custom color themes
102
+ ```
103
+
104
+ Existing config? oh-pi! detects it and offers backup before overwriting.
105
+
106
+ ## Included Resources
107
+
108
+ ### Themes
109
+
110
+ | Theme | Style |
111
+ |-------|-------|
112
+ | oh-pi Dark | Cyan + Purple, high contrast |
113
+ | Cyberpunk | Neon magenta + electric cyan |
114
+ | Nord | Arctic blue palette |
115
+ | Catppuccin Mocha | Pastel colors on dark |
116
+ | Tokyo Night | Blue + purple twilight |
117
+ | Gruvbox Dark | Warm retro tones |
118
+
119
+ ### Prompt Templates
120
+
121
+ | Command | Description |
122
+ |---------|-------------|
123
+ | `/review` | Code review: bugs, security, performance |
124
+ | `/fix` | Fix errors with minimal changes |
125
+ | `/explain` | Explain code from simple to detailed |
126
+ | `/refactor` | Refactor while preserving behavior |
127
+ | `/test` | Generate tests for code |
128
+ | `/commit` | Conventional Commit message |
129
+ | `/pr` | Pull request description |
130
+ | `/security` | OWASP security audit |
131
+ | `/optimize` | Performance optimization |
132
+ | `/document` | Generate documentation |
133
+
134
+ ### Extensions
135
+
136
+ | Extension | Description |
137
+ |-----------|-------------|
138
+ | Safe Guard | Confirms dangerous commands (rm -rf, DROP, etc.) + protects .env, .git/ |
139
+ | Git Guard | Auto stash checkpoints + dirty repo warning + completion notification |
140
+ | Auto Session Name | Names sessions from first message |
141
+ | 🐜 Ant Colony | Autonomous multi-agent swarm with adaptive concurrency |
142
+
143
+ ### Skills
144
+
145
+ | Skill | Description |
146
+ |-------|-------------|
147
+ | `/skill:quick-setup` | Detect project type, generate .pi/ config |
148
+ | `/skill:debug-helper` | Error analysis, log interpretation, profiling |
149
+ | `/skill:git-workflow` | Branch strategy, PR workflow, conflict resolution |
150
+ | `/skill:ant-colony` | Colony orchestration strategies and tuning |
151
+
152
+ ### AGENTS.md Templates
153
+
154
+ | Template | Description |
155
+ |----------|-------------|
156
+ | General Developer | Universal coding guidelines |
157
+ | Full-Stack Developer | Frontend + Backend + DB |
158
+ | Security Researcher | Pentesting & audit |
159
+ | Data & AI Engineer | MLOps & pipelines |
160
+ | 🐜 Colony Operator | Ant swarm multi-agent orchestration |
161
+
162
+ ## Also a Pi Package
163
+
164
+ oh-pi! is also a pi package. Install just the resources without the configurator:
165
+
166
+ ```bash
167
+ pi install npm:oh-pi
168
+ ```
169
+
170
+ This adds all themes, prompts, skills, and extensions to your pi setup.
171
+
172
+ ## Requirements
173
+
174
+ - Node.js >= 20
175
+ - pi-coding-agent (installed automatically if missing)
176
+ - At least one LLM API key
177
+
178
+ ## License
179
+
180
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { run } from "../index.js";
3
+ run().catch((e) => { console.error(e); process.exit(1); });
@@ -0,0 +1 @@
1
+ export declare function run(): Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,62 @@
1
+ import { welcome } from "./tui/welcome.js";
2
+ import { selectMode } from "./tui/mode-select.js";
3
+ import { setupProviders } from "./tui/provider-setup.js";
4
+ import { selectPreset } from "./tui/preset-select.js";
5
+ import { selectTheme } from "./tui/theme-select.js";
6
+ import { selectKeybindings } from "./tui/keybinding-select.js";
7
+ import { selectExtensions } from "./tui/extension-select.js";
8
+ import { selectAgents } from "./tui/agents-select.js";
9
+ import { confirmApply } from "./tui/confirm-apply.js";
10
+ import { detectEnv } from "./utils/detect.js";
11
+ export async function run() {
12
+ const env = await detectEnv();
13
+ welcome(env);
14
+ const mode = await selectMode(env);
15
+ let config;
16
+ if (mode === "quick") {
17
+ config = await quickFlow(env);
18
+ }
19
+ else if (mode === "preset") {
20
+ config = await presetFlow(env);
21
+ }
22
+ else {
23
+ config = await customFlow(env);
24
+ }
25
+ await confirmApply(config, env);
26
+ }
27
+ async function quickFlow(env) {
28
+ const providers = await setupProviders();
29
+ const theme = "oh-p-dark";
30
+ return {
31
+ providers,
32
+ theme,
33
+ keybindings: "default",
34
+ extensions: ["safe-guard", "git-guard", "auto-session-name"],
35
+ skills: ["quick-setup", "debug-helper", "git-workflow"],
36
+ prompts: ["review", "fix", "explain", "commit", "test"],
37
+ agents: "general-developer",
38
+ thinking: "medium",
39
+ };
40
+ }
41
+ async function presetFlow(env) {
42
+ const preset = await selectPreset();
43
+ const providers = await setupProviders();
44
+ return { ...preset, providers };
45
+ }
46
+ async function customFlow(env) {
47
+ const providers = await setupProviders();
48
+ const theme = await selectTheme();
49
+ const keybindings = await selectKeybindings();
50
+ const extensions = await selectExtensions();
51
+ const agents = await selectAgents();
52
+ return {
53
+ providers,
54
+ theme,
55
+ keybindings,
56
+ extensions,
57
+ skills: ["quick-setup", "debug-helper", "git-workflow"],
58
+ prompts: ["review", "fix", "explain", "commit", "test", "refactor", "optimize", "security", "document", "pr"],
59
+ agents,
60
+ thinking: "medium",
61
+ };
62
+ }
@@ -0,0 +1 @@
1
+ export declare function selectAgents(): Promise<string>;
@@ -0,0 +1,18 @@
1
+ import * as p from "@clack/prompts";
2
+ export async function selectAgents() {
3
+ const agent = await p.select({
4
+ message: "AGENTS.md template:",
5
+ options: [
6
+ { value: "general-developer", label: "📋 General Developer", hint: "Universal coding guidelines" },
7
+ { value: "fullstack-developer", label: "🏗️ Full-Stack Developer", hint: "Frontend + Backend + DB" },
8
+ { value: "security-researcher", label: "🔒 Security Researcher", hint: "Pentesting & audit" },
9
+ { value: "data-ai-engineer", label: "🤖 Data & AI Engineer", hint: "MLOps & pipelines" },
10
+ { value: "colony-operator", label: "🐜 Colony Operator", hint: "Ant swarm multi-agent" },
11
+ ],
12
+ });
13
+ if (p.isCancel(agent)) {
14
+ p.cancel("Cancelled.");
15
+ process.exit(0);
16
+ }
17
+ return agent;
18
+ }
@@ -0,0 +1,3 @@
1
+ import type { OhPConfig } from "../types.js";
2
+ import type { EnvInfo } from "../utils/detect.js";
3
+ export declare function confirmApply(config: OhPConfig, env: EnvInfo): Promise<void>;
@@ -0,0 +1,90 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import { applyConfig, installPi, backupConfig } from "../utils/install.js";
4
+ function countExisting(env, dir) {
5
+ return env.existingFiles.filter(f => f.startsWith(dir + "/")).length;
6
+ }
7
+ export async function confirmApply(config, env) {
8
+ // ═══ Summary ═══
9
+ const summary = [
10
+ `Providers: ${chalk.cyan(config.providers.map(p => p.name).join(", "))}`,
11
+ `Model: ${chalk.cyan(config.providers[0]?.defaultModel || "default")}`,
12
+ `Theme: ${chalk.cyan(config.theme)}`,
13
+ `Keybindings: ${chalk.cyan(config.keybindings)}`,
14
+ `Thinking: ${chalk.cyan(config.thinking)}`,
15
+ `Extensions: ${chalk.cyan(config.extensions.join(", ") || "none")}`,
16
+ `Skills: ${chalk.cyan(config.skills.join(", ") || "none")}`,
17
+ `Prompts: ${chalk.cyan(`${config.prompts.length} templates`)}`,
18
+ `AGENTS.md: ${chalk.cyan(config.agents)}`,
19
+ ].join("\n");
20
+ p.note(summary, "Configuration");
21
+ // ═══ Diff (if existing) ═══
22
+ if (env.hasExistingConfig) {
23
+ const diff = [
24
+ `Extensions: ${chalk.dim(countExisting(env, "extensions"))} ${chalk.yellow("→")} ${chalk.green(config.extensions.length)}`,
25
+ `Skills: ${chalk.dim(countExisting(env, "skills"))} ${chalk.yellow("→")} ${chalk.green(config.skills.length)}`,
26
+ `Prompts: ${chalk.dim(countExisting(env, "prompts"))} ${chalk.yellow("→")} ${chalk.green(config.prompts.length)}`,
27
+ ].join("\n");
28
+ p.note(diff, "⚠ Changes");
29
+ }
30
+ // ═══ Backup prompt ═══
31
+ if (env.hasExistingConfig) {
32
+ const action = await p.select({
33
+ message: "Existing config detected. How to proceed?",
34
+ options: [
35
+ { value: "backup", label: "📦 Backup & apply", hint: "Safe — backup first, then overwrite" },
36
+ { value: "overwrite", label: "⚡ Overwrite", hint: "Replace without backup" },
37
+ { value: "cancel", label: "✖ Cancel", hint: "Keep current config" },
38
+ ],
39
+ });
40
+ if (p.isCancel(action) || action === "cancel") {
41
+ p.cancel("No changes made.");
42
+ return;
43
+ }
44
+ if (action === "backup") {
45
+ const s = p.spinner();
46
+ s.start("Backing up ~/.pi/agent/");
47
+ const backupDir = backupConfig();
48
+ s.stop(`Backed up to ${chalk.dim(backupDir)}`);
49
+ }
50
+ }
51
+ else {
52
+ const ok = await p.confirm({ message: "Apply configuration?" });
53
+ if (p.isCancel(ok) || !ok) {
54
+ p.cancel("No changes made.");
55
+ return;
56
+ }
57
+ }
58
+ // ═══ Install pi if needed ═══
59
+ if (!env.piInstalled) {
60
+ const s = p.spinner();
61
+ s.start("Installing pi-coding-agent");
62
+ try {
63
+ installPi();
64
+ s.stop("pi installed");
65
+ }
66
+ catch (e) {
67
+ s.stop(`Failed: ${e}`);
68
+ p.log.warn("Run manually: npm install -g @mariozechner/pi-coding-agent");
69
+ }
70
+ }
71
+ // ═══ Apply ═══
72
+ const s = p.spinner();
73
+ s.start("Writing configuration");
74
+ applyConfig(config);
75
+ s.stop("Configuration applied");
76
+ // ═══ Result ═══
77
+ const tree = [
78
+ `${chalk.gray("~/.pi/agent/")}`,
79
+ `${chalk.gray("├── ")}auth.json ${chalk.dim("🔒")}`,
80
+ `${chalk.gray("├── ")}settings.json`,
81
+ ...(config.keybindings !== "default" ? [`${chalk.gray("├── ")}keybindings.json`] : []),
82
+ `${chalk.gray("├── ")}AGENTS.md ${chalk.dim(config.agents)}`,
83
+ ...(config.extensions.length > 0 ? [`${chalk.gray("├── ")}extensions/ ${chalk.dim(`${config.extensions.length} items`)}`] : []),
84
+ ...(config.prompts.length > 0 ? [`${chalk.gray("├── ")}prompts/ ${chalk.dim(`${config.prompts.length} templates`)}`] : []),
85
+ ...(config.skills.length > 0 ? [`${chalk.gray("├── ")}skills/ ${chalk.dim(`${config.skills.length} skills`)}`] : []),
86
+ ...(!["dark", "light"].includes(config.theme) ? [`${chalk.gray("└── ")}themes/ ${chalk.dim(config.theme)}`] : []),
87
+ ].join("\n");
88
+ p.note(tree, "✓ Installed");
89
+ p.outro(`Run ${chalk.cyan.bold("pi")} to start coding!`);
90
+ }
@@ -0,0 +1 @@
1
+ export declare function selectExtensions(): Promise<string[]>;
@@ -0,0 +1,17 @@
1
+ import * as p from "@clack/prompts";
2
+ import { EXTENSIONS } from "../types.js";
3
+ export async function selectExtensions() {
4
+ const exts = await p.multiselect({
5
+ message: "Select extensions:",
6
+ options: EXTENSIONS.map(e => ({
7
+ value: e.name,
8
+ label: e.label,
9
+ })),
10
+ initialValues: EXTENSIONS.filter(e => e.default).map(e => e.name),
11
+ });
12
+ if (p.isCancel(exts)) {
13
+ p.cancel("Cancelled.");
14
+ process.exit(0);
15
+ }
16
+ return exts;
17
+ }
@@ -0,0 +1 @@
1
+ export declare function selectKeybindings(): Promise<string>;
@@ -0,0 +1,16 @@
1
+ import * as p from "@clack/prompts";
2
+ export async function selectKeybindings() {
3
+ const kb = await p.select({
4
+ message: "Keybinding scheme:",
5
+ options: [
6
+ { value: "default", label: "⌨️ Default", hint: "Pi standard keybindings" },
7
+ { value: "vim", label: "🟢 Vim", hint: "Alt+hjkl navigation" },
8
+ { value: "emacs", label: "🔵 Emacs", hint: "Ctrl+pnbf navigation" },
9
+ ],
10
+ });
11
+ if (p.isCancel(kb)) {
12
+ p.cancel("Cancelled.");
13
+ process.exit(0);
14
+ }
15
+ return kb;
16
+ }
@@ -0,0 +1,3 @@
1
+ import type { EnvInfo } from "../utils/detect.js";
2
+ export type Mode = "quick" | "custom" | "preset";
3
+ export declare function selectMode(env: EnvInfo): Promise<Mode>;
@@ -0,0 +1,16 @@
1
+ import * as p from "@clack/prompts";
2
+ export async function selectMode(env) {
3
+ const mode = await p.select({
4
+ message: "How would you like to set up pi?",
5
+ options: [
6
+ { value: "quick", label: "🚀 Quick Setup", hint: "Recommended defaults, 3 steps" },
7
+ { value: "preset", label: "📦 Preset", hint: "Choose a pre-made configuration" },
8
+ { value: "custom", label: "🎛️ Custom", hint: "Pick everything yourself" },
9
+ ],
10
+ });
11
+ if (p.isCancel(mode)) {
12
+ p.cancel("Cancelled.");
13
+ process.exit(0);
14
+ }
15
+ return mode;
16
+ }
@@ -0,0 +1,5 @@
1
+ import type { OhPConfig } from "../types.js";
2
+ interface Preset extends Omit<OhPConfig, "providers"> {
3
+ }
4
+ export declare function selectPreset(): Promise<Preset>;
5
+ export {};
@@ -0,0 +1,81 @@
1
+ import * as p from "@clack/prompts";
2
+ const PRESETS = {
3
+ starter: {
4
+ label: "🟢 Starter",
5
+ hint: "New to AI coding? Start here",
6
+ config: {
7
+ theme: "oh-p-dark", keybindings: "default", thinking: "medium",
8
+ extensions: ["safe-guard", "git-guard", "auto-session-name"],
9
+ skills: ["quick-setup", "debug-helper"],
10
+ prompts: ["review", "fix", "explain", "commit"],
11
+ agents: "general-developer",
12
+ },
13
+ },
14
+ pro: {
15
+ label: "🔵 Pro Developer",
16
+ hint: "Full-stack dev with all the bells and whistles",
17
+ config: {
18
+ theme: "catppuccin-mocha", keybindings: "default", thinking: "high",
19
+ extensions: ["safe-guard", "git-guard", "auto-session-name"],
20
+ skills: ["quick-setup", "debug-helper", "git-workflow"],
21
+ prompts: ["review", "fix", "explain", "commit", "test", "refactor", "optimize", "document", "pr"],
22
+ agents: "fullstack-developer",
23
+ },
24
+ },
25
+ security: {
26
+ label: "🟣 Security Researcher",
27
+ hint: "Pentesting, auditing, vulnerability research",
28
+ config: {
29
+ theme: "cyberpunk", keybindings: "default", thinking: "high",
30
+ extensions: ["safe-guard"],
31
+ skills: ["debug-helper"],
32
+ prompts: ["review", "security", "fix", "explain"],
33
+ agents: "security-researcher",
34
+ },
35
+ },
36
+ dataai: {
37
+ label: "🟠 Data & AI Engineer",
38
+ hint: "MLOps, data pipelines, AI applications",
39
+ config: {
40
+ theme: "tokyo-night", keybindings: "default", thinking: "medium",
41
+ extensions: ["safe-guard", "git-guard", "auto-session-name"],
42
+ skills: ["quick-setup", "debug-helper"],
43
+ prompts: ["review", "fix", "explain", "optimize", "document", "test"],
44
+ agents: "data-ai-engineer",
45
+ },
46
+ },
47
+ minimal: {
48
+ label: "🔴 Minimal",
49
+ hint: "Just the core, nothing extra",
50
+ config: {
51
+ theme: "dark", keybindings: "default", thinking: "off",
52
+ extensions: [], skills: [], prompts: [], agents: "general-developer",
53
+ },
54
+ },
55
+ full: {
56
+ label: "⚫ Full Power",
57
+ hint: "Everything installed, ant colony included",
58
+ config: {
59
+ theme: "oh-p-dark", keybindings: "default", thinking: "high",
60
+ extensions: ["safe-guard", "git-guard", "auto-session-name", "ant-colony"],
61
+ skills: ["quick-setup", "debug-helper", "git-workflow", "ant-colony"],
62
+ prompts: ["review", "fix", "explain", "commit", "test", "refactor", "optimize", "security", "document", "pr"],
63
+ agents: "colony-operator",
64
+ },
65
+ },
66
+ };
67
+ export async function selectPreset() {
68
+ const key = await p.select({
69
+ message: "Choose a preset:",
70
+ options: Object.entries(PRESETS).map(([k, v]) => ({
71
+ value: k,
72
+ label: v.label,
73
+ hint: v.hint,
74
+ })),
75
+ });
76
+ if (p.isCancel(key)) {
77
+ p.cancel("Cancelled.");
78
+ process.exit(0);
79
+ }
80
+ return PRESETS[key].config;
81
+ }
@@ -0,0 +1,2 @@
1
+ import { type ProviderConfig } from "../types.js";
2
+ export declare function setupProviders(): Promise<ProviderConfig[]>;
@@ -0,0 +1,68 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import { PROVIDERS } from "../types.js";
4
+ export async function setupProviders() {
5
+ const entries = Object.entries(PROVIDERS);
6
+ const selected = await p.multiselect({
7
+ message: "Select API providers",
8
+ options: entries.map(([key, info]) => ({
9
+ value: key,
10
+ label: info.label,
11
+ hint: info.env,
12
+ })),
13
+ initialValues: ["anthropic"],
14
+ required: true,
15
+ });
16
+ if (p.isCancel(selected)) {
17
+ p.cancel("Cancelled.");
18
+ process.exit(0);
19
+ }
20
+ const configs = [];
21
+ for (const name of selected) {
22
+ const info = PROVIDERS[name];
23
+ const envVal = process.env[info.env];
24
+ let apiKey;
25
+ if (envVal) {
26
+ const useEnv = await p.confirm({
27
+ message: `Found ${chalk.cyan(info.env)} in environment. Use it?`,
28
+ });
29
+ if (p.isCancel(useEnv)) {
30
+ p.cancel("Cancelled.");
31
+ process.exit(0);
32
+ }
33
+ apiKey = useEnv ? info.env : await promptKey(info);
34
+ }
35
+ else {
36
+ apiKey = await promptKey(info);
37
+ }
38
+ let defaultModel;
39
+ if (info.models.length > 1) {
40
+ const model = await p.select({
41
+ message: `Default model for ${info.label}:`,
42
+ options: info.models.map(m => ({ value: m, label: m })),
43
+ });
44
+ if (p.isCancel(model)) {
45
+ p.cancel("Cancelled.");
46
+ process.exit(0);
47
+ }
48
+ defaultModel = model;
49
+ }
50
+ else {
51
+ defaultModel = info.models[0];
52
+ }
53
+ configs.push({ name, apiKey, defaultModel });
54
+ p.log.success(`${info.label} configured`);
55
+ }
56
+ return configs;
57
+ }
58
+ async function promptKey(info) {
59
+ const key = await p.password({
60
+ message: `API key for ${info.label}:`,
61
+ validate: (v) => (!v || v.trim().length === 0) ? "API key cannot be empty" : undefined,
62
+ });
63
+ if (p.isCancel(key)) {
64
+ p.cancel("Cancelled.");
65
+ process.exit(0);
66
+ }
67
+ return key;
68
+ }
@@ -0,0 +1 @@
1
+ export declare function selectTheme(): Promise<string>;
@@ -0,0 +1,16 @@
1
+ import * as p from "@clack/prompts";
2
+ import { THEMES } from "../types.js";
3
+ export async function selectTheme() {
4
+ const theme = await p.select({
5
+ message: "Choose a theme:",
6
+ options: THEMES.map(t => ({
7
+ value: t.name,
8
+ label: `${t.style === "dark" ? "🌙" : "☀️"} ${t.label}`,
9
+ })),
10
+ });
11
+ if (p.isCancel(theme)) {
12
+ p.cancel("Cancelled.");
13
+ process.exit(0);
14
+ }
15
+ return theme;
16
+ }
@@ -0,0 +1,2 @@
1
+ import type { EnvInfo } from "../utils/detect.js";
2
+ export declare function welcome(env: EnvInfo): void;
@@ -0,0 +1,25 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ export function welcome(env) {
4
+ console.clear();
5
+ p.intro(chalk.cyan.bold(" oh-pi ") + chalk.dim("— one-click setup for pi agent"));
6
+ if (env.piInstalled) {
7
+ p.log.success(`pi ${env.piVersion} detected`);
8
+ }
9
+ else {
10
+ p.log.warn("pi not found — will install");
11
+ }
12
+ p.log.info(`${env.terminal} │ ${env.os} │ Node ${process.version}`);
13
+ if (env.hasExistingConfig) {
14
+ p.note(`${env.existingFiles.length} files (${env.configSizeKB}KB) at ~/.pi/agent/\n` +
15
+ categorize(env.existingFiles), "⚠ Existing config found");
16
+ }
17
+ }
18
+ function categorize(files) {
19
+ const cats = {};
20
+ for (const f of files) {
21
+ const cat = f.includes("/") ? f.split("/")[0] : f;
22
+ cats[cat] = (cats[cat] || 0) + 1;
23
+ }
24
+ return Object.entries(cats).map(([k, v]) => `${k} (${v})`).join(" ");
25
+ }