wave-agent-sdk 1.2.0 → 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.
Files changed (175) hide show
  1. package/dist/agent.d.ts +58 -4
  2. package/dist/agent.js +91 -19
  3. package/dist/builtin/index.js +2 -0
  4. package/dist/builtin/skills/settings.js +1 -12
  5. package/dist/builtin/skills/wave-daemon.d.ts +1 -0
  6. package/dist/builtin/skills/wave-daemon.js +194 -0
  7. package/dist/constants/images.d.ts +26 -0
  8. package/dist/constants/images.js +26 -0
  9. package/dist/constants/index.d.ts +16 -0
  10. package/dist/constants/index.js +16 -0
  11. package/dist/constants/memory.d.ts +26 -0
  12. package/dist/constants/memory.js +34 -0
  13. package/dist/constants/messages.d.ts +11 -0
  14. package/dist/constants/messages.js +11 -0
  15. package/dist/constants/plugins.d.ts +8 -0
  16. package/dist/constants/plugins.js +8 -0
  17. package/dist/constants/tools.d.ts +1 -0
  18. package/dist/constants/tools.js +1 -0
  19. package/dist/core/plugin.d.ts +53 -13
  20. package/dist/core/plugin.js +134 -26
  21. package/dist/core/session.d.ts +1 -1
  22. package/dist/core/session.js +1 -1
  23. package/dist/exec/catalog.d.ts +140 -0
  24. package/dist/exec/catalog.js +470 -0
  25. package/dist/exec/catalogAnnouncement.d.ts +89 -0
  26. package/dist/exec/catalogAnnouncement.js +293 -0
  27. package/dist/exec/constants.d.ts +51 -0
  28. package/dist/exec/constants.js +51 -0
  29. package/dist/exec/execRuntime.d.ts +55 -0
  30. package/dist/exec/execRuntime.js +217 -0
  31. package/dist/exec/workerSource.d.ts +28 -0
  32. package/dist/exec/workerSource.js +299 -0
  33. package/dist/host/index.d.ts +23 -0
  34. package/dist/host/index.js +23 -0
  35. package/dist/index.d.ts +5 -0
  36. package/dist/index.js +6 -0
  37. package/dist/managers/MemoryRuleManager.d.ts +6 -0
  38. package/dist/managers/MemoryRuleManager.js +12 -0
  39. package/dist/managers/aiManager.d.ts +35 -1
  40. package/dist/managers/aiManager.js +190 -21
  41. package/dist/managers/backgroundTaskManager.js +14 -0
  42. package/dist/managers/hookManager.d.ts +13 -0
  43. package/dist/managers/hookManager.js +31 -4
  44. package/dist/managers/liveConfigManager.d.ts +33 -0
  45. package/dist/managers/liveConfigManager.js +103 -8
  46. package/dist/managers/lspManager.d.ts +9 -0
  47. package/dist/managers/lspManager.js +47 -18
  48. package/dist/managers/mcpManager.d.ts +45 -10
  49. package/dist/managers/mcpManager.js +103 -1
  50. package/dist/managers/messageManager.d.ts +48 -5
  51. package/dist/managers/messageManager.js +107 -21
  52. package/dist/managers/permissionManager.d.ts +40 -0
  53. package/dist/managers/permissionManager.js +63 -8
  54. package/dist/managers/pluginManager.d.ts +46 -2
  55. package/dist/managers/pluginManager.js +117 -11
  56. package/dist/managers/pluginScopeManager.d.ts +15 -2
  57. package/dist/managers/pluginScopeManager.js +20 -1
  58. package/dist/managers/skillManager.d.ts +19 -0
  59. package/dist/managers/skillManager.js +44 -0
  60. package/dist/managers/slashCommandManager.d.ts +10 -0
  61. package/dist/managers/slashCommandManager.js +35 -3
  62. package/dist/managers/subagentManager.d.ts +8 -0
  63. package/dist/managers/subagentManager.js +20 -0
  64. package/dist/managers/toolManager.d.ts +29 -3
  65. package/dist/managers/toolManager.js +87 -13
  66. package/dist/prompts/autoMemory.d.ts +9 -0
  67. package/dist/prompts/autoMemory.js +30 -31
  68. package/dist/prompts/autoMemoryExtraction.d.ts +4 -0
  69. package/dist/prompts/autoMemoryExtraction.js +8 -111
  70. package/dist/prompts/memoryTypes.d.ts +63 -0
  71. package/dist/prompts/memoryTypes.js +191 -0
  72. package/dist/services/GitService.d.ts +7 -0
  73. package/dist/services/GitService.js +23 -0
  74. package/dist/services/MarketplaceService.d.ts +101 -17
  75. package/dist/services/MarketplaceService.js +318 -119
  76. package/dist/services/artifactContent.d.ts +84 -0
  77. package/dist/services/artifactContent.js +204 -0
  78. package/dist/services/artifactSession.d.ts +6 -0
  79. package/dist/services/artifactSession.js +17 -0
  80. package/dist/services/autoMemoryService.js +5 -13
  81. package/dist/services/configurationService.d.ts +60 -9
  82. package/dist/services/configurationService.js +129 -54
  83. package/dist/services/contentSummarizer.d.ts +15 -0
  84. package/dist/services/contentSummarizer.js +45 -0
  85. package/dist/services/execAvailability.d.ts +9 -0
  86. package/dist/services/execAvailability.js +32 -0
  87. package/dist/services/fileWatcher.js +61 -6
  88. package/dist/services/initializationService.js +19 -15
  89. package/dist/services/interactionService.d.ts +9 -1
  90. package/dist/services/interactionService.js +28 -8
  91. package/dist/services/jsonlHandler.d.ts +84 -0
  92. package/dist/services/jsonlHandler.js +209 -14
  93. package/dist/services/memory.d.ts +3 -1
  94. package/dist/services/memory.js +13 -9
  95. package/dist/services/officialMarketplaceMirror.js +3 -2
  96. package/dist/services/pluginLoader.d.ts +12 -4
  97. package/dist/services/pluginLoader.js +38 -7
  98. package/dist/services/remoteSettingsService.js +16 -2
  99. package/dist/services/session.d.ts +74 -0
  100. package/dist/services/session.js +144 -3
  101. package/dist/services/sessionEntries.d.ts +2 -0
  102. package/dist/services/sessionEntries.js +20 -0
  103. package/dist/stdio/index.d.ts +3 -1
  104. package/dist/stdio/index.js +3 -1
  105. package/dist/stdio/notificationRouter.js +1 -0
  106. package/dist/stdio/stdioAgent.d.ts +14 -7
  107. package/dist/stdio/stdioAgent.js +19 -0
  108. package/dist/tools/artifactTool.js +406 -273
  109. package/dist/tools/bashTool.js +8 -6
  110. package/dist/tools/editTool.js +6 -3
  111. package/dist/tools/execTool.d.ts +2 -0
  112. package/dist/tools/execTool.js +165 -0
  113. package/dist/tools/grepTool.js +7 -1
  114. package/dist/tools/readTool.js +30 -2
  115. package/dist/tools/types.d.ts +34 -8
  116. package/dist/tools/webFetchTool.js +15 -166
  117. package/dist/tools/workflowTool.js +40 -8
  118. package/dist/tools/writeTool.js +6 -3
  119. package/dist/types/agent.d.ts +20 -5
  120. package/dist/types/configuration.d.ts +39 -1
  121. package/dist/types/marketplace.d.ts +40 -2
  122. package/dist/types/mcp.d.ts +39 -0
  123. package/dist/types/permissions.d.ts +22 -0
  124. package/dist/types/permissions.js +17 -0
  125. package/dist/types/plugins.d.ts +26 -2
  126. package/dist/types/skills.d.ts +15 -0
  127. package/dist/utils/constants.d.ts +10 -0
  128. package/dist/utils/constants.js +10 -0
  129. package/dist/utils/containerSetup.js +43 -0
  130. package/dist/utils/convertMessagesForAPI.d.ts +7 -1
  131. package/dist/utils/convertMessagesForAPI.js +64 -14
  132. package/dist/utils/fileChangeReminder.d.ts +20 -0
  133. package/dist/utils/fileChangeReminder.js +153 -0
  134. package/dist/utils/fileSearch.js +4 -3
  135. package/dist/utils/fileUtils.d.ts +33 -0
  136. package/dist/utils/fileUtils.js +81 -0
  137. package/dist/utils/frontmatterYaml.d.ts +33 -0
  138. package/dist/utils/frontmatterYaml.js +192 -0
  139. package/dist/utils/imageBudget.d.ts +85 -0
  140. package/dist/utils/imageBudget.js +109 -0
  141. package/dist/utils/imageDimensions.d.ts +83 -0
  142. package/dist/utils/imageDimensions.js +232 -0
  143. package/dist/utils/imageProcessor.d.ts +66 -0
  144. package/dist/utils/imageProcessor.js +84 -0
  145. package/dist/utils/imageRewrite.d.ts +29 -0
  146. package/dist/utils/imageRewrite.js +251 -0
  147. package/dist/utils/markdownParser.d.ts +5 -1
  148. package/dist/utils/markdownParser.js +9 -51
  149. package/dist/utils/mcpInstructions.d.ts +61 -0
  150. package/dist/utils/mcpInstructions.js +126 -0
  151. package/dist/utils/mcpUtils.d.ts +7 -0
  152. package/dist/utils/mcpUtils.js +11 -2
  153. package/dist/utils/memoryAge.d.ts +32 -0
  154. package/dist/utils/memoryAge.js +47 -0
  155. package/dist/utils/memoryEntrypoint.d.ts +20 -0
  156. package/dist/utils/memoryEntrypoint.js +49 -0
  157. package/dist/utils/memoryIndex.d.ts +30 -0
  158. package/dist/utils/memoryIndex.js +76 -0
  159. package/dist/utils/messageOperations.d.ts +6 -2
  160. package/dist/utils/messageOperations.js +40 -29
  161. package/dist/utils/nestedMemory.d.ts +22 -0
  162. package/dist/utils/nestedMemory.js +61 -0
  163. package/dist/utils/npmTarball.d.ts +19 -0
  164. package/dist/utils/npmTarball.js +92 -0
  165. package/dist/utils/pluginSource.d.ts +37 -0
  166. package/dist/utils/pluginSource.js +73 -0
  167. package/dist/utils/ripgrep.d.ts +18 -4
  168. package/dist/utils/ripgrep.js +56 -4
  169. package/dist/utils/runtimeDeps.d.ts +35 -0
  170. package/dist/utils/runtimeDeps.js +426 -0
  171. package/dist/utils/skillParser.js +22 -52
  172. package/dist/utils/subagentParser.js +39 -43
  173. package/dist/utils/userSettings.d.ts +90 -0
  174. package/dist/utils/userSettings.js +291 -0
  175. package/package.json +10 -7
