c0de-agent 0.0.0 → 1.1.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 (336) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/dist/cli/commands/acp.d.ts +19 -0
  4. package/dist/cli/commands/acp.js +50 -0
  5. package/dist/cli/commands/chat.d.ts +13 -0
  6. package/dist/cli/commands/chat.js +26 -0
  7. package/dist/cli/commands/config.d.ts +17 -0
  8. package/dist/cli/commands/config.js +77 -0
  9. package/dist/cli/commands/init.d.ts +9 -0
  10. package/dist/cli/commands/init.js +14 -0
  11. package/dist/cli/commands/plugin.d.ts +11 -0
  12. package/dist/cli/commands/plugin.js +31 -0
  13. package/dist/cli/commands/serve.d.ts +18 -0
  14. package/dist/cli/commands/serve.js +35 -0
  15. package/dist/cli/commands/update.d.ts +24 -0
  16. package/dist/cli/commands/update.js +40 -0
  17. package/dist/cli/deps.d.ts +30 -0
  18. package/dist/cli/deps.js +70 -0
  19. package/dist/cli/index.d.ts +8 -0
  20. package/dist/cli/index.js +155 -0
  21. package/dist/cli/modes/acp.d.ts +18 -0
  22. package/dist/cli/modes/acp.js +57 -0
  23. package/dist/cli/modes/print.d.ts +16 -0
  24. package/dist/cli/modes/print.js +30 -0
  25. package/dist/cli/parser.d.ts +19 -0
  26. package/dist/cli/parser.js +28 -0
  27. package/dist/cli/utils/output.d.ts +11 -0
  28. package/dist/cli/utils/output.js +23 -0
  29. package/dist/cli/utils/prompt.d.ts +12 -0
  30. package/dist/cli/utils/prompt.js +18 -0
  31. package/dist/core/agent.d.ts +12 -0
  32. package/dist/core/agent.js +100 -0
  33. package/dist/core/agents/builtin.d.ts +6 -0
  34. package/dist/core/agents/builtin.js +76 -0
  35. package/dist/core/agents/discovery.d.ts +6 -0
  36. package/dist/core/agents/discovery.js +96 -0
  37. package/dist/core/agents/index.d.ts +6 -0
  38. package/dist/core/agents/index.js +4 -0
  39. package/dist/core/agents/parallel.d.ts +13 -0
  40. package/dist/core/agents/parallel.js +37 -0
  41. package/dist/core/agents/registry.d.ts +4 -0
  42. package/dist/core/agents/registry.js +23 -0
  43. package/dist/core/agents/types.d.ts +37 -0
  44. package/dist/core/agents/types.js +1 -0
  45. package/dist/core/compact.d.ts +11 -0
  46. package/dist/core/compact.js +31 -0
  47. package/dist/core/config.d.ts +7 -0
  48. package/dist/core/config.js +85 -0
  49. package/dist/core/context.d.ts +23 -0
  50. package/dist/core/context.js +93 -0
  51. package/dist/core/index.d.ts +13 -0
  52. package/dist/core/index.js +11 -0
  53. package/dist/core/loop.d.ts +35 -0
  54. package/dist/core/loop.js +915 -0
  55. package/dist/core/metrics.d.ts +27 -0
  56. package/dist/core/metrics.js +94 -0
  57. package/dist/core/prompt-registry.d.ts +21 -0
  58. package/dist/core/prompt-registry.js +200 -0
  59. package/dist/core/prompt.d.ts +11 -0
  60. package/dist/core/prompt.js +13 -0
  61. package/dist/core/secret.d.ts +12 -0
  62. package/dist/core/secret.js +51 -0
  63. package/dist/core/slash.d.ts +15 -0
  64. package/dist/core/slash.js +113 -0
  65. package/dist/core/steering.d.ts +8 -0
  66. package/dist/core/steering.js +15 -0
  67. package/dist/core/title.d.ts +42 -0
  68. package/dist/core/title.js +116 -0
  69. package/dist/core/tool-exec.d.ts +20 -0
  70. package/dist/core/tool-exec.js +64 -0
  71. package/dist/core/types.d.ts +97 -0
  72. package/dist/core/types.js +1 -0
  73. package/dist/core/worktree.d.ts +24 -0
  74. package/dist/core/worktree.js +70 -0
  75. package/dist/dap/index.d.ts +6 -0
  76. package/dist/dap/index.js +4 -0
  77. package/dist/dap/protocol.d.ts +40 -0
  78. package/dist/dap/protocol.js +132 -0
  79. package/dist/dap/session.d.ts +23 -0
  80. package/dist/dap/session.js +130 -0
  81. package/dist/dap/transport.d.ts +8 -0
  82. package/dist/dap/transport.js +30 -0
  83. package/dist/dap/types.d.ts +50 -0
  84. package/dist/dap/types.js +2 -0
  85. package/dist/db/client.d.ts +22 -0
  86. package/dist/db/client.js +39 -0
  87. package/dist/db/index.d.ts +6 -0
  88. package/dist/db/index.js +4 -0
  89. package/dist/db/migrate.d.ts +9 -0
  90. package/dist/db/migrate.js +15 -0
  91. package/dist/db/schema.d.ts +965 -0
  92. package/dist/db/schema.js +112 -0
  93. package/dist/db/types.d.ts +11 -0
  94. package/dist/db/types.js +1 -0
  95. package/dist/llm/index.d.ts +13 -0
  96. package/dist/llm/index.js +8 -0
  97. package/dist/llm/protocols/openai-compat.d.ts +139 -0
  98. package/dist/llm/protocols/openai-compat.js +214 -0
  99. package/dist/llm/protocols/utils/index.d.ts +2 -0
  100. package/dist/llm/protocols/utils/index.js +2 -0
  101. package/dist/llm/protocols/utils/lifecycle.d.ts +23 -0
  102. package/dist/llm/protocols/utils/lifecycle.js +46 -0
  103. package/dist/llm/protocols/utils/tool-stream.d.ts +46 -0
  104. package/dist/llm/protocols/utils/tool-stream.js +94 -0
  105. package/dist/llm/provider-error.d.ts +5 -0
  106. package/dist/llm/provider-error.js +33 -0
  107. package/dist/llm/provider.d.ts +32 -0
  108. package/dist/llm/provider.js +195 -0
  109. package/dist/llm/registry.d.ts +44 -0
  110. package/dist/llm/registry.js +107 -0
  111. package/dist/llm/retry.d.ts +37 -0
  112. package/dist/llm/retry.js +82 -0
  113. package/dist/llm/routing.d.ts +36 -0
  114. package/dist/llm/routing.js +53 -0
  115. package/dist/llm/schema/errors.d.ts +88 -0
  116. package/dist/llm/schema/errors.js +33 -0
  117. package/dist/llm/schema/events.d.ts +135 -0
  118. package/dist/llm/schema/events.js +35 -0
  119. package/dist/llm/schema/ids.d.ts +22 -0
  120. package/dist/llm/schema/ids.js +3 -0
  121. package/dist/llm/schema/index.d.ts +5 -0
  122. package/dist/llm/schema/index.js +5 -0
  123. package/dist/llm/schema/messages.d.ts +97 -0
  124. package/dist/llm/schema/messages.js +18 -0
  125. package/dist/llm/schema/options.d.ts +54 -0
  126. package/dist/llm/schema/options.js +54 -0
  127. package/dist/llm/token.d.ts +2 -0
  128. package/dist/llm/token.js +13 -0
  129. package/dist/llm/transport.d.ts +31 -0
  130. package/dist/llm/transport.js +165 -0
  131. package/dist/mcp/index.d.ts +1 -0
  132. package/dist/mcp/index.js +3 -0
  133. package/dist/plugins/builtin.d.ts +6 -0
  134. package/dist/plugins/builtin.js +54 -0
  135. package/dist/plugins/hooks.d.ts +3 -0
  136. package/dist/plugins/hooks.js +79 -0
  137. package/dist/plugins/index.d.ts +9 -0
  138. package/dist/plugins/index.js +8 -0
  139. package/dist/plugins/init.d.ts +23 -0
  140. package/dist/plugins/init.js +30 -0
  141. package/dist/plugins/lifecycle.d.ts +6 -0
  142. package/dist/plugins/lifecycle.js +74 -0
  143. package/dist/plugins/loader.d.ts +16 -0
  144. package/dist/plugins/loader.js +69 -0
  145. package/dist/plugins/logger.d.ts +4 -0
  146. package/dist/plugins/logger.js +31 -0
  147. package/dist/plugins/registry.d.ts +7 -0
  148. package/dist/plugins/registry.js +24 -0
  149. package/dist/plugins/types.d.ts +113 -0
  150. package/dist/plugins/types.js +1 -0
  151. package/dist/project/detect.d.ts +4 -0
  152. package/dist/project/detect.js +131 -0
  153. package/dist/project/index.d.ts +4 -0
  154. package/dist/project/index.js +2 -0
  155. package/dist/project/project.d.ts +23 -0
  156. package/dist/project/project.js +87 -0
  157. package/dist/project/resolve.d.ts +8 -0
  158. package/dist/project/resolve.js +81 -0
  159. package/dist/server/agent-manager.d.ts +34 -0
  160. package/dist/server/agent-manager.js +62 -0
  161. package/dist/server/app.d.ts +5 -0
  162. package/dist/server/app.js +78 -0
  163. package/dist/server/context.d.ts +20 -0
  164. package/dist/server/context.js +49 -0
  165. package/dist/server/dev.d.ts +14 -0
  166. package/dist/server/dev.js +148 -0
  167. package/dist/server/index.d.ts +11 -0
  168. package/dist/server/index.js +7 -0
  169. package/dist/server/middleware/auth.d.ts +15 -0
  170. package/dist/server/middleware/auth.js +29 -0
  171. package/dist/server/middleware/cors.d.ts +16 -0
  172. package/dist/server/middleware/cors.js +44 -0
  173. package/dist/server/middleware/error.d.ts +15 -0
  174. package/dist/server/middleware/error.js +11 -0
  175. package/dist/server/permission/interactive.d.ts +24 -0
  176. package/dist/server/permission/interactive.js +56 -0
  177. package/dist/server/permission/store.d.ts +32 -0
  178. package/dist/server/permission/store.js +56 -0
  179. package/dist/server/routes/agent.d.ts +4 -0
  180. package/dist/server/routes/agent.js +19 -0
  181. package/dist/server/routes/catalog.d.ts +42 -0
  182. package/dist/server/routes/catalog.js +194 -0
  183. package/dist/server/routes/chat.d.ts +8 -0
  184. package/dist/server/routes/chat.js +318 -0
  185. package/dist/server/routes/commands.d.ts +5 -0
  186. package/dist/server/routes/commands.js +17 -0
  187. package/dist/server/routes/config.d.ts +4 -0
  188. package/dist/server/routes/config.js +27 -0
  189. package/dist/server/routes/files.d.ts +4 -0
  190. package/dist/server/routes/files.js +183 -0
  191. package/dist/server/routes/filesystem.d.ts +29 -0
  192. package/dist/server/routes/filesystem.js +108 -0
  193. package/dist/server/routes/health.d.ts +3 -0
  194. package/dist/server/routes/health.js +13 -0
  195. package/dist/server/routes/permissions.d.ts +5 -0
  196. package/dist/server/routes/permissions.js +23 -0
  197. package/dist/server/routes/project.d.ts +4 -0
  198. package/dist/server/routes/project.js +51 -0
  199. package/dist/server/routes/provider.d.ts +16 -0
  200. package/dist/server/routes/provider.js +66 -0
  201. package/dist/server/routes/session.d.ts +4 -0
  202. package/dist/server/routes/session.js +204 -0
  203. package/dist/server/routes/terminal.d.ts +5 -0
  204. package/dist/server/routes/terminal.js +66 -0
  205. package/dist/server/routes/tool.d.ts +4 -0
  206. package/dist/server/routes/tool.js +28 -0
  207. package/dist/server/routes/update.d.ts +14 -0
  208. package/dist/server/routes/update.js +49 -0
  209. package/dist/server/server.d.ts +56 -0
  210. package/dist/server/server.js +269 -0
  211. package/dist/server/terminal/pty-manager.d.ts +53 -0
  212. package/dist/server/terminal/pty-manager.js +160 -0
  213. package/dist/server/types.d.ts +76 -0
  214. package/dist/server/types.js +2 -0
  215. package/dist/server/util/safe-path.d.ts +7 -0
  216. package/dist/server/util/safe-path.js +7 -0
  217. package/dist/session/archive.d.ts +15 -0
  218. package/dist/session/archive.js +129 -0
  219. package/dist/session/branch.d.ts +9 -0
  220. package/dist/session/branch.js +63 -0
  221. package/dist/session/compaction.d.ts +33 -0
  222. package/dist/session/compaction.js +261 -0
  223. package/dist/session/context.d.ts +16 -0
  224. package/dist/session/context.js +173 -0
  225. package/dist/session/index.d.ts +10 -0
  226. package/dist/session/index.js +10 -0
  227. package/dist/session/message.d.ts +22 -0
  228. package/dist/session/message.js +145 -0
  229. package/dist/session/session.d.ts +37 -0
  230. package/dist/session/session.js +144 -0
  231. package/dist/session/shake.d.ts +66 -0
  232. package/dist/session/shake.js +304 -0
  233. package/dist/session/snapshot.d.ts +11 -0
  234. package/dist/session/snapshot.js +60 -0
  235. package/dist/session/squash.d.ts +9 -0
  236. package/dist/session/squash.js +88 -0
  237. package/dist/session/token.d.ts +10 -0
  238. package/dist/session/token.js +33 -0
  239. package/dist/session/types.d.ts +122 -0
  240. package/dist/session/types.js +1 -0
  241. package/dist/shared/index.d.ts +2 -0
  242. package/dist/shared/index.js +1 -0
  243. package/dist/shared/types/agent.d.ts +229 -0
  244. package/dist/shared/types/agent.js +1 -0
  245. package/dist/shared/types/base.d.ts +32 -0
  246. package/dist/shared/types/base.js +1 -0
  247. package/dist/shared/types/config.d.ts +114 -0
  248. package/dist/shared/types/config.js +1 -0
  249. package/dist/shared/types/index.d.ts +6 -0
  250. package/dist/shared/types/index.js +1 -0
  251. package/dist/shared/types/llm.d.ts +123 -0
  252. package/dist/shared/types/llm.js +1 -0
  253. package/dist/shared/types/message.d.ts +71 -0
  254. package/dist/shared/types/message.js +1 -0
  255. package/dist/shared/types/tool.d.ts +137 -0
  256. package/dist/shared/types/tool.js +1 -0
  257. package/dist/shared/utils/path.d.ts +15 -0
  258. package/dist/shared/utils/path.js +23 -0
  259. package/dist/shared/utils.d.ts +5 -0
  260. package/dist/shared/utils.js +10 -0
  261. package/dist/tools/builtin/bash.d.ts +12 -0
  262. package/dist/tools/builtin/bash.js +121 -0
  263. package/dist/tools/builtin/dap.d.ts +23 -0
  264. package/dist/tools/builtin/dap.js +231 -0
  265. package/dist/tools/builtin/edit.d.ts +12 -0
  266. package/dist/tools/builtin/edit.js +151 -0
  267. package/dist/tools/builtin/glob.d.ts +11 -0
  268. package/dist/tools/builtin/glob.js +120 -0
  269. package/dist/tools/builtin/grep.d.ts +6 -0
  270. package/dist/tools/builtin/grep.js +141 -0
  271. package/dist/tools/builtin/read.d.ts +6 -0
  272. package/dist/tools/builtin/read.js +73 -0
  273. package/dist/tools/builtin/resolvers.d.ts +12 -0
  274. package/dist/tools/builtin/resolvers.js +79 -0
  275. package/dist/tools/builtin/task.d.ts +9 -0
  276. package/dist/tools/builtin/task.js +100 -0
  277. package/dist/tools/builtin/write.d.ts +6 -0
  278. package/dist/tools/builtin/write.js +36 -0
  279. package/dist/tools/builtin/yield.d.ts +9 -0
  280. package/dist/tools/builtin/yield.js +40 -0
  281. package/dist/tools/executor.d.ts +9 -0
  282. package/dist/tools/executor.js +54 -0
  283. package/dist/tools/hashline/index.d.ts +2 -0
  284. package/dist/tools/hashline/index.js +3 -0
  285. package/dist/tools/hashline/patch.d.ts +48 -0
  286. package/dist/tools/hashline/patch.js +201 -0
  287. package/dist/tools/index.d.ts +30 -0
  288. package/dist/tools/index.js +55 -0
  289. package/dist/tools/permission.d.ts +13 -0
  290. package/dist/tools/permission.js +39 -0
  291. package/dist/tools/registry.d.ts +15 -0
  292. package/dist/tools/registry.js +54 -0
  293. package/dist/tools/resolver.d.ts +15 -0
  294. package/dist/tools/resolver.js +47 -0
  295. package/dist/tools/truncate.d.ts +8 -0
  296. package/dist/tools/truncate.js +50 -0
  297. package/dist/tools/types.d.ts +101 -0
  298. package/dist/tools/types.js +1 -0
  299. package/dist/tools/validate.d.ts +8 -0
  300. package/dist/tools/validate.js +130 -0
  301. package/dist/tools/websearch/fetch.d.ts +11 -0
  302. package/dist/tools/websearch/fetch.js +21 -0
  303. package/dist/tools/websearch/index.d.ts +19 -0
  304. package/dist/tools/websearch/index.js +78 -0
  305. package/dist/tools/websearch/providers/brave.d.ts +5 -0
  306. package/dist/tools/websearch/providers/brave.js +53 -0
  307. package/dist/tools/websearch/providers/duckduckgo.d.ts +3 -0
  308. package/dist/tools/websearch/providers/duckduckgo.js +75 -0
  309. package/dist/tools/websearch/providers/tavily.d.ts +11 -0
  310. package/dist/tools/websearch/providers/tavily.js +89 -0
  311. package/dist/tools/websearch/types.d.ts +51 -0
  312. package/dist/tools/websearch/types.js +18 -0
  313. package/dist/tools/websearch/websearch.d.ts +10 -0
  314. package/dist/tools/websearch/websearch.js +48 -0
  315. package/dist/update/index.d.ts +10 -0
  316. package/dist/update/index.js +6 -0
  317. package/dist/update/ipc.d.ts +15 -0
  318. package/dist/update/ipc.js +41 -0
  319. package/dist/update/scheduler.d.ts +34 -0
  320. package/dist/update/scheduler.js +57 -0
  321. package/dist/update/snapshot.d.ts +39 -0
  322. package/dist/update/snapshot.js +99 -0
  323. package/dist/update/updater.d.ts +48 -0
  324. package/dist/update/updater.js +83 -0
  325. package/dist/update/version.d.ts +18 -0
  326. package/dist/update/version.js +49 -0
  327. package/drizzle/0000_magical_nightshade.sql +55 -0
  328. package/drizzle/0001_chemical_doctor_faustus.sql +13 -0
  329. package/drizzle/0002_amusing_micromacro.sql +12 -0
  330. package/drizzle/0003_regular_purifiers.sql +2 -0
  331. package/drizzle/meta/0000_snapshot.json +448 -0
  332. package/drizzle/meta/0001_snapshot.json +539 -0
  333. package/drizzle/meta/0002_snapshot.json +633 -0
  334. package/drizzle/meta/0003_snapshot.json +645 -0
  335. package/drizzle/meta/_journal.json +34 -0
  336. package/package.json +108 -8
