@oh-my-pi/pi-coding-agent 2.3.1337 → 3.1.1337

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 (117) hide show
  1. package/CHANGELOG.md +72 -34
  2. package/README.md +100 -100
  3. package/docs/compaction.md +8 -8
  4. package/docs/config-usage.md +113 -0
  5. package/docs/custom-tools.md +8 -8
  6. package/docs/extension-loading.md +58 -58
  7. package/docs/hooks.md +11 -11
  8. package/docs/rpc.md +4 -4
  9. package/docs/sdk.md +14 -14
  10. package/docs/session-tree-plan.md +1 -1
  11. package/docs/session.md +2 -2
  12. package/docs/skills.md +16 -16
  13. package/docs/theme.md +9 -9
  14. package/docs/tui.md +1 -1
  15. package/examples/README.md +1 -1
  16. package/examples/custom-tools/README.md +4 -4
  17. package/examples/custom-tools/subagent/README.md +13 -13
  18. package/examples/custom-tools/subagent/agents.ts +2 -2
  19. package/examples/custom-tools/subagent/index.ts +5 -5
  20. package/examples/hooks/README.md +3 -3
  21. package/examples/hooks/auto-commit-on-exit.ts +1 -1
  22. package/examples/hooks/custom-compaction.ts +1 -1
  23. package/examples/sdk/01-minimal.ts +1 -1
  24. package/examples/sdk/04-skills.ts +1 -1
  25. package/examples/sdk/05-tools.ts +1 -1
  26. package/examples/sdk/08-slash-commands.ts +1 -1
  27. package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
  28. package/examples/sdk/README.md +2 -2
  29. package/package.json +13 -11
  30. package/src/capability/context-file.ts +40 -0
  31. package/src/capability/extension.ts +48 -0
  32. package/src/capability/hook.ts +40 -0
  33. package/src/capability/index.ts +616 -0
  34. package/src/capability/instruction.ts +37 -0
  35. package/src/capability/mcp.ts +52 -0
  36. package/src/capability/prompt.ts +35 -0
  37. package/src/capability/rule.ts +52 -0
  38. package/src/capability/settings.ts +35 -0
  39. package/src/capability/skill.ts +49 -0
  40. package/src/capability/slash-command.ts +40 -0
  41. package/src/capability/system-prompt.ts +35 -0
  42. package/src/capability/tool.ts +38 -0
  43. package/src/capability/types.ts +166 -0
  44. package/src/cli/args.ts +2 -2
  45. package/src/cli/plugin-cli.ts +24 -19
  46. package/src/cli/update-cli.ts +10 -10
  47. package/src/config.ts +290 -6
  48. package/src/core/auth-storage.ts +32 -9
  49. package/src/core/bash-executor.ts +1 -1
  50. package/src/core/custom-commands/loader.ts +44 -50
  51. package/src/core/custom-tools/index.ts +1 -0
  52. package/src/core/custom-tools/loader.ts +67 -69
  53. package/src/core/custom-tools/types.ts +10 -1
  54. package/src/core/hooks/loader.ts +13 -42
  55. package/src/core/index.ts +0 -1
  56. package/src/core/logger.ts +7 -7
  57. package/src/core/mcp/client.ts +1 -1
  58. package/src/core/mcp/config.ts +94 -146
  59. package/src/core/mcp/index.ts +0 -4
  60. package/src/core/mcp/loader.ts +26 -22
  61. package/src/core/mcp/manager.ts +18 -23
  62. package/src/core/mcp/tool-bridge.ts +9 -1
  63. package/src/core/mcp/types.ts +2 -0
  64. package/src/core/model-registry.ts +25 -8
  65. package/src/core/plugins/installer.ts +1 -1
  66. package/src/core/plugins/loader.ts +17 -11
  67. package/src/core/plugins/manager.ts +2 -2
  68. package/src/core/plugins/paths.ts +12 -7
  69. package/src/core/plugins/types.ts +3 -3
  70. package/src/core/sdk.ts +48 -27
  71. package/src/core/session-manager.ts +4 -4
  72. package/src/core/settings-manager.ts +45 -21
  73. package/src/core/skills.ts +208 -293
  74. package/src/core/slash-commands.ts +34 -165
  75. package/src/core/system-prompt.ts +58 -65
  76. package/src/core/timings.ts +2 -2
  77. package/src/core/tools/lsp/config.ts +38 -17
  78. package/src/core/tools/task/agents.ts +21 -0
  79. package/src/core/tools/task/artifacts.ts +1 -1
  80. package/src/core/tools/task/bundled-agents/reviewer.md +2 -1
  81. package/src/core/tools/task/bundled-agents/task.md +1 -0
  82. package/src/core/tools/task/commands.ts +30 -107
  83. package/src/core/tools/task/discovery.ts +75 -66
  84. package/src/core/tools/task/executor.ts +25 -10
  85. package/src/core/tools/task/index.ts +35 -10
  86. package/src/core/tools/task/model-resolver.ts +27 -25
  87. package/src/core/tools/task/types.ts +6 -2
  88. package/src/core/tools/web-fetch.ts +3 -3
  89. package/src/core/tools/web-search/auth.ts +40 -34
  90. package/src/core/tools/web-search/index.ts +1 -1
  91. package/src/core/tools/web-search/providers/anthropic.ts +1 -1
  92. package/src/discovery/agents-md.ts +75 -0
  93. package/src/discovery/builtin.ts +646 -0
  94. package/src/discovery/claude.ts +623 -0
  95. package/src/discovery/cline.ts +102 -0
  96. package/src/discovery/codex.ts +571 -0
  97. package/src/discovery/cursor.ts +264 -0
  98. package/src/discovery/gemini.ts +368 -0
  99. package/src/discovery/github.ts +120 -0
  100. package/src/discovery/helpers.test.ts +127 -0
  101. package/src/discovery/helpers.ts +249 -0
  102. package/src/discovery/index.ts +84 -0
  103. package/src/discovery/mcp-json.ts +127 -0
  104. package/src/discovery/vscode.ts +99 -0
  105. package/src/discovery/windsurf.ts +216 -0
  106. package/src/main.ts +14 -13
  107. package/src/migrations.ts +24 -3
  108. package/src/modes/interactive/components/hook-editor.ts +1 -1
  109. package/src/modes/interactive/components/plugin-settings.ts +1 -1
  110. package/src/modes/interactive/components/settings-defs.ts +38 -2
  111. package/src/modes/interactive/components/settings-selector.ts +1 -0
  112. package/src/modes/interactive/components/welcome.ts +2 -2
  113. package/src/modes/interactive/interactive-mode.ts +233 -16
  114. package/src/modes/interactive/theme/theme-schema.json +1 -1
  115. package/src/utils/clipboard.ts +1 -1
  116. package/src/utils/shell-snapshot.ts +2 -2
  117. package/src/utils/shell.ts +7 -7
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Prompts Capability
3
+ *
4
+ * Reusable prompt templates (Codex format) available via /prompts: menu.
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * A reusable prompt template.
12
+ */
13
+ export interface Prompt {
14
+ /** Prompt name (filename without extension) */
15
+ name: string;
16
+ /** Absolute path to prompt file */
17
+ path: string;
18
+ /** Prompt content (markdown) */
19
+ content: string;
20
+ /** Source metadata */
21
+ _source: SourceMeta;
22
+ }
23
+
24
+ export const promptCapability = defineCapability<Prompt>({
25
+ id: "prompts",
26
+ displayName: "Prompts",
27
+ description: "Reusable prompt templates available via /prompts: menu",
28
+ key: (prompt) => prompt.name,
29
+ validate: (prompt) => {
30
+ if (!prompt.name) return "Missing name";
31
+ if (!prompt.path) return "Missing path";
32
+ if (prompt.content === undefined) return "Missing content";
33
+ return undefined;
34
+ },
35
+ });
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Rules Capability
3
+ *
4
+ * Project-specific rules from Cursor (.mdc), Windsurf (.md), and Cline formats.
5
+ * Translated to a canonical shape regardless of source format.
6
+ */
7
+
8
+ import { defineCapability } from "./index";
9
+ import type { SourceMeta } from "./types";
10
+
11
+ /**
12
+ * Parsed frontmatter from MDC rule files (Cursor format).
13
+ */
14
+ export interface RuleFrontmatter {
15
+ description?: string;
16
+ globs?: string[];
17
+ alwaysApply?: boolean;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ /**
22
+ * A rule providing project-specific guidance and constraints.
23
+ */
24
+ export interface Rule {
25
+ /** Rule name (derived from filename) */
26
+ name: string;
27
+ /** Absolute path to rule file */
28
+ path: string;
29
+ /** Rule content (after frontmatter stripped) */
30
+ content: string;
31
+ /** Globs this rule applies to (if any) */
32
+ globs?: string[];
33
+ /** Whether to always include this rule */
34
+ alwaysApply?: boolean;
35
+ /** Description (for agent-requested rules) */
36
+ description?: string;
37
+ /** Source metadata */
38
+ _source: SourceMeta;
39
+ }
40
+
41
+ export const ruleCapability = defineCapability<Rule>({
42
+ id: "rules",
43
+ displayName: "Rules",
44
+ description: "Project-specific rules and constraints (Cursor MDC, Windsurf, Cline formats)",
45
+ key: (rule) => rule.name,
46
+ validate: (rule) => {
47
+ if (!rule.name) return "Missing rule name";
48
+ if (!rule.path) return "Missing rule path";
49
+ if (!rule.content || typeof rule.content !== "string") return "Rule must have content";
50
+ return undefined;
51
+ },
52
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Settings Capability
3
+ *
4
+ * Configuration settings from various sources (JSON, TOML, etc.)
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * A settings file.
12
+ */
13
+ export interface Settings {
14
+ /** Absolute path to settings file */
15
+ path: string;
16
+ /** Parsed settings data */
17
+ data: Record<string, unknown>;
18
+ /** Source level */
19
+ level: "user" | "project";
20
+ /** Source metadata */
21
+ _source: SourceMeta;
22
+ }
23
+
24
+ export const settingsCapability = defineCapability<Settings>({
25
+ id: "settings",
26
+ displayName: "Settings",
27
+ description: "Configuration settings from various sources",
28
+ // Settings are merged, not deduplicated by key
29
+ key: () => undefined,
30
+ validate: (settings) => {
31
+ if (!settings.path) return "Missing path";
32
+ if (!settings.data || typeof settings.data !== "object") return "Missing or invalid data";
33
+ return undefined;
34
+ },
35
+ });
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Skills Capability
3
+ *
4
+ * Skills provide specialized knowledge or workflows that extend agent capabilities.
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * Parsed frontmatter from a skill file.
12
+ */
13
+ export interface SkillFrontmatter {
14
+ name?: string;
15
+ description?: string;
16
+ globs?: string[];
17
+ alwaysApply?: boolean;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ /**
22
+ * A skill that provides specialized knowledge or workflows.
23
+ */
24
+ export interface Skill {
25
+ /** Skill name (unique key, derived from filename or frontmatter) */
26
+ name: string;
27
+ /** Absolute path to skill file */
28
+ path: string;
29
+ /** Skill content (markdown) */
30
+ content: string;
31
+ /** Parsed frontmatter */
32
+ frontmatter?: SkillFrontmatter;
33
+ /** Source level */
34
+ level: "user" | "project";
35
+ /** Source metadata */
36
+ _source: SourceMeta;
37
+ }
38
+
39
+ export const skillCapability = defineCapability<Skill>({
40
+ id: "skills",
41
+ displayName: "Skills",
42
+ description: "Specialized knowledge and workflow files that extend agent capabilities",
43
+ key: (skill) => skill.name,
44
+ validate: (skill) => {
45
+ if (!skill.name) return "Missing skill name";
46
+ if (!skill.path) return "Missing skill path";
47
+ return undefined;
48
+ },
49
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Slash Commands Capability
3
+ *
4
+ * File-based slash commands defined as markdown files.
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * A file-based slash command.
12
+ */
13
+ export interface SlashCommand {
14
+ /** Command name (without leading slash) */
15
+ name: string;
16
+ /** Absolute path to command file */
17
+ path: string;
18
+ /** Command content (markdown template) */
19
+ content: string;
20
+ /** Source level */
21
+ level: "user" | "project" | "native";
22
+ /** Source metadata */
23
+ _source: SourceMeta;
24
+ }
25
+
26
+ export const slashCommandCapability = defineCapability<SlashCommand>({
27
+ id: "slash-commands",
28
+ displayName: "Slash Commands",
29
+ description: "Custom slash commands defined as markdown files",
30
+ key: (cmd) => cmd.name,
31
+ validate: (cmd) => {
32
+ if (!cmd.name) return "Missing name";
33
+ if (!cmd.path) return "Missing path";
34
+ if (cmd.content === undefined) return "Missing content";
35
+ if (cmd.level !== "user" && cmd.level !== "project" && cmd.level !== "native") {
36
+ return "Invalid level: must be 'user', 'project', or 'native'";
37
+ }
38
+ return undefined;
39
+ },
40
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * System Prompt Capability
3
+ *
4
+ * Custom system prompt files (SYSTEM.md) that modify the agent's base system prompt.
5
+ * Distinct from context-files which are user instructions shown in conversation.
6
+ */
7
+
8
+ import { defineCapability } from "./index";
9
+ import type { SourceMeta } from "./types";
10
+
11
+ /**
12
+ * A system prompt customization file.
13
+ */
14
+ export interface SystemPrompt {
15
+ /** Absolute path to the file */
16
+ path: string;
17
+ /** File content */
18
+ content: string;
19
+ /** Which level this came from */
20
+ level: "user" | "project";
21
+ /** Source metadata */
22
+ _source: SourceMeta;
23
+ }
24
+
25
+ export const systemPromptCapability = defineCapability<SystemPrompt>({
26
+ id: "system-prompt",
27
+ displayName: "System Prompt",
28
+ description: "Custom system prompt files (SYSTEM.md) that modify agent behavior",
29
+ key: (sp) => sp.level,
30
+ validate: (sp) => {
31
+ if (!sp.path) return "Missing path";
32
+ if (sp.content === undefined) return "Missing content";
33
+ return undefined;
34
+ },
35
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Custom Tools Capability
3
+ *
4
+ * User-defined tools that extend agent capabilities.
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * A custom tool definition.
12
+ */
13
+ export interface CustomTool {
14
+ /** Tool name (unique key) */
15
+ name: string;
16
+ /** Absolute path to tool definition file */
17
+ path: string;
18
+ /** Tool description */
19
+ description?: string;
20
+ /** Tool implementation (script path or inline) */
21
+ implementation?: string;
22
+ /** Source level */
23
+ level: "user" | "project";
24
+ /** Source metadata */
25
+ _source: SourceMeta;
26
+ }
27
+
28
+ export const toolCapability = defineCapability<CustomTool>({
29
+ id: "tools",
30
+ displayName: "Custom Tools",
31
+ description: "User-defined tools that extend agent capabilities",
32
+ key: (tool) => tool.name,
33
+ validate: (tool) => {
34
+ if (!tool.name) return "Missing name";
35
+ if (!tool.path) return "Missing path";
36
+ return undefined;
37
+ },
38
+ });
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Core types for the capability-based config discovery system.
3
+ *
4
+ * This architecture inverts control: instead of callers knowing about paths like
5
+ * `.claude`, `.codex`, `.gemini`, they simply ask for `load("mcps")` and get back
6
+ * a unified array of MCP servers.
7
+ */
8
+
9
+ /**
10
+ * Context passed to every provider loader.
11
+ */
12
+ export interface LoadContext {
13
+ /** Current working directory (project root) */
14
+ cwd: string;
15
+ /** User home directory */
16
+ home: string;
17
+ /** Filesystem helpers (cached) */
18
+ fs: {
19
+ exists(path: string): boolean;
20
+ isDir(path: string): boolean;
21
+ isFile(path: string): boolean;
22
+ readFile(path: string): string | null;
23
+ readDir(path: string): string[];
24
+ /** Walk up from cwd looking for a file/dir, returns first match */
25
+ walkUp(name: string, opts?: { file?: boolean; dir?: boolean }): string | null;
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Result from a provider's load function.
31
+ */
32
+ export interface LoadResult<T> {
33
+ items: T[];
34
+ /** Warnings encountered during loading (parse errors, etc.) */
35
+ warnings?: string[];
36
+ }
37
+
38
+ /**
39
+ * A provider that can load items for a capability.
40
+ */
41
+ export interface Provider<T> {
42
+ /** Unique provider ID (e.g., "claude", "omp", "mcp-json", "agents-md") */
43
+ id: string;
44
+
45
+ /** Human-readable name for UI display (e.g., "Claude Code", "OpenAI Codex") */
46
+ displayName: string;
47
+
48
+ /** Short description for settings UI (e.g., "Load config from ~/.claude and .claude/") */
49
+ description: string;
50
+
51
+ /**
52
+ * Priority (higher = checked first, wins on conflicts).
53
+ * Suggested ranges:
54
+ * 100+ : Primary providers (omp, pi)
55
+ * 50-99: Tool-specific providers (claude, codex, gemini)
56
+ * 1-49 : Shared standards (mcp-json, agents-md)
57
+ */
58
+ priority: number;
59
+
60
+ /**
61
+ * Load items for this capability.
62
+ * Returns items in provider's preferred order (usually project before user).
63
+ */
64
+ load(ctx: LoadContext): LoadResult<T> | Promise<LoadResult<T>>;
65
+ }
66
+
67
+ /**
68
+ * Options for loading a capability.
69
+ */
70
+ export interface LoadOptions {
71
+ /** Only use these providers (by ID). Default: all registered */
72
+ providers?: string[];
73
+ /** Exclude these providers (by ID). Default: none */
74
+ excludeProviders?: string[];
75
+ /** Custom cwd. Default: process.cwd() */
76
+ cwd?: string;
77
+ /** Include items even if they fail validation. Default: false */
78
+ includeInvalid?: boolean;
79
+ }
80
+
81
+ /**
82
+ * Source metadata attached to every loaded item.
83
+ */
84
+ export interface SourceMeta {
85
+ /** Provider ID that loaded this item */
86
+ provider: string;
87
+ /** Provider display name (for UI) */
88
+ providerName: string;
89
+ /** Absolute path to the source file */
90
+ path: string;
91
+ /** Whether this came from user-level, project-level, or native config */
92
+ level: "user" | "project" | "native";
93
+ }
94
+
95
+ /**
96
+ * Merged result from loading a capability across all providers.
97
+ */
98
+ export interface CapabilityResult<T> {
99
+ /** Deduplicated items in priority order */
100
+ items: Array<T & { _source: SourceMeta }>;
101
+ /** All items including shadowed duplicates (for diagnostics) */
102
+ all: Array<T & { _source: SourceMeta; _shadowed?: boolean }>;
103
+ /** Warnings from all providers */
104
+ warnings: string[];
105
+ /** Which providers contributed items (IDs) */
106
+ providers: string[];
107
+ }
108
+
109
+ /**
110
+ * Definition of a capability.
111
+ */
112
+ export interface Capability<T> {
113
+ /** Capability ID (e.g., "mcps", "skills", "context-files") */
114
+ id: string;
115
+
116
+ /** Human-readable name for UI display (e.g., "MCP Servers", "Skills") */
117
+ displayName: string;
118
+
119
+ /** Short description for settings/status UI */
120
+ description: string;
121
+
122
+ /**
123
+ * Extract a unique key from an item for deduplication.
124
+ * Items with the same key: first one wins (highest priority provider).
125
+ * Return undefined to never deduplicate (all items kept).
126
+ */
127
+ key(item: T): string | undefined;
128
+
129
+ /**
130
+ * Optional validation. Return error message if invalid, undefined if valid.
131
+ */
132
+ validate?(item: T): string | undefined;
133
+
134
+ /** Registered providers, sorted by priority (highest first) */
135
+ providers: Provider<T>[];
136
+ }
137
+
138
+ /**
139
+ * Metadata about a capability (for introspection/UI).
140
+ */
141
+ export interface CapabilityInfo {
142
+ id: string;
143
+ displayName: string;
144
+ description: string;
145
+ providers: Array<{
146
+ id: string;
147
+ displayName: string;
148
+ description: string;
149
+ priority: number;
150
+ enabled: boolean;
151
+ }>;
152
+ }
153
+
154
+ /**
155
+ * Metadata about a provider (for introspection/UI).
156
+ */
157
+ export interface ProviderInfo {
158
+ id: string;
159
+ displayName: string;
160
+ description: string;
161
+ priority: number;
162
+ /** Which capabilities this provider is registered for */
163
+ capabilities: string[];
164
+ /** Whether this provider is currently enabled */
165
+ enabled: boolean;
166
+ }
package/src/cli/args.ts CHANGED
@@ -153,8 +153,8 @@ ${chalk.bold("Usage:")}
153
153
 
154
154
  ${chalk.bold("Options:")}
155
155
  --model <pattern> Model to use (fuzzy match: "opus", "gpt-5.2", or "p-openai/gpt-5.2")
156
- --smol <id> Smol/fast model for lightweight tasks (or PI_SMOL_MODEL env)
157
- --slow <id> Slow/reasoning model for thorough analysis (or PI_SLOW_MODEL env)
156
+ --smol <id> Smol/fast model for lightweight tasks (or OMP_SMOL_MODEL env)
157
+ --slow <id> Slow/reasoning model for thorough analysis (or OMP_SLOW_MODEL env)
158
158
  --api-key <key> API key (defaults to env vars)
159
159
  --system-prompt <text> System prompt (default: coding assistant prompt)
160
160
  --append-system-prompt <text> Append text or file contents to the system prompt
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Plugin CLI command handlers.
3
3
  *
4
- * Handles `pi plugin <command>` subcommands for plugin lifecycle management.
4
+ * Handles `omp plugin <command>` subcommands for plugin lifecycle management.
5
5
  */
6
6
 
7
7
  import chalk from "chalk";
8
+ import { APP_NAME } from "../config";
8
9
  import { PluginManager, parseSettingValue, validateSetting } from "../core/plugins/index";
9
10
 
10
11
  // =============================================================================
@@ -153,12 +154,12 @@ async function handleInstall(
153
154
  flags: { json?: boolean; force?: boolean; dryRun?: boolean },
154
155
  ): Promise<void> {
155
156
  if (packages.length === 0) {
156
- console.error(chalk.red("Usage: pi plugin install <package[@version]>[features] ..."));
157
+ console.error(chalk.red(`Usage: ${APP_NAME} plugin install <package[@version]>[features] ...`));
157
158
  console.error(chalk.dim("Examples:"));
158
- console.error(chalk.dim(" pi plugin install @oh-my-pi/exa"));
159
- console.error(chalk.dim(" pi plugin install @oh-my-pi/exa[search,websets]"));
160
- console.error(chalk.dim(" pi plugin install @oh-my-pi/exa[*] # all features"));
161
- console.error(chalk.dim(" pi plugin install @oh-my-pi/exa[] # no optional features"));
159
+ console.error(chalk.dim(` ${APP_NAME} plugin install @oh-my-pi/exa`));
160
+ console.error(chalk.dim(` ${APP_NAME} plugin install @oh-my-pi/exa[search,websets]`));
161
+ console.error(chalk.dim(` ${APP_NAME} plugin install @oh-my-pi/exa[*] # all features`));
162
+ console.error(chalk.dim(` ${APP_NAME} plugin install @oh-my-pi/exa[] # no optional features`));
162
163
  process.exit(1);
163
164
  }
164
165
 
@@ -190,7 +191,7 @@ async function handleInstall(
190
191
 
191
192
  async function handleUninstall(manager: PluginManager, packages: string[], flags: { json?: boolean }): Promise<void> {
192
193
  if (packages.length === 0) {
193
- console.error(chalk.red("Usage: pi plugin uninstall <package> ..."));
194
+ console.error(chalk.red(`Usage: ${APP_NAME} plugin uninstall <package> ...`));
194
195
  process.exit(1);
195
196
  }
196
197
 
@@ -220,7 +221,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
220
221
 
221
222
  if (plugins.length === 0) {
222
223
  console.log(chalk.dim("No plugins installed"));
223
- console.log(chalk.dim("\nInstall plugins with: pi plugin install <package>"));
224
+ console.log(chalk.dim(`\nInstall plugins with: ${APP_NAME} plugin install <package>`));
224
225
  return;
225
226
  }
226
227
 
@@ -254,7 +255,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
254
255
 
255
256
  async function handleLink(manager: PluginManager, paths: string[], flags: { json?: boolean }): Promise<void> {
256
257
  if (paths.length === 0) {
257
- console.error(chalk.red("Usage: pi plugin link <path>"));
258
+ console.error(chalk.red(`Usage: ${APP_NAME} plugin link <path>`));
258
259
  process.exit(1);
259
260
  }
260
261
 
@@ -313,7 +314,9 @@ async function handleFeatures(
313
314
  flags: { json?: boolean; enable?: string; disable?: string; set?: string },
314
315
  ): Promise<void> {
315
316
  if (args.length === 0) {
316
- console.error(chalk.red("Usage: pi plugin features <plugin> [--enable f1,f2] [--disable f1] [--set f1,f2]"));
317
+ console.error(
318
+ chalk.red(`Usage: ${APP_NAME} plugin features <plugin> [--enable f1,f2] [--disable f1] [--set f1,f2]`),
319
+ );
317
320
  process.exit(1);
318
321
  }
319
322
 
@@ -404,7 +407,9 @@ async function handleConfig(
404
407
  flags: { json?: boolean; local?: boolean },
405
408
  ): Promise<void> {
406
409
  if (args.length === 0) {
407
- console.error(chalk.red("Usage: pi plugin config <list|get|set|delete|validate> <plugin> [key] [value]"));
410
+ console.error(
411
+ chalk.red(`Usage: ${APP_NAME} plugin config <list|get|set|delete|validate> <plugin> [key] [value]`),
412
+ );
408
413
  process.exit(1);
409
414
  }
410
415
 
@@ -560,7 +565,7 @@ async function handleConfigValidate(manager: PluginManager, flags: { json?: bool
560
565
 
561
566
  async function handleEnable(manager: PluginManager, plugins: string[], flags: { json?: boolean }): Promise<void> {
562
567
  if (plugins.length === 0) {
563
- console.error(chalk.red("Usage: pi plugin enable <plugin> ..."));
568
+ console.error(chalk.red(`Usage: ${APP_NAME} plugin enable <plugin> ...`));
564
569
  process.exit(1);
565
570
  }
566
571
 
@@ -582,7 +587,7 @@ async function handleEnable(manager: PluginManager, plugins: string[], flags: {
582
587
 
583
588
  async function handleDisable(manager: PluginManager, plugins: string[], flags: { json?: boolean }): Promise<void> {
584
589
  if (plugins.length === 0) {
585
- console.error(chalk.red("Usage: pi plugin disable <plugin> ..."));
590
+ console.error(chalk.red(`Usage: ${APP_NAME} plugin disable <plugin> ...`));
586
591
  process.exit(1);
587
592
  }
588
593
 
@@ -607,7 +612,7 @@ async function handleDisable(manager: PluginManager, plugins: string[], flags: {
607
612
  // =============================================================================
608
613
 
609
614
  export function printPluginHelp(): void {
610
- console.log(`${chalk.bold("pi plugin")} - Plugin lifecycle management
615
+ console.log(`${chalk.bold(`${APP_NAME} plugin`)} - Plugin lifecycle management
611
616
 
612
617
  ${chalk.bold("Commands:")}
613
618
  install <pkg[@ver]>[features] Install plugins from npm
@@ -641,10 +646,10 @@ ${chalk.bold("Options:")}
641
646
  -l, --local Use project-local overrides
642
647
 
643
648
  ${chalk.bold("Examples:")}
644
- pi plugin install @oh-my-pi/exa[search]
645
- pi plugin list --json
646
- pi plugin features my-plugin --enable search,web
647
- pi plugin config set my-plugin apiKey sk-xxx
648
- pi plugin doctor --fix
649
+ ${APP_NAME} plugin install @oh-my-pi/exa[search]
650
+ ${APP_NAME} plugin list --json
651
+ ${APP_NAME} plugin features my-plugin --enable search,web
652
+ ${APP_NAME} plugin config set my-plugin apiKey sk-xxx
653
+ ${APP_NAME} plugin doctor --fix
649
654
  `);
650
655
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Update CLI command handler.
3
3
  *
4
- * Handles `pi update` to check for and install updates.
4
+ * Handles `omp update` to check for and install updates.
5
5
  * Uses bun if available, otherwise downloads binary from GitHub releases.
6
6
  */
7
7
 
@@ -11,7 +11,7 @@ import { dirname } from "node:path";
11
11
  import { Readable } from "node:stream";
12
12
  import { pipeline } from "node:stream/promises";
13
13
  import chalk from "chalk";
14
- import { VERSION } from "../config";
14
+ import { APP_NAME, VERSION } from "../config";
15
15
 
16
16
  /**
17
17
  * Detect if we're running as a Bun compiled binary.
@@ -129,9 +129,9 @@ function getBinaryName(): string {
129
129
  }
130
130
 
131
131
  if (os === "windows") {
132
- return `pi-${os}-${archName}.exe`;
132
+ return `${APP_NAME}-${os}-${archName}.exe`;
133
133
  }
134
- return `pi-${os}-${archName}`;
134
+ return `${APP_NAME}-${os}-${archName}`;
135
135
  }
136
136
 
137
137
  /**
@@ -193,7 +193,7 @@ async function updateViaBinary(release: ReleaseInfo): Promise<void> {
193
193
  unlinkSync(backupPath);
194
194
 
195
195
  console.log(chalk.green(`\n✓ Updated to ${release.version}`));
196
- console.log(chalk.dim("Restart pi to use the new version"));
196
+ console.log(chalk.dim(`Restart ${APP_NAME} to use the new version`));
197
197
  } catch (err) {
198
198
  // Restore from backup if possible
199
199
  if (existsSync(backupPath) && !existsSync(execPath)) {
@@ -256,18 +256,18 @@ export async function runUpdateCommand(opts: { force: boolean; check: boolean })
256
256
  * Print update command help.
257
257
  */
258
258
  export function printUpdateHelp(): void {
259
- console.log(`${chalk.bold("pi update")} - Check for and install updates
259
+ console.log(`${chalk.bold(`${APP_NAME} update`)} - Check for and install updates
260
260
 
261
261
  ${chalk.bold("Usage:")}
262
- pi update [options]
262
+ ${APP_NAME} update [options]
263
263
 
264
264
  ${chalk.bold("Options:")}
265
265
  -c, --check Check for updates without installing
266
266
  -f, --force Force reinstall even if up to date
267
267
 
268
268
  ${chalk.bold("Examples:")}
269
- pi update Update to latest version
270
- pi update --check Check if updates are available
271
- pi update --force Force reinstall
269
+ ${APP_NAME} update Update to latest version
270
+ ${APP_NAME} update --check Check if updates are available
271
+ ${APP_NAME} update --force Force reinstall
272
272
  `);
273
273
  }