@oh-my-pi/pi-coding-agent 1.341.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 +73 -0
- package/README.md +1 -1
- package/examples/custom-tools/subagent/index.ts +1 -1
- package/package.json +5 -3
- package/src/cli/args.ts +5 -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 +157 -15
- 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 +2 -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 +77 -35
- package/src/core/session-manager.ts +6 -6
- package/src/core/settings-manager.ts +16 -3
- 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 +2 -2
- package/src/core/tools/bash.ts +32 -155
- package/src/core/tools/context.ts +2 -2
- package/src/core/tools/edit-diff.ts +3 -3
- package/src/core/tools/edit.ts +18 -5
- 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 +3 -3
- package/src/core/tools/index.ts +48 -34
- package/src/core/tools/ls.ts +4 -4
- package/src/core/tools/lsp/client.ts +161 -90
- package/src/core/tools/lsp/config.ts +1 -1
- package/src/core/tools/lsp/edits.ts +2 -2
- package/src/core/tools/lsp/index.ts +15 -13
- package/src/core/tools/lsp/render.ts +2 -2
- package/src/core/tools/lsp/rust-analyzer.ts +3 -3
- 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/reviewer.md +52 -37
- 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 +30 -20
- 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 +4 -4
- package/src/index.ts +29 -18
- package/src/main.ts +37 -32
- 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 +281 -59
- 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 +4 -4
- package/src/modes/interactive/components/settings-defs.ts +1 -1
- package/src/modes/interactive/components/settings-selector.ts +5 -5
- 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 +26 -8
- package/src/modes/interactive/components/tree-selector.ts +3 -3
- 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 +2 -2
- package/src/modes/interactive/interactive-mode.ts +85 -41
- 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
package/src/core/messages.ts
CHANGED
|
@@ -64,6 +64,19 @@ export interface CompactionSummaryMessage {
|
|
|
64
64
|
timestamp: number;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Message type for auto-read file mentions via @filepath syntax.
|
|
69
|
+
*/
|
|
70
|
+
export interface FileMentionMessage {
|
|
71
|
+
role: "fileMention";
|
|
72
|
+
files: Array<{
|
|
73
|
+
path: string;
|
|
74
|
+
content: string;
|
|
75
|
+
lineCount: number;
|
|
76
|
+
}>;
|
|
77
|
+
timestamp: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
// Extend CustomAgentMessages via declaration merging
|
|
68
81
|
declare module "@oh-my-pi/pi-agent-core" {
|
|
69
82
|
interface CustomAgentMessages {
|
|
@@ -71,6 +84,7 @@ declare module "@oh-my-pi/pi-agent-core" {
|
|
|
71
84
|
hookMessage: HookMessage;
|
|
72
85
|
branchSummary: BranchSummaryMessage;
|
|
73
86
|
compactionSummary: CompactionSummaryMessage;
|
|
87
|
+
fileMention: FileMentionMessage;
|
|
74
88
|
}
|
|
75
89
|
}
|
|
76
90
|
|
|
@@ -175,6 +189,14 @@ export function convertToLlm(messages: AgentMessage[]): Message[] {
|
|
|
175
189
|
],
|
|
176
190
|
timestamp: m.timestamp,
|
|
177
191
|
};
|
|
192
|
+
case "fileMention": {
|
|
193
|
+
const fileContents = m.files.map((f) => `<file path="${f.path}">\n${f.content}\n</file>`).join("\n\n");
|
|
194
|
+
return {
|
|
195
|
+
role: "user",
|
|
196
|
+
content: [{ type: "text" as const, text: `<system-reminder>\n${fileContents}\n</system-reminder>` }],
|
|
197
|
+
timestamp: m.timestamp,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
178
200
|
case "user":
|
|
179
201
|
case "assistant":
|
|
180
202
|
case "toolResult":
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Model registry - manages built-in and custom models, provides API key resolution.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
6
|
import {
|
|
6
7
|
type Api,
|
|
7
8
|
getGitHubCopilotBaseUrl,
|
|
@@ -13,8 +14,7 @@ import {
|
|
|
13
14
|
} from "@oh-my-pi/pi-ai";
|
|
14
15
|
import { type Static, Type } from "@sinclair/typebox";
|
|
15
16
|
import AjvModule from "ajv";
|
|
16
|
-
import {
|
|
17
|
-
import type { AuthStorage } from "./auth-storage.js";
|
|
17
|
+
import type { AuthStorage } from "./auth-storage";
|
|
18
18
|
|
|
19
19
|
const Ajv = (AjvModule as any).default || AjvModule;
|
|
20
20
|
|
|
@@ -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> = {
|
|
@@ -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,
|
|
@@ -80,7 +84,7 @@ import {
|
|
|
80
84
|
type Tool,
|
|
81
85
|
warmupLspServers,
|
|
82
86
|
writeTool,
|
|
83
|
-
} from "./tools/index
|
|
87
|
+
} from "./tools/index";
|
|
84
88
|
|
|
85
89
|
// Types
|
|
86
90
|
|
|
@@ -127,6 +131,9 @@ export interface CreateAgentSessionOptions {
|
|
|
127
131
|
/** Enable MCP server discovery from .mcp.json files. Default: true */
|
|
128
132
|
enableMCP?: boolean;
|
|
129
133
|
|
|
134
|
+
/** Tool names explicitly requested (enables disabled-by-default tools) */
|
|
135
|
+
explicitTools?: string[];
|
|
136
|
+
|
|
130
137
|
/** Session manager. Default: SessionManager.create(cwd) */
|
|
131
138
|
sessionManager?: SessionManager;
|
|
132
139
|
|
|
@@ -153,13 +160,14 @@ export interface CreateAgentSessionResult {
|
|
|
153
160
|
|
|
154
161
|
// Re-exports
|
|
155
162
|
|
|
156
|
-
export type {
|
|
157
|
-
export type {
|
|
158
|
-
export type {
|
|
159
|
-
export type {
|
|
160
|
-
export type {
|
|
161
|
-
export type {
|
|
162
|
-
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";
|
|
163
171
|
|
|
164
172
|
export {
|
|
165
173
|
// Pre-built tools (use process.cwd())
|
|
@@ -278,10 +286,29 @@ export function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ p
|
|
|
278
286
|
/**
|
|
279
287
|
* Discover slash commands from cwd and agentDir.
|
|
280
288
|
*/
|
|
281
|
-
export function discoverSlashCommands(
|
|
289
|
+
export function discoverSlashCommands(
|
|
290
|
+
cwd?: string,
|
|
291
|
+
agentDir?: string,
|
|
292
|
+
settings?: CommandsSettings,
|
|
293
|
+
): FileSlashCommand[] {
|
|
282
294
|
return loadSlashCommandsInternal({
|
|
283
295
|
cwd: cwd ?? process.cwd(),
|
|
284
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,
|
|
285
312
|
});
|
|
286
313
|
}
|
|
287
314
|
|
|
@@ -555,12 +582,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
555
582
|
const contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);
|
|
556
583
|
time("discoverContextFiles");
|
|
557
584
|
|
|
558
|
-
// Hook runner - created
|
|
559
|
-
let
|
|
585
|
+
// Hook runner - always created (needed for custom command context even without hooks)
|
|
586
|
+
let loadedHooks: LoadedHook[] = [];
|
|
560
587
|
if (options.hooks !== undefined) {
|
|
561
588
|
if (options.hooks.length > 0) {
|
|
562
|
-
|
|
563
|
-
hookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);
|
|
589
|
+
loadedHooks = createLoadedHooksFromDefinitions(options.hooks);
|
|
564
590
|
}
|
|
565
591
|
} else {
|
|
566
592
|
// Discover hooks, merging with additional paths
|
|
@@ -570,10 +596,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
570
596
|
for (const { path, error } of errors) {
|
|
571
597
|
console.error(`Failed to load hook "${path}": ${error}`);
|
|
572
598
|
}
|
|
573
|
-
|
|
574
|
-
hookRunner = new HookRunner(hooks, cwd, sessionManager, modelRegistry);
|
|
575
|
-
}
|
|
599
|
+
loadedHooks = hooks;
|
|
576
600
|
}
|
|
601
|
+
const hookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);
|
|
577
602
|
|
|
578
603
|
const sessionContext = {
|
|
579
604
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
@@ -695,6 +720,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
695
720
|
};
|
|
696
721
|
|
|
697
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
|
+
}
|
|
698
731
|
time("combineTools");
|
|
699
732
|
|
|
700
733
|
// Apply bash interception to redirect common shell patterns to proper tools (if enabled)
|
|
@@ -730,9 +763,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
730
763
|
systemPrompt = options.systemPrompt(defaultPrompt);
|
|
731
764
|
}
|
|
732
765
|
|
|
733
|
-
const
|
|
766
|
+
const commandsSettings = settingsManager.getCommandsSettings();
|
|
767
|
+
const slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir, commandsSettings);
|
|
734
768
|
time("discoverSlashCommands");
|
|
735
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
|
+
|
|
736
777
|
agent = new Agent({
|
|
737
778
|
initialState: {
|
|
738
779
|
systemPrompt,
|
|
@@ -782,6 +823,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
782
823
|
fileCommands: slashCommands,
|
|
783
824
|
hookRunner,
|
|
784
825
|
customTools: customToolsResult.tools,
|
|
826
|
+
customCommands: customCommandsResult.commands,
|
|
785
827
|
skillsSettings: settingsManager.getSkillsSettings(),
|
|
786
828
|
modelRegistry,
|
|
787
829
|
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
|
|
3
1
|
import {
|
|
4
2
|
appendFileSync,
|
|
5
3
|
closeSync,
|
|
@@ -11,16 +9,18 @@ import {
|
|
|
11
9
|
readSync,
|
|
12
10
|
statSync,
|
|
13
11
|
writeFileSync,
|
|
14
|
-
} from "fs";
|
|
15
|
-
import { join, resolve } from "path";
|
|
16
|
-
import {
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
15
|
+
import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
|
|
16
|
+
import { getAgentDir as getDefaultAgentDir } from "../config";
|
|
17
17
|
import {
|
|
18
18
|
type BashExecutionMessage,
|
|
19
19
|
createBranchSummaryMessage,
|
|
20
20
|
createCompactionSummaryMessage,
|
|
21
21
|
createHookMessage,
|
|
22
22
|
type HookMessage,
|
|
23
|
-
} from "./messages
|
|
23
|
+
} from "./messages";
|
|
24
24
|
|
|
25
25
|
export const CURRENT_SESSION_VERSION = 2;
|
|
26
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
-
import { dirname, join } from "path";
|
|
3
|
-
import { CONFIG_DIR_NAME, getAgentDir } from "../config
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { CONFIG_DIR_NAME, getAgentDir } from "../config";
|
|
4
4
|
|
|
5
5
|
export interface CompactionSettings {
|
|
6
6
|
enabled?: boolean; // default: true
|
|
@@ -30,6 +30,11 @@ export interface SkillsSettings {
|
|
|
30
30
|
includeSkills?: string[]; // default: [] (empty = include all; glob patterns to filter)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface CommandsSettings {
|
|
34
|
+
enableClaudeUser?: boolean; // default: true (load from ~/.claude/commands/)
|
|
35
|
+
enableClaudeProject?: boolean; // default: true (load from .claude/commands/)
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
export interface TerminalSettings {
|
|
34
39
|
showImages?: boolean; // default: true (only relevant if terminal supports images)
|
|
35
40
|
}
|
|
@@ -78,6 +83,7 @@ export interface Settings {
|
|
|
78
83
|
hooks?: string[]; // Array of hook file paths
|
|
79
84
|
customTools?: string[]; // Array of custom tool file paths
|
|
80
85
|
skills?: SkillsSettings;
|
|
86
|
+
commands?: CommandsSettings;
|
|
81
87
|
terminal?: TerminalSettings;
|
|
82
88
|
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
|
83
89
|
exa?: ExaSettings;
|
|
@@ -399,6 +405,13 @@ export class SettingsManager {
|
|
|
399
405
|
};
|
|
400
406
|
}
|
|
401
407
|
|
|
408
|
+
getCommandsSettings(): Required<CommandsSettings> {
|
|
409
|
+
return {
|
|
410
|
+
enableClaudeUser: this.settings.commands?.enableClaudeUser ?? true,
|
|
411
|
+
enableClaudeProject: this.settings.commands?.enableClaudeProject ?? true,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
402
415
|
getShowImages(): boolean {
|
|
403
416
|
return this.settings.terminal?.showImages ?? true;
|
|
404
417
|
}
|
package/src/core/skills.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
2
4
|
import { minimatch } from "minimatch";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
6
|
-
import type { SkillsSettings } from "./settings-manager.js";
|
|
5
|
+
import { CONFIG_DIR_NAME, getAgentDir } from "../config";
|
|
6
|
+
import type { SkillsSettings } from "./settings-manager";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Standard frontmatter fields per Agent Skills spec.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { CONFIG_DIR_NAME, getCommandsDir } from "../config";
|
|
5
|
+
import { logger } from "./logger";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Represents a custom slash command loaded from a file
|
|
@@ -98,14 +100,12 @@ export function substituteArgs(content: string, args: string[]): string {
|
|
|
98
100
|
return result;
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
type CommandSource = "builtin" | "claude-user" | "claude-project" | "user" | "project";
|
|
104
|
+
|
|
101
105
|
/**
|
|
102
106
|
* Recursively scan a directory for .md files (and symlinks to .md files) and load them as slash commands
|
|
103
107
|
*/
|
|
104
|
-
function loadCommandsFromDir(
|
|
105
|
-
dir: string,
|
|
106
|
-
source: "builtin" | "user" | "project",
|
|
107
|
-
subdir: string = "",
|
|
108
|
-
): FileSlashCommand[] {
|
|
108
|
+
function loadCommandsFromDir(dir: string, source: CommandSource, subdir: string = ""): FileSlashCommand[] {
|
|
109
109
|
const commands: FileSlashCommand[] = [];
|
|
110
110
|
|
|
111
111
|
if (!existsSync(dir)) {
|
|
@@ -129,15 +129,18 @@ function loadCommandsFromDir(
|
|
|
129
129
|
|
|
130
130
|
const name = entry.name.slice(0, -3); // Remove .md extension
|
|
131
131
|
|
|
132
|
-
// Build source string
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
132
|
+
// Build source string based on source type
|
|
133
|
+
const sourceLabel =
|
|
134
|
+
source === "builtin"
|
|
135
|
+
? "builtin"
|
|
136
|
+
: source === "claude-user"
|
|
137
|
+
? "claude-user"
|
|
138
|
+
: source === "claude-project"
|
|
139
|
+
? "claude-project"
|
|
140
|
+
: source === "user"
|
|
141
|
+
? "user"
|
|
142
|
+
: "project";
|
|
143
|
+
const sourceStr = subdir ? `(${sourceLabel}:${subdir})` : `(${sourceLabel})`;
|
|
141
144
|
|
|
142
145
|
// Get description from frontmatter or first non-empty line
|
|
143
146
|
let description = frontmatter.description || "";
|
|
@@ -159,13 +162,13 @@ function loadCommandsFromDir(
|
|
|
159
162
|
content,
|
|
160
163
|
source: sourceStr,
|
|
161
164
|
});
|
|
162
|
-
} catch (
|
|
163
|
-
|
|
165
|
+
} catch (err) {
|
|
166
|
+
logger.debug("Failed to read slash command file", { error: String(err) });
|
|
164
167
|
}
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
|
-
} catch (
|
|
168
|
-
|
|
170
|
+
} catch (err) {
|
|
171
|
+
logger.debug("Failed to read slash command directory", { error: String(err) });
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
return commands;
|
|
@@ -176,54 +179,66 @@ export interface LoadSlashCommandsOptions {
|
|
|
176
179
|
cwd?: string;
|
|
177
180
|
/** Agent config directory for global commands. Default: from getCommandsDir() */
|
|
178
181
|
agentDir?: string;
|
|
182
|
+
/** Enable loading from ~/.claude/commands/. Default: true */
|
|
183
|
+
enableClaudeUser?: boolean;
|
|
184
|
+
/** Enable loading from .claude/commands/. Default: true */
|
|
185
|
+
enableClaudeProject?: boolean;
|
|
179
186
|
}
|
|
180
187
|
|
|
181
188
|
/**
|
|
182
189
|
* Load all custom slash commands from:
|
|
183
190
|
* 1. Builtin: package commands/
|
|
184
|
-
* 2.
|
|
185
|
-
* 3.
|
|
191
|
+
* 2. Claude user: ~/.claude/commands/
|
|
192
|
+
* 3. Claude project: .claude/commands/
|
|
193
|
+
* 4. Pi user: agentDir/commands/
|
|
194
|
+
* 5. Pi project: cwd/{CONFIG_DIR_NAME}/commands/
|
|
195
|
+
*
|
|
196
|
+
* First occurrence wins (earlier sources have priority).
|
|
186
197
|
*/
|
|
187
198
|
export function loadSlashCommands(options: LoadSlashCommandsOptions = {}): FileSlashCommand[] {
|
|
188
199
|
const resolvedCwd = options.cwd ?? process.cwd();
|
|
189
200
|
const resolvedAgentDir = options.agentDir ?? getCommandsDir();
|
|
201
|
+
const enableClaudeUser = options.enableClaudeUser ?? true;
|
|
202
|
+
const enableClaudeProject = options.enableClaudeProject ?? true;
|
|
190
203
|
|
|
191
204
|
const commands: FileSlashCommand[] = [];
|
|
192
205
|
const seenNames = new Set<string>();
|
|
193
206
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (existsSync(builtinDir)) {
|
|
197
|
-
const builtinCommands = loadCommandsFromDir(builtinDir, "builtin");
|
|
198
|
-
for (const cmd of builtinCommands) {
|
|
207
|
+
const addCommands = (newCommands: FileSlashCommand[]) => {
|
|
208
|
+
for (const cmd of newCommands) {
|
|
199
209
|
if (!seenNames.has(cmd.name)) {
|
|
200
210
|
commands.push(cmd);
|
|
201
211
|
seenNames.add(cmd.name);
|
|
202
212
|
}
|
|
203
213
|
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// 1. Builtin commands (from package)
|
|
217
|
+
const builtinDir = join(import.meta.dir, "../commands");
|
|
218
|
+
if (existsSync(builtinDir)) {
|
|
219
|
+
addCommands(loadCommandsFromDir(builtinDir, "builtin"));
|
|
204
220
|
}
|
|
205
221
|
|
|
206
|
-
// 2.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
for (const cmd of globalCommands) {
|
|
211
|
-
if (!seenNames.has(cmd.name)) {
|
|
212
|
-
commands.push(cmd);
|
|
213
|
-
seenNames.add(cmd.name);
|
|
214
|
-
}
|
|
222
|
+
// 2. Claude user commands (~/.claude/commands/)
|
|
223
|
+
if (enableClaudeUser) {
|
|
224
|
+
const claudeUserDir = join(homedir(), ".claude", "commands");
|
|
225
|
+
addCommands(loadCommandsFromDir(claudeUserDir, "claude-user"));
|
|
215
226
|
}
|
|
216
227
|
|
|
217
|
-
// 3.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (!seenNames.has(cmd.name)) {
|
|
222
|
-
commands.push(cmd);
|
|
223
|
-
seenNames.add(cmd.name);
|
|
224
|
-
}
|
|
228
|
+
// 3. Claude project commands (.claude/commands/)
|
|
229
|
+
if (enableClaudeProject) {
|
|
230
|
+
const claudeProjectDir = resolve(resolvedCwd, ".claude", "commands");
|
|
231
|
+
addCommands(loadCommandsFromDir(claudeProjectDir, "claude-project"));
|
|
225
232
|
}
|
|
226
233
|
|
|
234
|
+
// 4. Pi user commands (agentDir/commands/)
|
|
235
|
+
const globalCommandsDir = options.agentDir ? join(options.agentDir, "commands") : resolvedAgentDir;
|
|
236
|
+
addCommands(loadCommandsFromDir(globalCommandsDir, "user"));
|
|
237
|
+
|
|
238
|
+
// 5. Pi project commands (cwd/{CONFIG_DIR_NAME}/commands/)
|
|
239
|
+
const projectCommandsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, "commands");
|
|
240
|
+
addCommands(loadCommandsFromDir(projectCommandsDir, "project"));
|
|
241
|
+
|
|
227
242
|
return commands;
|
|
228
243
|
}
|
|
229
244
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* System prompt construction and project context loading
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { join, resolve } from "node:path";
|
|
5
7
|
import chalk from "chalk";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
10
|
-
import { formatSkillsForPrompt, loadSkills, type Skill } from "./skills.js";
|
|
11
|
-
import type { ToolName } from "./tools/index.js";
|
|
8
|
+
import { getAgentDir, getDocsPath, getExamplesPath, getReadmePath } from "../config";
|
|
9
|
+
import type { SkillsSettings } from "./settings-manager";
|
|
10
|
+
import { formatSkillsForPrompt, loadSkills, type Skill } from "./skills";
|
|
11
|
+
import type { ToolName } from "./tools/index";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Execute a git command synchronously and return stdout or null on failure.
|