@@ -1,5 +1,33 @@
1
+ import * as path from "node:path";
1
2
  import { WORKFLOW_TOOL_NAME } from "../constants/tools.js";
3
+ import { parseScript } from "../workflow/scriptRuntime.js";
2
4
  import { logger } from "../utils/globalLogger.js";
5
+ /** Characters that would corrupt a single-line summary (ANSI-adjacent controls, separators, invisibles). */
6
+ const SUMMARY_UNSAFE_CHARS = /[\p{Cc}\p{Cf}\p{Cs}\p{Default_Ignorable_Code_Point}\u2028\u2029]/gu;
7
+ /** Max characters of the script head shown when `meta` cannot be parsed. */
8
+ const FALLBACK_SUMMARY_MAX_CHARS = 80;
9
+ function sanitizeForSummary(text) {
10
+ return text.replace(SUMMARY_UNSAFE_CHARS, "");
11
+ }
12
+ /**
13
+ * Summary for a script whose `meta` could not be parsed: its first non-empty
14
+ * line, truncated if needed, plus a hint that more lines follow.
15
+ */
16
+ function summarizeUnparsedScript(script) {
17
+ const lines = script.split("\n");
18
+ const head = sanitizeForSummary(lines.find((line) => line.trim()) ?? "");
19
+ if (!head) {
20
+ return "";
21
+ }
22
+ const preview = head.length > FALLBACK_SUMMARY_MAX_CHARS
23
+ ? `${head.slice(0, FALLBACK_SUMMARY_MAX_CHARS - 1)}…`
24
+ : head;
25
+ const extraLines = lines.length - 1;
26
+ if (extraLines <= 0) {
27
+ return preview;
28
+ }
29
+ return `${preview} … +${extraLines} line${extraLines === 1 ? "" : "s"}`;
30
+ }
3
31
  /**
4
32
  * Workflow tool plugin for executing deterministic multi-subagent orchestration scripts.
5
33
  *
@@ -176,15 +204,19 @@ Use this tool for multi-step orchestration where control flow should be determin
176
204
  }
177
205
  },
178
206
  formatCompactParams: (params) => {
179
- if (params.scriptPath) {
180
- return `scriptPath: ${params.scriptPath}`;
181
- }
182
207
  const script = params.script;
183
- if (script) {
184
- // Extract meta.name from the script
185
- const nameMatch = script.match(/name:\s*['"]([^'"]+)['"]/);
186
- return nameMatch ? nameMatch[1] : script.slice(0, 50) + "...";
208
+ if (typeof script === "string" && script) {
209
+ try {
210
+ return sanitizeForSummary(parseScript(script).meta.description);
211
+ }
212
+ catch {
213
+ return summarizeUnparsedScript(script);
214
+ }
215
+ }
216
+ const scriptPath = params.scriptPath;
217
+ if (typeof scriptPath === "string" && scriptPath) {
218
+ return sanitizeForSummary(path.basename(scriptPath));
187
219
  }
188
- return "workflow";
220
+ return "";
189
221
  },
190
222
  };
@@ -1,7 +1,8 @@
1
- import { readFile, writeFile, mkdir, stat } from "fs/promises";
1
+ import { readFile, mkdir, stat } from "fs/promises";
2
2
  import { createHash } from "crypto";
3
3
  import { dirname } from "path";
4
4
  import { logger } from "../utils/globalLogger.js";
5
+ import { atomicWriteFile } from "../utils/atomicWrite.js";
5
6
  import { resolvePath, getDisplayPath } from "../utils/path.js";
6
7
  import { READ_TOOL_NAME } from "../constants/tools.js";
7
8
  /**
@@ -157,9 +158,10 @@ Usage:
157
158
  if (context.reversionManager && context.messageId) {
158
159
  snapshotId = await context.reversionManager.recordSnapshot(context.messageId, resolvedPath, isExistingFile ? "modify" : "create");
159
160
  }
160
- // Write file
161
+ // Write file (atomic: temp file + rename, so concurrent readers never
162
+ // observe a truncated file). Staleness/OCC was checked above.
161
163
  try {
162
- await writeFile(resolvedPath, content, "utf-8");
164
+ await atomicWriteFile(resolvedPath, content);
163
165
  // Commit snapshot on success
164
166
  if (context.reversionManager && snapshotId) {
165
167
  await context.reversionManager.commitSnapshot(snapshotId);
@@ -180,6 +182,7 @@ Usage:
180
182
  mtime: newStats.mtime.getTime(),
181
183
  hash,
182
184
  source: "write",
185
+ content,
183
186
  offset: undefined,
184
187
  limit: undefined,
185
188
  });
@@ -29,15 +29,24 @@ export interface AgentOptions {
29
29
  visionModel?: string;
30
30
  maxInputTokens?: number;
31
31
  maxTokens?: number;
32
- /** Preferred language for agent communication */
32
+ /**
33
+ * Preferred language for agent communication, injected verbatim into the
34
+ * system prompt (`# Language\nAlways respond in <value>`). When unset, the
35
+ * resolve chain falls back to `DEFAULT_LANGUAGE` (`zh-CN`).
36
+ */
33
37
  language?: string;
