@ai-zen/agents-host 0.0.0-stage → 0.1.0-alpha.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 (146) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +759 -2
  4. package/dist/app.d.ts +384 -0
  5. package/dist/app.js +1148 -0
  6. package/dist/cli.d.ts +21 -0
  7. package/dist/cli.js +353 -0
  8. package/dist/config.d.ts +97 -0
  9. package/dist/config.js +171 -0
  10. package/dist/handlers/agentHandlers.d.ts +18 -0
  11. package/dist/handlers/agentHandlers.js +20 -0
  12. package/dist/handlers/assetHandlers.d.ts +29 -0
  13. package/dist/handlers/assetHandlers.js +35 -0
  14. package/dist/handlers/capabilities.d.ts +26 -0
  15. package/dist/handlers/capabilities.js +138 -0
  16. package/dist/handlers/completionHandlers.d.ts +18 -0
  17. package/dist/handlers/completionHandlers.js +13 -0
  18. package/dist/handlers/configHandlers.d.ts +31 -0
  19. package/dist/handlers/configHandlers.js +59 -0
  20. package/dist/handlers/conversationHandlers.d.ts +118 -0
  21. package/dist/handlers/conversationHandlers.js +314 -0
  22. package/dist/handlers/handoffHandlers.d.ts +17 -0
  23. package/dist/handlers/handoffHandlers.js +14 -0
  24. package/dist/handlers/hostHandlers.d.ts +39 -0
  25. package/dist/handlers/hostHandlers.js +56 -0
  26. package/dist/handlers/index.d.ts +128 -0
  27. package/dist/handlers/index.js +92 -0
  28. package/dist/handlers/messageHandlers.d.ts +11 -0
  29. package/dist/handlers/messageHandlers.js +10 -0
  30. package/dist/handlers/modelHandlers.d.ts +17 -0
  31. package/dist/handlers/modelHandlers.js +19 -0
  32. package/dist/handlers/noticeHandlers.d.ts +24 -0
  33. package/dist/handlers/noticeHandlers.js +24 -0
  34. package/dist/handlers/questionHandlers.d.ts +16 -0
  35. package/dist/handlers/questionHandlers.js +16 -0
  36. package/dist/handlers/searchHandlers.d.ts +12 -0
  37. package/dist/handlers/searchHandlers.js +12 -0
  38. package/dist/handlers/workspaceHandlers.d.ts +29 -0
  39. package/dist/handlers/workspaceHandlers.js +47 -0
  40. package/dist/i18n/en.d.ts +243 -0
  41. package/dist/i18n/en.js +270 -0
  42. package/dist/i18n/index.d.ts +43 -0
  43. package/dist/i18n/index.js +72 -0
  44. package/dist/i18n/zh.d.ts +240 -0
  45. package/dist/i18n/zh.js +257 -0
  46. package/dist/index.d.ts +17 -0
  47. package/dist/index.js +15 -0
  48. package/dist/net/UploadReceiver.d.ts +186 -0
  49. package/dist/net/UploadReceiver.js +494 -0
  50. package/dist/net/WsHub.d.ts +231 -0
  51. package/dist/net/WsHub.js +689 -0
  52. package/dist/net/auth.d.ts +73 -0
  53. package/dist/net/auth.js +74 -0
  54. package/dist/net/discovery.d.ts +72 -0
  55. package/dist/net/discovery.js +171 -0
  56. package/dist/net/index.d.ts +14 -0
  57. package/dist/net/index.js +10 -0
  58. package/dist/runtime/ChatRunner.d.ts +374 -0
  59. package/dist/runtime/ChatRunner.js +1204 -0
  60. package/dist/runtime/ConversationDrafts.d.ts +43 -0
  61. package/dist/runtime/ConversationDrafts.js +47 -0
  62. package/dist/runtime/RunRegistry.d.ts +79 -0
  63. package/dist/runtime/RunRegistry.js +108 -0
  64. package/dist/runtime/ScopeRegistry.d.ts +153 -0
  65. package/dist/runtime/ScopeRegistry.js +259 -0
  66. package/dist/runtime/TransientRunner.d.ts +90 -0
  67. package/dist/runtime/TransientRunner.js +179 -0
  68. package/dist/runtime/index.d.ts +14 -0
  69. package/dist/runtime/index.js +10 -0
  70. package/dist/services/AgentService.d.ts +150 -0
  71. package/dist/services/AgentService.js +718 -0
  72. package/dist/services/AssetService.d.ts +338 -0
  73. package/dist/services/AssetService.js +739 -0
  74. package/dist/services/AutoNaming.d.ts +92 -0
  75. package/dist/services/AutoNaming.js +235 -0
  76. package/dist/services/CompletionService.d.ts +122 -0
  77. package/dist/services/CompletionService.js +442 -0
  78. package/dist/services/ConfigService.d.ts +171 -0
  79. package/dist/services/ConfigService.js +695 -0
  80. package/dist/services/ConversationService.d.ts +274 -0
  81. package/dist/services/ConversationService.js +902 -0
  82. package/dist/services/CredentialService.d.ts +33 -0
  83. package/dist/services/CredentialService.js +86 -0
  84. package/dist/services/DiscoveryService.d.ts +182 -0
  85. package/dist/services/DiscoveryService.js +998 -0
  86. package/dist/services/HandoffService.d.ts +189 -0
  87. package/dist/services/HandoffService.js +414 -0
  88. package/dist/services/Logger.d.ts +130 -0
  89. package/dist/services/Logger.js +256 -0
  90. package/dist/services/MessageService.d.ts +88 -0
  91. package/dist/services/MessageService.js +280 -0
  92. package/dist/services/ModelService.d.ts +89 -0
  93. package/dist/services/ModelService.js +489 -0
  94. package/dist/services/NoticeService.d.ts +93 -0
  95. package/dist/services/NoticeService.js +217 -0
  96. package/dist/services/QuestionService.d.ts +184 -0
  97. package/dist/services/QuestionService.js +457 -0
  98. package/dist/services/SearchService.d.ts +54 -0
  99. package/dist/services/SearchService.js +117 -0
  100. package/dist/services/WorkspaceService.d.ts +96 -0
  101. package/dist/services/WorkspaceService.js +213 -0
  102. package/dist/services/imageSize.d.ts +41 -0
  103. package/dist/services/imageSize.js +146 -0
  104. package/dist/services/index.d.ts +20 -0
  105. package/dist/services/index.js +15 -0
  106. package/dist/services/secretMask.d.ts +24 -0
  107. package/dist/services/secretMask.js +34 -0
  108. package/dist/storage/AssetRepository.d.ts +87 -0
  109. package/dist/storage/AssetRepository.js +180 -0
  110. package/dist/storage/ConversationRepository.d.ts +55 -0
  111. package/dist/storage/ConversationRepository.js +128 -0
  112. package/dist/storage/CredentialRepository.d.ts +28 -0
  113. package/dist/storage/CredentialRepository.js +47 -0
  114. package/dist/storage/Database.d.ts +95 -0
  115. package/dist/storage/Database.js +180 -0
  116. package/dist/storage/MessageRepository.d.ts +104 -0
  117. package/dist/storage/MessageRepository.js +323 -0
  118. package/dist/storage/MetaRepository.d.ts +21 -0
  119. package/dist/storage/MetaRepository.js +33 -0
  120. package/dist/storage/NoticeRepository.d.ts +31 -0
  121. package/dist/storage/NoticeRepository.js +89 -0
  122. package/dist/storage/QuestionRepository.d.ts +34 -0
  123. package/dist/storage/QuestionRepository.js +96 -0
  124. package/dist/storage/WorkspaceRepository.d.ts +25 -0
  125. package/dist/storage/WorkspaceRepository.js +44 -0
  126. package/dist/storage/dbWorker.d.ts +10 -0
  127. package/dist/storage/dbWorker.js +132 -0
  128. package/dist/storage/index.d.ts +20 -0
  129. package/dist/storage/index.js +16 -0
  130. package/dist/storage/migrations.d.ts +26 -0
  131. package/dist/storage/migrations.js +207 -0
  132. package/dist/storage/types.d.ts +298 -0
  133. package/dist/storage/types.js +14 -0
  134. package/dist/wire/errors.d.ts +105 -0
  135. package/dist/wire/errors.js +143 -0
  136. package/dist/wire/events.d.ts +102 -0
  137. package/dist/wire/events.js +13 -0
  138. package/dist/wire/frames.d.ts +106 -0
  139. package/dist/wire/frames.js +156 -0
  140. package/dist/wire/index.d.ts +31 -0
  141. package/dist/wire/index.js +31 -0
  142. package/dist/wire/methods.d.ts +1896 -0
  143. package/dist/wire/methods.js +99 -0
  144. package/dist/wire/states.d.ts +487 -0
  145. package/dist/wire/states.js +61 -0
  146. package/package.json +63 -3
