wave-agent-sdk 0.7.1 → 0.8.0
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/dist/agent.d.ts +9 -79
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +85 -302
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +20 -13
- package/dist/managers/backgroundTaskManager.d.ts +1 -1
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +1 -1
- package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
- package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
- package/dist/managers/{bashManager.js → bangManager.js} +5 -6
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +12 -3
- package/dist/managers/messageManager.d.ts +18 -6
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +42 -20
- package/dist/managers/permissionManager.d.ts +22 -1
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +106 -85
- package/dist/managers/planManager.d.ts +6 -0
- package/dist/managers/planManager.d.ts.map +1 -1
- package/dist/managers/planManager.js +21 -0
- package/dist/managers/skillManager.d.ts +7 -2
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +30 -10
- package/dist/managers/slashCommandManager.d.ts +7 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +57 -45
- package/dist/managers/subagentManager.d.ts +4 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +47 -13
- package/dist/managers/toolManager.d.ts +7 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +15 -2
- package/dist/prompts/index.d.ts +0 -4
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +0 -9
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +6 -6
- package/dist/services/configurationService.d.ts +2 -2
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +4 -4
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +6 -0
- package/dist/services/initializationService.d.ts +44 -0
- package/dist/services/initializationService.d.ts.map +1 -0
- package/dist/services/initializationService.js +170 -0
- package/dist/services/interactionService.d.ts +29 -0
- package/dist/services/interactionService.d.ts.map +1 -0
- package/dist/services/interactionService.js +97 -0
- package/dist/services/session.js +1 -1
- package/dist/services/taskManager.d.ts +5 -0
- package/dist/services/taskManager.d.ts.map +1 -1
- package/dist/services/taskManager.js +16 -2
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +7 -18
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/exitPlanMode.js +1 -1
- package/dist/tools/lspTool.d.ts +2 -0
- package/dist/tools/lspTool.d.ts.map +1 -1
- package/dist/tools/lspTool.js +144 -52
- package/dist/tools/skillTool.d.ts.map +1 -1
- package/dist/tools/skillTool.js +97 -2
- package/dist/tools/taskManagementTools.d.ts.map +1 -1
- package/dist/tools/taskManagementTools.js +23 -2
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +9 -15
- package/dist/tools/types.d.ts +1 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.js +1 -1
- package/dist/types/agent.d.ts +64 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/commands.d.ts +0 -4
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +3 -1
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/messaging.d.ts +3 -3
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/skills.d.ts +13 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/utils/commandPathResolver.d.ts +3 -36
- package/dist/utils/commandPathResolver.d.ts.map +1 -1
- package/dist/utils/commandPathResolver.js +16 -93
- package/dist/utils/configValidator.d.ts +2 -2
- package/dist/utils/configValidator.d.ts.map +1 -1
- package/dist/utils/configValidator.js +4 -6
- package/dist/utils/containerSetup.d.ts +3 -4
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +14 -9
- package/dist/utils/customCommands.d.ts +2 -3
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +20 -60
- package/dist/utils/gitUtils.d.ts +25 -0
- package/dist/utils/gitUtils.d.ts.map +1 -1
- package/dist/utils/gitUtils.js +75 -0
- package/dist/utils/markdownParser.d.ts +4 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +33 -0
- package/dist/utils/messageOperations.d.ts +16 -7
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +45 -20
- package/dist/utils/nameGenerator.d.ts +1 -1
- package/dist/utils/nameGenerator.d.ts.map +1 -1
- package/dist/utils/nameGenerator.js +10 -6
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/dist/utils/skillParser.js +48 -0
- package/package.json +1 -1
- package/src/agent.ts +103 -458
- package/src/index.ts +2 -2
- package/src/managers/aiManager.ts +23 -17
- package/src/managers/backgroundTaskManager.ts +2 -2
- package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
- package/src/managers/hookManager.ts +13 -3
- package/src/managers/messageManager.ts +55 -26
- package/src/managers/permissionManager.ts +121 -98
- package/src/managers/planManager.ts +26 -0
- package/src/managers/skillManager.ts +51 -14
- package/src/managers/slashCommandManager.ts +75 -55
- package/src/managers/subagentManager.ts +57 -13
- package/src/managers/toolManager.ts +22 -2
- package/src/prompts/index.ts +0 -15
- package/src/services/aiService.ts +9 -12
- package/src/services/configurationService.ts +4 -4
- package/src/services/hook.ts +7 -0
- package/src/services/initializationService.ts +291 -0
- package/src/services/interactionService.ts +171 -0
- package/src/services/session.ts +1 -1
- package/src/services/taskManager.ts +18 -2
- package/src/tools/bashTool.ts +8 -18
- package/src/tools/editTool.ts +1 -1
- package/src/tools/exitPlanMode.ts +1 -1
- package/src/tools/lsTool.ts +1 -1
- package/src/tools/lspTool.ts +184 -52
- package/src/tools/skillTool.ts +127 -2
- package/src/tools/taskManagementTools.ts +32 -2
- package/src/tools/taskTool.ts +13 -15
- package/src/tools/types.ts +1 -2
- package/src/tools/writeTool.ts +1 -1
- package/src/types/agent.ts +83 -0
- package/src/types/commands.ts +0 -6
- package/src/types/config.ts +1 -1
- package/src/types/hooks.ts +5 -1
- package/src/types/index.ts +1 -0
- package/src/types/messaging.ts +3 -3
- package/src/types/skills.ts +13 -0
- package/src/utils/commandPathResolver.ts +14 -117
- package/src/utils/configValidator.ts +5 -9
- package/src/utils/containerSetup.ts +17 -14
- package/src/utils/customCommands.ts +20 -83
- package/src/utils/gitUtils.ts +75 -0
- package/src/utils/markdownParser.ts +47 -0
- package/src/utils/messageOperations.ts +58 -28
- package/src/utils/nameGenerator.ts +10 -6
- package/src/utils/skillParser.ts +52 -0
- package/dist/managers/backgroundBashManager.d.ts +0 -27
- package/dist/managers/backgroundBashManager.d.ts.map +0 -1
- package/dist/managers/backgroundBashManager.js +0 -169
- package/src/managers/backgroundBashManager.ts +0 -206
package/src/tools/writeTool.ts
CHANGED
|
@@ -123,7 +123,7 @@ Usage:
|
|
|
123
123
|
return {
|
|
124
124
|
success: false,
|
|
125
125
|
content: "",
|
|
126
|
-
error: `Write operation denied, reason: ${permissionResult.message || "No reason provided"}`,
|
|
126
|
+
error: `Write operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
} catch {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ClientOptions } from "openai";
|
|
2
|
+
import type {
|
|
3
|
+
Message,
|
|
4
|
+
Logger,
|
|
5
|
+
PermissionMode,
|
|
6
|
+
PermissionCallback,
|
|
7
|
+
ILspManager,
|
|
8
|
+
PluginConfig,
|
|
9
|
+
BackgroundTask,
|
|
10
|
+
} from "./index.js";
|
|
11
|
+
import type { MessageManagerCallbacks } from "../managers/messageManager.js";
|
|
12
|
+
import type { BackgroundTaskManagerCallbacks } from "../managers/backgroundTaskManager.js";
|
|
13
|
+
import type { McpManagerCallbacks } from "../managers/mcpManager.js";
|
|
14
|
+
import type { SubagentManagerCallbacks } from "../managers/subagentManager.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configuration options for Agent instances
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT: This interface is used by both Agent constructor and Agent.create()
|
|
20
|
+
* Any changes to this interface must be compatible with both methods.
|
|
21
|
+
*/
|
|
22
|
+
export interface AgentOptions {
|
|
23
|
+
// Optional configuration with environment fallbacks
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
baseURL?: string;
|
|
26
|
+
defaultHeaders?: Record<string, string>;
|
|
27
|
+
fetchOptions?: ClientOptions["fetchOptions"];
|
|
28
|
+
fetch?: ClientOptions["fetch"];
|
|
29
|
+
model?: string;
|
|
30
|
+
fastModel?: string;
|
|
31
|
+
maxInputTokens?: number;
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
/** Preferred language for agent communication */
|
|
34
|
+
language?: string;
|
|
35
|
+
|
|
36
|
+
// Existing options (preserved)
|
|
37
|
+
callbacks?: AgentCallbacks;
|
|
38
|
+
restoreSessionId?: string;
|
|
39
|
+
continueLastSession?: boolean;
|
|
40
|
+
logger?: Logger;
|
|
41
|
+
/**Add optional initial messages parameter for testing convenience */
|
|
42
|
+
messages?: Message[];
|
|
43
|
+
/**Working directory - if not specified, use process.cwd() */
|
|
44
|
+
workdir?: string;
|
|
45
|
+
/**Optional custom system prompt - if provided, replaces default system prompt */
|
|
46
|
+
systemPrompt?: string;
|
|
47
|
+
/**Permission mode - defaults to "default" */
|
|
48
|
+
permissionMode?: PermissionMode;
|
|
49
|
+
/**Custom permission callback */
|
|
50
|
+
canUseTool?: PermissionCallback;
|
|
51
|
+
/**Whether to use streaming mode for AI responses - defaults to true */
|
|
52
|
+
stream?: boolean;
|
|
53
|
+
/**Optional custom LSP manager - if not provided, a standalone one will be created */
|
|
54
|
+
lspManager?: ILspManager;
|
|
55
|
+
/**Optional local plugins to load */
|
|
56
|
+
plugins?: PluginConfig[];
|
|
57
|
+
/**
|
|
58
|
+
* Optional list of tool names to enable.
|
|
59
|
+
* - undefined: Enable all built-in tools and plugins (default).
|
|
60
|
+
* - []: Disable all tools.
|
|
61
|
+
* - string[]: Enable only the tools with the specified names.
|
|
62
|
+
*/
|
|
63
|
+
tools?: string[];
|
|
64
|
+
/**Optional worktree name */
|
|
65
|
+
worktreeName?: string;
|
|
66
|
+
/**Whether this is a newly created worktree */
|
|
67
|
+
isNewWorktree?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface AgentCallbacks
|
|
71
|
+
extends MessageManagerCallbacks,
|
|
72
|
+
BackgroundTaskManagerCallbacks,
|
|
73
|
+
McpManagerCallbacks,
|
|
74
|
+
SubagentManagerCallbacks {
|
|
75
|
+
onBackgroundTasksChange?: (tasks: BackgroundTask[]) => void;
|
|
76
|
+
onTasksChange?: (tasks: import("./tasks.js").Task[]) => void;
|
|
77
|
+
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
78
|
+
onSubagentLatestTotalTokensChange?: (
|
|
79
|
+
subagentId: string,
|
|
80
|
+
tokens: number,
|
|
81
|
+
) => void;
|
|
82
|
+
onBackgroundCurrentTask?: () => void;
|
|
83
|
+
}
|
package/src/types/commands.ts
CHANGED
|
@@ -24,12 +24,6 @@ export interface CustomSlashCommand {
|
|
|
24
24
|
content: string;
|
|
25
25
|
config?: CustomSlashCommandConfig;
|
|
26
26
|
|
|
27
|
-
// Nested command support
|
|
28
|
-
namespace?: string; // Parent directory for nested commands (e.g., "openspec")
|
|
29
|
-
isNested: boolean; // Whether command is in a subdirectory
|
|
30
|
-
depth: number; // 0 = root, 1 = nested
|
|
31
|
-
segments: string[]; // Path components for ID generation (e.g., ["openspec", "apply"])
|
|
32
|
-
|
|
33
27
|
// Plugin support
|
|
34
28
|
pluginPath?: string; // Absolute path to the plugin root directory (only set for plugin commands)
|
|
35
29
|
}
|
package/src/types/config.ts
CHANGED
package/src/types/hooks.ts
CHANGED
|
@@ -19,7 +19,8 @@ export type HookEvent =
|
|
|
19
19
|
| "UserPromptSubmit"
|
|
20
20
|
| "Stop"
|
|
21
21
|
| "SubagentStop"
|
|
22
|
-
| "Notification"
|
|
22
|
+
| "Notification"
|
|
23
|
+
| "WorktreeCreate";
|
|
23
24
|
|
|
24
25
|
// Individual hook command configuration
|
|
25
26
|
export interface HookCommand {
|
|
@@ -98,6 +99,7 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
98
99
|
"Stop",
|
|
99
100
|
"SubagentStop",
|
|
100
101
|
"Notification",
|
|
102
|
+
"WorktreeCreate",
|
|
101
103
|
].includes(event);
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -146,6 +148,7 @@ export interface HookJsonInput {
|
|
|
146
148
|
subagent_type?: string; // Present when hook is executed by a subagent
|
|
147
149
|
message?: string; // Present for Notification events
|
|
148
150
|
notification_type?: string; // Present for Notification events
|
|
151
|
+
name?: string; // Present for WorktreeCreate events
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
// Extended context interface for passing additional data to hook executor
|
|
@@ -160,6 +163,7 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
160
163
|
subagentType?: string; // Subagent type when hook is executed by a subagent
|
|
161
164
|
message?: string; // Notification message (Notification only)
|
|
162
165
|
notificationType?: string; // Notification type (Notification only)
|
|
166
|
+
worktreeName?: string; // Worktree name (WorktreeCreate only)
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
// Environment variables injected into hook processes
|
package/src/types/index.ts
CHANGED
package/src/types/messaging.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type MessageBlock =
|
|
|
23
23
|
| ErrorBlock
|
|
24
24
|
| ToolBlock
|
|
25
25
|
| ImageBlock
|
|
26
|
-
|
|
|
26
|
+
| BangBlock
|
|
27
27
|
| CompressBlock
|
|
28
28
|
| ReasoningBlock
|
|
29
29
|
| FileHistoryBlock;
|
|
@@ -73,8 +73,8 @@ export interface ImageBlock {
|
|
|
73
73
|
imageUrls?: string[];
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export interface
|
|
77
|
-
type: "
|
|
76
|
+
export interface BangBlock {
|
|
77
|
+
type: "bang";
|
|
78
78
|
command: string;
|
|
79
79
|
output: string;
|
|
80
80
|
isRunning: boolean;
|
package/src/types/skills.ts
CHANGED
|
@@ -8,6 +8,12 @@ export interface SkillMetadata {
|
|
|
8
8
|
description: string;
|
|
9
9
|
type: "personal" | "project";
|
|
10
10
|
skillPath: string;
|
|
11
|
+
allowedTools?: string[];
|
|
12
|
+
context?: "fork";
|
|
13
|
+
agent?: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
disableModelInvocation?: boolean;
|
|
16
|
+
userInvocable?: boolean;
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
export interface Skill extends SkillMetadata {
|
|
@@ -20,6 +26,12 @@ export interface Skill extends SkillMetadata {
|
|
|
20
26
|
export interface SkillFrontmatter {
|
|
21
27
|
name: string;
|
|
22
28
|
description: string;
|
|
29
|
+
"allowed-tools"?: string | string[];
|
|
30
|
+
context?: "fork";
|
|
31
|
+
agent?: string;
|
|
32
|
+
model?: string;
|
|
33
|
+
"disable-model-invocation"?: boolean | string;
|
|
34
|
+
"user-invocable"?: boolean | string;
|
|
23
35
|
[key: string]: unknown;
|
|
24
36
|
}
|
|
25
37
|
|
|
@@ -53,6 +65,7 @@ export interface SkillInvocationContext {
|
|
|
53
65
|
|
|
54
66
|
export interface SkillToolArgs {
|
|
55
67
|
skill_name: string;
|
|
68
|
+
args?: string;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export interface SkillManagerOptions {
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
import { relative, basename } from "path";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Command path resolver utilities for
|
|
5
|
-
* Handles conversion between file paths and command IDs
|
|
4
|
+
* Command path resolver utilities for command discovery
|
|
5
|
+
* Handles conversion between file paths and command IDs
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export interface CommandIdParts {
|
|
9
|
-
namespace?: string; // e.g., "openspec" for "openspec:apply"
|
|
10
|
-
commandName: string; // e.g., "apply" for "openspec:apply"
|
|
11
|
-
isNested: boolean; // true if command has namespace
|
|
12
|
-
depth: number; // 0 for root, 1 for nested
|
|
13
|
-
segments: string[]; // Path components array
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
/**
|
|
17
9
|
* Generate command ID from file path
|
|
18
10
|
* @param filePath - Absolute path to markdown file
|
|
19
11
|
* @param rootDir - Root commands directory path
|
|
20
|
-
* @returns Command identifier string
|
|
12
|
+
* @returns Command identifier string
|
|
21
13
|
* @throws Error on invalid path structure
|
|
22
14
|
*/
|
|
23
15
|
export function generateCommandId(filePath: string, rootDir: string): string {
|
|
@@ -42,84 +34,28 @@ export function generateCommandId(filePath: string, rootDir: string): string {
|
|
|
42
34
|
throw new Error(`Command files must have .md extension`);
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
const commandName = basename(lastSegment, ".md");
|
|
46
38
|
|
|
47
39
|
// Handle empty filename after removing extension
|
|
48
|
-
if (
|
|
40
|
+
if (commandName === "") {
|
|
49
41
|
throw new Error("Command filename cannot be empty");
|
|
50
42
|
}
|
|
51
43
|
|
|
52
|
-
// Validate depth (
|
|
53
|
-
if (segments.length >
|
|
44
|
+
// Validate depth (no nesting allowed)
|
|
45
|
+
if (segments.length > 1) {
|
|
54
46
|
throw new Error(
|
|
55
|
-
`Command nesting
|
|
47
|
+
`Command nesting not supported: ${relativePath}. Commands must be in the root directory.`,
|
|
56
48
|
);
|
|
57
49
|
}
|
|
58
50
|
|
|
59
|
-
// Validate
|
|
60
|
-
|
|
61
|
-
if (!validateSegment(segment)) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`Invalid command path segment: "${segment}" in ${relativePath}. Must match pattern /^[a-zA-Z][a-zA-Z0-9_.-]*$/`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Generate command ID
|
|
69
|
-
if (segments.length === 1) {
|
|
70
|
-
return segments[0]; // Flat command
|
|
71
|
-
} else {
|
|
72
|
-
return segments.join(":"); // Nested command with colon syntax
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Parse command ID into components
|
|
78
|
-
* @param commandId - Command identifier (e.g., "openspec:apply")
|
|
79
|
-
* @returns Object with namespace and command name
|
|
80
|
-
* @throws Error on malformed command ID
|
|
81
|
-
*/
|
|
82
|
-
export function parseCommandId(commandId: string): CommandIdParts {
|
|
83
|
-
// Handle null/undefined inputs
|
|
84
|
-
if (commandId == null) {
|
|
85
|
-
throw new Error("Command ID cannot be null or undefined");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (commandId === "") {
|
|
89
|
-
throw new Error("Command ID cannot be empty");
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!validateCommandId(commandId)) {
|
|
51
|
+
// Validate command name
|
|
52
|
+
if (!validateSegment(commandName)) {
|
|
93
53
|
throw new Error(
|
|
94
|
-
`Invalid command
|
|
54
|
+
`Invalid command name: "${commandName}" in ${relativePath}. Must match pattern /^[a-zA-Z][a-zA-Z0-9_.-]*$/`,
|
|
95
55
|
);
|
|
96
56
|
}
|
|
97
57
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (parts.length === 1) {
|
|
101
|
-
// Flat command
|
|
102
|
-
return {
|
|
103
|
-
namespace: undefined,
|
|
104
|
-
commandName: parts[0],
|
|
105
|
-
isNested: false,
|
|
106
|
-
depth: 0,
|
|
107
|
-
segments: [parts[0]],
|
|
108
|
-
};
|
|
109
|
-
} else if (parts.length === 2) {
|
|
110
|
-
// Nested command
|
|
111
|
-
return {
|
|
112
|
-
namespace: parts[0],
|
|
113
|
-
commandName: parts[1],
|
|
114
|
-
isNested: true,
|
|
115
|
-
depth: 1,
|
|
116
|
-
segments: [parts[0], parts[1]],
|
|
117
|
-
};
|
|
118
|
-
} else {
|
|
119
|
-
throw new Error(
|
|
120
|
-
`Invalid command ID format: "${commandId}". Too many colon separators.`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
58
|
+
return commandName;
|
|
123
59
|
}
|
|
124
60
|
|
|
125
61
|
/**
|
|
@@ -133,9 +69,8 @@ export function validateCommandId(commandId: string): boolean {
|
|
|
133
69
|
return false;
|
|
134
70
|
}
|
|
135
71
|
|
|
136
|
-
// Command ID
|
|
137
|
-
|
|
138
|
-
const pattern = /^[a-zA-Z][a-zA-Z0-9_-]*(?::[a-zA-Z][a-zA-Z0-9_-]*)*$/;
|
|
72
|
+
// Command ID must be a single segment (no colons)
|
|
73
|
+
const pattern = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
|
|
139
74
|
return pattern.test(commandId);
|
|
140
75
|
}
|
|
141
76
|
|
|
@@ -149,41 +84,3 @@ function validateSegment(segment: string): boolean {
|
|
|
149
84
|
const pattern = /^[a-zA-Z][a-zA-Z0-9_.-]*$/;
|
|
150
85
|
return pattern.test(segment);
|
|
151
86
|
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Convert file path to command segments array
|
|
155
|
-
* @param filePath - Absolute path to markdown file
|
|
156
|
-
* @param rootDir - Root commands directory path
|
|
157
|
-
* @returns Array of path segments
|
|
158
|
-
*/
|
|
159
|
-
export function getCommandSegments(
|
|
160
|
-
filePath: string,
|
|
161
|
-
rootDir: string,
|
|
162
|
-
): string[] {
|
|
163
|
-
const relativePath = relative(rootDir, filePath);
|
|
164
|
-
const segments = relativePath.split("/").filter((segment) => segment !== "");
|
|
165
|
-
|
|
166
|
-
// Remove .md extension from the last segment
|
|
167
|
-
const lastSegment = segments[segments.length - 1];
|
|
168
|
-
segments[segments.length - 1] = basename(lastSegment, ".md");
|
|
169
|
-
|
|
170
|
-
return segments;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Get namespace from command segments
|
|
175
|
-
* @param segments - Command path segments
|
|
176
|
-
* @returns Namespace string or undefined for flat commands
|
|
177
|
-
*/
|
|
178
|
-
export function getNamespace(segments: string[]): string | undefined {
|
|
179
|
-
return segments.length > 1 ? segments[0] : undefined;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Get command depth from segments
|
|
184
|
-
* @param segments - Command path segments
|
|
185
|
-
* @returns Depth number (0 for root, 1 for nested)
|
|
186
|
-
*/
|
|
187
|
-
export function getDepth(segments: string[]): number {
|
|
188
|
-
return Math.max(0, segments.length - 1);
|
|
189
|
-
}
|
|
@@ -89,20 +89,16 @@ export class ConfigValidator {
|
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
91
|
* Validates model configuration (basic validation)
|
|
92
|
-
* @param
|
|
92
|
+
* @param model - Agent model string
|
|
93
93
|
* @param fastModel - Fast model string
|
|
94
94
|
* @throws ConfigurationError if invalid
|
|
95
95
|
*/
|
|
96
|
-
static validateModelConfig(
|
|
97
|
-
if (
|
|
98
|
-
!agentModel ||
|
|
99
|
-
typeof agentModel !== "string" ||
|
|
100
|
-
agentModel.trim() === ""
|
|
101
|
-
) {
|
|
96
|
+
static validateModelConfig(model: string, fastModel: string): void {
|
|
97
|
+
if (!model || typeof model !== "string" || model.trim() === "") {
|
|
102
98
|
throw new ConfigurationError(
|
|
103
99
|
"Agent model must be a non-empty string.",
|
|
104
|
-
"
|
|
105
|
-
|
|
100
|
+
"model",
|
|
101
|
+
model,
|
|
106
102
|
);
|
|
107
103
|
}
|
|
108
104
|
|
|
@@ -14,14 +14,14 @@ import { HookManager } from "../managers/hookManager.js";
|
|
|
14
14
|
import { SkillManager } from "../managers/skillManager.js";
|
|
15
15
|
import { SlashCommandManager } from "../managers/slashCommandManager.js";
|
|
16
16
|
import { PluginManager } from "../managers/pluginManager.js";
|
|
17
|
-
import {
|
|
17
|
+
import { BangManager } from "../managers/bangManager.js";
|
|
18
18
|
import { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
|
|
19
19
|
import { ReversionManager } from "../managers/reversionManager.js";
|
|
20
20
|
import { SubagentManager } from "../managers/subagentManager.js";
|
|
21
21
|
import { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
22
22
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
23
23
|
import { ReversionService } from "../services/reversionService.js";
|
|
24
|
-
import type { AgentOptions } from "../
|
|
24
|
+
import type { AgentOptions } from "../types/index.js";
|
|
25
25
|
import type {
|
|
26
26
|
PermissionMode,
|
|
27
27
|
Usage,
|
|
@@ -41,9 +41,8 @@ export interface AgentContainerSetupOptions {
|
|
|
41
41
|
stream: boolean;
|
|
42
42
|
|
|
43
43
|
// Callbacks to Agent methods
|
|
44
|
-
|
|
45
|
-
onTasksChange: (tasks:
|
|
46
|
-
onSessionTasksChange: (tasks: Task[]) => void;
|
|
44
|
+
onBackgroundTasksChange: (tasks: BackgroundTask[]) => void;
|
|
45
|
+
onTasksChange: (tasks: Task[]) => void;
|
|
47
46
|
onPermissionModeChange: (mode: PermissionMode) => void;
|
|
48
47
|
handlePlanModeTransition: (mode: PermissionMode) => void;
|
|
49
48
|
setPermissionMode: (mode: PermissionMode) => void;
|
|
@@ -66,9 +65,8 @@ export function setupAgentContainer(
|
|
|
66
65
|
configurationService,
|
|
67
66
|
systemPrompt,
|
|
68
67
|
stream,
|
|
69
|
-
|
|
68
|
+
onBackgroundTasksChange,
|
|
70
69
|
onTasksChange,
|
|
71
|
-
onSessionTasksChange,
|
|
72
70
|
onPermissionModeChange,
|
|
73
71
|
handlePlanModeTransition,
|
|
74
72
|
setPermissionMode,
|
|
@@ -94,7 +92,12 @@ export function setupAgentContainer(
|
|
|
94
92
|
callbacks: {
|
|
95
93
|
...callbacks,
|
|
96
94
|
onSessionIdChange: (sessionId) => {
|
|
97
|
-
|
|
95
|
+
const taskManager = container.get<TaskManager>("TaskManager");
|
|
96
|
+
if (taskManager) {
|
|
97
|
+
taskManager.syncWithSession().catch((error) => {
|
|
98
|
+
logger.error("Failed to sync task list with session:", error);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
98
101
|
callbacks.onSessionIdChange?.(sessionId);
|
|
99
102
|
},
|
|
100
103
|
},
|
|
@@ -111,15 +114,15 @@ export function setupAgentContainer(
|
|
|
111
114
|
container.register("TaskManager", taskManager);
|
|
112
115
|
taskManager.on("tasksChange", async () => {
|
|
113
116
|
const tasks = await taskManager.listTasks();
|
|
114
|
-
|
|
117
|
+
onTasksChange(tasks);
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
const backgroundTaskManager = new BackgroundTaskManager(container, {
|
|
118
121
|
callbacks: {
|
|
119
122
|
...callbacks,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
callbacks.
|
|
123
|
+
onBackgroundTasksChange: (tasks) => {
|
|
124
|
+
onBackgroundTasksChange(tasks);
|
|
125
|
+
callbacks.onBackgroundTasksChange?.(tasks);
|
|
123
126
|
},
|
|
124
127
|
},
|
|
125
128
|
workdir,
|
|
@@ -272,8 +275,8 @@ export function setupAgentContainer(
|
|
|
272
275
|
const pluginManager = new PluginManager(container, { workdir });
|
|
273
276
|
container.register("PluginManager", pluginManager);
|
|
274
277
|
|
|
275
|
-
const
|
|
276
|
-
container.register("
|
|
278
|
+
const bangManager = new BangManager(container, { workdir });
|
|
279
|
+
container.register("BangManager", bangManager);
|
|
277
280
|
|
|
278
281
|
return container;
|
|
279
282
|
}
|
|
@@ -3,12 +3,7 @@ import { join, extname, basename } from "path";
|
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import type { CustomSlashCommand } from "../types/index.js";
|
|
5
5
|
import { parseMarkdownFile } from "./markdownParser.js";
|
|
6
|
-
import {
|
|
7
|
-
generateCommandId,
|
|
8
|
-
getCommandSegments,
|
|
9
|
-
getNamespace,
|
|
10
|
-
getDepth,
|
|
11
|
-
} from "./commandPathResolver.js";
|
|
6
|
+
import { generateCommandId } from "./commandPathResolver.js";
|
|
12
7
|
import { logger } from "./globalLogger.js";
|
|
13
8
|
|
|
14
9
|
/**
|
|
@@ -26,104 +21,46 @@ export function getUserCommandsDir(): string {
|
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
/**
|
|
29
|
-
* Scan a directory for markdown command files
|
|
24
|
+
* Scan a directory for markdown command files (flat structure only)
|
|
30
25
|
* @param dirPath - Root commands directory path
|
|
31
|
-
* @param maxDepth - Maximum nesting depth to scan (default: 1)
|
|
32
26
|
*/
|
|
33
|
-
export function scanCommandsDirectory(
|
|
34
|
-
dirPath: string,
|
|
35
|
-
maxDepth: number = 1,
|
|
36
|
-
): CustomSlashCommand[] {
|
|
27
|
+
export function scanCommandsDirectory(dirPath: string): CustomSlashCommand[] {
|
|
37
28
|
if (!existsSync(dirPath)) {
|
|
38
29
|
return [];
|
|
39
30
|
}
|
|
40
31
|
|
|
41
|
-
return scanCommandsDirectoryRecursive(dirPath, dirPath, 0, maxDepth);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Recursively scan directory for commands with depth control
|
|
46
|
-
* @param currentPath - Current directory being scanned
|
|
47
|
-
* @param rootPath - Root commands directory (for relative path calculation)
|
|
48
|
-
* @param currentDepth - Current nesting depth
|
|
49
|
-
* @param maxDepth - Maximum allowed depth
|
|
50
|
-
*/
|
|
51
|
-
function scanCommandsDirectoryRecursive(
|
|
52
|
-
currentPath: string,
|
|
53
|
-
rootPath: string,
|
|
54
|
-
currentDepth: number,
|
|
55
|
-
maxDepth: number,
|
|
56
|
-
): CustomSlashCommand[] {
|
|
57
32
|
const commands: CustomSlashCommand[] = [];
|
|
58
33
|
|
|
59
34
|
try {
|
|
60
|
-
const entries = readdirSync(
|
|
35
|
+
const entries = readdirSync(dirPath);
|
|
61
36
|
|
|
62
37
|
for (const entryName of entries) {
|
|
63
|
-
const fullPath = join(
|
|
64
|
-
|
|
65
|
-
let isDirectory = false;
|
|
66
|
-
let isFile = false;
|
|
38
|
+
const fullPath = join(dirPath, entryName);
|
|
67
39
|
|
|
68
40
|
try {
|
|
69
41
|
const stats = statSync(fullPath);
|
|
70
|
-
|
|
71
|
-
isFile = stats.isFile();
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// Skip entries that cannot be stat'd
|
|
74
|
-
logger.warn(`Cannot access ${fullPath}:`, error);
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (isDirectory) {
|
|
79
|
-
// Skip subdirectories if we're at max depth
|
|
80
|
-
if (currentDepth >= maxDepth) {
|
|
81
|
-
logger.warn(
|
|
82
|
-
`Skipping directory ${fullPath}: exceeds maximum nesting depth of ${maxDepth}`,
|
|
83
|
-
);
|
|
42
|
+
if (!stats.isFile() || extname(entryName) !== ".md") {
|
|
84
43
|
continue;
|
|
85
44
|
}
|
|
86
45
|
|
|
87
|
-
// Recursively scan subdirectory
|
|
88
|
-
const nestedCommands = scanCommandsDirectoryRecursive(
|
|
89
|
-
fullPath,
|
|
90
|
-
rootPath,
|
|
91
|
-
currentDepth + 1,
|
|
92
|
-
maxDepth,
|
|
93
|
-
);
|
|
94
|
-
commands.push(...nestedCommands);
|
|
95
|
-
} else if (isFile && extname(entryName) === ".md") {
|
|
96
46
|
// Process markdown file
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
content,
|
|
111
|
-
config,
|
|
112
|
-
|
|
113
|
-
// Nested command metadata
|
|
114
|
-
namespace,
|
|
115
|
-
isNested: depth > 0,
|
|
116
|
-
depth,
|
|
117
|
-
segments,
|
|
118
|
-
});
|
|
119
|
-
} catch (error) {
|
|
120
|
-
logger.warn(`Failed to load custom command from ${fullPath}:`, error);
|
|
121
|
-
}
|
|
47
|
+
const commandId = generateCommandId(fullPath, dirPath);
|
|
48
|
+
const { content, config } = parseMarkdownFile(fullPath);
|
|
49
|
+
|
|
50
|
+
commands.push({
|
|
51
|
+
id: commandId,
|
|
52
|
+
name: basename(entryName, ".md"),
|
|
53
|
+
description: config?.description,
|
|
54
|
+
filePath: fullPath,
|
|
55
|
+
content,
|
|
56
|
+
config,
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.warn(`Failed to load custom command from ${fullPath}:`, error);
|
|
122
60
|
}
|
|
123
|
-
// Skip non-markdown files silently
|
|
124
61
|
}
|
|
125
62
|
} catch (error) {
|
|
126
|
-
logger.warn(`Failed to scan commands directory ${
|
|
63
|
+
logger.warn(`Failed to scan commands directory ${dirPath}:`, error);
|
|
127
64
|
}
|
|
128
65
|
|
|
129
66
|
return commands;
|