34
38
  /**
35
- * Per-session override for auto-memory extraction (settings-page toggle
36
- * value, carried by hosts over stdio). Takes precedence over settings.json
37
- * merged config and WAVE_DISABLE_AUTO_MEMORY env; undefined defers to them.
39
+ * Per-session override for auto-memory extraction (程序化会话级覆盖).
40
+ * Takes precedence over settings.json merged config and
41
+ * WAVE_DISABLE_AUTO_MEMORY env; undefined defers to them. 三端设置页的开关
42
+ * **不**经这一层下发——它落用户级 `~/.wave/settings.json`,由实时重载在下一轮
43
+ * 生效(spec core/agent-config.md「设置实时重载」)。
38
44
  */
39
45
  autoMemoryEnabled?: boolean;
40
- /** Per-session override for auto-memory extraction frequency (turns). */
46
+ /**
47
+ * Per-session override for auto-memory extraction frequency (turns). 同
48
+ * `autoMemoryEnabled`:设置页的值不在这一层。
49
+ */
41
50
  autoMemoryFrequency?: number;
42
51
  callbacks?: AgentCallbacks;
43
52
  restoreSessionId?: string;
@@ -119,4 +128,10 @@ export interface AgentCallbacks extends MessageManagerCallbacks, BackgroundTaskM
119
128
  onCompactionContentUpdate?: (content: string) => void;
