@oh-my-pi/pi-coding-agent 15.1.2 → 15.1.4
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 +60 -0
- package/dist/types/async/job-manager.d.ts +3 -2
- package/dist/types/cli/auth-broker-cli.d.ts +25 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +18 -0
- package/dist/types/cli/grievances-cli.d.ts +12 -0
- package/dist/types/commands/auth-broker.d.ts +54 -0
- package/dist/types/commands/auth-gateway.d.ts +32 -0
- package/dist/types/commands/grievances.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +9 -1
- package/dist/types/commit/agentic/tools/schemas.d.ts +9 -1
- package/dist/types/commit/agentic/tools/split-commit.d.ts +9 -1
- package/dist/types/config/model-registry.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +1 -0
- package/dist/types/config/settings-schema.d.ts +46 -0
- package/dist/types/discovery/agents.d.ts +12 -1
- package/dist/types/edit/renderer.d.ts +3 -0
- package/dist/types/eval/index.d.ts +0 -2
- package/dist/types/goals/tools/goal-tool.d.ts +10 -2
- package/dist/types/index.d.ts +0 -1
- package/dist/types/internal-urls/index.d.ts +1 -1
- package/dist/types/internal-urls/{pi-protocol.d.ts → omp-protocol.d.ts} +3 -3
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/main.d.ts +11 -2
- package/dist/types/modes/acp/acp-agent.d.ts +2 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +13 -1
- package/dist/types/modes/acp/acp-mode.d.ts +3 -1
- package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
- package/dist/types/plan-mode/approved-plan.d.ts +10 -4
- package/dist/types/sdk.d.ts +10 -3
- package/dist/types/session/agent-session.d.ts +7 -3
- package/dist/types/session/auth-broker-config.d.ts +13 -0
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/client-bridge.d.ts +3 -0
- package/dist/types/tools/eval.d.ts +41 -7
- package/dist/types/tools/irc.d.ts +8 -2
- package/dist/types/tools/report-tool-issue.d.ts +118 -1
- package/dist/types/tools/resolve.d.ts +8 -2
- package/examples/custom-tools/README.md +3 -12
- package/examples/extensions/README.md +2 -15
- package/examples/extensions/api-demo.ts +1 -7
- package/package.json +7 -7
- package/src/async/job-manager.ts +111 -13
- package/src/autoresearch/tools/init-experiment.ts +11 -33
- package/src/autoresearch/tools/log-experiment.ts +10 -24
- package/src/autoresearch/tools/run-experiment.ts +1 -1
- package/src/autoresearch/tools/update-notes.ts +2 -9
- package/src/cli/auth-broker-cli.ts +746 -0
- package/src/cli/auth-gateway-cli.ts +342 -0
- package/src/cli/grievances-cli.ts +109 -16
- package/src/cli/update-cli.ts +1 -5
- package/src/cli.ts +4 -2
- package/src/commands/auth-broker.ts +96 -0
- package/src/commands/auth-gateway.ts +61 -0
- package/src/commands/grievances.ts +13 -8
- package/src/commands/launch.ts +1 -1
- package/src/commit/agentic/agent.ts +2 -0
- package/src/commit/agentic/tools/analyze-file.ts +2 -2
- package/src/commit/agentic/tools/git-file-diff.ts +2 -2
- package/src/commit/agentic/tools/git-hunk.ts +3 -3
- package/src/commit/agentic/tools/git-overview.ts +2 -2
- package/src/commit/agentic/tools/propose-changelog.ts +1 -3
- package/src/commit/agentic/tools/recent-commits.ts +1 -1
- package/src/commit/agentic/tools/schemas.ts +1 -9
- package/src/config/model-equivalence.ts +279 -174
- package/src/config/model-registry.ts +37 -6
- package/src/config/model-resolver.ts +13 -8
- package/src/config/models-config-schema.ts +8 -0
- package/src/config/settings-schema.ts +52 -0
- package/src/cursor.ts +1 -1
- package/src/debug/log-formatting.ts +1 -1
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/profiler.ts +4 -0
- package/src/debug/raw-sse-buffer.ts +100 -59
- package/src/debug/raw-sse.ts +1 -1
- package/src/discovery/agents.ts +15 -4
- package/src/edit/modes/apply-patch.ts +1 -5
- package/src/edit/modes/patch.ts +5 -5
- package/src/edit/modes/replace.ts +5 -5
- package/src/edit/renderer.ts +2 -1
- package/src/edit/streaming.ts +1 -1
- package/src/eval/index.ts +0 -2
- package/src/eval/js/shared/runtime.ts +107 -2
- package/src/eval/py/kernel.ts +1 -1
- package/src/exa/researcher.ts +4 -4
- package/src/exa/search.ts +10 -22
- package/src/exa/websets.ts +33 -33
- package/src/extensibility/typebox.ts +44 -17
- package/src/goals/tools/goal-tool.ts +3 -3
- package/src/index.ts +0 -3
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/internal-urls/index.ts +1 -1
- package/src/internal-urls/{pi-protocol.ts → omp-protocol.ts} +10 -10
- package/src/internal-urls/router.ts +3 -3
- package/src/internal-urls/types.ts +1 -1
- package/src/lsp/types.ts +8 -11
- package/src/main.ts +216 -146
- package/src/mcp/tool-bridge.ts +3 -3
- package/src/modes/acp/acp-agent.ts +203 -57
- package/src/modes/acp/acp-client-bridge.ts +2 -1
- package/src/modes/acp/acp-event-mapper.ts +208 -32
- package/src/modes/acp/acp-mode.ts +11 -3
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/diff.ts +1 -2
- package/src/modes/components/eval-execution.ts +1 -1
- package/src/modes/components/oauth-selector.ts +38 -2
- package/src/modes/components/tool-execution.ts +1 -2
- package/src/modes/components/tree-selector.ts +26 -7
- package/src/modes/controllers/command-controller.ts +95 -34
- package/src/modes/controllers/input-controller.ts +4 -3
- package/src/modes/data/emojis.json +1 -0
- package/src/modes/emoji-autocomplete.ts +285 -0
- package/src/modes/interactive-mode.ts +92 -19
- package/src/modes/print-mode.ts +3 -3
- package/src/modes/prompt-action-autocomplete.ts +14 -0
- package/src/plan-mode/approved-plan.ts +30 -9
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/ttsr-tool-reminder.md +5 -0
- package/src/prompts/tools/ask.md +4 -3
- package/src/prompts/tools/eval.md +25 -26
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/resolve.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/web-search.md +1 -1
- package/src/sdk.ts +81 -8
- package/src/session/agent-session.ts +362 -131
- package/src/session/agent-storage.ts +7 -2
- package/src/session/auth-broker-config.ts +102 -0
- package/src/session/auth-storage.ts +7 -1
- package/src/session/client-bridge.ts +3 -0
- package/src/session/streaming-output.ts +1 -1
- package/src/task/types.ts +10 -35
- package/src/tools/bash-interactive.ts +4 -1
- package/src/tools/bash-pty-selection.ts +2 -2
- package/src/tools/browser.ts +12 -20
- package/src/tools/eval.ts +77 -100
- package/src/tools/gh.ts +21 -45
- package/src/tools/hindsight-recall.ts +1 -1
- package/src/tools/hindsight-reflect.ts +2 -2
- package/src/tools/hindsight-retain.ts +3 -7
- package/src/tools/index.ts +8 -1
- package/src/tools/inspect-image.ts +4 -1
- package/src/tools/irc.ts +4 -12
- package/src/tools/job.ts +3 -11
- package/src/tools/report-tool-issue.ts +462 -17
- package/src/tools/resolve.ts +2 -7
- package/src/tools/todo-write.ts +8 -15
- package/src/utils/title-generator.ts +3 -0
- package/src/web/search/index.ts +6 -6
- package/dist/types/eval/parse.d.ts +0 -28
- package/dist/types/eval/sniff.d.ts +0 -11
- package/src/eval/eval.lark +0 -36
- package/src/eval/parse.ts +0 -407
- package/src/eval/sniff.ts +0 -28
|
@@ -15,8 +15,8 @@ export * from "./json-query";
|
|
|
15
15
|
export * from "./local-protocol";
|
|
16
16
|
export * from "./mcp-protocol";
|
|
17
17
|
export * from "./memory-protocol";
|
|
18
|
+
export * from "./omp-protocol";
|
|
18
19
|
export * from "./parse";
|
|
19
|
-
export * from "./pi-protocol";
|
|
20
20
|
export * from "./router";
|
|
21
21
|
export * from "./rule-protocol";
|
|
22
22
|
export * from "./skill-protocol";
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Protocol handler for
|
|
2
|
+
* Protocol handler for omp:// URLs.
|
|
3
3
|
*
|
|
4
4
|
* Serves statically embedded documentation files bundled at build time.
|
|
5
5
|
*
|
|
6
6
|
* URL forms:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
7
|
+
* - omp:// - Lists all available documentation files
|
|
8
|
+
* - omp://<file>.md - Reads a specific documentation file
|
|
9
9
|
*/
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import { EMBEDDED_DOC_FILENAMES, EMBEDDED_DOCS } from "./docs-index.generated";
|
|
12
12
|
import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Handler for
|
|
15
|
+
* Handler for omp:// URLs.
|
|
16
16
|
*
|
|
17
17
|
* Resolves documentation file names to their content, or lists available docs.
|
|
18
18
|
*/
|
|
19
|
-
export class
|
|
20
|
-
readonly scheme = "
|
|
19
|
+
export class OmpProtocolHandler implements ProtocolHandler {
|
|
20
|
+
readonly scheme = "omp";
|
|
21
21
|
readonly immutable = true;
|
|
22
22
|
|
|
23
23
|
async resolve(url: InternalUrl): Promise<InternalResource> {
|
|
@@ -38,7 +38,7 @@ export class PiProtocolHandler implements ProtocolHandler {
|
|
|
38
38
|
throw new Error("No documentation files found");
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const listing = EMBEDDED_DOC_FILENAMES.map(f => `- [${f}](
|
|
41
|
+
const listing = EMBEDDED_DOC_FILENAMES.map(f => `- [${f}](omp://${f})`).join("\n");
|
|
42
42
|
const content = `# Documentation\n\n${EMBEDDED_DOC_FILENAMES.length} files available:\n\n${listing}\n`;
|
|
43
43
|
|
|
44
44
|
return {
|
|
@@ -52,12 +52,12 @@ export class PiProtocolHandler implements ProtocolHandler {
|
|
|
52
52
|
async #readDoc(filename: string, url: InternalUrl): Promise<InternalResource> {
|
|
53
53
|
// Validate: no traversal, no absolute paths
|
|
54
54
|
if (path.isAbsolute(filename)) {
|
|
55
|
-
throw new Error("Absolute paths are not allowed in
|
|
55
|
+
throw new Error("Absolute paths are not allowed in omp:// URLs");
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const normalized = path.posix.normalize(filename.replaceAll("\\", "/"));
|
|
59
59
|
if (normalized === ".." || normalized.startsWith("../") || normalized.includes("/../")) {
|
|
60
|
-
throw new Error("Path traversal (..) is not allowed in
|
|
60
|
+
throw new Error("Path traversal (..) is not allowed in omp:// URLs");
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const content = EMBEDDED_DOCS[normalized];
|
|
@@ -69,7 +69,7 @@ export class PiProtocolHandler implements ProtocolHandler {
|
|
|
69
69
|
const suffix =
|
|
70
70
|
suggestions.length > 0
|
|
71
71
|
? `\nDid you mean: ${suggestions.join(", ")}`
|
|
72
|
-
: "\nUse
|
|
72
|
+
: "\nUse omp:// to list available files.";
|
|
73
73
|
throw new Error(`Documentation file not found: ${filename}${suffix}`);
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Internal URL router for internal protocols (agent://, artifact://, memory://, skill://, rule://, mcp://,
|
|
2
|
+
* Internal URL router for internal protocols (agent://, artifact://, memory://, skill://, rule://, mcp://, omp://, local://).
|
|
3
3
|
*
|
|
4
4
|
* One process-global router with one handler per scheme. Access via
|
|
5
5
|
* `InternalUrlRouter.instance()`. Handlers are stateless; per-session and
|
|
@@ -11,8 +11,8 @@ import { IssueProtocolHandler, PrProtocolHandler } from "./issue-pr-protocol";
|
|
|
11
11
|
import { LocalProtocolHandler } from "./local-protocol";
|
|
12
12
|
import { McpProtocolHandler } from "./mcp-protocol";
|
|
13
13
|
import { MemoryProtocolHandler } from "./memory-protocol";
|
|
14
|
+
import { OmpProtocolHandler } from "./omp-protocol";
|
|
14
15
|
import { parseInternalUrl } from "./parse";
|
|
15
|
-
import { PiProtocolHandler } from "./pi-protocol";
|
|
16
16
|
import { RuleProtocolHandler } from "./rule-protocol";
|
|
17
17
|
import { SkillProtocolHandler } from "./skill-protocol";
|
|
18
18
|
import type { InternalResource, InternalUrl, ProtocolHandler, ResolveContext } from "./types";
|
|
@@ -23,7 +23,7 @@ export class InternalUrlRouter {
|
|
|
23
23
|
#handlers = new Map<string, ProtocolHandler>();
|
|
24
24
|
|
|
25
25
|
constructor() {
|
|
26
|
-
this.register(new
|
|
26
|
+
this.register(new OmpProtocolHandler());
|
|
27
27
|
this.register(new AgentProtocolHandler());
|
|
28
28
|
this.register(new ArtifactProtocolHandler());
|
|
29
29
|
this.register(new MemoryProtocolHandler());
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Types for the internal URL routing system.
|
|
3
3
|
*
|
|
4
|
-
* Internal URLs (agent://, artifact://, memory://, skill://, rule://, mcp://,
|
|
4
|
+
* Internal URLs (agent://, artifact://, memory://, skill://, rule://, mcp://, omp://, local://) are resolved by tools like read,
|
|
5
5
|
* providing access to agent outputs and server resources without exposing filesystem paths.
|
|
6
6
|
*/
|
|
7
7
|
|
package/src/lsp/types.ts
CHANGED
|
@@ -22,17 +22,14 @@ export const lspSchema = z.object({
|
|
|
22
22
|
"capabilities",
|
|
23
23
|
"request",
|
|
24
24
|
]),
|
|
25
|
-
file: z.string().describe("
|
|
26
|
-
line: z.number().describe("
|
|
27
|
-
symbol: z.string().describe("
|
|
28
|
-
query: z.string().describe("
|
|
29
|
-
new_name: z.string().describe("
|
|
30
|
-
apply: z.boolean().describe("
|
|
31
|
-
timeout: z.number().describe("
|
|
32
|
-
payload: z
|
|
33
|
-
.string()
|
|
34
|
-
.describe("JSON-encoded params for action=request. When omitted, params are auto-built from file/line/symbol.")
|
|
35
|
-
.optional(),
|
|
25
|
+
file: z.string().describe("file path or source path for rename_file").optional(),
|
|
26
|
+
line: z.number().describe("line number (1-indexed)").optional(),
|
|
27
|
+
symbol: z.string().describe("symbol substring on the line").optional(),
|
|
28
|
+
query: z.string().describe("search query or code-action selector").optional(),
|
|
29
|
+
new_name: z.string().describe("new symbol name or destination path").optional(),
|
|
30
|
+
apply: z.boolean().describe("apply edits").optional(),
|
|
31
|
+
timeout: z.number().describe("request timeout in seconds").optional(),
|
|
32
|
+
payload: z.string().describe("json-encoded request params").optional(),
|
|
36
33
|
});
|
|
37
34
|
|
|
38
35
|
export type LspParams = z.infer<typeof lspSchema>;
|
package/src/main.ts
CHANGED
|
@@ -49,8 +49,14 @@ import type { MCPManager } from "./mcp";
|
|
|
49
49
|
import { InteractiveMode, runAcpMode, runPrintMode, runRpcMode } from "./modes";
|
|
50
50
|
import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
|
|
51
51
|
import type { SubmittedUserInput } from "./modes/types";
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
type CreateAgentSessionOptions,
|
|
54
|
+
type CreateAgentSessionResult,
|
|
55
|
+
createAgentSession,
|
|
56
|
+
discoverAuthStorage,
|
|
57
|
+
} from "./sdk";
|
|
53
58
|
import type { AgentSession } from "./session/agent-session";
|
|
59
|
+
import type { AuthStorage } from "./session/auth-storage";
|
|
54
60
|
import { resolveResumableSession, type SessionInfo, SessionManager } from "./session/session-manager";
|
|
55
61
|
import { resolvePromptInput } from "./system-prompt";
|
|
56
62
|
import type { LspStartupServerInfo } from "./tools";
|
|
@@ -102,9 +108,9 @@ const RPC_DEFAULTED_SETTING_PATHS: SettingPath[] = [
|
|
|
102
108
|
"memories.enabled",
|
|
103
109
|
];
|
|
104
110
|
|
|
105
|
-
function applyRpcDefaultSettingOverrides(): void {
|
|
111
|
+
function applyRpcDefaultSettingOverrides(targetSettings: Settings = settings): void {
|
|
106
112
|
for (const settingPath of RPC_DEFAULTED_SETTING_PATHS) {
|
|
107
|
-
|
|
113
|
+
targetSettings.override(settingPath, getDefault(settingPath));
|
|
108
114
|
}
|
|
109
115
|
}
|
|
110
116
|
|
|
@@ -160,6 +166,73 @@ export async function submitInteractiveInput(
|
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
168
|
|
|
169
|
+
function applyExtensionFlagValues(session: AgentSession, rawArgs: string[]): Map<string, boolean | string> {
|
|
170
|
+
const extensionRunner = session.extensionRunner;
|
|
171
|
+
if (!extensionRunner) {
|
|
172
|
+
return new Map();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const extFlags = extensionRunner.getFlags();
|
|
176
|
+
if (extFlags.size > 0) {
|
|
177
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
178
|
+
const arg = rawArgs[i];
|
|
179
|
+
if (!arg.startsWith("--")) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const flagName = arg.slice(2);
|
|
183
|
+
const extFlag = extFlags.get(flagName);
|
|
184
|
+
if (!extFlag) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (extFlag.type === "boolean") {
|
|
188
|
+
extensionRunner.setFlagValue(flagName, true);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (i + 1 < rawArgs.length) {
|
|
192
|
+
extensionRunner.setFlagValue(flagName, rawArgs[++i]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return extensionRunner.getFlagValues();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
type AcpSessionFactory = (cwd: string) => Promise<AgentSession>;
|
|
201
|
+
|
|
202
|
+
interface AcpSessionFactoryOptions {
|
|
203
|
+
baseOptions: CreateAgentSessionOptions;
|
|
204
|
+
settings: Settings;
|
|
205
|
+
sessionDir?: string;
|
|
206
|
+
authStorage: AuthStorage;
|
|
207
|
+
modelRegistry: ModelRegistry;
|
|
208
|
+
parsedArgs: Pick<Args, "apiKey">;
|
|
209
|
+
rawArgs: string[];
|
|
210
|
+
createSession: (options: CreateAgentSessionOptions) => Promise<CreateAgentSessionResult>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function createAcpSessionFactory(args: AcpSessionFactoryOptions): AcpSessionFactory {
|
|
214
|
+
return async cwd => {
|
|
215
|
+
const nextSettings = await args.settings.cloneForCwd(cwd);
|
|
216
|
+
const nextSessionManager = SessionManager.create(cwd, args.sessionDir);
|
|
217
|
+
const agentId = `acp:${nextSessionManager.getSessionId()}`;
|
|
218
|
+
const { session: nextSession } = await args.createSession({
|
|
219
|
+
...args.baseOptions,
|
|
220
|
+
cwd,
|
|
221
|
+
sessionManager: nextSessionManager,
|
|
222
|
+
settings: nextSettings,
|
|
223
|
+
authStorage: args.authStorage,
|
|
224
|
+
modelRegistry: args.modelRegistry,
|
|
225
|
+
agentId,
|
|
226
|
+
hasUI: false,
|
|
227
|
+
});
|
|
228
|
+
if (args.parsedArgs.apiKey && !args.baseOptions.model && nextSession.model) {
|
|
229
|
+
args.authStorage.setRuntimeApiKey(nextSession.model.provider, args.parsedArgs.apiKey);
|
|
230
|
+
}
|
|
231
|
+
applyExtensionFlagValues(nextSession, args.rawArgs);
|
|
232
|
+
return nextSession;
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
163
236
|
async function runInteractiveMode(
|
|
164
237
|
session: AgentSession,
|
|
165
238
|
version: string,
|
|
@@ -290,7 +363,11 @@ async function flushChangelogVersion(): Promise<void> {
|
|
|
290
363
|
}
|
|
291
364
|
}
|
|
292
365
|
|
|
293
|
-
async function createSessionManager(
|
|
366
|
+
async function createSessionManager(
|
|
367
|
+
parsed: Args,
|
|
368
|
+
cwd: string,
|
|
369
|
+
activeSettings: Settings = settings,
|
|
370
|
+
): Promise<SessionManager | undefined> {
|
|
294
371
|
if (parsed.fork) {
|
|
295
372
|
if (parsed.noSession) {
|
|
296
373
|
throw new Error("--fork requires session persistence");
|
|
@@ -343,7 +420,7 @@ async function createSessionManager(parsed: Args, cwd: string): Promise<SessionM
|
|
|
343
420
|
// session exists. When a prior session is resumed, mark parsed.continue so
|
|
344
421
|
// buildSessionOptions restores the session's model/thinking instead of
|
|
345
422
|
// overriding them with CLI defaults.
|
|
346
|
-
if (
|
|
423
|
+
if (activeSettings.get("autoResume")) {
|
|
347
424
|
const manager = await SessionManager.continueRecent(cwd, parsed.sessionDir);
|
|
348
425
|
if (manager.getEntries().length > 0) {
|
|
349
426
|
parsed.continue = true;
|
|
@@ -437,6 +514,7 @@ async function buildSessionOptions(
|
|
|
437
514
|
scopedModels: ScopedModel[],
|
|
438
515
|
sessionManager: SessionManager | undefined,
|
|
439
516
|
modelRegistry: ModelRegistry,
|
|
517
|
+
activeSettings: Settings,
|
|
440
518
|
): Promise<{ options: CreateAgentSessionOptions }> {
|
|
441
519
|
const options: CreateAgentSessionOptions = {
|
|
442
520
|
cwd: parsed.cwd ?? getProjectDir(),
|
|
@@ -459,7 +537,7 @@ async function buildSessionOptions(
|
|
|
459
537
|
// - supports --provider <name> --model <pattern>
|
|
460
538
|
// - supports --model <provider>/<pattern>
|
|
461
539
|
const modelMatchPreferences = {
|
|
462
|
-
usageOrder:
|
|
540
|
+
usageOrder: activeSettings.getStorage()?.getModelUsageOrder(),
|
|
463
541
|
};
|
|
464
542
|
if (parsed.model) {
|
|
465
543
|
const resolved = resolveCliModel({
|
|
@@ -482,7 +560,7 @@ async function buildSessionOptions(
|
|
|
482
560
|
}
|
|
483
561
|
} else if (resolved.model) {
|
|
484
562
|
options.model = resolved.model;
|
|
485
|
-
|
|
563
|
+
activeSettings.overrideModelRoles({
|
|
486
564
|
default: resolved.selector ?? `${resolved.model.provider}/${resolved.model.id}`,
|
|
487
565
|
});
|
|
488
566
|
if (!parsed.thinking && resolved.thinkingLevel) {
|
|
@@ -490,13 +568,13 @@ async function buildSessionOptions(
|
|
|
490
568
|
}
|
|
491
569
|
}
|
|
492
570
|
} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {
|
|
493
|
-
const remembered =
|
|
571
|
+
const remembered = activeSettings.getModelRole("default");
|
|
494
572
|
if (remembered) {
|
|
495
573
|
const rememberedSpec = resolveModelRoleValue(
|
|
496
574
|
remembered,
|
|
497
575
|
scopedModels.map(scopedModel => scopedModel.model),
|
|
498
576
|
{
|
|
499
|
-
settings,
|
|
577
|
+
settings: activeSettings,
|
|
500
578
|
matchPreferences: modelMatchPreferences,
|
|
501
579
|
modelRegistry,
|
|
502
580
|
},
|
|
@@ -534,7 +612,7 @@ async function buildSessionOptions(
|
|
|
534
612
|
|
|
535
613
|
// Scoped models for Ctrl+P cycling - fill in default thinking levels when not explicit
|
|
536
614
|
if (scopedModels.length > 0) {
|
|
537
|
-
const defaultThinkingLevel =
|
|
615
|
+
const defaultThinkingLevel = activeSettings.get("defaultThinkingLevel");
|
|
538
616
|
options.scopedModels = scopedModels.map(scopedModel => ({
|
|
539
617
|
model: scopedModel.model,
|
|
540
618
|
thinkingLevel: scopedModel.explicitThinkingLevel
|
|
@@ -571,7 +649,7 @@ async function buildSessionOptions(
|
|
|
571
649
|
options.skills = [];
|
|
572
650
|
} else if (parsed.skills && parsed.skills.length > 0) {
|
|
573
651
|
// Override includeSkills for this session
|
|
574
|
-
|
|
652
|
+
activeSettings.override("skills.includeSkills", parsed.skills as string[]);
|
|
575
653
|
}
|
|
576
654
|
|
|
577
655
|
// Rules
|
|
@@ -593,7 +671,18 @@ async function buildSessionOptions(
|
|
|
593
671
|
return { options };
|
|
594
672
|
}
|
|
595
673
|
|
|
596
|
-
|
|
674
|
+
interface RunRootCommandDependencies {
|
|
675
|
+
createAgentSession?: typeof createAgentSession;
|
|
676
|
+
discoverAuthStorage?: typeof discoverAuthStorage;
|
|
677
|
+
runAcpMode?: typeof runAcpMode;
|
|
678
|
+
settings?: Settings;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export async function runRootCommand(
|
|
682
|
+
parsed: Args,
|
|
683
|
+
rawArgs: string[],
|
|
684
|
+
deps: RunRootCommandDependencies = {},
|
|
685
|
+
): Promise<void> {
|
|
597
686
|
logger.startTiming();
|
|
598
687
|
|
|
599
688
|
// Initialize theme early with defaults (CLI commands need symbols)
|
|
@@ -606,7 +695,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
606
695
|
const notifs: (InteractiveModeNotify | null)[] = [];
|
|
607
696
|
|
|
608
697
|
// Create AuthStorage and ModelRegistry upfront
|
|
609
|
-
const authStorage = await logger.time("discoverModels", discoverAuthStorage);
|
|
698
|
+
const authStorage = await logger.time("discoverModels", deps.discoverAuthStorage ?? discoverAuthStorage);
|
|
610
699
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
611
700
|
|
|
612
701
|
if (parsedArgs.version) {
|
|
@@ -668,9 +757,9 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
668
757
|
pluginPreloadPromise.catch(() => {});
|
|
669
758
|
|
|
670
759
|
const cwd = getProjectDir();
|
|
671
|
-
const settingsInstance = await logger.time("settings:init", Settings.init, { cwd });
|
|
760
|
+
const settingsInstance = deps.settings ?? (await logger.time("settings:init", Settings.init, { cwd }));
|
|
672
761
|
if (parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui" || parsedArgs.mode === "acp") {
|
|
673
|
-
applyRpcDefaultSettingOverrides();
|
|
762
|
+
applyRpcDefaultSettingOverrides(settingsInstance);
|
|
674
763
|
}
|
|
675
764
|
if (parsedArgs.noPty || parsedArgs.mode === "rpc-ui") {
|
|
676
765
|
Bun.env.PI_NO_PTY = "1";
|
|
@@ -684,7 +773,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
684
773
|
return { pipedInput, fileText: undefined, fileImages: undefined };
|
|
685
774
|
}
|
|
686
775
|
const processed = await processFileArguments(parsedArgs.fileArgs, {
|
|
687
|
-
autoResizeImages:
|
|
776
|
+
autoResizeImages: settingsInstance.get("images.autoResize"),
|
|
688
777
|
});
|
|
689
778
|
return { pipedInput, fileText: processed.text, fileImages: processed.images };
|
|
690
779
|
});
|
|
@@ -699,14 +788,14 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
699
788
|
const mode = parsedArgs.mode || "text";
|
|
700
789
|
|
|
701
790
|
// Initialize discovery system with settings for provider persistence
|
|
702
|
-
logger.time("initializeWithSettings", initializeWithSettings,
|
|
791
|
+
logger.time("initializeWithSettings", initializeWithSettings, settingsInstance);
|
|
703
792
|
|
|
704
793
|
// Apply model role overrides from CLI args or env vars (ephemeral, not persisted)
|
|
705
794
|
const smolModel = parsedArgs.smol ?? $env.PI_SMOL_MODEL;
|
|
706
795
|
const slowModel = parsedArgs.slow ?? $env.PI_SLOW_MODEL;
|
|
707
796
|
const planModel = parsedArgs.plan ?? $env.PI_PLAN_MODEL;
|
|
708
797
|
if (smolModel || slowModel || planModel) {
|
|
709
|
-
|
|
798
|
+
settingsInstance.overrideModelRoles({
|
|
710
799
|
smol: smolModel,
|
|
711
800
|
slow: slowModel,
|
|
712
801
|
plan: planModel,
|
|
@@ -717,16 +806,16 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
717
806
|
"initTheme:final",
|
|
718
807
|
initTheme,
|
|
719
808
|
isInteractive,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
809
|
+
settingsInstance.get("symbolPreset"),
|
|
810
|
+
settingsInstance.get("colorBlindMode"),
|
|
811
|
+
settingsInstance.get("theme.dark"),
|
|
812
|
+
settingsInstance.get("theme.light"),
|
|
724
813
|
);
|
|
725
814
|
|
|
726
815
|
let scopedModels: ScopedModel[] = [];
|
|
727
|
-
const modelPatterns = parsedArgs.models ??
|
|
816
|
+
const modelPatterns = parsedArgs.models ?? settingsInstance.get("enabledModels");
|
|
728
817
|
const modelMatchPreferences = {
|
|
729
|
-
usageOrder:
|
|
818
|
+
usageOrder: settingsInstance.getStorage()?.getModelUsageOrder(),
|
|
730
819
|
};
|
|
731
820
|
if (modelPatterns && modelPatterns.length > 0) {
|
|
732
821
|
scopedModels = await logger.time(
|
|
@@ -739,7 +828,13 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
739
828
|
}
|
|
740
829
|
|
|
741
830
|
// Create session manager based on CLI flags
|
|
742
|
-
let sessionManager = await logger.time(
|
|
831
|
+
let sessionManager = await logger.time(
|
|
832
|
+
"createSessionManager",
|
|
833
|
+
createSessionManager,
|
|
834
|
+
parsedArgs,
|
|
835
|
+
cwd,
|
|
836
|
+
settingsInstance,
|
|
837
|
+
);
|
|
743
838
|
|
|
744
839
|
// Handle --resume (no value): show session picker
|
|
745
840
|
if (parsedArgs.resume === true && !parsedArgs.fork) {
|
|
@@ -759,7 +854,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
759
854
|
await pluginPreloadPromise;
|
|
760
855
|
|
|
761
856
|
// Background marketplace auto-update — never blocks startup.
|
|
762
|
-
const autoUpdate =
|
|
857
|
+
const autoUpdate = settingsInstance.get("marketplace.autoUpdate");
|
|
763
858
|
if (autoUpdate !== "off") {
|
|
764
859
|
void (async () => {
|
|
765
860
|
try {
|
|
@@ -793,6 +888,7 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
793
888
|
scopedModels,
|
|
794
889
|
sessionManager,
|
|
795
890
|
modelRegistry,
|
|
891
|
+
settingsInstance,
|
|
796
892
|
);
|
|
797
893
|
sessionOptions.authStorage = authStorage;
|
|
798
894
|
sessionOptions.modelRegistry = modelRegistry;
|
|
@@ -812,137 +908,111 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
812
908
|
}
|
|
813
909
|
}
|
|
814
910
|
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
createAgentSession,
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (parsedArgs.apiKey && !sessionOptions.model && session.model) {
|
|
825
|
-
authStorage.setRuntimeApiKey(session.model.provider, parsedArgs.apiKey);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
if (modelFallbackMessage) {
|
|
829
|
-
notifs.push({ kind: "warn", message: modelFallbackMessage });
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
const modelRegistryError = modelRegistry.getError();
|
|
833
|
-
if (modelRegistryError) {
|
|
834
|
-
notifs.push({ kind: "error", message: modelRegistryError.message });
|
|
835
|
-
}
|
|
911
|
+
const createAgentSessionImpl = deps.createAgentSession ?? createAgentSession;
|
|
912
|
+
const createSession = async (options: CreateAgentSessionOptions): Promise<CreateAgentSessionResult> => {
|
|
913
|
+
const result = await logger.time("createAgentSession", createAgentSessionImpl, options);
|
|
914
|
+
// Kick off background model discovery only after createAgentSession finishes its parallel
|
|
915
|
+
// discovery arms; running these concurrently contends for the event loop and stretches
|
|
916
|
+
// every parallel arm by ~30ms.
|
|
917
|
+
modelRegistry.refreshInBackground();
|
|
918
|
+
return result;
|
|
919
|
+
};
|
|
836
920
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
if (i + 1 < rawArgs.length) {
|
|
856
|
-
session.extensionRunner.setFlagValue(flagName, rawArgs[++i]);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
921
|
+
if (mode === "acp") {
|
|
922
|
+
const createAcpSession = createAcpSessionFactory({
|
|
923
|
+
baseOptions: sessionOptions,
|
|
924
|
+
settings: settingsInstance,
|
|
925
|
+
sessionDir: parsedArgs.sessionDir,
|
|
926
|
+
authStorage,
|
|
927
|
+
modelRegistry,
|
|
928
|
+
parsedArgs,
|
|
929
|
+
rawArgs,
|
|
930
|
+
createSession,
|
|
931
|
+
});
|
|
932
|
+
await (deps.runAcpMode ?? runAcpMode)(createAcpSession);
|
|
933
|
+
} else {
|
|
934
|
+
const { session, setToolUIContext, modelFallbackMessage, lspServers, mcpManager, eventBus } =
|
|
935
|
+
await createSession(sessionOptions);
|
|
936
|
+
if (parsedArgs.apiKey && !sessionOptions.model && session.model) {
|
|
937
|
+
authStorage.setRuntimeApiKey(session.model.provider, parsedArgs.apiKey);
|
|
859
938
|
}
|
|
860
|
-
}
|
|
861
939
|
|
|
862
|
-
if (!isInteractive && parsedArgs.mode !== "acp" && !session.model) {
|
|
863
940
|
if (modelFallbackMessage) {
|
|
864
|
-
|
|
865
|
-
} else {
|
|
866
|
-
process.stderr.write(`${chalk.red("No models available.")}\n`);
|
|
941
|
+
notifs.push({ kind: "warn", message: modelFallbackMessage });
|
|
867
942
|
}
|
|
868
|
-
process.stderr.write(`${chalk.yellow("\nSet an API key environment variable:")}\n`);
|
|
869
|
-
process.stderr.write(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\n");
|
|
870
|
-
process.stderr.write(`${chalk.yellow(`\nOr create ${ModelsConfigFile.path()}`)}\n`);
|
|
871
|
-
process.exit(1);
|
|
872
|
-
}
|
|
873
943
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const nextSessionManager = SessionManager.create(cwd, parsedArgs.sessionDir);
|
|
878
|
-
const { session: nextSession } = await createAgentSession({
|
|
879
|
-
...sessionOptions,
|
|
880
|
-
cwd,
|
|
881
|
-
sessionManager: nextSessionManager,
|
|
882
|
-
settings: nextSettings,
|
|
883
|
-
authStorage,
|
|
884
|
-
modelRegistry,
|
|
885
|
-
hasUI: false,
|
|
886
|
-
});
|
|
887
|
-
if (nextSession.extensionRunner) {
|
|
888
|
-
for (const [flagName, value] of extensionFlagValues) {
|
|
889
|
-
nextSession.extensionRunner.setFlagValue(flagName, value);
|
|
890
|
-
}
|
|
944
|
+
const modelRegistryError = modelRegistry.getError();
|
|
945
|
+
if (modelRegistryError) {
|
|
946
|
+
notifs.push({ kind: "error", message: modelRegistryError.message });
|
|
891
947
|
}
|
|
892
|
-
return nextSession;
|
|
893
|
-
};
|
|
894
948
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
|
|
904
|
-
if (scopedModelsForDisplay.length > 0) {
|
|
905
|
-
const modelList = scopedModelsForDisplay
|
|
906
|
-
.map(scopedModel => {
|
|
907
|
-
const thinkingStr = !scopedModel.thinkingLevel ? `:${scopedModel.thinkingLevel}` : "";
|
|
908
|
-
return `${scopedModel.model.id}${thinkingStr}`;
|
|
909
|
-
})
|
|
910
|
-
.join(", ");
|
|
911
|
-
process.stdout.write(`${chalk.dim(`Model scope: ${modelList} ${chalk.gray("(Ctrl+P to cycle)")}`)}\n`);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
if ($env.PI_TIMING) {
|
|
915
|
-
logger.printTimings();
|
|
916
|
-
if ($env.PI_TIMING === "x") {
|
|
917
|
-
process.exit(0);
|
|
949
|
+
applyExtensionFlagValues(session, rawArgs);
|
|
950
|
+
|
|
951
|
+
if (!isInteractive && !session.model) {
|
|
952
|
+
if (modelFallbackMessage) {
|
|
953
|
+
process.stderr.write(`${chalk.red(modelFallbackMessage)}\n`);
|
|
954
|
+
} else {
|
|
955
|
+
process.stderr.write(`${chalk.red("No models available.")}\n`);
|
|
918
956
|
}
|
|
957
|
+
process.stderr.write(`${chalk.yellow("\nSet an API key environment variable:")}\n`);
|
|
958
|
+
process.stderr.write(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\n");
|
|
959
|
+
process.stderr.write(`${chalk.yellow(`\nOr create ${ModelsConfigFile.path()}`)}\n`);
|
|
960
|
+
process.exit(1);
|
|
919
961
|
}
|
|
920
962
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
VERSION
|
|
925
|
-
changelogMarkdown,
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
963
|
+
if (mode === "rpc" || mode === "rpc-ui") {
|
|
964
|
+
await runRpcMode(session, mode === "rpc-ui" ? setToolUIContext : undefined);
|
|
965
|
+
} else if (isInteractive) {
|
|
966
|
+
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
|
|
967
|
+
const changelogMarkdown = await logger.time("main:getChangelogForDisplay", getChangelogForDisplay, parsedArgs);
|
|
968
|
+
|
|
969
|
+
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
|
|
970
|
+
if (scopedModelsForDisplay.length > 0) {
|
|
971
|
+
const modelList = scopedModelsForDisplay
|
|
972
|
+
.map(scopedModel => {
|
|
973
|
+
const thinkingStr = !scopedModel.thinkingLevel ? `:${scopedModel.thinkingLevel}` : "";
|
|
974
|
+
return `${scopedModel.model.id}${thinkingStr}`;
|
|
975
|
+
})
|
|
976
|
+
.join(", ");
|
|
977
|
+
process.stdout.write(`${chalk.dim(`Model scope: ${modelList} ${chalk.gray("(Ctrl+P to cycle)")}`)}\n`);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if ($env.PI_TIMING) {
|
|
981
|
+
logger.printTimings();
|
|
982
|
+
if ($env.PI_TIMING === "x") {
|
|
983
|
+
process.exit(0);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
logger.endTiming();
|
|
988
|
+
await runInteractiveMode(
|
|
989
|
+
session,
|
|
990
|
+
VERSION,
|
|
991
|
+
changelogMarkdown,
|
|
992
|
+
notifs,
|
|
993
|
+
versionCheckPromise,
|
|
994
|
+
parsedArgs.messages,
|
|
995
|
+
setToolUIContext,
|
|
996
|
+
lspServers,
|
|
997
|
+
mcpManager,
|
|
998
|
+
eventBus,
|
|
999
|
+
initialMessage,
|
|
1000
|
+
initialImages,
|
|
1001
|
+
);
|
|
1002
|
+
} else {
|
|
1003
|
+
await runPrintMode(session, {
|
|
1004
|
+
mode,
|
|
1005
|
+
messages: parsedArgs.messages,
|
|
1006
|
+
initialMessage,
|
|
1007
|
+
initialImages,
|
|
1008
|
+
});
|
|
1009
|
+
if ($env.PI_TIMING) {
|
|
1010
|
+
logger.printTimings();
|
|
1011
|
+
}
|
|
1012
|
+
await session.dispose();
|
|
1013
|
+
stopThemeWatcher();
|
|
1014
|
+
await postmortem.quit(0);
|
|
1015
|
+
}
|
|
946
1016
|
}
|
|
947
1017
|
}
|
|
948
1018
|
|