wave-agent-sdk 1.1.5 → 1.3.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 +128 -28
- package/dist/agent.js +201 -49
- package/dist/builtin/index.js +2 -0
- package/dist/builtin/plugins.js +11 -20
- package/dist/builtin/skills/settings.js +7 -20
- package/dist/builtin/skills/wave-daemon.d.ts +1 -0
- package/dist/builtin/skills/wave-daemon.js +194 -0
- package/dist/constants/images.d.ts +26 -0
- package/dist/constants/images.js +26 -0
- package/dist/constants/index.d.ts +16 -0
- package/dist/constants/index.js +16 -0
- package/dist/constants/memory.d.ts +26 -0
- package/dist/constants/memory.js +34 -0
- package/dist/constants/messages.d.ts +11 -0
- package/dist/constants/messages.js +11 -0
- package/dist/constants/plugins.d.ts +8 -0
- package/dist/constants/plugins.js +8 -0
- package/dist/constants/tools.d.ts +1 -0
- package/dist/constants/tools.js +1 -0
- package/dist/core/plugin.d.ts +54 -10
- package/dist/core/plugin.js +137 -23
- package/dist/core/session.d.ts +1 -1
- package/dist/core/session.js +1 -1
- package/dist/exec/catalog.d.ts +140 -0
- package/dist/exec/catalog.js +470 -0
- package/dist/exec/catalogAnnouncement.d.ts +89 -0
- package/dist/exec/catalogAnnouncement.js +293 -0
- package/dist/exec/constants.d.ts +51 -0
- package/dist/exec/constants.js +51 -0
- package/dist/exec/execRuntime.d.ts +55 -0
- package/dist/exec/execRuntime.js +217 -0
- package/dist/exec/workerSource.d.ts +28 -0
- package/dist/exec/workerSource.js +299 -0
- package/dist/host/index.d.ts +23 -0
- package/dist/host/index.js +23 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +8 -1
- package/dist/managers/MemoryRuleManager.d.ts +6 -0
- package/dist/managers/MemoryRuleManager.js +12 -0
- package/dist/managers/aiManager.d.ts +35 -25
- package/dist/managers/aiManager.js +204 -202
- package/dist/managers/backgroundTaskManager.js +14 -0
- package/dist/managers/bashModeManager.d.ts +33 -0
- package/dist/managers/bashModeManager.js +110 -0
- package/dist/managers/hookManager.d.ts +18 -0
- package/dist/managers/hookManager.js +37 -3
- package/dist/managers/liveConfigManager.d.ts +33 -0
- package/dist/managers/liveConfigManager.js +106 -11
- package/dist/managers/lspManager.d.ts +9 -0
- package/dist/managers/lspManager.js +47 -18
- package/dist/managers/mcpManager.d.ts +68 -10
- package/dist/managers/mcpManager.js +265 -15
- package/dist/managers/messageManager.d.ts +60 -18
- package/dist/managers/messageManager.js +170 -81
- package/dist/managers/permissionManager.d.ts +69 -0
- package/dist/managers/permissionManager.js +221 -78
- package/dist/managers/planManager.d.ts +9 -0
- package/dist/managers/planManager.js +19 -1
- package/dist/managers/pluginManager.d.ts +46 -2
- package/dist/managers/pluginManager.js +117 -11
- package/dist/managers/pluginScopeManager.d.ts +15 -2
- package/dist/managers/pluginScopeManager.js +20 -1
- package/dist/managers/skillManager.d.ts +50 -0
- package/dist/managers/skillManager.js +166 -12
- package/dist/managers/slashCommandManager.d.ts +10 -0
- package/dist/managers/slashCommandManager.js +44 -31
- package/dist/managers/subagentManager.d.ts +15 -0
- package/dist/managers/subagentManager.js +81 -9
- package/dist/managers/toolManager.d.ts +29 -3
- package/dist/managers/toolManager.js +87 -13
- package/dist/managers/workflowManager.js +6 -0
- package/dist/prompts/autoMemory.d.ts +9 -0
- package/dist/prompts/autoMemory.js +30 -31
- package/dist/prompts/autoMemoryExtraction.d.ts +4 -0
- package/dist/prompts/autoMemoryExtraction.js +8 -111
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.js +0 -4
- package/dist/prompts/memoryTypes.d.ts +63 -0
- package/dist/prompts/memoryTypes.js +191 -0
- package/dist/services/GitService.d.ts +7 -0
- package/dist/services/GitService.js +23 -0
- package/dist/services/MarketplaceService.d.ts +101 -17
- package/dist/services/MarketplaceService.js +323 -102
- package/dist/services/artifactContent.d.ts +84 -0
- package/dist/services/artifactContent.js +204 -0
- package/dist/services/artifactSession.d.ts +6 -0
- package/dist/services/artifactSession.js +17 -0
- package/dist/services/autoMemoryService.js +5 -13
- package/dist/services/configurationService.d.ts +92 -9
- package/dist/services/configurationService.js +246 -64
- package/dist/services/contentSummarizer.d.ts +15 -0
- package/dist/services/contentSummarizer.js +45 -0
- package/dist/services/execAvailability.d.ts +9 -0
- package/dist/services/execAvailability.js +32 -0
- package/dist/services/fileWatcher.js +61 -6
- package/dist/services/initializationService.js +21 -17
- package/dist/services/interactionService.d.ts +9 -1
- package/dist/services/interactionService.js +28 -8
- package/dist/services/jsonlHandler.d.ts +98 -0
- package/dist/services/jsonlHandler.js +250 -12
- package/dist/services/memory.d.ts +17 -1
- package/dist/services/memory.js +44 -7
- package/dist/services/officialMarketplaceMirror.d.ts +85 -0
- package/dist/services/officialMarketplaceMirror.js +290 -0
- package/dist/services/pluginLoader.d.ts +12 -4
- package/dist/services/pluginLoader.js +38 -7
- package/dist/services/remoteSettingsService.js +20 -6
- package/dist/services/session.d.ts +74 -0
- package/dist/services/session.js +174 -16
- package/dist/services/sessionEntries.d.ts +2 -0
- package/dist/services/sessionEntries.js +20 -0
- package/dist/services/worktreeHooks.js +6 -1
- package/dist/stdio/index.d.ts +12 -0
- package/dist/stdio/index.js +12 -0
- package/dist/stdio/notificationRouter.d.ts +38 -0
- package/dist/stdio/notificationRouter.js +97 -0
- package/dist/stdio/rpcClient.d.ts +18 -0
- package/dist/stdio/rpcClient.js +10 -0
- package/dist/stdio/stdioAgent.d.ts +229 -0
- package/dist/stdio/stdioAgent.js +360 -0
- package/dist/tools/artifactTool.js +406 -273
- package/dist/tools/bashTool.js +10 -6
- package/dist/tools/editTool.js +6 -3
- package/dist/tools/execTool.d.ts +2 -0
- package/dist/tools/execTool.js +165 -0
- package/dist/tools/exitPlanMode.js +10 -2
- package/dist/tools/grepTool.js +7 -1
- package/dist/tools/readTool.js +30 -2
- package/dist/tools/types.d.ts +34 -8
- package/dist/tools/webFetchTool.js +15 -166
- package/dist/tools/workflowTool.js +40 -8
- package/dist/tools/writeTool.js +6 -3
- package/dist/types/agent.d.ts +24 -1
- package/dist/types/commands.d.ts +7 -0
- package/dist/types/configuration.d.ts +45 -2
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/hooks.js +19 -0
- package/dist/types/marketplace.d.ts +40 -2
- package/dist/types/mcp.d.ts +42 -0
- package/dist/types/messaging.d.ts +1 -8
- package/dist/types/permissions.d.ts +22 -0
- package/dist/types/permissions.js +17 -0
- package/dist/types/plugins.d.ts +26 -2
- package/dist/types/skills.d.ts +26 -0
- package/dist/utils/bashParser.d.ts +17 -0
- package/dist/utils/bashParser.js +72 -0
- package/dist/utils/bashStructure/bashLexer.d.ts +96 -0
- package/dist/utils/bashStructure/bashLexer.js +676 -0
- package/dist/utils/bashStructure/bashParser.d.ts +144 -0
- package/dist/utils/bashStructure/bashParser.js +606 -0
- package/dist/utils/bashStructure/bashSemantics.d.ts +70 -0
- package/dist/utils/bashStructure/bashSemantics.js +477 -0
- package/dist/utils/bashStructure/index.d.ts +26 -0
- package/dist/utils/bashStructure/index.js +27 -0
- package/dist/utils/bashStructure/types.d.ts +62 -0
- package/dist/utils/bashStructure/types.js +47 -0
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.js +10 -0
- package/dist/utils/containerSetup.js +48 -6
- package/dist/utils/convertMessagesForAPI.d.ts +7 -1
- package/dist/utils/convertMessagesForAPI.js +64 -14
- package/dist/utils/fileChangeReminder.d.ts +20 -0
- package/dist/utils/fileChangeReminder.js +153 -0
- package/dist/utils/fileSearch.js +4 -3
- package/dist/utils/fileUtils.d.ts +44 -0
- package/dist/utils/fileUtils.js +118 -0
- package/dist/utils/frontmatterYaml.d.ts +33 -0
- package/dist/utils/frontmatterYaml.js +192 -0
- package/dist/utils/imageBudget.d.ts +85 -0
- package/dist/utils/imageBudget.js +109 -0
- package/dist/utils/imageDimensions.d.ts +83 -0
- package/dist/utils/imageDimensions.js +232 -0
- package/dist/utils/imageProcessor.d.ts +66 -0
- package/dist/utils/imageProcessor.js +84 -0
- package/dist/utils/imageRewrite.d.ts +29 -0
- package/dist/utils/imageRewrite.js +251 -0
- package/dist/utils/markdownParser.d.ts +5 -1
- package/dist/utils/markdownParser.js +9 -51
- package/dist/utils/mcpInstructions.d.ts +61 -0
- package/dist/utils/mcpInstructions.js +126 -0
- package/dist/utils/mcpUtils.d.ts +7 -0
- package/dist/utils/mcpUtils.js +11 -2
- package/dist/utils/memoryAge.d.ts +32 -0
- package/dist/utils/memoryAge.js +47 -0
- package/dist/utils/memoryEntrypoint.d.ts +20 -0
- package/dist/utils/memoryEntrypoint.js +49 -0
- package/dist/utils/memoryIndex.d.ts +30 -0
- package/dist/utils/memoryIndex.js +76 -0
- package/dist/utils/messageOperations.d.ts +6 -20
- package/dist/utils/messageOperations.js +40 -91
- package/dist/utils/nestedMemory.d.ts +22 -0
- package/dist/utils/nestedMemory.js +61 -0
- package/dist/utils/npmTarball.d.ts +19 -0
- package/dist/utils/npmTarball.js +92 -0
- package/dist/utils/pluginSource.d.ts +37 -0
- package/dist/utils/pluginSource.js +73 -0
- package/dist/utils/ripgrep.d.ts +18 -4
- package/dist/utils/ripgrep.js +56 -4
- package/dist/utils/runtimeDeps.d.ts +35 -0
- package/dist/utils/runtimeDeps.js +426 -0
- package/dist/utils/skillParser.js +22 -52
- package/dist/utils/subagentParser.js +48 -45
- package/dist/utils/tokenCalculation.js +0 -8
- package/dist/utils/userSettings.d.ts +90 -0
- package/dist/utils/userSettings.js +291 -0
- package/dist/utils/worktreeUtils.d.ts +2 -1
- package/dist/utils/worktreeUtils.js +64 -34
- package/package.json +12 -4
- package/dist/managers/bangManager.d.ts +0 -26
- package/dist/managers/bangManager.js +0 -78
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StdioAgent — host-side typed wrapper around a JSON-RPC client that mirrors
|
|
3
|
+
* the Agent API (shared by the VS Code extension and the desktop app).
|
|
4
|
+
*
|
|
5
|
+
* In the single-shared-process architecture, all sessions share one transport
|
|
6
|
+
* client. The NotificationRouter dispatches incoming notifications to the
|
|
7
|
+
* appropriate StdioAgent via `handleNotification()`. The agent no longer
|
|
8
|
+
* subscribes directly to the client.
|
|
9
|
+
*
|
|
10
|
+
* All session-scoped requests carry `this.sessionId` on the JSON-RPC envelope
|
|
11
|
+
* so the server can route them to the right Agent.
|
|
12
|
+
*
|
|
13
|
+
* `destroy()` only unregisters from the router and sends the destroy request;
|
|
14
|
+
* it does NOT dispose the shared client.
|
|
15
|
+
*
|
|
16
|
+
* The client dependency is the structural `RpcClient` surface (request/notify/
|
|
17
|
+
* onNotification) so both hosts keep their own transports: vscode's
|
|
18
|
+
* `StdioClient` (spawn + hostLog) and desktop's `JsonRpcClient` subclasses
|
|
19
|
+
* (StdioClient / SocketClient).
|
|
20
|
+
*/
|
|
21
|
+
import type { Message, Task, BackgroundTaskSummary, SerializableWorkflowRun, QueuedMessage, McpServerStatus, PermissionMode, PermissionDecision, ToolPermissionContext, ToolBlockUpdateCallbackParams, SlashCommand, McpServerConfig, SubagentConfiguration, SkillMetadata } from "../types/index.js";
|
|
22
|
+
import type { RpcClient } from "./rpcClient.js";
|
|
23
|
+
import type { NotificationRouter } from "./notificationRouter.js";
|
|
24
|
+
export interface InitializeParams {
|
|
25
|
+
workdir?: string;
|
|
26
|
+
restoreSessionId?: string;
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
baseURL?: string;
|
|
29
|
+
serverUrl?: string;
|
|
30
|
+
defaultHeaders?: Record<string, string>;
|
|
31
|
+
model?: string;
|
|
32
|
+
fastModel?: string;
|
|
33
|
+
permissionMode?: PermissionMode;
|
|
34
|
+
tools?: string[];
|
|
35
|
+
allowedTools?: string[];
|
|
36
|
+
disallowedTools?: string[];
|
|
37
|
+
pluginDirs?: string[];
|
|
38
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
39
|
+
worktreeName?: string;
|
|
40
|
+
isNewWorktree?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface InitializeResult {
|
|
43
|
+
sessionId: string;
|
|
44
|
+
workingDirectory: string;
|
|
45
|
+
permissionMode: PermissionMode;
|
|
46
|
+
latestTotalTokens: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Session-level overrides only. 用户偏好(语言 / 上下文长度 / 自动记忆开关与频率)
|
|
50
|
+
* **不得**经本层下发——它们写用户级 `~/.wave/settings.json` 并由实时重载生效;
|
|
51
|
+
* 覆盖层优先级高于 settings.json,会把实时值永久遮蔽(docs/specs/core/agent-config.md
|
|
52
|
+
* 「分层职责」)。
|
|
53
|
+
*/
|
|
54
|
+
export interface UpdateConfigParams {
|
|
55
|
+
apiKey?: string;
|
|
56
|
+
baseURL?: string;
|
|
57
|
+
serverUrl?: string;
|
|
58
|
+
defaultHeaders?: Record<string, string>;
|
|
59
|
+
model?: string;
|
|
60
|
+
fastModel?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface StdioAgentCallbacks {
|
|
63
|
+
onUserMessageAdded?: (message: Message) => void;
|
|
64
|
+
onAssistantMessageAdded?: (message: Message) => void;
|
|
65
|
+
onAssistantContentUpdated?: (params: {
|
|
66
|
+
messageId: string;
|
|
67
|
+
chunk: string;
|
|
68
|
+
stage: "streaming" | "end";
|
|
69
|
+
}) => void;
|
|
70
|
+
onAssistantReasoningUpdated?: (params: {
|
|
71
|
+
messageId: string;
|
|
72
|
+
chunk: string;
|
|
73
|
+
stage: "streaming" | "end";
|
|
74
|
+
}) => void;
|
|
75
|
+
onToolBlockUpdated?: (params: ToolBlockUpdateCallbackParams) => void;
|
|
76
|
+
onErrorBlockAdded?: (error: string) => void;
|
|
77
|
+
onCompactBlockAdded?: (content: string) => void;
|
|
78
|
+
onCompactionStateChange?: (isCompacting: boolean) => void;
|
|
79
|
+
onCompactionContentUpdate?: (content: string) => void;
|
|
80
|
+
/** Full plan-file content after the model writes it (spec: 计划文件更新后刷新计划面板). */
|
|
81
|
+
onPlanFileUpdated?: (content: string) => void;
|
|
82
|
+
onLoadingChange?: (loading: boolean) => void;
|
|
83
|
+
onContextUsage?: (percent: number) => void;
|
|
84
|
+
onCommandRunningChange?: (running: boolean) => void;
|
|
85
|
+
onQueuedMessagesChange?: (messages: QueuedMessage[]) => void;
|
|
86
|
+
onTasksChange?: (tasks: Task[]) => void;
|
|
87
|
+
onBackgroundTasksChange?: (tasks: BackgroundTaskSummary[]) => void;
|
|
88
|
+
onSessionIdChange?: (sessionId: string) => void;
|
|
89
|
+
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
90
|
+
onMcpServersChange?: (servers: McpServerStatus[]) => void;
|
|
91
|
+
onWorkdirChange?: (workdir: string) => void;
|
|
92
|
+
onNotificationMessageAdded?: (params: {
|
|
93
|
+
taskId: string;
|
|
94
|
+
taskType: string;
|
|
95
|
+
status: string;
|
|
96
|
+
summary: string;
|
|
97
|
+
message?: Message;
|
|
98
|
+
}) => void;
|
|
99
|
+
onPermissionRequest?: (requestId: string, context: ToolPermissionContext) => void;
|
|
100
|
+
onBtwContent?: (params: {
|
|
101
|
+
question: string;
|
|
102
|
+
content: string;
|
|
103
|
+
type: "thinking" | "content";
|
|
104
|
+
}) => void;
|
|
105
|
+
}
|
|
106
|
+
export declare class StdioAgent {
|
|
107
|
+
sessionId: string | undefined;
|
|
108
|
+
workingDirectory: string | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Initialize-time cwd — the session's stable root. Unlike
|
|
111
|
+
* `workingDirectory` it is never overwritten by the workdirChange
|
|
112
|
+
* notification (bash cd), so @file search and the /status workdir stay
|
|
113
|
+
* anchored to the project root.
|
|
114
|
+
*/
|
|
115
|
+
sessionCwd: string | undefined;
|
|
116
|
+
latestTotalTokens: number;
|
|
117
|
+
/**
|
|
118
|
+
* Context-usage percentage reported with the most recent getMessages pull.
|
|
119
|
+
* A host whose webview was re-created long after the last token change gets
|
|
120
|
+
* no contextUsage notification, so it replays this on webviewReady instead.
|
|
121
|
+
*/
|
|
122
|
+
contextUsagePercent: number | undefined;
|
|
123
|
+
permissionMode: PermissionMode | undefined;
|
|
124
|
+
messages: Message[];
|
|
125
|
+
queuedMessages: QueuedMessage[];
|
|
126
|
+
tasks: Task[];
|
|
127
|
+
backgroundTasks: BackgroundTaskSummary[];
|
|
128
|
+
isStreaming: boolean;
|
|
129
|
+
isCommandRunning: boolean;
|
|
130
|
+
isCompacting: boolean;
|
|
131
|
+
private client;
|
|
132
|
+
private router;
|
|
133
|
+
private callbacks;
|
|
134
|
+
constructor(client: RpcClient, router: NotificationRouter, callbacks: StdioAgentCallbacks);
|
|
135
|
+
initialize(params: InitializeParams): Promise<InitializeResult>;
|
|
136
|
+
destroy(): Promise<void>;
|
|
137
|
+
restoreSession(sessionId: string): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Set this session's custom title (spec session-management.md「会话自定义标题
|
|
140
|
+
* (重命名)」). The title is appended to the session's own JSONL file as a
|
|
141
|
+
* reserved `custom-title` entry, so every host reading that file sees it.
|
|
142
|
+
*/
|
|
143
|
+
renameSession(title: string): Promise<void>;
|
|
144
|
+
updateConfig(params: UpdateConfigParams): Promise<{
|
|
145
|
+
sessionId: string;
|
|
146
|
+
}>;
|
|
147
|
+
sendMessage(text: string, images?: Array<{
|
|
148
|
+
path: string;
|
|
149
|
+
mimeType: string;
|
|
150
|
+
}>, force?: boolean): Promise<void>;
|
|
151
|
+
bang(command: string): Promise<void>;
|
|
152
|
+
abortMessage(): Promise<void>;
|
|
153
|
+
clearMessages(): Promise<void>;
|
|
154
|
+
compact(customInstructions?: string): Promise<void>;
|
|
155
|
+
rewindToMessage(messageId: string): Promise<{
|
|
156
|
+
inputContent: string;
|
|
157
|
+
}>;
|
|
158
|
+
askBtw(question: string): Promise<string>;
|
|
159
|
+
removeQueuedMessage(index: number): Promise<void>;
|
|
160
|
+
updateQueuedMessageById(id: string, patch: {
|
|
161
|
+
content?: string;
|
|
162
|
+
images?: Array<{
|
|
163
|
+
path: string;
|
|
164
|
+
mimeType: string;
|
|
165
|
+
}>;
|
|
166
|
+
type?: "message" | "bang";
|
|
167
|
+
}): Promise<boolean>;
|
|
168
|
+
removeQueuedMessageById(id: string): Promise<void>;
|
|
169
|
+
getFullMessageThread(): Promise<{
|
|
170
|
+
messages: Message[];
|
|
171
|
+
sessionIds: string[];
|
|
172
|
+
}>;
|
|
173
|
+
getMessages(): Promise<Message[]>;
|
|
174
|
+
listRewindCheckpoints(): Promise<{
|
|
175
|
+
checkpoints: Array<{
|
|
176
|
+
id: string;
|
|
177
|
+
content: string;
|
|
178
|
+
}>;
|
|
179
|
+
}>;
|
|
180
|
+
getConfiguredModels(): Promise<{
|
|
181
|
+
models: string[];
|
|
182
|
+
currentModel: string | undefined;
|
|
183
|
+
}>;
|
|
184
|
+
setModel(model: string): Promise<void>;
|
|
185
|
+
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
186
|
+
/** Returns cached permission mode (updated via notification). */
|
|
187
|
+
getPermissionMode(): PermissionMode | undefined;
|
|
188
|
+
/**
|
|
189
|
+
* Reads the session's current plan file (path + contents). Used by the
|
|
190
|
+
* /plan command to display the plan when already in plan mode; the CLI side
|
|
191
|
+
* awaits the path if it is still being generated after setPermissionMode.
|
|
192
|
+
*/
|
|
193
|
+
getPlanFile(): Promise<{
|
|
194
|
+
path: string | null;
|
|
195
|
+
content: string | null;
|
|
196
|
+
}>;
|
|
197
|
+
sendPermissionResponse(requestId: string, decision: PermissionDecision): void;
|
|
198
|
+
getBackgroundTaskOutput(taskId: string): Promise<{
|
|
199
|
+
stdout: string;
|
|
200
|
+
stderr: string;
|
|
201
|
+
status: string;
|
|
202
|
+
outputPath?: string;
|
|
203
|
+
type: string;
|
|
204
|
+
exitCode?: number;
|
|
205
|
+
} | null>;
|
|
206
|
+
stopBackgroundTask(taskId: string): Promise<boolean>;
|
|
207
|
+
backgroundCurrentTask(): Promise<void>;
|
|
208
|
+
getWorkflowRuns(): Promise<SerializableWorkflowRun[]>;
|
|
209
|
+
stopWorkflowRun(runId: string): Promise<boolean>;
|
|
210
|
+
getMcpServers(): Promise<McpServerStatus[]>;
|
|
211
|
+
connectMcpServer(serverName: string): Promise<boolean>;
|
|
212
|
+
disconnectMcpServer(serverName: string): Promise<boolean>;
|
|
213
|
+
getMcpConfigPaths(): Promise<{
|
|
214
|
+
userPath: string | null;
|
|
215
|
+
projectPath: string | null;
|
|
216
|
+
}>;
|
|
217
|
+
removeMcpServer(scope: "user" | "project", serverName: string): Promise<boolean>;
|
|
218
|
+
deleteSkill(name: string): Promise<boolean>;
|
|
219
|
+
deleteSubagent(name: string): Promise<boolean>;
|
|
220
|
+
getHooksByScope(scope: "user" | "project" | "plugin"): Promise<{
|
|
221
|
+
hooks: Partial<Record<string, unknown[]>>;
|
|
222
|
+
configPath: string | null;
|
|
223
|
+
}>;
|
|
224
|
+
deleteHook(scope: "user" | "project", hookName: string): Promise<void>;
|
|
225
|
+
getSlashCommands(): Promise<SlashCommand[]>;
|
|
226
|
+
getSubagentConfigurations(): Promise<SubagentConfiguration[]>;
|
|
227
|
+
getSkillMetadata(): Promise<SkillMetadata[]>;
|
|
228
|
+
handleNotification(method: string, params: unknown): void;
|
|
229
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StdioAgent — host-side typed wrapper around a JSON-RPC client that mirrors
|
|
3
|
+
* the Agent API (shared by the VS Code extension and the desktop app).
|
|
4
|
+
*
|
|
5
|
+
* In the single-shared-process architecture, all sessions share one transport
|
|
6
|
+
* client. The NotificationRouter dispatches incoming notifications to the
|
|
7
|
+
* appropriate StdioAgent via `handleNotification()`. The agent no longer
|
|
8
|
+
* subscribes directly to the client.
|
|
9
|
+
*
|
|
10
|
+
* All session-scoped requests carry `this.sessionId` on the JSON-RPC envelope
|
|
11
|
+
* so the server can route them to the right Agent.
|
|
12
|
+
*
|
|
13
|
+
* `destroy()` only unregisters from the router and sends the destroy request;
|
|
14
|
+
* it does NOT dispose the shared client.
|
|
15
|
+
*
|
|
16
|
+
* The client dependency is the structural `RpcClient` surface (request/notify/
|
|
17
|
+
* onNotification) so both hosts keep their own transports: vscode's
|
|
18
|
+
* `StdioClient` (spawn + hostLog) and desktop's `JsonRpcClient` subclasses
|
|
19
|
+
* (StdioClient / SocketClient).
|
|
20
|
+
*/
|
|
21
|
+
// ── StdioAgent ───────────────────────────────────────────────────
|
|
22
|
+
export class StdioAgent {
|
|
23
|
+
constructor(client, router, callbacks) {
|
|
24
|
+
this.latestTotalTokens = 0;
|
|
25
|
+
this.messages = [];
|
|
26
|
+
this.queuedMessages = [];
|
|
27
|
+
this.tasks = [];
|
|
28
|
+
this.backgroundTasks = [];
|
|
29
|
+
this.isStreaming = false;
|
|
30
|
+
this.isCommandRunning = false;
|
|
31
|
+
this.isCompacting = false;
|
|
32
|
+
this.client = client;
|
|
33
|
+
this.router = router;
|
|
34
|
+
this.callbacks = callbacks;
|
|
35
|
+
}
|
|
36
|
+
// ── Lifecycle ─────────────────────────────────────────────────
|
|
37
|
+
async initialize(params) {
|
|
38
|
+
const result = (await this.client.request("initialize", params));
|
|
39
|
+
this.sessionId = result.sessionId;
|
|
40
|
+
this.workingDirectory = result.workingDirectory;
|
|
41
|
+
this.sessionCwd = result.workingDirectory;
|
|
42
|
+
this.permissionMode = result.permissionMode;
|
|
43
|
+
this.latestTotalTokens = result.latestTotalTokens;
|
|
44
|
+
// A fresh session has no usage yet; don't let a previous session's
|
|
45
|
+
// percentage survive into this agent.
|
|
46
|
+
this.contextUsagePercent = undefined;
|
|
47
|
+
// Register with the router so subsequent notifications are routed here
|
|
48
|
+
this.router.register(this.sessionId, this);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
async destroy() {
|
|
52
|
+
if (this.sessionId) {
|
|
53
|
+
this.router.unregister(this.sessionId);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
await this.client.request("destroy", undefined, this.sessionId);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Process may have already exited; best-effort
|
|
60
|
+
}
|
|
61
|
+
// NOTE: do NOT dispose the shared client — other sessions may still use it
|
|
62
|
+
}
|
|
63
|
+
async restoreSession(sessionId) {
|
|
64
|
+
await this.client.request("restoreSession", { sessionId }, this.sessionId);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Set this session's custom title (spec session-management.md「会话自定义标题
|
|
68
|
+
* (重命名)」). The title is appended to the session's own JSONL file as a
|
|
69
|
+
* reserved `custom-title` entry, so every host reading that file sees it.
|
|
70
|
+
*/
|
|
71
|
+
async renameSession(title) {
|
|
72
|
+
await this.client.request("renameSession", {
|
|
73
|
+
sessionId: this.sessionId,
|
|
74
|
+
// The session file lives under the session root; a cwd drifted by `cd`
|
|
75
|
+
// inside a turn must not address it (see sessionCwd).
|
|
76
|
+
workdir: this.sessionCwd ?? this.workingDirectory,
|
|
77
|
+
title,
|
|
78
|
+
}, this.sessionId);
|
|
79
|
+
}
|
|
80
|
+
async updateConfig(params) {
|
|
81
|
+
const oldSessionId = this.sessionId;
|
|
82
|
+
const result = (await this.client.request("updateConfig", params, this.sessionId));
|
|
83
|
+
// If sessionId changed, re-register with the router
|
|
84
|
+
if (oldSessionId && result.sessionId !== oldSessionId) {
|
|
85
|
+
this.router.unregister(oldSessionId);
|
|
86
|
+
this.sessionId = result.sessionId;
|
|
87
|
+
this.router.register(this.sessionId, this);
|
|
88
|
+
// Sync the host session state: the bridge may have downgraded to a
|
|
89
|
+
// fresh session (session file missing on recreate). Without this the
|
|
90
|
+
// host keeps the destroyed sessionId and every later request fails
|
|
91
|
+
// with "Session not found".
|
|
92
|
+
this.callbacks.onSessionIdChange?.(this.sessionId);
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
// ── Messages ──────────────────────────────────────────────────
|
|
97
|
+
async sendMessage(text, images, force) {
|
|
98
|
+
await this.client.request("sendMessage", { text, images, force }, this.sessionId);
|
|
99
|
+
}
|
|
100
|
+
async bang(command) {
|
|
101
|
+
await this.client.request("bang", { command }, this.sessionId);
|
|
102
|
+
}
|
|
103
|
+
async abortMessage() {
|
|
104
|
+
await this.client.request("abortMessage", undefined, this.sessionId);
|
|
105
|
+
}
|
|
106
|
+
async clearMessages() {
|
|
107
|
+
await this.client.request("clearMessages", undefined, this.sessionId);
|
|
108
|
+
}
|
|
109
|
+
async compact(customInstructions) {
|
|
110
|
+
await this.client.request("compact", { customInstructions }, this.sessionId);
|
|
111
|
+
}
|
|
112
|
+
async rewindToMessage(messageId) {
|
|
113
|
+
return (await this.client.request("rewindToMessage", { messageId }, this.sessionId));
|
|
114
|
+
}
|
|
115
|
+
async askBtw(question) {
|
|
116
|
+
return (await this.client.request("askBtw", { question }, this.sessionId));
|
|
117
|
+
}
|
|
118
|
+
async removeQueuedMessage(index) {
|
|
119
|
+
await this.client.request("deleteQueuedMessage", { index }, this.sessionId);
|
|
120
|
+
}
|
|
121
|
+
async updateQueuedMessageById(id, patch) {
|
|
122
|
+
const result = (await this.client.request("updateQueuedMessage", { id, text: patch.content, images: patch.images }, this.sessionId));
|
|
123
|
+
return result?.ok ?? false;
|
|
124
|
+
}
|
|
125
|
+
async removeQueuedMessageById(id) {
|
|
126
|
+
await this.client.request("deleteQueuedMessageById", { id }, this.sessionId);
|
|
127
|
+
}
|
|
128
|
+
async getFullMessageThread() {
|
|
129
|
+
return (await this.client.request("getFullMessageThread", undefined, this.sessionId));
|
|
130
|
+
}
|
|
131
|
+
async getMessages() {
|
|
132
|
+
const result = (await this.client.request("getMessages", undefined, this.sessionId));
|
|
133
|
+
this.messages = result.messages;
|
|
134
|
+
this.contextUsagePercent = result.contextUsagePercent;
|
|
135
|
+
return result.messages;
|
|
136
|
+
}
|
|
137
|
+
async listRewindCheckpoints() {
|
|
138
|
+
return (await this.client.request("listRewindCheckpoints", undefined, this.sessionId));
|
|
139
|
+
}
|
|
140
|
+
async getConfiguredModels() {
|
|
141
|
+
return (await this.client.request("getConfiguredModels", undefined, this.sessionId));
|
|
142
|
+
}
|
|
143
|
+
async setModel(model) {
|
|
144
|
+
await this.client.request("setModel", { model }, this.sessionId);
|
|
145
|
+
}
|
|
146
|
+
// ── Permissions ───────────────────────────────────────────────
|
|
147
|
+
async setPermissionMode(mode) {
|
|
148
|
+
await this.client.request("setPermissionMode", { mode }, this.sessionId);
|
|
149
|
+
}
|
|
150
|
+
/** Returns cached permission mode (updated via notification). */
|
|
151
|
+
getPermissionMode() {
|
|
152
|
+
return this.permissionMode;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Reads the session's current plan file (path + contents). Used by the
|
|
156
|
+
* /plan command to display the plan when already in plan mode; the CLI side
|
|
157
|
+
* awaits the path if it is still being generated after setPermissionMode.
|
|
158
|
+
*/
|
|
159
|
+
async getPlanFile() {
|
|
160
|
+
return (await this.client.request("getPlanFile", undefined, this.sessionId));
|
|
161
|
+
}
|
|
162
|
+
sendPermissionResponse(requestId, decision) {
|
|
163
|
+
this.client.notify("permissionResponse", { requestId, decision }, this.sessionId);
|
|
164
|
+
}
|
|
165
|
+
async getBackgroundTaskOutput(taskId) {
|
|
166
|
+
const result = (await this.client.request("getBackgroundTaskOutput", { taskId }, this.sessionId));
|
|
167
|
+
return result.output;
|
|
168
|
+
}
|
|
169
|
+
async stopBackgroundTask(taskId) {
|
|
170
|
+
const result = (await this.client.request("stopBackgroundTask", { taskId }, this.sessionId));
|
|
171
|
+
return result.success;
|
|
172
|
+
}
|
|
173
|
+
async backgroundCurrentTask() {
|
|
174
|
+
await this.client.request("backgroundCurrentTask", undefined, this.sessionId);
|
|
175
|
+
}
|
|
176
|
+
async getWorkflowRuns() {
|
|
177
|
+
const result = (await this.client.request("getWorkflowRuns", undefined, this.sessionId));
|
|
178
|
+
return result?.runs ?? [];
|
|
179
|
+
}
|
|
180
|
+
async stopWorkflowRun(runId) {
|
|
181
|
+
const result = (await this.client.request("stopWorkflowRun", { runId }, this.sessionId));
|
|
182
|
+
return result?.success ?? false;
|
|
183
|
+
}
|
|
184
|
+
// ── MCP ───────────────────────────────────────────────────────
|
|
185
|
+
async getMcpServers() {
|
|
186
|
+
const result = (await this.client.request("getMcpServers", undefined, this.sessionId));
|
|
187
|
+
return result.servers;
|
|
188
|
+
}
|
|
189
|
+
async connectMcpServer(serverName) {
|
|
190
|
+
const result = (await this.client.request("connectMcpServer", { serverName }, this.sessionId));
|
|
191
|
+
return result.success;
|
|
192
|
+
}
|
|
193
|
+
async disconnectMcpServer(serverName) {
|
|
194
|
+
const result = (await this.client.request("disconnectMcpServer", { serverName }, this.sessionId));
|
|
195
|
+
return result.success;
|
|
196
|
+
}
|
|
197
|
+
async getMcpConfigPaths() {
|
|
198
|
+
const result = (await this.client.request("getMcpConfigPaths", undefined, this.sessionId));
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
async removeMcpServer(scope, serverName) {
|
|
202
|
+
const result = (await this.client.request("removeMcpServer", { scope, serverName }, this.sessionId));
|
|
203
|
+
return result.success;
|
|
204
|
+
}
|
|
205
|
+
async deleteSkill(name) {
|
|
206
|
+
const result = (await this.client.request("deleteSkill", { name }, this.sessionId));
|
|
207
|
+
return result.success;
|
|
208
|
+
}
|
|
209
|
+
async deleteSubagent(name) {
|
|
210
|
+
const result = (await this.client.request("deleteSubagent", { name }, this.sessionId));
|
|
211
|
+
return result.success;
|
|
212
|
+
}
|
|
213
|
+
async getHooksByScope(scope) {
|
|
214
|
+
const result = (await this.client.request("getHooksByScope", { scope }, this.sessionId));
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
async deleteHook(scope, hookName) {
|
|
218
|
+
await this.client.request("deleteHook", { scope, hookName }, this.sessionId);
|
|
219
|
+
}
|
|
220
|
+
// ── Commands ──────────────────────────────────────────────────
|
|
221
|
+
async getSlashCommands() {
|
|
222
|
+
const result = (await this.client.request("getSlashCommands", undefined, this.sessionId));
|
|
223
|
+
return result.commands;
|
|
224
|
+
}
|
|
225
|
+
async getSubagentConfigurations() {
|
|
226
|
+
const result = (await this.client.request("getSubagentConfigurations", undefined, this.sessionId));
|
|
227
|
+
return result.configurations;
|
|
228
|
+
}
|
|
229
|
+
async getSkillMetadata() {
|
|
230
|
+
const result = (await this.client.request("getSkillMetadata", undefined, this.sessionId));
|
|
231
|
+
return result.skills;
|
|
232
|
+
}
|
|
233
|
+
// ── Notification dispatch (called by NotificationRouter) ──────
|
|
234
|
+
handleNotification(method, params) {
|
|
235
|
+
switch (method) {
|
|
236
|
+
case "userMessageAdded": {
|
|
237
|
+
const p = params;
|
|
238
|
+
if (p.message)
|
|
239
|
+
this.callbacks.onUserMessageAdded?.(p.message);
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case "assistantMessageAdded": {
|
|
243
|
+
const p = params;
|
|
244
|
+
if (p.message)
|
|
245
|
+
this.callbacks.onAssistantMessageAdded?.(p.message);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case "assistantContentUpdated":
|
|
249
|
+
this.callbacks.onAssistantContentUpdated?.(params);
|
|
250
|
+
break;
|
|
251
|
+
case "assistantReasoningUpdated":
|
|
252
|
+
this.callbacks.onAssistantReasoningUpdated?.(params);
|
|
253
|
+
break;
|
|
254
|
+
case "toolBlockUpdated":
|
|
255
|
+
this.callbacks.onToolBlockUpdated?.(params);
|
|
256
|
+
break;
|
|
257
|
+
case "errorBlockAdded": {
|
|
258
|
+
const p = params;
|
|
259
|
+
this.callbacks.onErrorBlockAdded?.(p.error);
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
case "compactBlockAdded": {
|
|
263
|
+
const p = params;
|
|
264
|
+
this.callbacks.onCompactBlockAdded?.(p.content);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case "compactionStateChange": {
|
|
268
|
+
const p = params;
|
|
269
|
+
this.isCompacting = p.isCompacting;
|
|
270
|
+
this.callbacks.onCompactionStateChange?.(p.isCompacting);
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
case "compactionContentUpdate": {
|
|
274
|
+
const p = params;
|
|
275
|
+
this.callbacks.onCompactionContentUpdate?.(p.content);
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case "planFileUpdated": {
|
|
279
|
+
const p = params;
|
|
280
|
+
this.callbacks.onPlanFileUpdated?.(p.content);
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case "loadingChange": {
|
|
284
|
+
const p = params;
|
|
285
|
+
if (p.latestTotalTokens !== undefined) {
|
|
286
|
+
this.latestTotalTokens = p.latestTotalTokens;
|
|
287
|
+
}
|
|
288
|
+
this.isStreaming = p.loading;
|
|
289
|
+
this.callbacks.onLoadingChange?.(p.loading);
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case "contextUsage": {
|
|
293
|
+
const p = params;
|
|
294
|
+
this.callbacks.onContextUsage?.(p.percent);
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
case "commandRunningChange": {
|
|
298
|
+
const p = params;
|
|
299
|
+
this.isCommandRunning = p.running;
|
|
300
|
+
this.callbacks.onCommandRunningChange?.(p.running);
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
case "queuedMessagesChange": {
|
|
304
|
+
const p = params;
|
|
305
|
+
this.queuedMessages = p.messages;
|
|
306
|
+
this.callbacks.onQueuedMessagesChange?.(p.messages);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case "tasksChange": {
|
|
310
|
+
const p = params;
|
|
311
|
+
this.tasks = p.tasks;
|
|
312
|
+
this.callbacks.onTasksChange?.(p.tasks);
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
case "backgroundTasksChange": {
|
|
316
|
+
const p = params;
|
|
317
|
+
this.backgroundTasks = p.tasks;
|
|
318
|
+
this.callbacks.onBackgroundTasksChange?.(p.tasks);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "sessionIdChange": {
|
|
322
|
+
const p = params;
|
|
323
|
+
this.sessionId = p.sessionId;
|
|
324
|
+
this.callbacks.onSessionIdChange?.(p.sessionId);
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
case "permissionModeChange": {
|
|
328
|
+
const p = params;
|
|
329
|
+
this.permissionMode = p.mode;
|
|
330
|
+
this.callbacks.onPermissionModeChange?.(p.mode);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
case "mcpServersChange": {
|
|
334
|
+
const p = params;
|
|
335
|
+
this.callbacks.onMcpServersChange?.(p.servers);
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
case "workdirChange": {
|
|
339
|
+
const p = params;
|
|
340
|
+
this.workingDirectory = p.workdir;
|
|
341
|
+
this.callbacks.onWorkdirChange?.(p.workdir);
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
case "notificationMessageAdded":
|
|
345
|
+
this.callbacks.onNotificationMessageAdded?.(params);
|
|
346
|
+
break;
|
|
347
|
+
case "permissionRequest": {
|
|
348
|
+
const p = params;
|
|
349
|
+
this.callbacks.onPermissionRequest?.(p.requestId, p.context);
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
case "btwContent": {
|
|
353
|
+
const p = params;
|
|
354
|
+
if (p)
|
|
355
|
+
this.callbacks.onBtwContent?.(p);
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|