@@ -0,0 +1,75 @@
1
+ const DUCKDUCKGO_SEARCH_URL = 'https://api.duckduckgo.com/';
2
+ const AGENT_TOKEN = 'c0de-agent';
3
+ function cleanText(value) {
4
+ const cleaned = value
5
+ ?.replace(/<[^>]*>/g, ' ')
6
+ .replace(/&nbsp;/gi, ' ')
7
+ .replace(/&amp;/gi, '&')
8
+ .replace(/&lt;/gi, '<')
9
+ .replace(/&gt;/gi, '>')
10
+ .replace(/&quot;/gi, '"')
11
+ .replace(/&#39;/gi, "'")
12
+ .replace(/\s+/g, ' ')
13
+ .trim();
14
+ return cleaned ? cleaned : undefined;
15
+ }
16
+ function addSource(sources, source) {
17
+ if (!source.url || sources.some((s) => s.url === source.url))
18
+ return;
19
+ sources.push(source);
20
+ }
21
+ function addTopicSource(sources, topic) {
22
+ const url = topic.FirstURL?.trim();
23
+ if (!url)
24
+ return;
25
+ const text = cleanText(topic.Text);
26
+ addSource(sources, { title: text ?? url, url, snippet: text });
27
+ }
28
+ function collectTopicSources(sources, topics) {
29
+ if (!topics)
30
+ return;
31
+ for (const topic of topics) {
32
+ addTopicSource(sources, topic);
33
+ collectTopicSources(sources, topic.Topics);
34
+ }
35
+ }
36
+ async function callDuckDuckGoSearch(params) {
37
+ const fetchImpl = params.fetchImpl ?? fetch;
38
+ const query = new URLSearchParams({
39
+ q: params.query,
40
+ format: 'json',
41
+ no_redirect: '1',
42
+ no_html: '1',
43
+ skip_disambig: '1',
44
+ t: AGENT_TOKEN,
45
+ });
46
+ const response = await fetchImpl(`${DUCKDUCKGO_SEARCH_URL}?${query.toString()}`, {
47
+ method: 'GET',
48
+ signal: params.signal,
49
+ });
50
+ if (!response.ok) {
51
+ const text = await response.text().catch(() => response.statusText);
52
+ throw new Error(`DuckDuckGo API error (${response.status}): ${text}`);
53
+ }
54
+ return (await response.json());
55
+ }
56
+ /** DuckDuckGo Instant Answer 后端(零 key,恒可用)。recency 不支持,忽略。 */
57
+ export const duckduckgoProvider = {
58
+ id: 'duckduckgo',
59
+ isAvailable: () => true,
60
+ search: async (params) => {
61
+ const data = await callDuckDuckGoSearch(params);
62
+ const answer = cleanText(data.AbstractText) ?? cleanText(data.Answer) ?? cleanText(data.Definition);
63
+ const sources = [];
64
+ // AbstractURL 作为首个来源(若无 RelatedTopics 填充)
65
+ if (data.AbstractURL) {
66
+ addSource(sources, {
67
+ title: cleanText(data.Heading) ?? data.AbstractURL,
68
+ url: data.AbstractURL,
69
+ });
70
+ }
71
+ collectTopicSources(sources, data.Results);
72
+ collectTopicSources(sources, data.RelatedTopics);
73
+ return { provider: 'duckduckgo', answer, sources };
74
+ },
75
+ };
@@ -0,0 +1,11 @@
1
+ import type { Recency, WebSearchProvider } from '../types.js';
2
+ interface TavilySearchParams {
3
+ query: string;
4
+ numResults?: number;
5
+ recency?: Recency;
6
+ }
7
+ /** 导出供测试:构造 Tavily 请求 body。始终用 general topic(避免技术查询窄化为新闻)。 */
8
+ export declare function buildRequestBody(params: TavilySearchParams): Record<string, unknown>;
9
+ /** Tavily 后端(AI 优化搜索,需 key,返回合成 answer)。 */
10
+ export declare const tavilyProvider: WebSearchProvider;
11
+ export {};
@@ -0,0 +1,89 @@
1
+ import { DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS, MIN_NUM_RESULTS } from '../types.js';
2
+ const TAVILY_SEARCH_URL = 'https://api.tavily.com/search';
3
+ function clamp(n) {
4
+ if (n === undefined || Number.isNaN(n))
5
+ return DEFAULT_NUM_RESULTS;
6
+ return Math.min(MAX_NUM_RESULTS, Math.max(MIN_NUM_RESULTS, Math.trunc(n)));
7
+ }
8
+ /** 导出供测试:构造 Tavily 请求 body。始终用 general topic(避免技术查询窄化为新闻)。 */
9
+ export function buildRequestBody(params) {
10
+ const body = {
11
+ query: params.query,
12
+ search_depth: 'basic',
13
+ max_results: clamp(params.numResults),
14
+ include_answer: 'advanced',
15
+ include_raw_content: false,
16
+ };
17
+ if (params.recency)
18
+ body.time_range = params.recency;
19
+ return body;
20
+ }
21
+ function safeParse(text) {
22
+ try {
23
+ return JSON.parse(text);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ function asRecord(value) {
30
+ return typeof value === 'object' && value !== null ? value : null;
31
+ }
32
+ function getErrorMessage(value) {
33
+ if (typeof value === 'string') {
34
+ const t = value.trim();
35
+ return t.length > 0 ? t : null;
36
+ }
37
+ const rec = asRecord(value);
38
+ if (!rec)
39
+ return null;
40
+ for (const key of ['detail', 'error', 'message']) {
41
+ const m = getErrorMessage(rec[key]);
42
+ if (m)
43
+ return m;
44
+ }
45
+ return null;
46
+ }
47
+ async function callTavilySearch(apiKey, params) {
48
+ const fetchImpl = params.fetchImpl ?? fetch;
49
+ const response = await fetchImpl(TAVILY_SEARCH_URL, {
50
+ method: 'POST',
51
+ headers: {
52
+ 'content-type': 'application/json',
53
+ Authorization: `Bearer ${apiKey}`,
54
+ },
55
+ body: JSON.stringify(buildRequestBody({
56
+ query: params.query,
57
+ numResults: params.limit,
58
+ recency: params.recency,
59
+ })),
60
+ signal: params.signal,
61
+ });
62
+ if (!response.ok) {
63
+ const raw = await response.text().catch(() => response.statusText);
64
+ const msg = getErrorMessage(safeParse(raw)) ?? (raw.trim() || response.statusText);
65
+ throw new Error(`Tavily API error (${response.status}): ${msg}`);
66
+ }
67
+ return (await response.json());
68
+ }
69
+ /** Tavily 后端(AI 优化搜索,需 key,返回合成 answer)。 */
70
+ export const tavilyProvider = {
71
+ id: 'tavily',
72
+ isAvailable: (apiKey) => Boolean(apiKey && apiKey.length > 0),
73
+ search: async (params) => {
74
+ if (!params.apiKey)
75
+ throw new Error('Tavily requires an API key (TAVILY_API_KEY or config).');
76
+ const data = await callTavilySearch(params.apiKey, params);
77
+ const sources = [];
78
+ for (const r of data.results ?? []) {
79
+ if (!r.url)
80
+ continue;
81
+ sources.push({ title: r.title ?? r.url, url: r.url, snippet: r.content ?? undefined });
82
+ }
83
+ return {
84
+ provider: 'tavily',
85
+ answer: data.answer?.trim() || undefined,
86
+ sources: sources.slice(0, clamp(params.limit)),
87
+ };
88
+ },
89
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * websearch 工具的统一类型、常量与工具函数。
3
+ *
4
+ * 来源:oh-my-pi(packages/coding-agent/src/web/search/)多后端 strategy 架构,
5
+ * 裁剪适配 c0de-agent 的 data+functions 范式(无 class)。
6
+ * 详见 docs/superpowers/specs/2026-06-30-websearch-tool-design.md §2-3。
7
+ */
8
+ /** 后端标识。strategy 接口预留,未来可加 'exa' | 'searxng' | … */
9
+ type WebSearchProviderId = 'duckduckgo' | 'tavily' | 'brave';
10
+ /** 时效过滤窗口。各后端映射为各自 API 参数。 */
11
+ type Recency = 'day' | 'week' | 'month' | 'year';
12
+ /** 单条搜索来源(所有后端统一)。 */
13
+ type WebSearchSource = {
14
+ title: string;
15
+ url: string;
16
+ snippet?: string;
17
+ };
18
+ /** 统一搜索参数。 */
19
+ type WebSearchParams = {
20
+ query: string;
21
+ limit?: number;
22
+ recency?: Recency;
23
+ signal?: AbortSignal;
24
+ /** Tavily/Brave 的 key(DuckDuckGo 不用)。 */
25
+ apiKey?: string;
26
+ /** 测试注入;默认用 createFetch()。 */
27
+ fetchImpl?: typeof fetch;
28
+ };
29
+ /** 统一响应(所有后端统一)。 */
30
+ type WebSearchResponse = {
31
+ provider: WebSearchProviderId;
32
+ /** Tavily 返回合成答案;DuckDuckGo/Brave 通常无。 */
33
+ answer?: string;
34
+ sources: WebSearchSource[];
35
+ };
36
+ /** 后端 strategy 接口(data + functions,非 class)。 */
37
+ type WebSearchProvider = {
38
+ id: WebSearchProviderId;
39
+ /** 是否当前可用(DuckDuckGo 恒真;Tavily/Brave 需 key)。驱动 'auto' 选择。 */
40
+ isAvailable: (apiKey?: string) => boolean;
41
+ /** 执行搜索。 */
42
+ search: (params: WebSearchParams) => Promise<WebSearchResponse>;
43
+ };
44
+ /** 工具参数校验常量。 */
45
+ declare const DEFAULT_NUM_RESULTS = 8;
46
+ declare const MAX_NUM_RESULTS = 20;
47
+ declare const MIN_NUM_RESULTS = 1;
48
+ /** clamp 结果数到 [MIN, MAX];undefined/NaN 回退到 fallback。 */
49
+ declare function clampNumResults(n: number | undefined, fallback?: number): number;
50
+ export type { Recency, WebSearchParams, WebSearchProvider, WebSearchProviderId, WebSearchResponse, WebSearchSource, };
51
+ export { clampNumResults, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS, MIN_NUM_RESULTS };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * websearch 工具的统一类型、常量与工具函数。
3
+ *
4
+ * 来源:oh-my-pi(packages/coding-agent/src/web/search/)多后端 strategy 架构,
5
+ * 裁剪适配 c0de-agent 的 data+functions 范式(无 class)。
6
+ * 详见 docs/superpowers/specs/2026-06-30-websearch-tool-design.md §2-3。
7
+ */
8
+ /** 工具参数校验常量。 */
9
+ const DEFAULT_NUM_RESULTS = 8;
10
+ const MAX_NUM_RESULTS = 20;
11
+ const MIN_NUM_RESULTS = 1;
12
+ /** clamp 结果数到 [MIN, MAX];undefined/NaN 回退到 fallback。 */
13
+ function clampNumResults(n, fallback = DEFAULT_NUM_RESULTS) {
14
+ if (n === undefined || Number.isNaN(n))
15
+ return fallback;
16
+ return Math.min(MAX_NUM_RESULTS, Math.max(MIN_NUM_RESULTS, Math.trunc(n)));
17
+ }
18
+ export { clampNumResults, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS, MIN_NUM_RESULTS };
@@ -0,0 +1,10 @@
1
+ import type { WebSearchConfig } from '../../shared/types/config.js';
2
+ import type { ToolDef } from '../../shared/types/tool.js';
3
+ import { setFetchOverride } from './index.js';
4
+ export { setFetchOverride };
5
+ /**
6
+ * websearch 工具工厂。config 由工厂闭包捕获(对齐 runSubAgent/debugSpawn 依赖反转模式)。
7
+ * permission: auto(只读网络搜索,不改本地状态)。timeout 30s。
8
+ * 详见 docs/superpowers/specs/2026-06-30-websearch-tool-design.md §5。
9
+ */
10
+ export declare function createWebSearchTool(config: WebSearchConfig): ToolDef;
@@ -0,0 +1,48 @@
1
+ import { formatForLLM, runWebSearch, setFetchOverride } from './index.js';
2
+ export { setFetchOverride };
3
+ const NO_RESULTS = 'No search results found. Try a different query.';
4
+ /**
5
+ * websearch 工具工厂。config 由工厂闭包捕获(对齐 runSubAgent/debugSpawn 依赖反转模式)。
6
+ * permission: auto(只读网络搜索,不改本地状态)。timeout 30s。
7
+ * 详见 docs/superpowers/specs/2026-06-30-websearch-tool-design.md §5。
8
+ */
9
+ export function createWebSearchTool(config) {
10
+ return {
11
+ name: 'websearch',
12
+ description: 'Search the web for up-to-date information beyond knowledge cutoff. ' +
13
+ 'Returns titled sources with snippets (and a synthesized answer when the ' +
14
+ 'backend supports it). Use for current events, recent releases, and docs. ' +
15
+ `The current year is ${new Date().getFullYear()}.`,
16
+ parameters: {
17
+ type: 'object',
18
+ properties: {
19
+ query: { type: 'string', description: 'Search query' },
20
+ numResults: {
21
+ type: 'number',
22
+ description: 'Number of results (default 8, max 20)',
23
+ },
24
+ recency: {
25
+ type: 'string',
26
+ enum: ['day', 'week', 'month', 'year'],
27
+ description: 'Time filter for results',
28
+ },
29
+ },
30
+ required: ['query'],
31
+ },
32
+ permission: 'auto',
33
+ timeout: 30_000,
34
+ execute: async (input, ctx) => {
35
+ const { query, numResults, recency } = input;
36
+ try {
37
+ const response = await runWebSearch({ query, numResults, recency }, config, ctx.abort);
38
+ if (!response.answer && response.sources.length === 0) {
39
+ return { _tag: 'success', output: NO_RESULTS };
40
+ }
41
+ return { _tag: 'success', output: formatForLLM(response) };
42
+ }
43
+ catch (err) {
44
+ return { _tag: 'error', error: err instanceof Error ? err.message : String(err) };
45
+ }
46
+ },
47
+ };
48
+ }
@@ -0,0 +1,10 @@
1
+ export type { HandoffServer } from './ipc.js';
2
+ export { createHandoffServer, requestHandoff } from './ipc.js';
3
+ export type { UpdateScheduler, UpdateSchedulerOptions } from './scheduler.js';
4
+ export { createUpdateScheduler } from './scheduler.js';
5
+ export type { SerializedEntry, SerializedSession, SessionSnapshot } from './snapshot.js';
6
+ export { orderSessionsByParent, restoreSessions, serializeSessions } from './snapshot.js';
7
+ export type { HotUpdateOptions, HotUpdateResult, SpawnFn } from './updater.js';
8
+ export { cleanupSnapshot, performHotUpdate } from './updater.js';
9
+ export type { UpdateCheckResult } from './version.js';
10
+ export { checkForUpdate, compareSemver } from './version.js';
@@ -0,0 +1,6 @@
1
+ // 热更新 + 会话迁移包(spec §18)。
2
+ export { createHandoffServer, requestHandoff } from './ipc.js';
3
+ export { createUpdateScheduler } from './scheduler.js';
4
+ export { orderSessionsByParent, restoreSessions, serializeSessions } from './snapshot.js';
5
+ export { cleanupSnapshot, performHotUpdate } from './updater.js';
6
+ export { checkForUpdate, compareSemver } from './version.js';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 端口接管 IPC(spec §18.3):新实例检测到端口被旧实例占用时,通过 HTTP
3
+ * `/handoff` 端点请求旧实例 graceful shutdown(序列化状态后退出),从而
4
+ * 接管端口。用普通 HTTP 而非 unix socket,便于跨平台。
5
+ */
6
+ type HandoffServer = {
7
+ port: number;
8
+ close: () => Promise<void>;
9
+ };
10
+ /** 旧实例启动时创建 handoff 端点。收到 POST /handoff 即触发 onHandoff(序列化 + 退出)。 */
11
+ declare function createHandoffServer(onHandoff: () => Promise<void>): Promise<HandoffServer>;
12
+ /** 新实例请求旧实例让出端口(graceful shutdown)。失败抛错。 */
13
+ declare function requestHandoff(port: number, host?: string): Promise<void>;
14
+ export type { HandoffServer };
15
+ export { createHandoffServer, requestHandoff };
@@ -0,0 +1,41 @@
1
+ import { createServer } from 'node:http';
2
+ /** 旧实例启动时创建 handoff 端点。收到 POST /handoff 即触发 onHandoff(序列化 + 退出)。 */
3
+ function createHandoffServer(onHandoff) {
4
+ return new Promise((resolve, reject) => {
5
+ const handler = async (req, res) => {
6
+ if (req.method === 'POST' && req.url === '/handoff') {
7
+ try {
8
+ await onHandoff();
9
+ res.writeHead(200, { 'content-type': 'application/json' });
10
+ res.end(JSON.stringify({ ok: true }));
11
+ }
12
+ catch (error) {
13
+ res.writeHead(500, { 'content-type': 'application/json' });
14
+ res.end(JSON.stringify({ ok: false, error: String(error) }));
15
+ }
16
+ return;
17
+ }
18
+ res.writeHead(404);
19
+ res.end();
20
+ };
21
+ const server = createServer(handler);
22
+ server.on('error', reject);
23
+ server.listen(0, '127.0.0.1', () => {
24
+ const addr = server.address();
25
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
26
+ resolve({
27
+ port,
28
+ close: () => new Promise((res) => {
29
+ server.close(() => res());
30
+ }),
31
+ });
32
+ });
33
+ });
34
+ }
35
+ /** 新实例请求旧实例让出端口(graceful shutdown)。失败抛错。 */
36
+ async function requestHandoff(port, host = '127.0.0.1') {
37
+ const res = await fetch(`http://${host}:${port}/handoff`, { method: 'POST' });
38
+ if (!res.ok)
39
+ throw new Error(`handoff failed: HTTP ${res.status}`);
40
+ }
41
+ export { createHandoffServer, requestHandoff };
@@ -0,0 +1,34 @@
1
+ import type { UpdateCheckResult } from './version.js';
2
+ /**
3
+ * 后台版本检查调度器(spec §18.1 步骤 1)。
4
+ *
5
+ * 启动时延迟 initialDelayMs 后执行首次 checkForUpdate,之后按 intervalMs
6
+ * 周期性检查。结果缓存到内存,供 /api/update 路由读取(避免每次请求都打
7
+ * npm registry)。发现新版本通过 onUpdate 回调通知上层(server.ts 转发到
8
+ * 前端 SSE 或前端轮询读取)。
9
+ *
10
+ * checkFn 抛错时不传播,缓存降级为 hasUpdate:false(与 checkForUpdate 自身
11
+ * 的容错语义一致)。
12
+ */
13
+ type UpdateSchedulerOptions = {
14
+ checkFn: () => Promise<UpdateCheckResult>;
15
+ /** 周期检查间隔(毫秒),默认 1 小时。 */
16
+ intervalMs?: number;
17
+ /** 首次检查延迟(毫秒),默认 10 秒。 */
18
+ initialDelayMs?: number;
19
+ /** 每次成功检查后回调(含 hasUpdate:false);异常路径不调用。 */
20
+ onUpdate?: (result: UpdateCheckResult) => void;
21
+ };
22
+ type UpdateScheduler = {
23
+ /** 启动调度(首次延迟 + 周期检查)。重复 start 是 no-op。 */
24
+ start(): void;
25
+ /** 停止调度;已缓存的 lastResult 保留。 */
26
+ stop(): void;
27
+ /** 立即触发一次检查并更新缓存;异常降级为 hasUpdate:false。 */
28
+ checkNow(): Promise<UpdateCheckResult>;
29
+ /** 当前缓存结果;未检查过返回 null。 */
30
+ getLastResult(): UpdateCheckResult | null;
31
+ };
32
+ declare function createUpdateScheduler(opts: UpdateSchedulerOptions): UpdateScheduler;
33
+ export type { UpdateScheduler, UpdateSchedulerOptions };
34
+ export { createUpdateScheduler };
@@ -0,0 +1,57 @@
1
+ const DEFAULT_INTERVAL_MS = 60 * 60 * 1000;
2
+ const DEFAULT_INITIAL_DELAY_MS = 10_000;
3
+ function createUpdateScheduler(opts) {
4
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
5
+ const initialDelayMs = opts.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
6
+ // 直接引用全局 timer;vitest useFakeTimers() 会替换全局,start() 时读取即拿到 mock。
7
+ let intervalId = null;
8
+ let initialId = null;
9
+ let lastResult = null;
10
+ let started = false;
11
+ async function runOnce() {
12
+ let r;
13
+ try {
14
+ r = await opts.checkFn();
15
+ }
16
+ catch {
17
+ // 异常降级:缓存 hasUpdate:false,但不触发 onUpdate(避免误报)。
18
+ lastResult = { hasUpdate: false, currentVersion: '0.0.0', latestVersion: '0.0.0' };
19
+ return lastResult;
20
+ }
21
+ lastResult = r;
22
+ if (opts.onUpdate)
23
+ opts.onUpdate(r);
24
+ return r;
25
+ }
26
+ return {
27
+ start() {
28
+ if (started)
29
+ return;
30
+ started = true;
31
+ // 首次延迟:到达后执行 runOnce,再挂周期 interval。
32
+ // 不能直接 setInterval——initialDelayMs 与 intervalMs 通常不同。
33
+ initialId = setTimeout(() => {
34
+ void runOnce();
35
+ intervalId = setInterval(() => void runOnce(), intervalMs);
36
+ }, initialDelayMs);
37
+ },
38
+ stop() {
39
+ if (initialId !== null) {
40
+ clearTimeout(initialId);
41
+ initialId = null;
42
+ }
43
+ if (intervalId !== null) {
44
+ clearInterval(intervalId);
45
+ intervalId = null;
46
+ }
47
+ started = false;
48
+ },
49
+ checkNow() {
50
+ return runOnce();
51
+ },
52
+ getLastResult() {
53
+ return lastResult;
54
+ },
55
+ };
56
+ }
57
+ export { createUpdateScheduler };
@@ -0,0 +1,39 @@
1
+ import type { DB } from '../db/client.js';
2
+ /** 序列化后的会话行(Date → epoch ms,纯 JSON 安全)。 */
3
+ type SerializedSession = {
4
+ id: string;
5
+ title: string;
6
+ parentId: string | null;
7
+ projectId: string | null;
8
+ branchPoint: number | null;
9
+ metadata: unknown;
10
+ createdAt: number;
11
+ updatedAt: number;
12
+ };
13
+ /** 序列化后的会话条目行(Date → epoch ms)。 */
14
+ type SerializedEntry = {
15
+ id: string;
16
+ sessionId: string;
17
+ tag: string;
18
+ role: string | null;
19
+ content: unknown;
20
+ toolName: string | null;
21
+ tokenCount: number;
22
+ createdAt: number;
23
+ };
24
+ /** 热更新迁移快照(spec §18.2)。 */
25
+ type SessionSnapshot = {
26
+ version: string;
27
+ sessions: SerializedSession[];
28
+ entries: SerializedEntry[];
29
+ config: unknown;
30
+ timestamp: number;
31
+ };
32
+ /** 按 parentId 拓扑序排列 sessions,使父会话先于子会话插入(满足自引用 FK)。 */
33
+ declare function orderSessionsByParent(list: SerializedSession[]): SerializedSession[];
34
+ /** 从 DB 导出所有会话与条目为可序列化快照。 */
35
+ declare function serializeSessions(handle: DB, config?: unknown): Promise<SessionSnapshot>;
36
+ /** 把快照导入 DB(保留原始 id 与时间戳;父会话先插入以满足 FK)。 */
37
+ declare function restoreSessions(handle: DB, snapshot: SessionSnapshot): Promise<void>;
38
+ export type { SerializedEntry, SerializedSession, SessionSnapshot };
39
+ export { orderSessionsByParent, restoreSessions, serializeSessions };
@@ -0,0 +1,99 @@
1
+ import { sessionEntries, sessions } from '../db/schema.js';
2
+ const CURRENT_SNAPSHOT_VERSION = '0.1.0';
3
+ function toDateMs(v) {
4
+ if (v instanceof Date)
5
+ return v.getTime();
6
+ if (typeof v === 'string' || typeof v === 'number')
7
+ return new Date(v).getTime();
8
+ return Date.now();
9
+ }
10
+ function toSerializedSession(row) {
11
+ return {
12
+ id: row.id,
13
+ title: row.title,
14
+ parentId: row.parentId,
15
+ projectId: row.projectId,
16
+ branchPoint: row.branchPoint,
17
+ metadata: row.metadata,
18
+ createdAt: toDateMs(row.createdAt),
19
+ updatedAt: toDateMs(row.updatedAt),
20
+ };
21
+ }
22
+ function toSerializedEntry(row) {
23
+ return {
24
+ id: row.id,
25
+ sessionId: row.sessionId,
26
+ tag: row.tag,
27
+ role: row.role,
28
+ content: row.content,
29
+ toolName: row.toolName,
30
+ tokenCount: row.tokenCount ?? 0,
31
+ createdAt: toDateMs(row.createdAt),
32
+ };
33
+ }
34
+ /** 按 parentId 拓扑序排列 sessions,使父会话先于子会话插入(满足自引用 FK)。 */
35
+ function orderSessionsByParent(list) {
36
+ const byId = new Map(list.map((s) => [s.id, s]));
37
+ const ordered = [];
38
+ const seen = new Set();
39
+ const visit = (s) => {
40
+ if (seen.has(s.id))
41
+ return;
42
+ const parent = s.parentId ? byId.get(s.parentId) : undefined;
43
+ if (parent && !seen.has(parent.id))
44
+ visit(parent);
45
+ seen.add(s.id);
46
+ ordered.push(s);
47
+ };
48
+ for (const s of list)
49
+ visit(s);
50
+ return ordered;
51
+ }
52
+ /** 从 DB 导出所有会话与条目为可序列化快照。 */
53
+ async function serializeSessions(handle, config) {
54
+ const [sRows, eRows] = await Promise.all([
55
+ handle.db.select().from(sessions),
56
+ handle.db.select().from(sessionEntries),
57
+ ]);
58
+ return {
59
+ version: CURRENT_SNAPSHOT_VERSION,
60
+ sessions: sRows.map(toSerializedSession),
61
+ entries: eRows.map(toSerializedEntry),
62
+ config: config ?? null,
63
+ timestamp: Date.now(),
64
+ };
65
+ }
66
+ /** 把快照导入 DB(保留原始 id 与时间戳;父会话先插入以满足 FK)。 */
67
+ async function restoreSessions(handle, snapshot) {
68
+ for (const s of orderSessionsByParent(snapshot.sessions)) {
69
+ await handle.db
70
+ .insert(sessions)
71
+ .values({
72
+ id: s.id,
73
+ title: s.title,
74
+ parentId: s.parentId,
75
+ projectId: s.projectId,
76
+ branchPoint: s.branchPoint,
77
+ metadata: s.metadata,
78
+ createdAt: new Date(s.createdAt),
79
+ updatedAt: new Date(s.updatedAt),
80
+ })
81
+ .onConflictDoNothing();
82
+ }
83
+ for (const e of snapshot.entries) {
84
+ await handle.db
85
+ .insert(sessionEntries)
86
+ .values({
87
+ id: e.id,
88
+ sessionId: e.sessionId,
89
+ tag: e.tag,
90
+ role: e.role,
91
+ content: e.content,
92
+ toolName: e.toolName,
93
+ tokenCount: e.tokenCount,
94
+ createdAt: new Date(e.createdAt),
95
+ })
96
+ .onConflictDoNothing();
97
+ }
98
+ }
99
+ export { orderSessionsByParent, restoreSessions, serializeSessions };
@@ -0,0 +1,48 @@
1
+ import type { SessionSnapshot } from './snapshot.js';
2
+ /** 热更新执行结果(spec §18)。 */
3
+ type HotUpdateResult = {
4
+ _tag: 'success';
5
+ snapshotPath: string;
6
+ } | {
7
+ _tag: 'install_failed';
8
+ error: string;
9
+ snapshotPath: string;
10
+ } | {
11
+ _tag: 'spawn_failed';
12
+ error: string;
13
+ snapshotPath: string;
14
+ };
15
+ /**
16
+ * 启动新实例的函数签名。
17
+ * @param snapshotPath 快照文件路径(旧实例已写入)
18
+ * @param argv 传给新进程的完整参数(含 restore flag + 可选 handoff flag)
19
+ */
20
+ type SpawnFn = (snapshotPath: string, argv: string[]) => Promise<void>;
21
+ type HotUpdateOptions = {
22
+ /** 自更新安装函数;默认 `npm install -g <pkg>`。 */
23
+ installFn?: (pkg: string) => Promise<void>;
24
+ /** 启动新实例的函数;默认 detached spawn 当前进程入口。 */
25
+ spawnNewInstanceFn?: SpawnFn;
26
+ packageName?: string;
27
+ /** 快照写入路径;默认临时目录。 */
28
+ snapshotPath?: string;
29
+ /** 新实例接收快照的参数前缀(默认 --restore)。 */
30
+ restoreFlag?: string;
31
+ /** 旧实例 handoff 端口;提供时新实例启动后请求旧实例 graceful shutdown。 */
32
+ handoffPort?: number;
33
+ };
34
+ /**
35
+ * 执行热更新(spec §18.1-18.2 流程):
36
+ * 1. 序列化当前会话状态到快照文件
37
+ * 2. 全局自更新(npm install -g)
38
+ * 3. detached 启动新版本实例,传入快照路径(新实例 restore + 端口接管)
39
+ *
40
+ * 注:旧实例的 graceful shutdown / 端口让渡由新实例启动后通过 IPC 协调
41
+ * (见 ipc.ts),本函数只负责"序列化 + 安装 + 接力"。若提供 handoffPort,
42
+ * argv 会带上 --handoff-port,新实例据此 requestHandoff 通知旧实例退出。
43
+ */
44
+ declare function performHotUpdate(snapshot: SessionSnapshot, opts?: HotUpdateOptions): Promise<HotUpdateResult>;
45
+ /** 清理快照临时目录(热更新完成或放弃后调用)。 */
46
+ declare function cleanupSnapshot(snapshotPath: string): Promise<void>;
47
+ export type { HotUpdateOptions, HotUpdateResult, SpawnFn };
48
+ export { cleanupSnapshot, performHotUpdate };