@@ -0,0 +1,257 @@
1
+ /**
2
+ * 中文文案表。
3
+ *
4
+ * `satisfies Record<keyof typeof en, string>` 让「少一个键」「多一个键」都在编译期露馅:
5
+ * 键的集合唯一真相在 `en.ts`,本文件只负责把每一句换成中文。语气与英文版一致 ——
6
+ * 说清发生了什么、用户能做什么,判断留给客户端(PRD D12)。
7
+ */
8
+ export const zh = {
9
+ // ---- 业务码对应的兜底文案(与 wire/errors.ts 的 BizCode 一一对应)----
10
+ "error.unauthorized": "这个访问密钥没被接受,检查一下密钥再试一次。",
11
+ "error.invalidParams": "这次请求里有不对的地方:{field}。",
12
+ "error.notFound": "找不到这个 id 对应的{entity}。",
13
+ "error.busy": "这段对话还在跑上一轮。等它跑完,或者先停下它。",
14
+ "error.payloadTooLarge": "这个文件是 {size},超过了 {limit} 的上限。",
15
+ "error.unsupported": "宿主处理不了{what}。",
16
+ "error.internal": "宿主内部出错了,细节写进日志里了。",
17
+ "error.configInvalid": "当前配置还用不了:{reason}。",
18
+ // 端口写得不对(D25 的三档来源里,显式给出的那个值不合法;裁定 R67)
19
+ "error.portInvalid": "这个端口号不能用:{value}(来自 {source})。端口要是 1..65535 的整数 —— 0 表示「让系统分配」,只在命令行里有效。",
20
+ // 助手没有可用模型(结构化原因在 `detail` 里)
21
+ "error.modelUnresolved": "这个助手没有可用的模型 —— 给它挑一个模型,或者在设置里指定一个默认模型。",
22
+ "error.notFactoryModel": "「{id}」不在出厂模型清单里,没有可以恢复的出厂版本。",
23
+ "error.mcpUnavailable": "{name} 没有响应,这一轮缺它的工具,其它能力照常。",
24
+ "error.modelUnsupported": "这段对话里已经有图片,{model} 读不了图片,所以没有换过去。",
25
+ "error.handoffDeclined": "这次不交接,对话继续往下跑。",
26
+ "error.questionPending": "还有一个问题没回答({question})。先回答它,再发新内容。",
27
+ "error.contextGuard": "这段对话在第 {used} 个 token 时到了 {limit} 这条线,请求在发出去之前就停下了。",
28
+ // ---- 通知:三档语气 + 是否到点消失(PRD L3 / F-I8)----
29
+ "notice.settingsSaved": "配置已保存。",
30
+ "notice.settingsApplied": "配置已生效,不用重启。",
31
+ "notice.conversationDeleted": "对话已删除。",
32
+ "notice.workspaceDeleted": "项目已移除,它名下的 {count} 段对话一起删掉了,磁盘上的目录没动。",
33
+ "notice.assetsUploaded": "已上传 {count} 张图片。",
34
+ "notice.attachmentDropped": "{name} 没能发出去,这条消息里没有它。",
35
+ "notice.upgradeRestarting": "已更新到 {version},现在重启。",
36
+ "notice.logWarning": "宿主警告:{summary}",
37
+ "notice.logError": "宿主错误:{summary}",
38
+ "notice.handoffWritten": "交接文档已写到 {path}。",
39
+ "notice.autoNamed": "给这段对话起名叫「{name}」。",
40
+ "notice.languageChanged": "这条连接现在说{language}。",
41
+ "notice.hardLimitHit": "这一轮在 {limit} 这条线停下了。东西都还在,对话等你继续。",
42
+ // ---- 生成六态(PRD L8 / F-I3)----
43
+ "status.connected": "已连上",
44
+ "status.awaitingFirstToken": "已连上,等第一个字",
45
+ "status.thinking": "在想…",
46
+ "status.generating": "在输出…",
47
+ "status.assemblingToolCalls": "正在拼 {count} 个工具调用…",
48
+ "status.awaitingTools": "在等 {tools}",
49
+ "status.idle": "空闲",
50
+ "status.done": "已结束",
51
+ "status.aborted": "已中止",
52
+ "status.error": "出错停下",
53
+ // ---- 问题对象(PRD D22 / F-I9)----
54
+ "question.handoff.prompt": "这段对话已用到上下文预算的 {percent}%。接下来怎么办?",
55
+ "question.handoff.self": "让助手自己写交接",
56
+ "question.handoff.selfDetail": "用完整对话和它的工具来写,质量最好,代价是多一次全量输入。",
57
+ "question.handoff.summary": "改成摘要历史",
58
+ "question.handoff.summaryDetail": "更便宜也更确定,但文档没那么多细节。",
59
+ "question.handoff.decline": "就在这段对话里继续",
60
+ "question.confirm.prompt": "「{action}」撤不回来。确定要做吗?",
61
+ "question.confirm.accept": "确定",
62
+ "question.confirm.decline": "取消",
63
+ "question.blocking": "这段对话被这个问题挡住了,答了才能继续。",
64
+ // ---- 消息与状态的事实叙述 ----
65
+ "message.reverted": "删掉了 {count} 条消息,内容已经放回输入框。",
66
+ "message.cwdMissing": "这个项目的目录已经不存在了({cwd})。对话和历史都还在。",
67
+ "message.injectedContext": "这段是宿主加进来的,不是你输入的:{summary}",
68
+ // 会话创建时那条 hidden 消息里的那句事实(PRD F-D9:cwd 来自对话所属项目,不是宿主进程的目录)
69
+ "message.injectedContext.cwd": "当前目录是 {cwd}",
70
+ "message.subagentFailed": "子 Agent {name} 失败了:{reason}",
71
+ "message.subagentFinished": "子 Agent {name} 跑完了。",
72
+ "message.imageAsText": "{model} 看不了图片,{name} 改成用文字描述发过去。",
73
+ "message.attachmentTooMany": "一条消息最多带 {limit} 张图片,{name} 没放进去。",
74
+ // ---- 用量(PRD F-I5)----
75
+ "usage.turn": "本轮 {value} tokens",
76
+ "usage.total": "累计 {value} tokens",
77
+ "usage.rate": "{value} tokens/秒",
78
+ "usage.withSubAgents": "累计里有 {value} 来自子 Agent",
79
+ // ---- 状态栏各块的标签(PRD F-I6)----
80
+ "label.agent": "助手",
81
+ "label.model": "模型",
82
+ "label.thinking": "思考强度",
83
+ "label.context": "上下文",
84
+ "label.usage": "用量",
85
+ "label.cwd": "目录",
86
+ "label.tools": "在跑的工具",
87
+ "label.subagents": "子 Agent",
88
+ // ---- `@` 补全(PRD F-H5 / D7)----
89
+ "completion.scanning": "还在读项目的文件清单,再多打几个字它就出来了。",
90
+ "completion.timedOut": "文件清单超过 {seconds} 秒才建好,可能不完整。",
91
+ "completion.unavailable": "这里拿不到文件清单:{reason}",
92
+ "completion.noFolder": "这个项目的目录已经不在了",
93
+ "completion.truncated": "只列了前 {limit} 个文件,再打几个字缩小范围就能看到其余的。",
94
+ // ---- 配置、模型、交接、工作区的短句 ----
95
+ "config.referenced": "还有 {count} 处引用它,所以不能删:{names}",
96
+ "config.fileBroken": "{path} 读不成配置:{reason}",
97
+ // ---- 端点、模型、助手的可用性(PRD F-B5:用不了也要列出来并说明原因)----
98
+ "endpoint.missing": "{id} 已经不在端点列表里了,所以这里连不出去。",
99
+ "endpoint.noKey": "{endpoint} 还没配访问密钥,它的模型答不了话。",
100
+ "model.endpointMissing": "{model} 指向的端点({id})已经不在端点列表里了。",
101
+ "agent.modelMissing": "这个助手绑定的模型({id})已经不在模型列表里了。",
102
+ "agent.fileBroken": "{name} 读不成助手定义:{reason}",
103
+ "agent.notFactory": "{id} 不在出厂助手清单里,没有可恢复的出厂版本。",
104
+ // ---- 配置检查(PRD F-A8:配错了要能当场修,问题指到具体字段)----
105
+ "config.issue.thresholdOrder": "{name} 的交接线({handoff} 个 token)到了或者超过了硬线({guard} 个 token)。",
106
+ "config.issue.defaultMissing": "{field} 指向 {id},那条已经不在清单里了。",
107
+ "config.issue.defaultAgentMissing": "默认助手({id})已经不在助手定义里了。",
108
+ // ---- 能力发现(PRD F-G2 / F-F6:坏掉的那一条也要看得见)----
109
+ "discovery.notADirectory": "{path} 不是目录,从它这里什么都读不到。",
110
+ "discovery.shadowed": "这一条被更近的 {path} 覆盖了。",
111
+ "discovery.mcpEntryInvalid": "{name} 既没有 transport 也没有 command,连不上。",
112
+ "discovery.skillBroken": "{name} 的 SKILL.md 用不成一个 Skill:{reason}",
113
+ "discovery.toolUnloadable": "{name} 加载不成一个工具:{reason}",
114
+ "discovery.subAgentBroken": "{name} 不是一个能用的子 Agent 定义:{reason}",
115
+ "model.unavailable": "{name} 还在列表里,但现在用不了:{reason}",
116
+ "model.visionRequired": "{model} 读不了图片,而这段对话里有图片。",
117
+ "handoff.degraded": "交接退回到了 {mode}:{reason}",
118
+ "handoff.declined": "这次不交接。",
119
+ "handoff.noDocuments": "这个项目里还没有交接文档。",
120
+ "workspace.removalCost": "这会删掉 {conversations} 段对话和它们的 {messages} 条消息,磁盘上的目录不动。",
121
+ "attachment.tooLarge": "一张图片最大 {limit},{name} 是 {size}。",
122
+ "attachment.tooMany": "一条消息最多带 {limit} 张图片。",
123
+ // ---- 通知 / 问题 / 交接 / 自动命名 / 临时对话(W4-H)----
124
+ "notice.unknown": "宿主有一条通知({code})。",
125
+ "error.handoffFailed": "交接没走通:{reason}",
126
+ "error.transientFailed": "这次一次性请求没跑完:{reason}",
127
+ "handoff.newConversationSummary": "这段对话接着上一段。交接文档在 {path},先读它,再接着做这件事。\n\n交接摘要:\n{summary}",
128
+ "handoff.degradeReason.fallback": "这次助手自己没能把文档写出来",
129
+ "autoName.failed": "没起出名字,保持原来的名字:{reason}",
130
+ // ---- 能力清单:帮助页与指令菜单按它渲染(F-E5 / F-E6 / F-F9)----
131
+ "capability.host.hello": "连上宿主",
132
+ "capability.host.hello.detail": "拿一串访问密钥建立连接,并定下这条连接说哪种语言。",
133
+ "capability.host.version": "看宿主版本",
134
+ "capability.host.version.detail": "正在跑的版本与协议版本,升级靠它比对。",
135
+ "capability.host.upgrade": "升级后重启",
136
+ "capability.host.upgrade.detail": "比对磁盘上的版本与正在跑的版本,确认新版本真的落盘了才重启。",
137
+ "capability.host.shutdown": "关掉宿主",
138
+ "capability.host.shutdown.detail": "等手上没有欠着的事之后停止服务,已连上的连接会断开。",
139
+ "capability.host.capabilities": "列出宿主能做什么",
140
+ "capability.host.capabilities.detail": "帮助页就是照这份清单渲染的:每件事做什么、会不会占住对话、能不能撤。",
141
+ "capability.host.reload": "从磁盘重载",
142
+ "capability.host.reload.detail": "重新读一遍配置、助手、工具、技能或 MCP 条目:受影响的项日会重建能力,不用重启。",
143
+ "capability.host.setLanguage": "换这条连接的语言",
144
+ "capability.host.setLanguage.detail": "这条连接上的文案都按选的语言渲染;断开重连就忘掉。",
145
+ "capability.workspace.list": "列出项目",
146
+ "capability.workspace.list.detail": "这台机器上的全部项目,包括目录已经不在的那些。",
147
+ "capability.workspace.create": "添加项目",
148
+ "capability.workspace.create.detail": "把一个目录登记成项目;同一个目录只能登记一次。",
149
+ "capability.workspace.get": "看一个项目",
150
+ "capability.workspace.get.detail": "按 id 取一个项目,同时告诉你它的目录还在不在。",
151
+ "capability.workspace.rename": "重命名项目",
152
+ "capability.workspace.rename.detail": "只改显示名,目录路径不变。",
153
+ "capability.workspace.remove": "移除项目",
154
+ "capability.workspace.remove.detail": "把这个项目和它名下的对话一起删掉,磁盘上的目录不动。",
155
+ "capability.conversation.list": "列出对话",
156
+ "capability.conversation.list.detail": "新的在前、置顶的在最上;可以只看某个项目的。",
157
+ "capability.conversation.create": "开一段对话",
158
+ "capability.conversation.create.detail": "创建时就把项目、助手、模型定下来。",
159
+ "capability.conversation.get": "打开一段对话",
160
+ "capability.conversation.get.detail": "按 id 取一段对话,接着上次聊靠它。",
161
+ "capability.conversation.state": "看现在到哪了",
162
+ "capability.conversation.state.detail": "一份快照里给出六态运行现场、上下文阈值、待答问题与用量。",
163
+ "capability.conversation.rename": "给对话改名",
164
+ "capability.conversation.rename.detail": "只改名字,身份与排序不变。",
165
+ "capability.conversation.pin": "置顶对话",
166
+ "capability.conversation.pin.detail": "把它钉在侧栏最上面,其余不变。",
167
+ "capability.conversation.delete": "删除对话",
168
+ "capability.conversation.delete.detail": "把这段对话和它的消息硬删,顺带清掉它引用的图片。",
169
+ "capability.conversation.send": "发一条消息",
170
+ "capability.conversation.send.detail": "跑一轮:消息 id 立刻回来,回答随后流式到达。",
171
+ "capability.conversation.abort": "停下这一轮",
172
+ "capability.conversation.abort.detail": "把正在写的回答停下来,已经写出的那些留在库里。",
173
+ "capability.conversation.revert": "撤回消息",
174
+ "capability.conversation.revert.detail": "把某条消息之后的全部删掉,并把那段正文回填到输入框。",
175
+ "capability.conversation.setModel": "只给这段对话换模型",
176
+ "capability.conversation.setModel.detail": "不动助手的默认模型,也不重开对话。",
177
+ "capability.conversation.setThinking": "调这段对话的思考强度",
178
+ "capability.conversation.setThinking.detail": "把档位展开成请求参数,只对这段对话生效。",
179
+ "capability.conversation.transient": "问一次、不留痕迹",
180
+ "capability.conversation.transient.detail": "一次请求一次回答,不入库、不建对话。",
181
+ "capability.message.list": "看消息",
182
+ "capability.message.list.detail": "一段对话的全部历史,或从某条消息开始的全部;子 Agent 的消息也能取。",
183
+ "capability.question.list": "看待答问题",
184
+ "capability.question.list.detail": "还在等回答的问题;多端看到的是同一批。",
185
+ "capability.question.answer": "回答问题",
186
+ "capability.question.answer.detail": "记下答案并接着往下走:交接问题会自己把交接开起来。",
187
+ "capability.notice.list": "看通知",
188
+ "capability.notice.list.detail": "现在还在界面上的通知——它不进消息流。",
189
+ "capability.notice.dismiss": "清掉一条通知",
190
+ "capability.notice.dismiss.detail": "把一条通知手动清掉;带持续时间的会自己到点消失。",
191
+ "capability.notice.clear": "清掉一批通知",
192
+ "capability.notice.clear.detail": "一次清一批:整个列表,或某一对话的那些。",
193
+ "capability.config.get": "看配置",
194
+ "capability.config.get.detail": "一次读出端点(密钥掩码)、模型、默认项,以及哪里配错了。",
195
+ "capability.config.patch": "改配置",
196
+ "capability.config.patch.detail": "改完当场生效——不用重启,也没有全局保存键。",
197
+ "capability.config.setDefaults": "设默认项",
198
+ "capability.config.setDefaults.detail": "默认助手、兜底模型、迁移模型、图片模型、取名模型。",
199
+ "capability.config.getDiscovery": "看能力从哪来",
200
+ "capability.config.getDiscovery.detail": "MCP 各层、Skill、工具、子 Agent 到底找到了哪些,以及哪些文件读不出来。",
201
+ "capability.config.saveMcp": "保存一条 MCP 服务器",
202
+ "capability.config.saveMcp.detail": "有这一条就改、没有就建;只动这一条,传输方式与它的参数都在入参里,这一版不认识的字段原样保留。",
203
+ "capability.config.deleteMcp": "删除一条 MCP 服务器",
204
+ "capability.config.deleteMcp.detail": "只从可编辑的那两个作用域里删这一条;本来就没有时如实回报,不算失败。",
205
+ "capability.config.saveEndpoint": "保存端点",
206
+ "capability.config.saveEndpoint.detail": "新建或修改端点;密钥省略就表示保留现有的。",
207
+ "capability.config.deleteEndpoint": "删除端点",
208
+ "capability.config.deleteEndpoint.detail": "还有模型指着它时拒删,并把引用者列出来。",
209
+ "capability.agent.list": "列出助手",
210
+ "capability.agent.list.detail": "全部助手,不可用的也列出来并说明原因。",
211
+ "capability.agent.get": "看一个助手",
212
+ "capability.agent.get.detail": "按 id 取一份助手定义,直接来自它的文件。",
213
+ "capability.agent.create": "新建助手",
214
+ "capability.agent.create.detail": "写一份新的定义文件——一助手一文件,能手改、能进 git。",
215
+ "capability.agent.update": "编辑助手",
216
+ "capability.agent.update.detail": "改定义文件;从此它算你自己定的,不再按出厂版覆盖。",
217
+ "capability.agent.delete": "删除助手",
218
+ "capability.agent.delete.detail": "删掉这份定义,删前先说清还有谁指着它。",
219
+ "capability.agent.setModel": "设助手默认模型",
220
+ "capability.agent.setModel.detail": "改的是助手的默认模型,影响以后新开的对话。",
221
+ "capability.agent.setThinking": "设助手的思考档位",
222
+ "capability.agent.setThinking.detail": "把展开后的请求参数写进助手定义。",
223
+ "capability.agent.restoreFactory": "恢复助手出厂设置",
224
+ "capability.agent.restoreFactory.detail": "把这份助手定义整条换回宿主自带的那一份——提示词、模型、权限、思考设置一起回退;可以先看恢复之后会是什么样再决定。",
225
+ "capability.model.list": "列出模型",
226
+ "capability.model.list.detail": "出厂托管与自定义的模型,带两条阈值、思考档位与可用性。",
227
+ "capability.model.listImages": "列出图片模型",
228
+ "capability.model.listImages.detail": "用来生成图片的那些模型,以及哪个是默认。",
229
+ "capability.model.create": "新建模型",
230
+ "capability.model.create.detail": "新建时就绑到某个端点上,并且立刻算自定义。",
231
+ "capability.model.update": "编辑模型",
232
+ "capability.model.update.detail": "编辑出厂模型会把它转成自定义,以后的出厂更新不再覆盖它。",
233
+ "capability.model.delete": "删除模型",
234
+ "capability.model.delete.detail": "还被助手指着时拒删;删掉时把默认项一起收拾干净。",
235
+ "capability.model.restoreFactory": "恢复出厂",
236
+ "capability.model.restoreFactory.detail": "用出厂那一份整条替换掉现在的模型定义。",
237
+ "capability.model.saveImage": "新建或修改图片模型",
238
+ "capability.model.saveImage.detail": "把图片模型绑到端点上,带默认尺寸与质量。",
239
+ "capability.model.deleteImage": "删除图片模型",
240
+ "capability.model.deleteImage.detail": "它还是默认图片模型时拒删。",
241
+ "capability.asset.begin": "开始上传",
242
+ "capability.asset.begin.detail": "先声明文件的大小与类型,超限的当场就拒。",
243
+ "capability.asset.end": "结束上传",
244
+ "capability.asset.end.detail": "校验长度与摘要,然后把它变成消息可以引用的素材。",
245
+ "capability.asset.get": "取回素材",
246
+ "capability.asset.get.detail": "把存着的字节取回来,任何模型都能重放历史里的图;缩略图这一档目前等同原图。",
247
+ "capability.completion.files": "补全文件路径",
248
+ "capability.completion.files.detail": "`@` 菜单背后的项目文件清单;还在读的时候会说出来。",
249
+ "capability.handoff.start": "写交接文档",
250
+ "capability.handoff.start.detail": "写出文档,需要的话顺手开新对话;旧对话完整保留。",
251
+ "capability.handoff.listDocuments": "列出交接文档",
252
+ "capability.handoff.listDocuments.detail": "这个项目里已经写好的文档,可以反复打磨同一份。",
253
+ "capability.search.conversations": "按名字搜对话",
254
+ "capability.search.conversations.detail": "按名字找旧对话,可以只在某个项目里找。",
255
+ "capability.search.messages": "搜对话内容",
256
+ "capability.search.messages.detail": "对说过的话做全文搜索,每条命中带一小段原文。",
257
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 包出口(`main` / `types` 都指这里)。
3
+ *
4
+ * 三件东西:
5
+ * 1. 起服务的入口:`createHost` / `HostApp` —— 别的进程(桌面端、脚本)可以把宿主
6
+ * 当库用,与命令行启动的是**同一个**单根,不各写一套组装。
7
+ * 2. 契约:`wire` 的全部类型与方法表,客户端照着接线,不必再抄一份形状。
8
+ * 3. 路径与监听来源:`resolvePaths` / `resolveListenTarget` —— 客户端与宿主读同一份数据根
9
+ * 规则,才不会出现「服务在 A、客户端看 B」。
10
+ *
11
+ * 这里只做再导出,不新增语义,也不导出任何单例。
12
+ */
13
+ export { createHost, resolveHostVersion, HostApp } from "./app.js";
14
+ export type { ExitFacts, ExitHook, ExitReason, HostAppOptions } from "./app.js";
15
+ export { DEFAULT_PORT, LOOPBACK_HOST, PUBLIC_HOST, isValidPort, resolveDataRoot, resolveListenTarget, resolvePaths, } from "./config.js";
16
+ export type { ListenTarget, ListenTargetInput, HostPaths } from "./config.js";
17
+ export * from "./wire/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 包出口(`main` / `types` 都指这里)。
3
+ *
4
+ * 三件东西:
5
+ * 1. 起服务的入口:`createHost` / `HostApp` —— 别的进程(桌面端、脚本)可以把宿主
6
+ * 当库用,与命令行启动的是**同一个**单根,不各写一套组装。
7
+ * 2. 契约:`wire` 的全部类型与方法表,客户端照着接线,不必再抄一份形状。
8
+ * 3. 路径与监听来源:`resolvePaths` / `resolveListenTarget` —— 客户端与宿主读同一份数据根
9
+ * 规则,才不会出现「服务在 A、客户端看 B」。
10
+ *
11
+ * 这里只做再导出,不新增语义,也不导出任何单例。
12
+ */
13
+ export { createHost, resolveHostVersion, HostApp } from "./app.js";
14
+ export { DEFAULT_PORT, LOOPBACK_HOST, PUBLIC_HOST, isValidPort, resolveDataRoot, resolveListenTarget, resolvePaths, } from "./config.js";
15
+ export * from "./wire/index.js";
@@ -0,0 +1,186 @@
1
+ /**
2
+ * 上传接收器:`asset.begin` → 若干二进制帧 → `asset.end`(architecture A11 / PRD D5、F-H8)。
3
+ *
4
+ * 三段式的分工:
5
+ * 1. `asset.begin`(JSON-RPC 请求):声明用途、类型、总字节数。**超限在这里就拒**(PRD D5:
6
+ * 20MB/张),不接收完再说不行 —— 那既浪费带宽,也让客户端在上传中途白等一下。
7
+ * 素材行要按对话挂外键,所以开临时文件之前先让归属的对话落库(草稿对话在库里还没有行,
8
+ * R56:落库发生在「第一次真正用到它」的那一刻,带图的第一条消息就属于这种)。
9
+ * 2. 任意多个二进制帧:每一帧带上「这是哪个上传」的头,字节直接追加进临时文件,不在内存里攒。
10
+ * 3. `asset.end`(JSON-RPC 请求):校验总长度与客户端给的 `sha256`,通过后交给落定回调,
11
+ * 把临时文件变成正式素材(`<dataRoot>/assets/` 下的正式文件 + 库里一行引用)。
12
+ *
13
+ * 二进制帧的形状(`asset.chunk`):
14
+ *
15
+ * ```
16
+ * | 4 字节大端无符号整数 N | N 字节 UTF-8 JSON 头 {"uploadId": "..."} | 若干字节片段 |
17
+ * ```
18
+ *
19
+ * 为什么头里要带 `uploadId` 而不是「一条连接同时只允许一个上传」:同一条连接上可以并发多个上传
20
+ * (一次拖进四张图就是四个),宿主分配的 `uploadId` 是它们之间唯一的区分方式。头做成
21
+ * 「长度前缀 + JSON」而不是固定长度二进制 id,是为了让帧在抓包/日志里仍然可读,也不绑定
22
+ * `uploadId` 的编码方式。
23
+ *
24
+ * 清理的口径(三处,都在本文件里):
25
+ * - 长度或摘要不符:删临时文件,报错;
26
+ * - 连接断开 / 宿主收尾:这条连接名下所有未完成的上传按 `begin` 记下的临时文件删掉;
27
+ * - 写盘出错:删临时文件,报错。
28
+ */
29
+ import { type Language } from "../i18n/index.js";
30
+ import type { AssetBeginParams, AssetBeginResult, AssetEndParams, AssetEndResult, AssetPurpose, AssetRef } from "../wire/index.js";
31
+ /**
32
+ * 收完一个上传之后要交给落定方的事实(临时文件此时已关闭、校验已通过)。
33
+ *
34
+ * 类型定在 net 这一侧(上传协议的一部分),落定实现(`AssetService.finalizeUpload`)按结构
35
+ * 满足它 —— 两边不需要互相 import 具体实现。
36
+ */
37
+ export interface UploadFinalizeRequest {
38
+ uploadId: string;
39
+ /** 临时文件的绝对路径;落定方负责把它改成正式文件 */
40
+ tempPath: string;
41
+ mime: string;
42
+ /** 实际写入的字节数(已校验过等于声明值) */
43
+ bytes: number;
44
+ /** 小写十六进制的摘要(已校验过等于客户端给的值) */
45
+ sha256: string;
46
+ name: string | null;
47
+ purpose: AssetPurpose;
48
+ conversationId: string;
49
+ }
50
+ /** 落定:把临时文件变成正式素材并登记引用 */
51
+ export type UploadFinalizer = (request: UploadFinalizeRequest) => Promise<AssetRef>;
52
+ /**
53
+ * 上传前的去重查询:库里是不是已经有同一份字节了。
54
+ *
55
+ * 命中时 `asset.begin` 直接回既有引用(`deduped: true`):不建临时文件、不分配 `uploadId`。
56
+ * 宿主自己算 `sha256` 也行,但它得先把 20MB 收完 —— 客户端本来就算过,问一句就够了。
57
+ * 去重是全局的(按内容摘要),所以这里不问「哪段对话」。
58
+ */
59
+ export type ExistingAssetLookup = (input: {
60
+ sha256: string;
61
+ bytes: number;
62
+ }) => Promise<AssetRef | null>;
63
+ /**
64
+ * 上传前让「这段对话」成为库里的行。
65
+ *
66
+ * `language` 是那条「这段对话在哪个目录」的隐藏消息的渲染语言(D8):上传是连接上的动作,
67
+ * 只有接线层知道收件人说的是哪种语言,所以逐次传进来而不是在构造时定死。
68
+ */
69
+ export type ConversationPersister = (conversationId: string, language: Language) => Promise<void>;
70
+ export interface UploadReceiverOptions {
71
+ /** 数据根下的 `assets/`:临时文件与正式文件同目录,改名不必跨设备复制 */
72
+ assetsDir: string;
73
+ /** 收完之后做什么(缺省实现见 `AssetService.finalizeUpload`) */
74
+ finalize: UploadFinalizer;
75
+ /**
76
+ * 上传前把这段对话落成库里的行(R56:`conversation.create` 只发 id 与身份)。
77
+ *
78
+ * 素材行按 `conversationId` 挂外键,所以「新对话第一条消息就带图」这条路上,对话的落库发生在
79
+ * `asset.begin`(与「第一次 `send`」同义)。实现方要自己幂等(同一段对话反复调只落一行);
80
+ * 不注入时上传不碰对话表。
81
+ */
82
+ ensureConversation?: ConversationPersister;
83
+ /**
84
+ * `asset.begin` 带了 `sha256` 时先问一句「库里是不是已经有它」。
85
+ *
86
+ * 不注入时不问去重(每次都收字节),也不报错:去重是优化,不是上传的前提。
87
+ */
88
+ findExisting?: ExistingAssetLookup;
89
+ /** 单张上限,缺省 `MAX_ASSET_BYTES`(20MB,PRD D5) */
90
+ maxAssetBytes?: number;
91
+ /** 内部错误去处(清理失败、落定失败等);缺省忽略 */
92
+ onError?: (error: unknown, context: string) => void;
93
+ }
94
+ export declare class UploadReceiver {
95
+ private readonly assetsDir;
96
+ private readonly finalize;
97
+ private readonly onError?;
98
+ /** 单张上限;`hello` 的 `limits` 也从这里取,两边不各写一个数 */
99
+ readonly maxAssetBytes: number;
100
+ private readonly ensureConversation?;
101
+ private readonly findExisting?;
102
+ /** connectionId → uploadId → 进行中的上传 */
103
+ private readonly sessions;
104
+ constructor(options: UploadReceiverOptions);
105
+ /**
106
+ * `asset.begin`:校验声明、让归属的对话落库、问去重、开临时文件、发一个上传句柄。
107
+ *
108
+ * 声明里只有「总长」能验,字节本身还没到;所以这里的拒绝都是**声明层面**的
109
+ * (超限、类型不合法、缺对话归属、对话不存在)。
110
+ *
111
+ * 去重命中时这条路就到此为止:不建临时文件、不分配 `uploadId`。去重按内容摘要做,不区分
112
+ * 对话,所以命中并不证明这段对话存在 —— 「让对话落库」排在问去重之前,不存在的对话这一趟
113
+ * 一个字节也不会收。
114
+ *
115
+ * 「让对话落库」排在建临时文件之前:对话不存在时这一趟上传一个字节都不该落盘,
116
+ * 也不该占住一个 `uploadId`。`language` 是这条连接的语言,用来渲染那条隐藏的 cwd 消息。
117
+ */
118
+ begin(connectionId: string, params: AssetBeginParams, language?: Language): Promise<AssetBeginResult>;
119
+ /**
120
+ * 一个二进制帧:解出上传句柄,把片段追加进临时文件。
121
+ *
122
+ * 返回值是这条上传目前已收到的字节数(用得上就返回,测试与调试都不必去翻文件)。
123
+ */
124
+ receiveBinary(connectionId: string, frame: Uint8Array): Promise<number>;
125
+ /**
126
+ * `asset.end`:等写盘排空、关文件、校验长度与摘要,通过后落定。
127
+ *
128
+ * 校验不过时的顺序是「先删文件、再报错」:报错之后这条上传就没有别的出口了,
129
+ * 留着半个文件只会变成没人认领的垃圾。
130
+ */
131
+ end(connectionId: string, params: AssetEndParams): Promise<AssetEndResult>;
132
+ /**
133
+ * 丢掉一条连接名下所有未完成的上传(连接断开时调)。
134
+ *
135
+ * 这是「中途断开按 `begin` 记的临时文件清理」的落点。清理本身失败只报给 `onError`:
136
+ * 连接已经没了,没有谁在等一个失败结果。
137
+ */
138
+ abortConnection(connectionId: string): Promise<void>;
139
+ /** 宿主收尾:把所有连接的上传都清掉 */
140
+ dispose(): Promise<void>;
141
+ /** 这条连接上还有几个未完成的上传(测试与诊断用) */
142
+ pendingCount(connectionId?: string): number;
143
+ /**
144
+ * 让这段对话先成为库里的行(幂等由注入方保证)。
145
+ *
146
+ * 业务错误(`not_found` 之类)原样上抛:客户端要按码说人话,不能让「对话不存在」在出网时
147
+ * 变成一句 internal。其余异常(写库失败这类)收敛成 `internal` 并留一个原因,原始错误同时
148
+ * 交给 `onError` 进日志。
149
+ */
150
+ private persistConversation;
151
+ private sessionMap;
152
+ /**
153
+ * 问一句「库里有没有同一份字节」。
154
+ *
155
+ * 查询本身失败时当作「没命中」:去重是省一次上传的优化,不能因为它的存储出错就把整个上传拒掉。
156
+ */
157
+ private lookupExisting;
158
+ private detach;
159
+ /** 追加一片:排在上一片之后写,累积摘要与已收字节数 */
160
+ private append;
161
+ private closeHandle;
162
+ /** 删临时文件(不存在不算错:清理动作要能重复执行) */
163
+ private discard;
164
+ }
165
+ /**
166
+ * 拼一个 `asset.chunk` 二进制帧(客户端按同一份实现编码,测试也用它)。
167
+ *
168
+ * 导出它是为了让「帧长什么样」只有一处定义:客户端与宿主各写一份编码器迟早会错开一个字段。
169
+ */
170
+ export declare function encodeChunkFrame(uploadId: string, chunk: Uint8Array): Uint8Array;
171
+ /**
172
+ * 解一个 `asset.chunk` 二进制帧。
173
+ *
174
+ * 坏帧一律 `invalid_params` 并带 `detail.reason`:帧是二进制的,客户端拼错时唯一能帮上忙的
175
+ * 就是「哪一步不对」(头长度越界、头不是 JSON、头里没有 `uploadId`)。
176
+ */
177
+ export declare function decodeChunkFrame(frame: Uint8Array): {
178
+ uploadId: string;
179
+ chunk: Uint8Array;
180
+ };
181
+ /**
182
+ * 字节数的人话形式(错误文案里的 `{size}` / `{limit}`)。
183
+ *
184
+ * 单位用 1024 进制、最多一位小数:`20 MB`、`8.5 MB`、`512 KB` —— 与用户看到文件大小时的口径一致。
185
+ */
186
+ export declare function formatBytes(bytes: number): string;