@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.
- package/CHANGELOG.md +72 -34
- package/README.md +100 -100
- package/docs/compaction.md +8 -8
- package/docs/config-usage.md +113 -0
- package/docs/custom-tools.md +8 -8
- package/docs/extension-loading.md +58 -58
- package/docs/hooks.md +11 -11
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +14 -14
- package/docs/session-tree-plan.md +1 -1
- package/docs/session.md +2 -2
- package/docs/skills.md +16 -16
- package/docs/theme.md +9 -9
- package/docs/tui.md +1 -1
- package/examples/README.md +1 -1
- package/examples/custom-tools/README.md +4 -4
- package/examples/custom-tools/subagent/README.md +13 -13
- package/examples/custom-tools/subagent/agents.ts +2 -2
- package/examples/custom-tools/subagent/index.ts +5 -5
- package/examples/hooks/README.md +3 -3
- package/examples/hooks/auto-commit-on-exit.ts +1 -1
- package/examples/hooks/custom-compaction.ts +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/05-tools.ts +1 -1
- package/examples/sdk/08-slash-commands.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/README.md +2 -2
- package/package.json +13 -11
- package/src/capability/context-file.ts +40 -0
- package/src/capability/extension.ts +48 -0
- package/src/capability/hook.ts +40 -0
- package/src/capability/index.ts +616 -0
- package/src/capability/instruction.ts +37 -0
- package/src/capability/mcp.ts +52 -0
- package/src/capability/prompt.ts +35 -0
- package/src/capability/rule.ts +52 -0
- package/src/capability/settings.ts +35 -0
- package/src/capability/skill.ts +49 -0
- package/src/capability/slash-command.ts +40 -0
- package/src/capability/system-prompt.ts +35 -0
- package/src/capability/tool.ts +38 -0
- package/src/capability/types.ts +166 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/plugin-cli.ts +24 -19
- package/src/cli/update-cli.ts +10 -10
- package/src/config.ts +290 -6
- package/src/core/auth-storage.ts +32 -9
- package/src/core/bash-executor.ts +1 -1
- package/src/core/custom-commands/loader.ts +44 -50
- package/src/core/custom-tools/index.ts +1 -0
- package/src/core/custom-tools/loader.ts +67 -69
- package/src/core/custom-tools/types.ts +10 -1
- package/src/core/hooks/loader.ts +13 -42
- package/src/core/index.ts +0 -1
- package/src/core/logger.ts +7 -7
- package/src/core/mcp/client.ts +1 -1
- package/src/core/mcp/config.ts +94 -146
- package/src/core/mcp/index.ts +0 -4
- package/src/core/mcp/loader.ts +26 -22
- package/src/core/mcp/manager.ts +18 -23
- package/src/core/mcp/tool-bridge.ts +9 -1
- package/src/core/mcp/types.ts +2 -0
- package/src/core/model-registry.ts +25 -8
- package/src/core/plugins/installer.ts +1 -1
- package/src/core/plugins/loader.ts +17 -11
- package/src/core/plugins/manager.ts +2 -2
- package/src/core/plugins/paths.ts +12 -7
- package/src/core/plugins/types.ts +3 -3
- package/src/core/sdk.ts +48 -27
- package/src/core/session-manager.ts +4 -4
- package/src/core/settings-manager.ts +45 -21
- package/src/core/skills.ts +208 -293
- package/src/core/slash-commands.ts +34 -165
- package/src/core/system-prompt.ts +58 -65
- package/src/core/timings.ts +2 -2
- package/src/core/tools/lsp/config.ts +38 -17
- package/src/core/tools/task/agents.ts +21 -0
- package/src/core/tools/task/artifacts.ts +1 -1
- package/src/core/tools/task/bundled-agents/reviewer.md +2 -1
- package/src/core/tools/task/bundled-agents/task.md +1 -0
- package/src/core/tools/task/commands.ts +30 -107
- package/src/core/tools/task/discovery.ts +75 -66
- package/src/core/tools/task/executor.ts +25 -10
- package/src/core/tools/task/index.ts +35 -10
- package/src/core/tools/task/model-resolver.ts +27 -25
- package/src/core/tools/task/types.ts +6 -2
- package/src/core/tools/web-fetch.ts +3 -3
- package/src/core/tools/web-search/auth.ts +40 -34
- package/src/core/tools/web-search/index.ts +1 -1
- package/src/core/tools/web-search/providers/anthropic.ts +1 -1
- package/src/discovery/agents-md.ts +75 -0
- package/src/discovery/builtin.ts +646 -0
- package/src/discovery/claude.ts +623 -0
- package/src/discovery/cline.ts +102 -0
- package/src/discovery/codex.ts +571 -0
- package/src/discovery/cursor.ts +264 -0
- package/src/discovery/gemini.ts +368 -0
- package/src/discovery/github.ts +120 -0
- package/src/discovery/helpers.test.ts +127 -0
- package/src/discovery/helpers.ts +249 -0
- package/src/discovery/index.ts +84 -0
- package/src/discovery/mcp-json.ts +127 -0
- package/src/discovery/vscode.ts +99 -0
- package/src/discovery/windsurf.ts +216 -0
- package/src/main.ts +14 -13
- package/src/migrations.ts +24 -3
- package/src/modes/interactive/components/hook-editor.ts +1 -1
- package/src/modes/interactive/components/plugin-settings.ts +1 -1
- package/src/modes/interactive/components/settings-defs.ts +38 -2
- package/src/modes/interactive/components/settings-selector.ts +1 -0
- package/src/modes/interactive/components/welcome.ts +2 -2
- package/src/modes/interactive/interactive-mode.ts +233 -16
- package/src/modes/interactive/theme/theme-schema.json +1 -1
- package/src/utils/clipboard.ts +1 -1
- package/src/utils/shell-snapshot.ts +2 -2
- package/src/utils/shell.ts +7 -7
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VS Code Provider
|
|
3
|
+
*
|
|
4
|
+
* Loads config from `.vscode` directory (project-only).
|
|
5
|
+
* Supports MCP server discovery from `mcp.json` with nested `mcp.servers` structure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { registerProvider } from "../capability/index";
|
|
9
|
+
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
10
|
+
import type { LoadContext, LoadResult } from "../capability/types";
|
|
11
|
+
import { createSourceMeta, expandEnvVarsDeep, getProjectPath, parseJSON } from "./helpers";
|
|
12
|
+
|
|
13
|
+
const PROVIDER_ID = "vscode";
|
|
14
|
+
const DISPLAY_NAME = "VS Code";
|
|
15
|
+
const PRIORITY = 20;
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// MCP Servers
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
registerProvider<MCPServer>(mcpCapability.id, {
|
|
22
|
+
id: PROVIDER_ID,
|
|
23
|
+
displayName: DISPLAY_NAME,
|
|
24
|
+
description: "Load MCP servers from .vscode/mcp.json",
|
|
25
|
+
priority: PRIORITY,
|
|
26
|
+
load(ctx: LoadContext): LoadResult<MCPServer> {
|
|
27
|
+
const items: MCPServer[] = [];
|
|
28
|
+
const warnings: string[] = [];
|
|
29
|
+
|
|
30
|
+
// Project-only (VS Code doesn't support user-level MCP config)
|
|
31
|
+
const projectPath = getProjectPath(ctx, "vscode", "mcp.json");
|
|
32
|
+
if (projectPath && ctx.fs.isFile(projectPath)) {
|
|
33
|
+
const result = loadMCPConfig(ctx, projectPath, "project");
|
|
34
|
+
items.push(...result.items);
|
|
35
|
+
if (result.warnings) warnings.push(...result.warnings);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { items, warnings };
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Load MCP servers from a mcp.json file.
|
|
44
|
+
* VS Code uses nested structure: { "mcp": { "servers": { ... } } }
|
|
45
|
+
*/
|
|
46
|
+
function loadMCPConfig(ctx: LoadContext, path: string, level: "user" | "project"): LoadResult<MCPServer> {
|
|
47
|
+
const items: MCPServer[] = [];
|
|
48
|
+
const warnings: string[] = [];
|
|
49
|
+
|
|
50
|
+
const content = ctx.fs.readFile(path);
|
|
51
|
+
if (!content) {
|
|
52
|
+
warnings.push(`Failed to read ${path}`);
|
|
53
|
+
return { items, warnings };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parsed = parseJSON<{ mcp?: { servers?: Record<string, unknown> } }>(content);
|
|
57
|
+
if (!parsed) {
|
|
58
|
+
warnings.push(`Invalid JSON in ${path}`);
|
|
59
|
+
return { items, warnings };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// VS Code uses nested structure: mcp.servers
|
|
63
|
+
const servers = parsed.mcp?.servers;
|
|
64
|
+
if (!servers || typeof servers !== "object") {
|
|
65
|
+
return { items, warnings };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
69
|
+
if (!config || typeof config !== "object") {
|
|
70
|
+
warnings.push(`Invalid config for server "${name}" in ${path}`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const raw = config as Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
// Expand environment variables
|
|
77
|
+
const expanded = expandEnvVarsDeep(raw);
|
|
78
|
+
|
|
79
|
+
const server: MCPServer = {
|
|
80
|
+
name,
|
|
81
|
+
command: typeof expanded.command === "string" ? expanded.command : undefined,
|
|
82
|
+
args: Array.isArray(expanded.args) ? (expanded.args as string[]) : undefined,
|
|
83
|
+
env: expanded.env && typeof expanded.env === "object" ? (expanded.env as Record<string, string>) : undefined,
|
|
84
|
+
url: typeof expanded.url === "string" ? expanded.url : undefined,
|
|
85
|
+
headers:
|
|
86
|
+
expanded.headers && typeof expanded.headers === "object"
|
|
87
|
+
? (expanded.headers as Record<string, string>)
|
|
88
|
+
: undefined,
|
|
89
|
+
transport: ["stdio", "sse", "http"].includes(expanded.transport as string)
|
|
90
|
+
? (expanded.transport as "stdio" | "sse" | "http")
|
|
91
|
+
: undefined,
|
|
92
|
+
_source: createSourceMeta(PROVIDER_ID, path, level),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
items.push(server);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { items, warnings };
|
|
99
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf (Codeium) Provider
|
|
3
|
+
*
|
|
4
|
+
* Loads configuration from Windsurf's config locations:
|
|
5
|
+
* - User: ~/.codeium/windsurf
|
|
6
|
+
* - Project: .windsurf
|
|
7
|
+
*
|
|
8
|
+
* Supports:
|
|
9
|
+
* - MCP servers from mcp_config.json
|
|
10
|
+
* - Rules from .windsurf/rules/*.md and ~/.codeium/windsurf/memories/global_rules.md
|
|
11
|
+
* - Legacy .windsurfrules file
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { registerProvider } from "../capability/index";
|
|
15
|
+
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
16
|
+
import { type Rule, ruleCapability } from "../capability/rule";
|
|
17
|
+
import type { LoadContext, LoadResult } from "../capability/types";
|
|
18
|
+
import {
|
|
19
|
+
createSourceMeta,
|
|
20
|
+
expandEnvVarsDeep,
|
|
21
|
+
getProjectPath,
|
|
22
|
+
getUserPath,
|
|
23
|
+
loadFilesFromDir,
|
|
24
|
+
parseFrontmatter,
|
|
25
|
+
parseJSON,
|
|
26
|
+
} from "./helpers";
|
|
27
|
+
|
|
28
|
+
const PROVIDER_ID = "windsurf";
|
|
29
|
+
const DISPLAY_NAME = "Windsurf";
|
|
30
|
+
const PRIORITY = 50;
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// MCP Servers
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
function loadMCPServers(ctx: LoadContext): LoadResult<MCPServer> {
|
|
37
|
+
const items: MCPServer[] = [];
|
|
38
|
+
const warnings: string[] = [];
|
|
39
|
+
|
|
40
|
+
// User-level: ~/.codeium/windsurf/mcp_config.json
|
|
41
|
+
const userPath = getUserPath(ctx, "windsurf", "mcp_config.json");
|
|
42
|
+
if (userPath && ctx.fs.isFile(userPath)) {
|
|
43
|
+
const content = ctx.fs.readFile(userPath);
|
|
44
|
+
if (content) {
|
|
45
|
+
const config = parseJSON<{ mcpServers?: Record<string, unknown> }>(content);
|
|
46
|
+
if (config?.mcpServers) {
|
|
47
|
+
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
48
|
+
if (typeof serverConfig !== "object" || serverConfig === null) {
|
|
49
|
+
warnings.push(`Invalid server config for "${name}" in ${userPath}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const server = expandEnvVarsDeep(serverConfig as Record<string, unknown>);
|
|
54
|
+
items.push({
|
|
55
|
+
name,
|
|
56
|
+
command: server.command as string | undefined,
|
|
57
|
+
args: server.args as string[] | undefined,
|
|
58
|
+
env: server.env as Record<string, string> | undefined,
|
|
59
|
+
url: server.url as string | undefined,
|
|
60
|
+
headers: server.headers as Record<string, string> | undefined,
|
|
61
|
+
transport: server.type as "stdio" | "sse" | "http" | undefined,
|
|
62
|
+
_source: createSourceMeta(PROVIDER_ID, userPath, "user"),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Project-level: .windsurf/mcp_config.json
|
|
70
|
+
const projectPath = getProjectPath(ctx, "windsurf", "mcp_config.json");
|
|
71
|
+
if (projectPath && ctx.fs.isFile(projectPath)) {
|
|
72
|
+
const content = ctx.fs.readFile(projectPath);
|
|
73
|
+
if (content) {
|
|
74
|
+
const config = parseJSON<{ mcpServers?: Record<string, unknown> }>(content);
|
|
75
|
+
if (config?.mcpServers) {
|
|
76
|
+
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
77
|
+
if (typeof serverConfig !== "object" || serverConfig === null) {
|
|
78
|
+
warnings.push(`Invalid server config for "${name}" in ${projectPath}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const server = expandEnvVarsDeep(serverConfig as Record<string, unknown>);
|
|
83
|
+
items.push({
|
|
84
|
+
name,
|
|
85
|
+
command: server.command as string | undefined,
|
|
86
|
+
args: server.args as string[] | undefined,
|
|
87
|
+
env: server.env as Record<string, string> | undefined,
|
|
88
|
+
url: server.url as string | undefined,
|
|
89
|
+
headers: server.headers as Record<string, string> | undefined,
|
|
90
|
+
transport: server.type as "stdio" | "sse" | "http" | undefined,
|
|
91
|
+
_source: createSourceMeta(PROVIDER_ID, projectPath, "project"),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { items, warnings };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// Rules
|
|
103
|
+
// =============================================================================
|
|
104
|
+
|
|
105
|
+
function loadRules(ctx: LoadContext): LoadResult<Rule> {
|
|
106
|
+
const items: Rule[] = [];
|
|
107
|
+
const warnings: string[] = [];
|
|
108
|
+
|
|
109
|
+
// User-level: ~/.codeium/windsurf/memories/global_rules.md
|
|
110
|
+
const userPath = getUserPath(ctx, "windsurf", "memories/global_rules.md");
|
|
111
|
+
if (userPath && ctx.fs.isFile(userPath)) {
|
|
112
|
+
const content = ctx.fs.readFile(userPath);
|
|
113
|
+
if (content) {
|
|
114
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
115
|
+
|
|
116
|
+
// Validate and normalize globs
|
|
117
|
+
let globs: string[] | undefined;
|
|
118
|
+
if (Array.isArray(frontmatter.globs)) {
|
|
119
|
+
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
120
|
+
} else if (typeof frontmatter.globs === "string") {
|
|
121
|
+
globs = [frontmatter.globs];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
items.push({
|
|
125
|
+
name: "global_rules",
|
|
126
|
+
path: userPath,
|
|
127
|
+
content: body,
|
|
128
|
+
globs,
|
|
129
|
+
alwaysApply: frontmatter.alwaysApply as boolean | undefined,
|
|
130
|
+
description: frontmatter.description as string | undefined,
|
|
131
|
+
_source: createSourceMeta(PROVIDER_ID, userPath, "user"),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Project-level: .windsurf/rules/*.md
|
|
137
|
+
const projectRulesDir = getProjectPath(ctx, "windsurf", "rules");
|
|
138
|
+
if (projectRulesDir) {
|
|
139
|
+
const result = loadFilesFromDir<Rule>(ctx, projectRulesDir, PROVIDER_ID, "project", {
|
|
140
|
+
extensions: ["md"],
|
|
141
|
+
transform: (name, content, path, source) => {
|
|
142
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
143
|
+
const ruleName = name.replace(/\.md$/, "");
|
|
144
|
+
|
|
145
|
+
// Validate and normalize globs
|
|
146
|
+
let globs: string[] | undefined;
|
|
147
|
+
if (Array.isArray(frontmatter.globs)) {
|
|
148
|
+
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
149
|
+
} else if (typeof frontmatter.globs === "string") {
|
|
150
|
+
globs = [frontmatter.globs];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
name: ruleName,
|
|
155
|
+
path,
|
|
156
|
+
content: body,
|
|
157
|
+
globs,
|
|
158
|
+
alwaysApply: frontmatter.alwaysApply as boolean | undefined,
|
|
159
|
+
description: frontmatter.description as string | undefined,
|
|
160
|
+
_source: source,
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
items.push(...result.items);
|
|
165
|
+
if (result.warnings) warnings.push(...result.warnings);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Legacy: .windsurfrules in project root
|
|
169
|
+
const legacyPath = ctx.fs.walkUp(".windsurfrules", { file: true });
|
|
170
|
+
if (legacyPath) {
|
|
171
|
+
const content = ctx.fs.readFile(legacyPath);
|
|
172
|
+
if (content) {
|
|
173
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
174
|
+
|
|
175
|
+
// Validate and normalize globs
|
|
176
|
+
let globs: string[] | undefined;
|
|
177
|
+
if (Array.isArray(frontmatter.globs)) {
|
|
178
|
+
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
179
|
+
} else if (typeof frontmatter.globs === "string") {
|
|
180
|
+
globs = [frontmatter.globs];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
items.push({
|
|
184
|
+
name: "windsurfrules",
|
|
185
|
+
path: legacyPath,
|
|
186
|
+
content: body,
|
|
187
|
+
globs,
|
|
188
|
+
alwaysApply: frontmatter.alwaysApply as boolean | undefined,
|
|
189
|
+
description: frontmatter.description as string | undefined,
|
|
190
|
+
_source: createSourceMeta(PROVIDER_ID, legacyPath, "project"),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return { items, warnings };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// =============================================================================
|
|
199
|
+
// Provider Registration
|
|
200
|
+
// =============================================================================
|
|
201
|
+
|
|
202
|
+
registerProvider<MCPServer>(mcpCapability.id, {
|
|
203
|
+
id: PROVIDER_ID,
|
|
204
|
+
displayName: DISPLAY_NAME,
|
|
205
|
+
description: "Load MCP servers from Windsurf config (mcp_config.json)",
|
|
206
|
+
priority: PRIORITY,
|
|
207
|
+
load: loadMCPServers,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
registerProvider<Rule>(ruleCapability.id, {
|
|
211
|
+
id: PROVIDER_ID,
|
|
212
|
+
displayName: DISPLAY_NAME,
|
|
213
|
+
description: "Load rules from Windsurf (.windsurf/rules/*.md, memories/global_rules.md, .windsurfrules)",
|
|
214
|
+
priority: PRIORITY,
|
|
215
|
+
load: loadRules,
|
|
216
|
+
});
|
package/src/main.ts
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* createAgentSession() options. The SDK does the heavy lifting.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { existsSync } from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
10
8
|
import { type ImageContent, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
11
9
|
import chalk from "chalk";
|
|
12
10
|
import { type Args, parseArgs, printHelp } from "./cli/args";
|
|
@@ -15,7 +13,7 @@ import { listModels } from "./cli/list-models";
|
|
|
15
13
|
import { parsePluginArgs, printPluginHelp, runPluginCommand } from "./cli/plugin-cli";
|
|
16
14
|
import { selectSession } from "./cli/session-picker";
|
|
17
15
|
import { parseUpdateArgs, printUpdateHelp, runUpdateCommand } from "./cli/update-cli";
|
|
18
|
-
import {
|
|
16
|
+
import { findConfigFile, getModelsPath, VERSION } from "./config";
|
|
19
17
|
import type { AgentSession } from "./core/agent-session";
|
|
20
18
|
import type { LoadedCustomTool } from "./core/custom-tools/index";
|
|
21
19
|
import { exportFromFile } from "./core/export-html/index";
|
|
@@ -199,18 +197,16 @@ function createSessionManager(parsed: Args, cwd: string): SessionManager | undef
|
|
|
199
197
|
|
|
200
198
|
/** Discover SYSTEM.md file if no CLI system prompt was provided */
|
|
201
199
|
function discoverSystemPromptFile(): string | undefined {
|
|
202
|
-
// Check project-local first
|
|
203
|
-
const projectPath =
|
|
204
|
-
if (
|
|
200
|
+
// Check project-local first (.omp/SYSTEM.md, .pi/SYSTEM.md legacy)
|
|
201
|
+
const projectPath = findConfigFile("SYSTEM.md", { user: false });
|
|
202
|
+
if (projectPath) {
|
|
205
203
|
return projectPath;
|
|
206
204
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (existsSync(globalPath)) {
|
|
205
|
+
// If not found, check SYSTEM.md file in the global directory.
|
|
206
|
+
const globalPath = findConfigFile("SYSTEM.md", { user: true });
|
|
207
|
+
if (globalPath) {
|
|
211
208
|
return globalPath;
|
|
212
209
|
}
|
|
213
|
-
|
|
214
210
|
return undefined;
|
|
215
211
|
}
|
|
216
212
|
|
|
@@ -374,9 +370,14 @@ export async function main(args: string[]) {
|
|
|
374
370
|
const settingsManager = SettingsManager.create(cwd);
|
|
375
371
|
time("SettingsManager.create");
|
|
376
372
|
|
|
373
|
+
// Initialize discovery system with settings for provider persistence
|
|
374
|
+
const { initializeWithSettings } = await import("./discovery");
|
|
375
|
+
initializeWithSettings(settingsManager);
|
|
376
|
+
time("initializeWithSettings");
|
|
377
|
+
|
|
377
378
|
// Apply model role overrides from CLI args or env vars (ephemeral, not persisted)
|
|
378
|
-
const smolModel = parsed.smol ?? process.env.
|
|
379
|
-
const slowModel = parsed.slow ?? process.env.
|
|
379
|
+
const smolModel = parsed.smol ?? process.env.OMP_SMOL_MODEL;
|
|
380
|
+
const slowModel = parsed.slow ?? process.env.OMP_SLOW_MODEL;
|
|
380
381
|
if (smolModel || slowModel) {
|
|
381
382
|
const roleOverrides: Record<string, string> = {};
|
|
382
383
|
if (smolModel) roleOverrides.smol = smolModel;
|
package/src/migrations.ts
CHANGED
|
@@ -6,6 +6,22 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFile
|
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { getAgentDir } from "./config";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Migrate PI_* environment variables to OMP_* equivalents.
|
|
11
|
+
* If PI_XX is set and OMP_XX is not, set OMP_XX to PI_XX's value.
|
|
12
|
+
* This provides backwards compatibility for users with existing PI_* env vars.
|
|
13
|
+
*/
|
|
14
|
+
export function migrateEnvVars(): void {
|
|
15
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
16
|
+
if (key.startsWith("PI_") && value !== undefined) {
|
|
17
|
+
const ompKey = `OMP_${key.slice(3)}`; // PI_FOO -> OMP_FOO
|
|
18
|
+
if (process.env[ompKey] === undefined) {
|
|
19
|
+
process.env[ompKey] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
/**
|
|
10
26
|
* Migrate legacy oauth.json and settings.json apiKeys to auth.json.
|
|
11
27
|
*
|
|
@@ -66,10 +82,10 @@ export function migrateAuthToAuthJson(): string[] {
|
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
/**
|
|
69
|
-
* Migrate sessions from ~/.
|
|
85
|
+
* Migrate sessions from ~/.omp/agent/*.jsonl to proper session directories.
|
|
70
86
|
*
|
|
71
|
-
* Bug in v0.30.0: Sessions were saved to ~/.
|
|
72
|
-
* ~/.
|
|
87
|
+
* Bug in v0.30.0: Sessions were saved to ~/.omp/agent/ instead of
|
|
88
|
+
* ~/.omp/agent/sessions/<encoded-cwd>/. This migration moves them
|
|
73
89
|
* to the correct location based on the cwd in their session header.
|
|
74
90
|
*
|
|
75
91
|
* See: https://github.com/badlogic/pi-mono/issues/320
|
|
@@ -129,7 +145,12 @@ export function migrateSessionsFromAgentRoot(): void {
|
|
|
129
145
|
* @returns Object with migration results
|
|
130
146
|
*/
|
|
131
147
|
export function runMigrations(): { migratedAuthProviders: string[] } {
|
|
148
|
+
// First: migrate env vars (before anything else reads them)
|
|
149
|
+
migrateEnvVars();
|
|
150
|
+
|
|
151
|
+
// Then: run data migrations
|
|
132
152
|
const migratedAuthProviders = migrateAuthToAuthJson();
|
|
133
153
|
migrateSessionsFromAgentRoot();
|
|
154
|
+
|
|
134
155
|
return { migratedAuthProviders };
|
|
135
156
|
}
|
|
@@ -89,7 +89,7 @@ export class HookEditorComponent extends Container {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
const currentText = this.editor.getText();
|
|
92
|
-
const tmpFile = path.join(os.tmpdir(), `
|
|
92
|
+
const tmpFile = path.join(os.tmpdir(), `omp-hook-editor-${Date.now()}.md`);
|
|
93
93
|
|
|
94
94
|
try {
|
|
95
95
|
fs.writeFileSync(tmpFile, currentText, "utf-8");
|
|
@@ -52,7 +52,7 @@ export class PluginListComponent extends Container {
|
|
|
52
52
|
if (plugins.length === 0) {
|
|
53
53
|
this.addChild(new Text(theme.fg("muted", " No plugins installed"), 0, 0));
|
|
54
54
|
this.addChild(new Spacer(1));
|
|
55
|
-
this.addChild(new Text(theme.fg("dim", " Install with:
|
|
55
|
+
this.addChild(new Text(theme.fg("dim", " Install with: omp plugin install <package>"), 0, 0));
|
|
56
56
|
this.addChild(new Spacer(1));
|
|
57
57
|
this.addChild(new DynamicBorder());
|
|
58
58
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
12
12
|
import { getCapabilities } from "@oh-my-pi/pi-tui";
|
|
13
13
|
import type { SettingsManager } from "../../../core/settings-manager";
|
|
14
|
+
import { getAllProvidersInfo, isProviderEnabled } from "../../../discovery";
|
|
14
15
|
|
|
15
16
|
// Setting value types
|
|
16
17
|
export type SettingValue = boolean | string;
|
|
@@ -266,12 +267,47 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
266
267
|
},
|
|
267
268
|
];
|
|
268
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Get discovery provider settings dynamically.
|
|
272
|
+
* These are generated at runtime from getAllProvidersInfo().
|
|
273
|
+
*/
|
|
274
|
+
function getDiscoverySettings(): SettingDef[] {
|
|
275
|
+
const providers = getAllProvidersInfo();
|
|
276
|
+
const settings: SettingDef[] = [];
|
|
277
|
+
|
|
278
|
+
for (const provider of providers) {
|
|
279
|
+
// Skip native provider - it can't be disabled
|
|
280
|
+
if (provider.id === "native") {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
settings.push({
|
|
285
|
+
id: `discovery.${provider.id}`,
|
|
286
|
+
tab: "discovery",
|
|
287
|
+
type: "boolean",
|
|
288
|
+
label: provider.displayName,
|
|
289
|
+
description: provider.description,
|
|
290
|
+
get: () => isProviderEnabled(provider.id),
|
|
291
|
+
set: () => {}, // Handled in interactive-mode.ts
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return settings;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* All settings with dynamic discovery settings merged in.
|
|
300
|
+
*/
|
|
301
|
+
function getAllSettings(): SettingDef[] {
|
|
302
|
+
return [...SETTINGS_DEFS, ...getDiscoverySettings()];
|
|
303
|
+
}
|
|
304
|
+
|
|
269
305
|
/** Get settings for a specific tab */
|
|
270
306
|
export function getSettingsForTab(tab: string): SettingDef[] {
|
|
271
|
-
return
|
|
307
|
+
return getAllSettings().filter((def) => def.tab === tab);
|
|
272
308
|
}
|
|
273
309
|
|
|
274
310
|
/** Get a setting definition by id */
|
|
275
311
|
export function getSettingDef(id: string): SettingDef | undefined {
|
|
276
|
-
return
|
|
312
|
+
return getAllSettings().find((def) => def.id === id);
|
|
277
313
|
}
|
|
@@ -14,7 +14,7 @@ export interface LspServerInfo {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Premium welcome screen with block-based
|
|
17
|
+
* Premium welcome screen with block-based OMP logo and two-column layout.
|
|
18
18
|
*/
|
|
19
19
|
export class WelcomeComponent implements Component {
|
|
20
20
|
private version: string;
|
|
@@ -60,7 +60,7 @@ export class WelcomeComponent implements Component {
|
|
|
60
60
|
const leftCol = 26;
|
|
61
61
|
const rightCol = boxWidth - leftCol - 3; // 3 = │ + │ + │
|
|
62
62
|
|
|
63
|
-
// Block-based
|
|
63
|
+
// Block-based OMP logo (gradient: magenta → cyan)
|
|
64
64
|
// biome-ignore format: preserve ASCII art layout
|
|
65
65
|
const piLogo = ["▀████████████▀", " ╘███ ███ ", " ███ ███ ", " ███ ███ ", " ▄███▄ ▄███▄ "];
|
|
66
66
|
|