120
129
  /** Streaming reasoning from the compaction fork (accumulated). */
121
130
  onCompactionReasoningUpdate?: (content: string) => void;
131
+ /**
132
+ * Full content of the plan file right after a successful `Write`/`Edit` of
133
+ * that file (spec: 计划文件更新后刷新计划面板). Hosts use it to refresh an
134
+ * already-open plan panel; it is not emitted for other files.
135
+ */
136
+ onPlanFileUpdated?: (content: string) => void;
122
137
  }
@@ -13,7 +13,6 @@ import type { TelemetryConfig } from "./telemetry.js";
13
13
  export type Scope = "user" | "project" | "local";
14
14
  export interface MarketplaceConfig {
15
15
  source: MarketplaceSource;
16
- autoUpdate?: boolean;
17
16
  }
18
17
  /**
19
18
  * Root configuration structure for all Wave Agent settings including hooks and environment variables
@@ -62,6 +61,8 @@ export interface WaveConfiguration {
62
61
  };
63
62
  /** Whether the Artifact tool is enabled. Unset follows the code default constant (ARTIFACT_DEFAULT_ENABLED). */
64
63
  enableArtifact?: boolean;
64
+ /** Whether the Exec tool is enabled. Unset follows the code default constant (EXEC_DEFAULT_ENABLED). */
65
+ enableExec?: boolean;
65
66
  /**
66
67
  * Session transcript retention in days (aligned with Claude Code's
67
68
  * cleanupPeriodDays). Session jsonl files in ~/.wave/projects older than
@@ -70,6 +71,43 @@ export interface WaveConfiguration {
70
71
  */
71
72
  cleanupPeriodDays?: number;
72
73
  }
74
+ /**
75
+ * 设置页读写的用户偏好子集(落点 = 用户级 `~/.wave/settings.json`;读写实现见
76
+ * `utils/userSettings.ts`)。三端(VSCE / JetBrains / desktop)设置页与 CLI 的
77
+ * `getUserSettings` / `updateUserSettings` RPC 共用这一形状;`contextLength` 单位
78
+ * 为 K(落盘换算为 `env.WAVE_MAX_INPUT_TOKENS`)。
79
+ */
80
+ export interface UserPreferenceSettings {
81
+ /** AI 回复语言(settings.json 顶层 `language`,如 zh-CN / en-US)。 */
82
+ language?: string;
83
+ /** 上下文长度,单位 K(如 200 = 200K)。 */
84
+ contextLength?: number;
85
+ /** 是否开启自动记忆提取。 */
86
+ autoMemoryEnabled?: boolean;
87
+ /** 自动记忆提取的轮次频率(1–100)。 */
88
+ autoMemoryFrequency?: number;
89
+ /** Wave 服务端地址(settings.json 的 `env.WAVE_SERVER_URL`,如 https://…)。 */
90
+ serverUrl?: string;
91
+ }
92
+ /** 用户偏好键(设置页控件)。 */
93
+ export type UserPreferenceKey = keyof UserPreferenceSettings;
94
+ /**
95
+ * 生效值的来源层。只归因**进程级可达**的层(Remote 组织下发 / 用户级文件 /
96
+ * 机器环境变量 / SDK 默认):`project` / `local` 需要 workdir,而
97
+ * `getUserSettings` 是刻意的无会话全局 RPC;`override` / `options` 是会话级
98
+ * 语义,不在这条链路上(见 spec core/agent-config.md 边界说明「用户偏好的层与来源」)。
99
+ */
100
+ export type UserPreferenceSource = "remote" | "user" | "env" | "default";
101
+ /**
102
+ * `getUserSettings` / `updateUserSettings` 的回包:**生效**用户偏好——键缺失
103
+ * 表示该偏好没有任何提供者(设置页据此显示「未设置」态)——外加每个键的来源层
104
+ * (`preferenceSources`,设置页对来源为 `remote` 的键显示生效值 + 置灰 +
105
+ * 「由组织配置管理」)。
106
+ */
107
+ export interface UserPreferenceSettingsView extends UserPreferenceSettings {
108
+ /** 每个键恒有来源(缺省即 `default`)。 */
109
+ preferenceSources?: Partial<Record<UserPreferenceKey, UserPreferenceSource>>;
110
+ }
73
111
  /**
74
112
  * Legacy alias for backward compatibility - will be deprecated
75
113
  */
