@oh-my-pi/pi-coding-agent 1.340.0 → 2.0.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 +115 -1
- package/README.md +1 -1
- package/examples/custom-tools/subagent/index.ts +1 -1
- package/package.json +5 -3
- package/src/cli/args.ts +13 -6
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +2 -2
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/session-picker.ts +2 -2
- package/src/cli.ts +1 -1
- package/src/config.ts +3 -3
- package/src/core/agent-session.ts +189 -29
- package/src/core/bash-executor.ts +50 -10
- package/src/core/compaction/branch-summarization.ts +5 -5
- package/src/core/compaction/compaction.ts +3 -3
- package/src/core/compaction/index.ts +3 -3
- package/src/core/custom-commands/bundled/review/index.ts +156 -0
- package/src/core/custom-commands/index.ts +15 -0
- package/src/core/custom-commands/loader.ts +232 -0
- package/src/core/custom-commands/types.ts +112 -0
- package/src/core/custom-tools/index.ts +3 -3
- package/src/core/custom-tools/loader.ts +10 -8
- package/src/core/custom-tools/types.ts +11 -6
- package/src/core/custom-tools/wrapper.ts +2 -1
- package/src/core/exec.ts +22 -12
- package/src/core/export-html/index.ts +5 -5
- package/src/core/file-mentions.ts +54 -0
- package/src/core/hooks/index.ts +5 -5
- package/src/core/hooks/loader.ts +21 -16
- package/src/core/hooks/runner.ts +6 -6
- package/src/core/hooks/tool-wrapper.ts +2 -2
- package/src/core/hooks/types.ts +12 -15
- package/src/core/index.ts +6 -6
- package/src/core/logger.ts +112 -0
- package/src/core/mcp/client.ts +3 -3
- package/src/core/mcp/config.ts +1 -1
- package/src/core/mcp/index.ts +12 -12
- package/src/core/mcp/loader.ts +2 -2
- package/src/core/mcp/manager.ts +6 -6
- package/src/core/mcp/tool-bridge.ts +3 -3
- package/src/core/mcp/transports/http.ts +1 -1
- package/src/core/mcp/transports/index.ts +2 -2
- package/src/core/mcp/transports/stdio.ts +1 -1
- package/src/core/messages.ts +22 -0
- package/src/core/model-registry.ts +2 -2
- package/src/core/model-resolver.ts +103 -2
- package/src/core/plugins/doctor.ts +1 -1
- package/src/core/plugins/index.ts +6 -6
- package/src/core/plugins/installer.ts +4 -4
- package/src/core/plugins/loader.ts +4 -9
- package/src/core/plugins/manager.ts +5 -5
- package/src/core/plugins/paths.ts +3 -3
- package/src/core/sdk.ts +127 -52
- package/src/core/session-manager.ts +123 -20
- package/src/core/settings-manager.ts +106 -22
- package/src/core/skills.ts +5 -5
- package/src/core/slash-commands.ts +60 -45
- package/src/core/system-prompt.ts +6 -6
- package/src/core/title-generator.ts +94 -0
- package/src/core/tools/bash.ts +33 -157
- package/src/core/tools/context.ts +2 -2
- package/src/core/tools/edit-diff.ts +5 -5
- package/src/core/tools/edit.ts +60 -9
- package/src/core/tools/exa/company.ts +3 -3
- package/src/core/tools/exa/index.ts +16 -17
- package/src/core/tools/exa/linkedin.ts +3 -3
- package/src/core/tools/exa/mcp-client.ts +9 -9
- package/src/core/tools/exa/render.ts +5 -5
- package/src/core/tools/exa/researcher.ts +3 -3
- package/src/core/tools/exa/search.ts +6 -5
- package/src/core/tools/exa/types.ts +5 -6
- package/src/core/tools/exa/websets.ts +3 -3
- package/src/core/tools/find.ts +3 -3
- package/src/core/tools/grep.ts +6 -5
- package/src/core/tools/index.ts +114 -40
- package/src/core/tools/ls.ts +4 -4
- package/src/core/tools/lsp/client.ts +204 -108
- package/src/core/tools/lsp/config.ts +709 -35
- package/src/core/tools/lsp/edits.ts +2 -2
- package/src/core/tools/lsp/index.ts +432 -30
- package/src/core/tools/lsp/render.ts +2 -2
- package/src/core/tools/lsp/rust-analyzer.ts +3 -3
- package/src/core/tools/lsp/types.ts +5 -0
- package/src/core/tools/lsp/utils.ts +1 -1
- package/src/core/tools/notebook.ts +1 -1
- package/src/core/tools/output.ts +175 -0
- package/src/core/tools/read.ts +7 -7
- package/src/core/tools/renderers.ts +92 -13
- package/src/core/tools/review.ts +268 -0
- package/src/core/tools/task/agents.ts +1 -1
- package/src/core/tools/task/bundled-agents/explore.md +1 -1
- package/src/core/tools/task/bundled-agents/reviewer.md +53 -38
- package/src/core/tools/task/discovery.ts +2 -2
- package/src/core/tools/task/executor.ts +145 -28
- package/src/core/tools/task/index.ts +78 -30
- package/src/core/tools/task/model-resolver.ts +72 -13
- package/src/core/tools/task/parallel.ts +1 -1
- package/src/core/tools/task/render.ts +219 -30
- package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
- package/src/core/tools/task/types.ts +36 -2
- package/src/core/tools/web-fetch.ts +5 -3
- package/src/core/tools/web-search/auth.ts +1 -1
- package/src/core/tools/web-search/index.ts +17 -15
- package/src/core/tools/web-search/providers/anthropic.ts +2 -2
- package/src/core/tools/web-search/providers/exa.ts +3 -5
- package/src/core/tools/web-search/providers/perplexity.ts +1 -1
- package/src/core/tools/web-search/render.ts +3 -3
- package/src/core/tools/write.ts +70 -7
- package/src/index.ts +33 -17
- package/src/main.ts +60 -34
- package/src/migrations.ts +3 -3
- package/src/modes/index.ts +5 -5
- package/src/modes/interactive/components/armin.ts +1 -1
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/bash-execution.ts +4 -4
- package/src/modes/interactive/components/bordered-loader.ts +2 -2
- package/src/modes/interactive/components/branch-summary-message.ts +2 -2
- package/src/modes/interactive/components/compaction-summary-message.ts +2 -2
- package/src/modes/interactive/components/diff.ts +1 -1
- package/src/modes/interactive/components/dynamic-border.ts +1 -1
- package/src/modes/interactive/components/footer.ts +5 -5
- package/src/modes/interactive/components/hook-editor.ts +2 -2
- package/src/modes/interactive/components/hook-input.ts +2 -2
- package/src/modes/interactive/components/hook-message.ts +3 -3
- package/src/modes/interactive/components/hook-selector.ts +2 -2
- package/src/modes/interactive/components/model-selector.ts +341 -41
- package/src/modes/interactive/components/oauth-selector.ts +3 -3
- package/src/modes/interactive/components/plugin-settings.ts +4 -4
- package/src/modes/interactive/components/queue-mode-selector.ts +2 -2
- package/src/modes/interactive/components/session-selector.ts +24 -11
- package/src/modes/interactive/components/settings-defs.ts +51 -3
- package/src/modes/interactive/components/settings-selector.ts +13 -16
- package/src/modes/interactive/components/show-images-selector.ts +2 -2
- package/src/modes/interactive/components/theme-selector.ts +2 -2
- package/src/modes/interactive/components/thinking-selector.ts +2 -2
- package/src/modes/interactive/components/tool-execution.ts +44 -8
- package/src/modes/interactive/components/tree-selector.ts +5 -5
- package/src/modes/interactive/components/user-message-selector.ts +2 -2
- package/src/modes/interactive/components/user-message.ts +1 -1
- package/src/modes/interactive/components/welcome.ts +42 -5
- package/src/modes/interactive/interactive-mode.ts +169 -48
- package/src/modes/interactive/theme/theme.ts +8 -7
- package/src/modes/print-mode.ts +4 -3
- package/src/modes/rpc/rpc-client.ts +4 -4
- package/src/modes/rpc/rpc-mode.ts +21 -11
- package/src/modes/rpc/rpc-types.ts +3 -3
- package/src/utils/changelog.ts +2 -2
- package/src/utils/clipboard.ts +1 -1
- package/src/utils/shell-snapshot.ts +218 -0
- package/src/utils/shell.ts +93 -13
- package/src/utils/tools-manager.ts +1 -1
- package/examples/custom-tools/subagent/agents/reviewer.md +0 -35
- package/src/core/tools/exa/logger.ts +0 -56
|
@@ -6,8 +6,8 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
6
6
|
import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai";
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import { minimatch } from "minimatch";
|
|
9
|
-
import { isValidThinkingLevel } from "../cli/args
|
|
10
|
-
import type { ModelRegistry } from "./model-registry
|
|
9
|
+
import { isValidThinkingLevel } from "../cli/args";
|
|
10
|
+
import type { ModelRegistry } from "./model-registry";
|
|
11
11
|
|
|
12
12
|
/** Default model IDs for each known provider */
|
|
13
13
|
export const defaultModelPerProvider: Record<KnownProvider, string> = {
|
|
@@ -30,6 +30,29 @@ export interface ScopedModel {
|
|
|
30
30
|
thinkingLevel: ThinkingLevel;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/** Priority chain for auto-discovering smol/fast models */
|
|
34
|
+
export const SMOL_MODEL_PRIORITY = ["claude-haiku-4-5", "haiku", "flash", "mini"];
|
|
35
|
+
|
|
36
|
+
/** Priority chain for auto-discovering slow/comprehensive models (reasoning, codex) */
|
|
37
|
+
export const SLOW_MODEL_PRIORITY = ["gpt-5.2-codex", "gpt-5.2", "codex", "gpt", "opus", "pro"];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse a model string in "provider/modelId" format.
|
|
41
|
+
* Returns undefined if the format is invalid.
|
|
42
|
+
*/
|
|
43
|
+
export function parseModelString(modelStr: string): { provider: string; id: string } | undefined {
|
|
44
|
+
const slashIdx = modelStr.indexOf("/");
|
|
45
|
+
if (slashIdx <= 0) return undefined;
|
|
46
|
+
return { provider: modelStr.slice(0, slashIdx), id: modelStr.slice(slashIdx + 1) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Format a model as "provider/modelId" string.
|
|
51
|
+
*/
|
|
52
|
+
export function formatModelString(model: Model<Api>): string {
|
|
53
|
+
return `${model.provider}/${model.id}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
33
56
|
/**
|
|
34
57
|
* Helper to check if a model ID looks like an alias (no date suffix)
|
|
35
58
|
* Dates are typically in format: -20241022 or -20250929
|
|
@@ -391,3 +414,81 @@ export async function restoreModelFromSession(
|
|
|
391
414
|
// No models available
|
|
392
415
|
return { model: undefined, fallbackMessage: undefined };
|
|
393
416
|
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Find a smol/fast model using the priority chain.
|
|
420
|
+
* Tries exact matches first, then fuzzy matches.
|
|
421
|
+
*
|
|
422
|
+
* @param modelRegistry The model registry to search
|
|
423
|
+
* @param savedModel Optional saved model string from settings (provider/modelId)
|
|
424
|
+
* @returns The best available smol model, or undefined if none found
|
|
425
|
+
*/
|
|
426
|
+
export async function findSmolModel(
|
|
427
|
+
modelRegistry: ModelRegistry,
|
|
428
|
+
savedModel?: string,
|
|
429
|
+
): Promise<Model<Api> | undefined> {
|
|
430
|
+
const availableModels = await modelRegistry.getAvailable();
|
|
431
|
+
if (availableModels.length === 0) return undefined;
|
|
432
|
+
|
|
433
|
+
// 1. Try saved model from settings
|
|
434
|
+
if (savedModel) {
|
|
435
|
+
const parsed = parseModelString(savedModel);
|
|
436
|
+
if (parsed) {
|
|
437
|
+
const match = availableModels.find((m) => m.provider === parsed.provider && m.id === parsed.id);
|
|
438
|
+
if (match) return match;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// 2. Try priority chain
|
|
443
|
+
for (const pattern of SMOL_MODEL_PRIORITY) {
|
|
444
|
+
// Try exact match first
|
|
445
|
+
const exactMatch = availableModels.find((m) => m.id.toLowerCase() === pattern.toLowerCase());
|
|
446
|
+
if (exactMatch) return exactMatch;
|
|
447
|
+
|
|
448
|
+
// Try fuzzy match (substring)
|
|
449
|
+
const fuzzyMatch = availableModels.find((m) => m.id.toLowerCase().includes(pattern.toLowerCase()));
|
|
450
|
+
if (fuzzyMatch) return fuzzyMatch;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// 3. Fallback to first available (same as default)
|
|
454
|
+
return availableModels[0];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Find a slow/comprehensive model using the priority chain.
|
|
459
|
+
* Prioritizes reasoning and codex models for thorough analysis.
|
|
460
|
+
*
|
|
461
|
+
* @param modelRegistry The model registry to search
|
|
462
|
+
* @param savedModel Optional saved model string from settings (provider/modelId)
|
|
463
|
+
* @returns The best available slow model, or undefined if none found
|
|
464
|
+
*/
|
|
465
|
+
export async function findSlowModel(
|
|
466
|
+
modelRegistry: ModelRegistry,
|
|
467
|
+
savedModel?: string,
|
|
468
|
+
): Promise<Model<Api> | undefined> {
|
|
469
|
+
const availableModels = await modelRegistry.getAvailable();
|
|
470
|
+
if (availableModels.length === 0) return undefined;
|
|
471
|
+
|
|
472
|
+
// 1. Try saved model from settings
|
|
473
|
+
if (savedModel) {
|
|
474
|
+
const parsed = parseModelString(savedModel);
|
|
475
|
+
if (parsed) {
|
|
476
|
+
const match = availableModels.find((m) => m.provider === parsed.provider && m.id === parsed.id);
|
|
477
|
+
if (match) return match;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// 2. Try priority chain
|
|
482
|
+
for (const pattern of SLOW_MODEL_PRIORITY) {
|
|
483
|
+
// Try exact match first
|
|
484
|
+
const exactMatch = availableModels.find((m) => m.id.toLowerCase() === pattern.toLowerCase());
|
|
485
|
+
if (exactMatch) return exactMatch;
|
|
486
|
+
|
|
487
|
+
// Try fuzzy match (substring)
|
|
488
|
+
const fuzzyMatch = availableModels.find((m) => m.id.toLowerCase().includes(pattern.toLowerCase()));
|
|
489
|
+
if (fuzzyMatch) return fuzzyMatch;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// 3. Fallback to first available (same as default)
|
|
493
|
+
return availableModels[0];
|
|
494
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Plugin system exports
|
|
2
|
-
export { formatDoctorResults, runDoctorChecks } from "./doctor
|
|
2
|
+
export { formatDoctorResults, runDoctorChecks } from "./doctor";
|
|
3
3
|
export {
|
|
4
4
|
getAllPluginCommandPaths,
|
|
5
5
|
getAllPluginHookPaths,
|
|
@@ -9,16 +9,16 @@ export {
|
|
|
9
9
|
resolvePluginCommandPaths,
|
|
10
10
|
resolvePluginHookPaths,
|
|
11
11
|
resolvePluginToolPaths,
|
|
12
|
-
} from "./loader
|
|
13
|
-
export { PluginManager, parseSettingValue, validateSetting } from "./manager
|
|
14
|
-
export { extractPackageName, formatPluginSpec, parsePluginSpec } from "./parser
|
|
12
|
+
} from "./loader";
|
|
13
|
+
export { PluginManager, parseSettingValue, validateSetting } from "./manager";
|
|
14
|
+
export { extractPackageName, formatPluginSpec, parsePluginSpec } from "./parser";
|
|
15
15
|
export {
|
|
16
16
|
getPluginsDir,
|
|
17
17
|
getPluginsLockfile,
|
|
18
18
|
getPluginsNodeModules,
|
|
19
19
|
getPluginsPackageJson,
|
|
20
20
|
getProjectPluginOverrides,
|
|
21
|
-
} from "./paths
|
|
21
|
+
} from "./paths";
|
|
22
22
|
export type {
|
|
23
23
|
BooleanSetting,
|
|
24
24
|
DoctorCheck,
|
|
@@ -35,4 +35,4 @@ export type {
|
|
|
35
35
|
PluginSettingType,
|
|
36
36
|
ProjectPluginOverrides,
|
|
37
37
|
StringSetting,
|
|
38
|
-
} from "./types
|
|
38
|
+
} from "./types";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { mkdir } from "fs/promises";
|
|
2
|
-
import { join, resolve } from "path";
|
|
3
|
-
import { getAgentDir } from "../../config
|
|
4
|
-
import type { InstalledPlugin } from "./types
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { getAgentDir } from "../../config";
|
|
4
|
+
import type { InstalledPlugin } from "./types";
|
|
5
5
|
|
|
6
6
|
const PLUGINS_DIR = join(getAgentDir(), "plugins");
|
|
7
7
|
|
|
@@ -5,15 +5,10 @@
|
|
|
5
5
|
* based on manifest entries and enabled features.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { existsSync, readFileSync } from "fs";
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
getPluginsNodeModules,
|
|
13
|
-
getPluginsPackageJson,
|
|
14
|
-
getProjectPluginOverrides,
|
|
15
|
-
} from "./paths.js";
|
|
16
|
-
import type { InstalledPlugin, PluginManifest, PluginRuntimeConfig, ProjectPluginOverrides } from "./types.js";
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { getPluginsLockfile, getPluginsNodeModules, getPluginsPackageJson, getProjectPluginOverrides } from "./paths";
|
|
11
|
+
import type { InstalledPlugin, PluginManifest, PluginRuntimeConfig, ProjectPluginOverrides } from "./types";
|
|
17
12
|
|
|
18
13
|
// =============================================================================
|
|
19
14
|
// Runtime Config Loading
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, symlinkSync, unlinkSync, writeFileSync } from "fs";
|
|
2
|
-
import { join, resolve } from "path";
|
|
3
|
-
import { extractPackageName, parsePluginSpec } from "./parser
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { extractPackageName, parsePluginSpec } from "./parser";
|
|
4
4
|
import {
|
|
5
5
|
getPluginsDir,
|
|
6
6
|
getPluginsLockfile,
|
|
7
7
|
getPluginsNodeModules,
|
|
8
8
|
getPluginsPackageJson,
|
|
9
9
|
getProjectPluginOverrides,
|
|
10
|
-
} from "./paths
|
|
10
|
+
} from "./paths";
|
|
11
11
|
import type {
|
|
12
12
|
DoctorCheck,
|
|
13
13
|
DoctorOptions,
|
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
PluginRuntimeConfig,
|
|
18
18
|
PluginSettingSchema,
|
|
19
19
|
ProjectPluginOverrides,
|
|
20
|
-
} from "./types
|
|
20
|
+
} from "./types";
|
|
21
21
|
|
|
22
22
|
// =============================================================================
|
|
23
23
|
// Validation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { homedir } from "os";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { CONFIG_DIR_NAME } from "../../config
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CONFIG_DIR_NAME } from "../../config";
|
|
4
4
|
|
|
5
5
|
// =============================================================================
|
|
6
6
|
// Plugin Directory Paths
|
package/src/core/sdk.ts
CHANGED
|
@@ -29,34 +29,38 @@
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
+
import { join } from "node:path";
|
|
32
33
|
import { Agent, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
33
34
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
35
|
+
import { getAgentDir } from "../config";
|
|
36
|
+
import { AgentSession } from "./agent-session";
|
|
37
|
+
import { AuthStorage } from "./auth-storage";
|
|
38
|
+
import {
|
|
39
|
+
type CustomCommandsLoadResult,
|
|
40
|
+
loadCustomCommands as loadCustomCommandsInternal,
|
|
41
|
+
} from "./custom-commands/index";
|
|
38
42
|
import {
|
|
39
43
|
type CustomToolsLoadResult,
|
|
40
44
|
discoverAndLoadCustomTools,
|
|
41
45
|
type LoadedCustomTool,
|
|
42
46
|
wrapCustomTools,
|
|
43
|
-
} from "./custom-tools/index
|
|
44
|
-
import type { CustomTool } from "./custom-tools/types
|
|
45
|
-
import { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from "./hooks/index
|
|
46
|
-
import type { HookFactory } from "./hooks/types
|
|
47
|
-
import { discoverAndLoadMCPTools, type MCPManager, type MCPToolsLoadResult } from "./mcp/index
|
|
48
|
-
import { convertToLlm } from "./messages
|
|
49
|
-
import { ModelRegistry } from "./model-registry
|
|
50
|
-
import { SessionManager } from "./session-manager
|
|
51
|
-
import { type Settings, SettingsManager, type SkillsSettings } from "./settings-manager
|
|
52
|
-
import { loadSkills as loadSkillsInternal, type Skill } from "./skills
|
|
53
|
-
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./slash-commands
|
|
47
|
+
} from "./custom-tools/index";
|
|
48
|
+
import type { CustomTool } from "./custom-tools/types";
|
|
49
|
+
import { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from "./hooks/index";
|
|
50
|
+
import type { HookFactory } from "./hooks/types";
|
|
51
|
+
import { discoverAndLoadMCPTools, type MCPManager, type MCPToolsLoadResult } from "./mcp/index";
|
|
52
|
+
import { convertToLlm } from "./messages";
|
|
53
|
+
import { ModelRegistry } from "./model-registry";
|
|
54
|
+
import { SessionManager } from "./session-manager";
|
|
55
|
+
import { type CommandsSettings, type Settings, SettingsManager, type SkillsSettings } from "./settings-manager";
|
|
56
|
+
import { loadSkills as loadSkillsInternal, type Skill } from "./skills";
|
|
57
|
+
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./slash-commands";
|
|
54
58
|
import {
|
|
55
59
|
buildSystemPrompt as buildSystemPromptInternal,
|
|
56
60
|
loadProjectContextFiles as loadContextFilesInternal,
|
|
57
|
-
} from "./system-prompt
|
|
58
|
-
import { time } from "./timings
|
|
59
|
-
import { createToolContextStore } from "./tools/context
|
|
61
|
+
} from "./system-prompt";
|
|
62
|
+
import { time } from "./timings";
|
|
63
|
+
import { createToolContextStore } from "./tools/context";
|
|
60
64
|
import {
|
|
61
65
|
allTools,
|
|
62
66
|
applyBashInterception,
|
|
@@ -78,8 +82,9 @@ import {
|
|
|
78
82
|
readOnlyTools,
|
|
79
83
|
readTool,
|
|
80
84
|
type Tool,
|
|
85
|
+
warmupLspServers,
|
|
81
86
|
writeTool,
|
|
82
|
-
} from "./tools/index
|
|
87
|
+
} from "./tools/index";
|
|
83
88
|
|
|
84
89
|
// Types
|
|
85
90
|
|
|
@@ -126,6 +131,9 @@ export interface CreateAgentSessionOptions {
|
|
|
126
131
|
/** Enable MCP server discovery from .mcp.json files. Default: true */
|
|
127
132
|
enableMCP?: boolean;
|
|
128
133
|
|
|
134
|
+
/** Tool names explicitly requested (enables disabled-by-default tools) */
|
|
135
|
+
explicitTools?: string[];
|
|
136
|
+
|
|
129
137
|
/** Session manager. Default: SessionManager.create(cwd) */
|
|
130
138
|
sessionManager?: SessionManager;
|
|
131
139
|
|
|
@@ -146,17 +154,20 @@ export interface CreateAgentSessionResult {
|
|
|
146
154
|
mcpManager?: MCPManager;
|
|
147
155
|
/** Warning if session was restored with a different model than saved */
|
|
148
156
|
modelFallbackMessage?: string;
|
|
157
|
+
/** LSP servers that were warmed up at startup */
|
|
158
|
+
lspServers?: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }>;
|
|
149
159
|
}
|
|
150
160
|
|
|
151
161
|
// Re-exports
|
|
152
162
|
|
|
153
|
-
export type {
|
|
154
|
-
export type {
|
|
155
|
-
export type {
|
|
156
|
-
export type {
|
|
157
|
-
export type {
|
|
158
|
-
export type {
|
|
159
|
-
export type {
|
|
163
|
+
export type { CustomCommand, CustomCommandFactory } from "./custom-commands/types";
|
|
164
|
+
export type { CustomTool } from "./custom-tools/types";
|
|
165
|
+
export type { HookAPI, HookCommandContext, HookContext, HookFactory } from "./hooks/types";
|
|
166
|
+
export type { MCPManager, MCPServerConfig, MCPServerConnection, MCPToolsLoadResult } from "./mcp/index";
|
|
167
|
+
export type { Settings, SkillsSettings } from "./settings-manager";
|
|
168
|
+
export type { Skill } from "./skills";
|
|
169
|
+
export type { FileSlashCommand } from "./slash-commands";
|
|
170
|
+
export type { Tool } from "./tools/index";
|
|
160
171
|
|
|
161
172
|
export {
|
|
162
173
|
// Pre-built tools (use process.cwd())
|
|
@@ -275,10 +286,29 @@ export function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ p
|
|
|
275
286
|
/**
|
|
276
287
|
* Discover slash commands from cwd and agentDir.
|
|
277
288
|
*/
|
|
278
|
-
export function discoverSlashCommands(
|
|
289
|
+
export function discoverSlashCommands(
|
|
290
|
+
cwd?: string,
|
|
291
|
+
agentDir?: string,
|
|
292
|
+
settings?: CommandsSettings,
|
|
293
|
+
): FileSlashCommand[] {
|
|
279
294
|
return loadSlashCommandsInternal({
|
|
280
295
|
cwd: cwd ?? process.cwd(),
|
|
281
296
|
agentDir: agentDir ?? getDefaultAgentDir(),
|
|
297
|
+
enableClaudeUser: settings?.enableClaudeUser,
|
|
298
|
+
enableClaudeProject: settings?.enableClaudeProject,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Discover custom commands (TypeScript slash commands) from cwd and agentDir.
|
|
304
|
+
*/
|
|
305
|
+
export async function discoverCustomTSCommands(cwd?: string, agentDir?: string): Promise<CustomCommandsLoadResult> {
|
|
306
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
307
|
+
const resolvedAgentDir = agentDir ?? getDefaultAgentDir();
|
|
308
|
+
|
|
309
|
+
return loadCustomCommandsInternal({
|
|
310
|
+
cwd: resolvedCwd,
|
|
311
|
+
agentDir: resolvedAgentDir,
|
|
282
312
|
});
|
|
283
313
|
}
|
|
284
314
|
|
|
@@ -323,8 +353,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|
|
323
353
|
export function loadSettings(cwd?: string, agentDir?: string): Settings {
|
|
324
354
|
const manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());
|
|
325
355
|
return {
|
|
326
|
-
|
|
327
|
-
defaultModel: manager.getDefaultModel(),
|
|
356
|
+
modelRoles: manager.getModelRoles(),
|
|
328
357
|
defaultThinkingLevel: manager.getDefaultThinkingLevel(),
|
|
329
358
|
queueMode: manager.getQueueMode(),
|
|
330
359
|
theme: manager.getTheme(),
|
|
@@ -479,24 +508,34 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
479
508
|
let modelFallbackMessage: string | undefined;
|
|
480
509
|
|
|
481
510
|
// If session has data, try to restore model from it
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
511
|
+
const defaultModelStr = existingSession.models.default;
|
|
512
|
+
if (!model && hasExistingSession && defaultModelStr) {
|
|
513
|
+
const slashIdx = defaultModelStr.indexOf("/");
|
|
514
|
+
if (slashIdx > 0) {
|
|
515
|
+
const provider = defaultModelStr.slice(0, slashIdx);
|
|
516
|
+
const modelId = defaultModelStr.slice(slashIdx + 1);
|
|
517
|
+
const restoredModel = modelRegistry.find(provider, modelId);
|
|
518
|
+
if (restoredModel && (await modelRegistry.getApiKey(restoredModel))) {
|
|
519
|
+
model = restoredModel;
|
|
520
|
+
}
|
|
521
|
+
if (!model) {
|
|
522
|
+
modelFallbackMessage = `Could not restore model ${defaultModelStr}`;
|
|
523
|
+
}
|
|
489
524
|
}
|
|
490
525
|
}
|
|
491
526
|
|
|
492
527
|
// If still no model, try settings default
|
|
493
528
|
if (!model) {
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
529
|
+
const settingsDefaultModel = settingsManager.getModelRole("default");
|
|
530
|
+
if (settingsDefaultModel) {
|
|
531
|
+
const slashIdx = settingsDefaultModel.indexOf("/");
|
|
532
|
+
if (slashIdx > 0) {
|
|
533
|
+
const provider = settingsDefaultModel.slice(0, slashIdx);
|
|
534
|
+
const modelId = settingsDefaultModel.slice(slashIdx + 1);
|
|
535
|
+
const settingsModel = modelRegistry.find(provider, modelId);
|
|
536
|
+
if (settingsModel && (await modelRegistry.getApiKey(settingsModel))) {
|
|
537
|
+
model = settingsModel;
|
|
538
|
+
}
|
|
500
539
|
}
|
|
501
540
|
}
|
|
502
541
|
}
|
|
@@ -543,12 +582,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
543
582
|
const contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);
|
|
544
583
|
time("discoverContextFiles");
|
|
545
584
|
|
|
546
|
-
// Hook runner - created
|
|
547
|
-
let
|
|
585
|
+
// Hook runner - always created (needed for custom command context even without hooks)
|
|
586
|
+
let loadedHooks: LoadedHook[] = [];
|
|
548
587
|
if (options.hooks !== undefined) {
|
|
549
588
|
if (options.hooks.length > 0) {
|
|
550
|
-
|
|
551
|
-
hookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);
|
|
589
|
+
loadedHooks = createLoadedHooksFromDefinitions(options.hooks);
|
|
552
590
|
}
|
|
553
591
|
} else {
|
|
554
592
|
// Discover hooks, merging with additional paths
|
|
@@ -558,15 +596,21 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
558
596
|
for (const { path, error } of errors) {
|
|
559
597
|
console.error(`Failed to load hook "${path}": ${error}`);
|
|
560
598
|
}
|
|
561
|
-
|
|
562
|
-
hookRunner = new HookRunner(hooks, cwd, sessionManager, modelRegistry);
|
|
563
|
-
}
|
|
599
|
+
loadedHooks = hooks;
|
|
564
600
|
}
|
|
601
|
+
const hookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);
|
|
565
602
|
|
|
566
603
|
const sessionContext = {
|
|
567
604
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
568
605
|
};
|
|
569
|
-
const builtInTools =
|
|
606
|
+
const builtInTools =
|
|
607
|
+
options.tools ??
|
|
608
|
+
createCodingTools(cwd, options.hasUI ?? false, sessionContext, {
|
|
609
|
+
lspFormatOnWrite: settingsManager.getLspFormatOnWrite(),
|
|
610
|
+
lspDiagnosticsOnWrite: settingsManager.getLspDiagnosticsOnWrite(),
|
|
611
|
+
lspDiagnosticsOnEdit: settingsManager.getLspDiagnosticsOnEdit(),
|
|
612
|
+
editFuzzyMatch: settingsManager.getEditFuzzyMatch(),
|
|
613
|
+
});
|
|
570
614
|
time("createCodingTools");
|
|
571
615
|
|
|
572
616
|
let customToolsResult: CustomToolsLoadResult;
|
|
@@ -676,6 +720,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
676
720
|
};
|
|
677
721
|
|
|
678
722
|
let allToolsArray: Tool[] = [...builtInTools, ...wrappedCustomTools];
|
|
723
|
+
|
|
724
|
+
// Filter out hidden tools unless explicitly requested
|
|
725
|
+
if (options.explicitTools) {
|
|
726
|
+
const explicitSet = new Set(options.explicitTools);
|
|
727
|
+
allToolsArray = allToolsArray.filter((tool) => !tool.hidden || explicitSet.has(tool.name));
|
|
728
|
+
} else {
|
|
729
|
+
allToolsArray = allToolsArray.filter((tool) => !tool.hidden);
|
|
730
|
+
}
|
|
679
731
|
time("combineTools");
|
|
680
732
|
|
|
681
733
|
// Apply bash interception to redirect common shell patterns to proper tools (if enabled)
|
|
@@ -711,9 +763,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
711
763
|
systemPrompt = options.systemPrompt(defaultPrompt);
|
|
712
764
|
}
|
|
713
765
|
|
|
714
|
-
const
|
|
766
|
+
const commandsSettings = settingsManager.getCommandsSettings();
|
|
767
|
+
const slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir, commandsSettings);
|
|
715
768
|
time("discoverSlashCommands");
|
|
716
769
|
|
|
770
|
+
// Discover custom commands (TypeScript slash commands)
|
|
771
|
+
const customCommandsResult = await loadCustomCommandsInternal({ cwd, agentDir });
|
|
772
|
+
time("discoverCustomCommands");
|
|
773
|
+
for (const { path, error } of customCommandsResult.errors) {
|
|
774
|
+
console.error(`Failed to load custom command "${path}": ${error}`);
|
|
775
|
+
}
|
|
776
|
+
|
|
717
777
|
agent = new Agent({
|
|
718
778
|
initialState: {
|
|
719
779
|
systemPrompt,
|
|
@@ -728,6 +788,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
728
788
|
}
|
|
729
789
|
: undefined,
|
|
730
790
|
queueMode: settingsManager.getQueueMode(),
|
|
791
|
+
interruptMode: settingsManager.getInterruptMode(),
|
|
731
792
|
getToolContext: toolContextStore.getContext,
|
|
732
793
|
getApiKey: async () => {
|
|
733
794
|
const currentModel = agent.state.model;
|
|
@@ -749,7 +810,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
749
810
|
} else {
|
|
750
811
|
// Save initial model and thinking level for new sessions so they can be restored on resume
|
|
751
812
|
if (model) {
|
|
752
|
-
sessionManager.appendModelChange(model.provider
|
|
813
|
+
sessionManager.appendModelChange(`${model.provider}/${model.id}`);
|
|
753
814
|
}
|
|
754
815
|
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
755
816
|
}
|
|
@@ -762,15 +823,29 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
762
823
|
fileCommands: slashCommands,
|
|
763
824
|
hookRunner,
|
|
764
825
|
customTools: customToolsResult.tools,
|
|
826
|
+
customCommands: customCommandsResult.commands,
|
|
765
827
|
skillsSettings: settingsManager.getSkillsSettings(),
|
|
766
828
|
modelRegistry,
|
|
767
829
|
});
|
|
768
830
|
time("createAgentSession");
|
|
769
831
|
|
|
832
|
+
// Warm up LSP servers (connects to detected servers)
|
|
833
|
+
let lspServers: CreateAgentSessionResult["lspServers"];
|
|
834
|
+
if (settingsManager.getLspDiagnosticsOnWrite()) {
|
|
835
|
+
try {
|
|
836
|
+
const result = await warmupLspServers(cwd);
|
|
837
|
+
lspServers = result.servers;
|
|
838
|
+
time("warmupLspServers");
|
|
839
|
+
} catch {
|
|
840
|
+
// Ignore warmup errors
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
770
844
|
return {
|
|
771
845
|
session,
|
|
772
846
|
customToolsResult,
|
|
773
847
|
mcpManager,
|
|
774
848
|
modelFallbackMessage,
|
|
849
|
+
lspServers,
|
|
775
850
|
};
|
|
776
851
|
}
|