@@ -3,18 +3,47 @@ export interface MarketplaceOwner {
3
3
  name: string;
4
4
  email?: string;
5
5
  }
6
+ /**
7
+ * Object form of a plugin entry's `source` (spec plugin A-021): `url` is a whole
8
+ * repository, `git-subdir` is a subdirectory of one. Both are outside the
9
+ * marketplace checkout, so they carry no readable local copy for「最新版本」(A-010).
10
+ */
11
+ export interface MarketplacePluginObjectSource {
12
+ source: "url" | "git-subdir";
13
+ url: string;
14
+ /** Only for `git-subdir`: path of the plugin inside the repository. */
15
+ path?: string;
16
+ /** Branch or tag. */
17
+ ref?: string;
18
+ /** Pinned commit; checked out after cloning. */
19
+ sha?: string;
20
+ }
6
21
  export interface MarketplacePluginEntry {
7
22
  name: string;
8
- source: string;
23
+ source: string | MarketplacePluginObjectSource;
9
24
  description: string;
10
25
  }
11
26
  export interface MarketplacePluginStatus extends MarketplacePluginEntry {
12
27
  marketplace: string;
13
28
  installed: boolean;
29
+ /** 已安装版本(未安装时 undefined) */
14
30
  version?: string;
31
+ /**
32
+ * 市场内该插件当前可安装的最新版本,取自市场检出目录内插件的
33
+ * `.wave-plugin/plugin.json`(兼容 `.claude-plugin/plugin.json`)。
34
+ * 插件来源是独立 Git 仓库等无法就地读取清单的情况为 undefined
35
+ * (spec plugin A-010:此时不展示最新版本)。
36
+ */
37
+ latestVersion?: string;
15
38
  cachePath?: string;
16
39
  projectPath?: string;
17
40
  scope?: Scope;
41
+ /**
42
+ * 该插件由组织的托管配置(远端托管设置)声明启用:成员不能卸载或禁用它,
43
+ * 界面据此把卸载入口判为不可用并给出由组织管理的说明(spec plugin A-024)。
44
+ * 判据只看下发值,本机不落任何标记。
45
+ */
46
+ managed?: boolean;
18
47
  }
19
48
  export interface MarketplaceManifest {
20
49
  name: string;
@@ -37,7 +66,6 @@ export interface KnownMarketplace {
37
66
  name: string;
38
67
  source: MarketplaceSource;
39
68
  isBuiltin?: boolean;
40
- autoUpdate?: boolean;
41
69
  lastUpdated?: string;
42
70
  /** The scope where this marketplace was declared (user, project, local, or builtin) */
43
71
  declaredScope?: "user" | "project" | "local" | "builtin";
@@ -46,12 +74,22 @@ export interface KnownMarketplacesRegistry {
46
74
  builtinSeeded?: boolean;
47
75
  marketplaces: KnownMarketplace[];
48
76
  }
77
+ /**
78
+ * 安装产物的记账位置(spec plugin A-015):用户作用域是本机全局的,不带
79
+ * projectPath;项目作用域与本地作用域归属某个仓库,以该仓库路径为 projectPath。
80
+ */
81
+ export interface PluginInstallLocation {
82
+ scope: Scope;
83
+ projectPath?: string;
84
+ }
49
85
  export interface InstalledPlugin {
50
86
  name: string;
51
87
  marketplace: string;
52
88
  version: string;
53
89
  cachePath: string;
90
+ /** 该条安装记录所属的作用域;引入作用域维度之前写入的历史记录不带此字段(spec plugin A-015)。 */
54
91
  scope?: Scope;
92
+ /** 项目作用域与本地作用域所属仓库的路径;用户作用域不带。 */
55
93
  projectPath?: string;
56
94
  }
57
95
  export interface InstalledPluginsRegistry {
@@ -19,6 +19,34 @@ export interface McpTool {
19
19
  name: string;
20
20
  description?: string;
21
21
  inputSchema: Record<string, unknown>;
22
+ /**
23
+ * The schema the server declared for its *output*, raw as listed. Not passed
24
+ * through `cleanSchema` like `inputSchema`: that cleaning exists because the
25
+ * input schema travels inside a request, and this one is only ever rendered as
26
+ * a return type. Absent for most servers today, and degenerate
27
+ * (`{ type: "object" }`) when present.
28
+ */
29
+ outputSchema?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * What one MCP tool call produced. Two audiences, two fields:
33
+ *
34
+ * - `content` is the display text the flat path hands the model — a placeholder
35
+ * when the tool said nothing (`No content`) or returned only images.
36
+ * - `output` is what a sandbox `await` resolves to: the server's
37
+ * `structuredContent` when it returned one, otherwise its text, otherwise
38
+ * `null`. The catalog renders its return types from this same rule, so a
39
+ * signature can never promise a shape the sandbox does not deliver.
40
+ */
41
+ export interface McpToolCallResult {
42
+ success: boolean;
43
+ content: string;
44
+ output: unknown;
45
+ serverName?: string;
46
+ images?: Array<{
47
+ data: string;
48
+ mediaType?: string;
49
+ }>;
22
50
  }
23
51
  export interface McpServerStatus {
24
52
  name: string;
@@ -32,6 +60,17 @@ export interface McpServerStatus {
32
60
  tools?: McpTool[];
33
61
  toolCount?: number;
34
62
  capabilities?: string[];
63
+ /**
64
+ * Usage notes the server described about itself during `initialize`
65
+ * (`instructions`): rate limits, preconditions, how the server is meant to be
66
+ * used. Server-level prose, announced once in the conversation instead of the
67
+ * system prompt — see `utils/mcpInstructions.ts` for why, and for the per-server
68
+ * cap — and already truncated by the time it lands here, unlike a tool
69
+ * description, which the catalog compresses.
70
+ * Retained across a reconnecting server (like `tools`) and cleared once the
71
+ * server is gone, so a dropped server cannot keep talking to the model.
72
+ */
73
+ instructions?: string;
35
74
  lastConnected?: number;
36
75
  error?: string;
37
76
  }
@@ -15,6 +15,8 @@ export interface PermissionDecision {
15
15
  newPermissionMode?: PermissionMode;
16
16
  /** Signal to persist a new allowed rule */
17
17
  newPermissionRule?: string;
18
+ /** Signal to add a directory to this session's Safe Zone (not persisted) */
19
+ newAdditionalDirectory?: string;
18
20
  }
19
21
  /** Callback function for custom permission logic */
20
22
  export type PermissionCallback = (context: ToolPermissionContext) => Promise<PermissionDecision>;
@@ -32,6 +34,12 @@ export interface ToolPermissionContext {
32
34
  suggestedPrefix?: string;
33
35
  /** Whether to hide the persistent permission option (e.g., "Don't ask again") in the UI */
34
36
  hidePersistentOption?: boolean;
37
+ /**
38
+ * Absolute path of the directory holding an out-of-Safe-Zone target, set for
39
+ * Edit/Write when the target lies outside the Safe Zone. Lets the confirmation
40
+ * UI offer adding that directory to the session Safe Zone.
41
+ */
42
+ outsideSafeZoneDirectory?: string;
35
43
  /** The ID of the tool call that triggered this permission request */
36
44
  toolCallId?: string;
37
45
  /** The content of the plan being exited from */
@@ -41,6 +49,20 @@ export interface ToolPermissionContext {
41
49
  }
42
50
  /** List of tools that require permission checks in default mode */
43
51
  export declare const RESTRICTED_TOOLS: readonly ["Edit", "Bash", "Write", "EnterPlanMode", "ExitPlanMode", "AskUserQuestion", "Artifact"];
52
+ /**
53
+ * Tools that must still reach the user when permission checks are bypassed
54
+ * (`bypassPermissions` mode, or `plan` mode in a session holding the bypass
55
+ * authorization) — aligned with Claude Code's `requiresUserInteraction`:
56
+ * its permission pipeline returns the tool's own ask result before the
57
+ * bypass step can allow it.
58
+ *
59
+ * - `AskUserQuestion`: the tool *is* the question; bypassing it would strand
60
+ * the agent without an answer.
61
+ * - `ExitPlanMode`: leaving plan mode is the user's approval of the plan, so
62
+ * it stays a user decision even in a "don't ask me" session. This is the
63
+ * one remaining gate on plan mode for such sessions (see plan-mode.md).
64
+ */
65
+ export declare const USER_INTERACTION_REQUIRED_TOOLS: readonly ["AskUserQuestion", "ExitPlanMode"];
44
66
  /** Type for restricted tool names */
45
67
  export type RestrictedTool = (typeof RESTRICTED_TOOLS)[number];
46
68
  export declare const OPERATION_CANCELLED_BY_USER = "Operation cancelled by user";
@@ -13,4 +13,21 @@ export const RESTRICTED_TOOLS = [
13
13
  ASK_USER_QUESTION_TOOL_NAME,
14
14
  ARTIFACT_TOOL_NAME,
15
15
  ];
16
+ /**
17
+ * Tools that must still reach the user when permission checks are bypassed
18
+ * (`bypassPermissions` mode, or `plan` mode in a session holding the bypass
19
+ * authorization) — aligned with Claude Code's `requiresUserInteraction`:
20
+ * its permission pipeline returns the tool's own ask result before the
21
+ * bypass step can allow it.
22
+ *
23
+ * - `AskUserQuestion`: the tool *is* the question; bypassing it would strand
24
+ * the agent without an answer.
25
+ * - `ExitPlanMode`: leaving plan mode is the user's approval of the plan, so
26
+ * it stays a user decision even in a "don't ask me" session. This is the
27
+ * one remaining gate on plan mode for such sessions (see plan-mode.md).
28
+ */
29
+ export const USER_INTERACTION_REQUIRED_TOOLS = [
30
+ ASK_USER_QUESTION_TOOL_NAME,
31
+ EXIT_PLAN_MODE_TOOL_NAME,
32
+ ];
16
33
  export const OPERATION_CANCELLED_BY_USER = "Operation cancelled by user";
@@ -1,7 +1,7 @@
1
1
  import { CustomSlashCommand } from "./commands.js";
2
2
  import { Skill } from "./skills.js";
3
3
  import { LspConfig } from "./lsp.js";
4
- import { McpConfig } from "./mcp.js";
4
+ import { McpConfig, McpServerConfig } from "./mcp.js";
5
5
  import { PartialHookConfiguration } from "./configuration.js";
6
6
  import { SubagentConfiguration } from "../utils/subagentParser.js";
7
7
  /**
@@ -10,10 +10,20 @@ import { SubagentConfiguration } from "../utils/subagentParser.js";
10
10
  export interface PluginManifest {
11
11
  name: string;
12
12
  description: string;
13
- version: string;
13
+ /**
14
+ * Optional: plugins in the Claude Code ecosystem often omit it (spec plugin
15
+ * A-022). Install and load both fall back to `1.0.0`.
16
+ */
17
+ version?: string;
14
18
  author?: {
15
19
  name: string;
16
20
  };
21
+ /**
22
+ * Inline MCP server declarations, equivalent to a sibling `.mcp.json`
23
+ * (spec plugin A-023). Claude Code also allows a path string or array of
24
+ * paths here; only the object form is supported.
25
+ */
26
+ mcpServers?: Record<string, McpServerConfig>;
17
27
  }
18
28
  /**
19
29
  * Plugin configuration in AgentOptions or wave.settings.json
@@ -22,10 +32,24 @@ export interface PluginConfig {
22
32
  type: "local";
23
33
  path: string;
24
34
  }
35
+ /** A plugin root that failed to load during the most recent load/reload. */
36
+ export interface PluginLoadFailure {
37
+ path: string;
38
+ error: string;
39
+ }
40
+ /** Result of `Agent.reloadPlugins()` / `PluginManager.reloadAllPlugins()`. */
41
+ export interface PluginReloadResult {
42
+ /** Plugin names loaded after the reload. */
43
+ plugins: string[];
44
+ /** Plugins that could not be loaded; the reload does not roll back. */
45
+ failures: PluginLoadFailure[];
46
+ }
25
47
  /**
26
48
  * Represents a loaded plugin in the system
27
49
  */
28
50
  export interface Plugin extends PluginManifest {
51
+ /** Always resolved on load: a missing manifest version becomes `1.0.0` (A-022). */
52
+ version: string;
29
53
  path: string;
30
54
  commands: CustomSlashCommand[];
31
55
  skills: Skill[];
@@ -91,6 +91,21 @@ export interface SkillParseOptions {
91
91
  validateMetadata?: boolean;
92
92
  basePath?: string;
93
93
  }
94
+ /**
95
+ * A skill invocation recorded for context restoration (post-compaction
96
+ * re-injection, spec core/message-compact 场景 4).
97
+ */
98
+ export interface InvokedSkillRecord {
99
+ skillName: string;
100
+ timestamp: number;
101
+ /**
102
+ * The content the model actually saw when the skill was invoked — directory
103
+ * placeholders already substituted, prefixed with
104
+ * `Base directory for this skill: <path>`. Re-injecting the raw SKILL.md
105
+ * instead would hand the model a literal `${WAVE_SKILL_DIR}`.
106
+ */
107
+ content?: string;
108
+ }
94
109
  export declare const SKILL_DEFAULTS: {
95
110
  readonly PERSONAL_SKILLS_DIR: ".wave/skills";
96
111
  readonly PROJECT_SKILLS_DIR: ".wave/skills";
@@ -23,6 +23,16 @@ export declare const USER_MEMORY_FILE: string;
23
23
  */
24
24
  export declare const DEFAULT_WAVE_MAX_INPUT_TOKENS = 200000;
25
25
  export declare const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 32000;
26
+ /**
27
+ * AI 回复语言的默认值(未设置 `language` 时生效)。
28
+ *
29
+ * 取值必须与设置页「AI 回复语言」下拉的默认项是同一个串(webview
30
+ * `SettingsPage.tsx` 的 `zh-CN` / `en-US`),否则未设置时会出现「设置页显示中文、
31
+ * 实际生效却不是中文」的分叉(spec core/agent-config.md 边界说明「语言默认值」:
32
+ * 未设置时 **显示 ≡ 生效**)。该值原样注入系统提示的
33
+ * `# Language\nAlways respond in <值>` 指令。
34
+ */
35
+ export declare const DEFAULT_LANGUAGE = "zh-CN";
26
36
  /**
27
37
  * Default server URL for SSO authentication.
28
38
  * Overridden by WAVE_SERVER_URL env var or programmatic AgentOptions.serverUrl.
@@ -25,6 +25,16 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
25
25
  */
26
26
  export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 200000; // Default token limit
27
27
  export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 32000; // Default output token limit (aligned with Claude Code)
28
+ /**
29
+ * AI 回复语言的默认值(未设置 `language` 时生效)。
30
+ *
31
+ * 取值必须与设置页「AI 回复语言」下拉的默认项是同一个串(webview
32
+ * `SettingsPage.tsx` 的 `zh-CN` / `en-US`),否则未设置时会出现「设置页显示中文、
33
+ * 实际生效却不是中文」的分叉(spec core/agent-config.md 边界说明「语言默认值」:
34
+ * 未设置时 **显示 ≡ 生效**)。该值原样注入系统提示的
35
+ * `# Language\nAlways respond in <值>` 指令。
36
+ */
37
+ export const DEFAULT_LANGUAGE = "zh-CN";
28
38
  /**
29
39
  * Default server URL for SSO authentication.
30
40
  * Overridden by WAVE_SERVER_URL env var or programmatic AgentOptions.serverUrl.
@@ -28,6 +28,8 @@ import { MemoryService } from "../services/memory.js";
28
28
  import { AutoMemoryService } from "../services/autoMemoryService.js";
29
29
  import { USER_MEMORY_FILE } from "./constants.js";
30
30
  import { getGitMainRepoRoot } from "./gitUtils.js";
31
+ import { toPosixPath } from "./path.js";
32
+ import { EDIT_TOOL_NAME, WRITE_TOOL_NAME } from "../constants/tools.js";
31
33
  import { AsyncWorkRegistry } from "./asyncWorkRegistry.js";
32
34
  import { logger } from "./globalLogger.js";
33
35
  import { authService } from "../services/authService.js";
@@ -211,6 +213,19 @@ export function setupAgentContainer(setupOptions) {
211
213
  if (decision.newPermissionRule) {
212
214
  await addPermissionRule(decision.newPermissionRule);
213
215
  }
216
+ if (decision.newAdditionalDirectory) {
217
+ // Session-level only: the user approved this directory from the
218
+ // confirmation dialog (never persisted to settings).
219
+ permissionManager.addInstanceAdditionalDirectory(decision.newAdditionalDirectory);
220
+ // The dialog option is "允许本会话编辑 <目录名>/" — it has to cover
221
+ // later edits too, otherwise `default` mode would keep prompting for
222
+ // every Write/Edit in that directory. Forward slashes: minimatch
223
+ // treats the pattern `\` as an escape, while it normalises the input
224
+ // path's separators on Windows.
225
+ const pattern = `${toPosixPath(decision.newAdditionalDirectory)}/**`;
226
+ permissionManager.addInstanceAllowedRule(`${EDIT_TOOL_NAME}(${pattern})`);
227
+ permissionManager.addInstanceAllowedRule(`${WRITE_TOOL_NAME}(${pattern})`);
228
+ }
214
229
  return decision;
215
230
  }
216
231
  : undefined;
@@ -248,13 +263,41 @@ export function setupAgentContainer(setupOptions) {
248
263
  },
249
264
  });
250
265
  container.register("LiveConfigManager", liveConfigManager);
266
+ // The turn-scoped configuration snapshot is held by LiveConfigManager (it owns
267
+ // the turn boundaries and the live reload) and read by ConfigurationService's
268
+ // resolve chain, so a mid-turn settings.json change applies from the next turn
269
+ // instead of shifting values under the running one.
270
+ configurationService.setTurnSnapshotSource(() => liveConfigManager.getTurnSnapshot());
251
271
  // Wire up remote settings hot-update: when polling detects changed settings,
252
272
  // reload configuration so admin changes propagate to the running agent.
253
273
  // The callback strongly captures the per-agent LiveConfigManager, so it MUST
254
274
  // be unsubscribed in destroy() via teardown — otherwise the module-level
255
275
  // callback array pins the whole agent object graph.
276
+ // Managed plugin config (enabledPlugins / marketplaces) last applied to the
277
+ // plugin subsystem, keyed by a JSON signature: a synced change that touches
278
+ // neither field must not bounce every plugin's MCP servers.
279
+ const remoteAtSetup = remoteSettingsService.getRemoteSettingsSync();
280
+ let managedPluginSignature = JSON.stringify([
281
+ remoteAtSetup?.enabledPlugins ?? null,
282
+ remoteAtSetup?.marketplaces ?? null,
283
+ ]);
256
284
  teardowns.push(remoteSettingsService.onSettingsUpdate(async () => {
257
285
  await liveConfigManager.reload();
286
+ // Managed settings also drive plugin installation and loading: a synced
287
+ // change to `enabledPlugins` / `marketplaces` must re-read the plugins in
288
+ // place, otherwise an admin push would only take effect after a restart
289
+ // (spec enterprise server-managed-config「托管配置下发插件市场与启用列表」
290
+ // 场景 1 与 3).
291
+ const remote = remoteSettingsService.getRemoteSettingsSync();
292
+ const signature = JSON.stringify([
293
+ remote?.enabledPlugins ?? null,
294
+ remote?.marketplaces ?? null,
295
+ ]);
296
+ if (signature === managedPluginSignature) {
297
+ return;
298
+ }
299
+ managedPluginSignature = signature;
300
+ await container.get("PluginManager")?.reloadAllPlugins();
258
301
  }));
259
302
  const subagentManager = new SubagentManager(container, {
260
303
  workdir,
@@ -10,8 +10,14 @@ export interface ConvertMessagesOptions {
10
10
  /**
11
11
  * Convert message format to API call format, stopping when a compacted message is encountered.
12
12
  * Messages with no meaningful content or tool calls are filtered out.
13
+ *
14
+ * Async because every outbound image is routed through `planOutboundImage`,
15
+ * which may have to re-encode an oversized image with the optional `sharp`
16
+ * codec (`utils/imageRewrite.ts`). Images that are already inside the budget —
17
+ * the common case — take a synchronous fast path and come out byte-identical.
18
+ *
13
19
  * @param messages Message list
14
20
  * @param options Optional conversion options (e.g. supportsVision)
15
21
  * @returns Converted API message format list
16
22
  */
17
- export declare function convertMessagesForAPI(messages: Message[], options?: ConvertMessagesOptions): ChatCompletionMessageParam[];
23
+ export declare function convertMessagesForAPI(messages: Message[], options?: ConvertMessagesOptions): Promise<ChatCompletionMessageParam[]>;