zcode-pro 0.17.2 → 0.19.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.
@@ -1,14 +1,22 @@
1
1
  // 注入脚本公共工具:与 helper 通信、DOM 构建、多语言文案。
2
2
  export const BOOT = typeof window !== 'undefined' ? (window.__ZCODEPRO__ || {}) : {};
3
3
  export const HELPER_URL = BOOT.helperUrl || 'http://127.0.0.1:47889';
4
- const TOKEN = BOOT.token || '';
4
+
5
+ // token/helperUrl 必须在每次调用时实时读 window.__ZCODEPRO__:cli.mjs 重启后 helper 换了
6
+ // 随机 token,重新注入会被 index.js 的幂等守卫跳过、页面继续用旧闭包——若在模块求值时
7
+ // 固化成常量,旧闭包会永远拿旧 token 报 unauthorized。重注入的 bootstrap 会先更新
8
+ // window.__ZCODEPRO__,实时读即可对上新一轮 token。
9
+ function liveBoot() {
10
+ return (typeof window !== 'undefined' && window.__ZCODEPRO__) || BOOT;
11
+ }
5
12
 
6
13
  export function rpc(path, options = {}) {
7
- return fetch(HELPER_URL + path, {
14
+ const boot = liveBoot();
15
+ return fetch((boot.helperUrl || HELPER_URL) + path, {
8
16
  method: options.method || 'GET',
9
17
  headers: {
10
18
  'Content-Type': 'application/json',
11
- 'X-ZCodePro-Token': TOKEN,
19
+ 'X-ZCodePro-Token': boot.token || '',
12
20
  },
13
21
  body: options.body ? JSON.stringify(options.body) : undefined,
14
22
  })
@@ -35,22 +43,31 @@ const zh = {
35
43
  tabFeatures: '功能',
36
44
  tabStyles: '样式',
37
45
  tabProxy: '代理',
46
+ tabBehavior: '行为',
38
47
  tabAgents: '全局提示词',
39
48
  agentsDesc: '写入 ~/.zcode/AGENTS.md,作为默认指令用于所有项目的每次会话;保存后从新会话起生效,项目内的 AGENTS.md 可补充或覆盖。内容超过 100KB 会被应用截断。',
40
49
  agentsPlaceholder: '填写希望所有项目默认遵循的指令;清空并保存即移除全局提示词',
41
50
  agentsSave: '保存',
42
51
  agentsSaved: '全局提示词已保存',
43
52
  agentsLoadFailed: '读取全局提示词失败',
44
- proxyDesc: '为 ZCode Pro 本地助手发起的网络访问设置 HTTP 代理:插件市场的更新与安装、Headroom 本体的检查更新与升级都会走该代理。不影响 ZCode 应用本身与模型请求,保存后立即生效。',
53
+ proxyDesc: '为 ZCode Pro 本地助手发起的网络访问设置 HTTP 代理:插件市场的更新与安装、插件依赖软件的安装与升级、WebDAV 同步都可走该代理,用下方开关选择生效范围。不影响 ZCode 应用本身与模型请求,保存后立即生效。',
45
54
  proxyPlaceholder: 'http://127.0.0.1:7890',
46
55
  proxySave: '保存',
47
56
  proxySaved: '代理设置已保存',
48
57
  proxyHint: '留空保存即清除代理。',
49
58
  proxyTest: '检测',
50
59
  proxyTesting: '检测中…',
60
+ proxyTestEmpty: '请先输入代理地址',
51
61
  proxyTestFailed: '检测失败',
62
+ proxyScopePlugins: '插件市场更新',
63
+ proxyScopePluginsDesc: '插件市场的检查更新、安装与卸载(zcode CLI 的 git 操作)走代理。',
64
+ proxyScopeDeps: '插件依赖软件',
65
+ proxyScopeDepsDesc: 'headroom 与 rtk 的安装、检查更新与升级(pip 与 GitHub 下载)走代理。',
66
+ proxyScopeSync: '同步',
67
+ proxyScopeSyncDesc: 'WebDAV 上传与下载走代理。默认关闭:坚果云等国内网盘直连即可,代理停了同步会跟着失败。',
52
68
  tabSync: '同步',
53
- syncDesc: '手动把 ZCode Pro 设置与模型设置备份到 WebDAV,或在新电脑上恢复。两项各自独立成文件,可只上传或只覆盖其中一项;仅在点击按钮时传输,不做自动同步。',
69
+ tabDebug: '调试',
70
+ syncDesc: '手动把 ZCode Pro 设置与模型设置备份到 WebDAV,或在新电脑上恢复。两项各自独立成文件,可只上传或只覆盖其中一项;每次上传会额外保留一份带时间戳的历史版本,下载时任选一个版本恢复;仅在点击按钮时传输,不做自动同步。',
54
71
  syncUrlPlaceholder: 'https://dav.jianguoyun.com/dav/',
55
72
  syncDir: '上传目录',
56
73
  syncDirPlaceholder: 'zcode-pro',
@@ -58,7 +75,7 @@ const zh = {
58
75
  syncPassword: '密码',
59
76
  syncSave: '保存',
60
77
  syncSaved: '同步配置已保存',
61
- syncFormHint: '同步文件存到“上传目录”(默认 zcode-pro,可多级,自动创建)下的 zcodepro.json 与 model.json。',
78
+ syncFormHint: '同步文件存到“上传目录”(默认 zcode-pro,可多级,自动创建):zcodepro.json 与 model.json 始终是最新一版,旁边另保留带时间戳的历史版本。',
62
79
  syncRecLink: '坚果云 WebDAV',
63
80
  syncRecSuffix: ':登录与密码填“应用密码”,不是账号密码。',
64
81
  syncIncludeZcp: 'ZCode Pro 设置',
@@ -68,16 +85,44 @@ const zh = {
68
85
  syncUpload: '上传到云端',
69
86
  syncDownload: '从云端下载',
70
87
  syncUploading: '上传中…',
71
- syncDownloading: '下载中…',
72
88
  syncUploaded: '已上传到云端',
73
89
  syncDownloaded: '已从云端恢复',
74
90
  syncLastPush: '上次上传',
75
91
  syncLastPull: '上次下载',
76
92
  syncNever: '无',
77
93
  syncConfirmTitle: '从云端下载',
78
- syncConfirmDesc: '将用云端数据覆盖本机勾选的同步内容(覆盖前会在原文件旁留下 .zcodepro-backup 备份);本机的同步配置与登录凭据不受影响。模型设置恢复后建议重启 ZCode 生效。确认下载?',
79
- syncConfirmGo: '确认下载',
94
+ syncConfirmDesc: '将用所选文件覆盖本机对应的一项(覆盖前会在原文件旁留下 .zcodepro-backup 备份);本机的同步配置与登录凭据不受影响。模型设置恢复后建议重启 ZCode 生效。确认导入?',
95
+ syncConfirmGo: '确认导入',
96
+ syncPickDesc: '固定名文件始终是最新一版,带时间戳的是每次上传留下的历史版本;「导入」用所选文件覆盖本机对应的一项。',
97
+ syncVerDeleteLatestNote: '注意:这是“最新”文件,旧版 zcode-pro 的「从云端下载」依赖它,删除后旧版机器将无法下载;带时间戳的历史版本不受影响。',
80
98
  syncHint: '同步登录凭据仅保存在本机 zcodepro.json;模型设置包含自定义供应商的 API Key,只会上传到你自己的 WebDAV。',
99
+ syncTest: '测试',
100
+ syncTesting: '测试中…',
101
+ syncTestEmpty: '请先填写 URL',
102
+ syncTestFailed: '测试失败',
103
+ syncTestStepConnect: '连接',
104
+ syncTestStepDir: '目录',
105
+ syncTestStepList: '文件',
106
+ syncTestFilesFound: '云端已有 {n} 个备份文件',
107
+ syncPickTitle: '请选择一个文件',
108
+ syncPickLoading: '正在读取云端文件列表…',
109
+ syncPickEmpty: '云端还没有备份文件,请先在其他电脑上传',
110
+ syncVerImport: '导入',
111
+ syncVerImporting: '导入中…',
112
+ syncVerDelete: '删除',
113
+ syncVerSave: '保存到磁盘',
114
+ syncVerSaving: '保存中…',
115
+ syncVerLatest: '最新',
116
+ syncVerDeleteTitle: '删除云端文件',
117
+ syncVerDeleteDesc: '将删除云端的这份备份,不可恢复:',
118
+ syncVerDeleted: '已删除云端备份',
119
+ syncVerSaved: '已保存到',
120
+ devMode: '开发模式',
121
+ devModeRowDesc: '开启后出现「重载 ZCode Pro」按钮;也可给启动器设环境变量 ZCODEPRO_DEV=1 启用。此标签页仅在开发模式生效时显示。',
122
+ devModeDesc: '开发调试用:改完 zcode-pro 代码后不必重启 ZCode,点「重载 ZCode Pro」即可加载新代码。流程为自动构建(需在源码目录运行)→ 以新进程重启 ZCode Pro(本地助手与注入脚本都换新)→ 所有 ZCode 窗口自动刷新并重新注入;ZCode 本体与已打开的会话不受影响。',
123
+ devReload: '重载 ZCode Pro',
124
+ devReloading: '重载中…',
125
+ devReloadDesc: '点击后约 2-3 秒内所有 ZCode 窗口自动刷新一次并加载新脚本。',
81
126
  rowGapName: '段落间距',
82
127
  rowGapDesc: '会话中段落等文本块之间的垂直间距(回合之间、答案内部)。',
83
128
  listSpacingName: '列表上下边距',
@@ -94,6 +139,8 @@ const zh = {
94
139
  tableCellPaddingDesc: '表格单元格内的留白;左输入框为上下、右为左右。',
95
140
  lineHeightName: '回答行高',
96
141
  lineHeightDesc: '回答正文的行高(倍数)。',
142
+ thinkingLineHeightName: '思考行高',
143
+ thinkingLineHeightDesc: '「已工作/工作中」过程记录(读取/编辑/查阅/终端条目与思考内容)的行高(倍数)。',
97
144
  userLineHeightName: '提问行高',
98
145
  userLineHeightDesc: '提问内容的行高(倍数)。',
99
146
  contentWidthName: '内容宽度',
@@ -108,6 +155,30 @@ const zh = {
108
155
  featureSessionSwitchDesc: 'alt+z 在当前与上次会话间来回切换;按住 alt 再按 x/c 弹出最近会话列表前后选择,松开 alt 切换(类 alt+tab)。',
109
156
  featureTitleLock: '重命名会话名锁定',
110
157
  featureTitleLockDesc: '手动重命名过的会话不再被自动标题覆盖:会话有新回答后界面可能改显自动标题,重启后又变回,本功能让侧栏始终显示重命名后的名字。',
158
+ tabTitleGen: '任务名提示词',
159
+ titleGenShortDesc: '新会话开始作答时,按所选供应商与提示词生成任务名并按手动重命名保存,官方自动标题不再覆盖。',
160
+ titleGenEnabled: '启用',
161
+ titleGenProvider: '供应商',
162
+ titleGenProviderNone: '不跟随(自填地址)',
163
+ titleGenProviderSession: '跟随当前会话',
164
+ titleGenProviderDeleted: '(已删除)',
165
+ titleGenModel: '模型',
166
+ titleGenModelHint: '从列表选择,或直接填写模型 id',
167
+ titleGenModelEmpty: '(未选择)',
168
+ titleGenModelSessionHint: '从列表选择模型;列表第一项为跟随会话当前模型',
169
+ titleGenModelFollowSession: '跟随当前会话当前模型',
170
+ titleGenModelManualHint: '输入模型 id',
171
+ titleGenBaseUrl: '接口地址',
172
+ titleGenApiKey: 'API Key',
173
+ titleGenFormat: '协议',
174
+ titleGenPrompt: '提示词',
175
+ titleGenPromptPlaceholder: '留空使用内置默认提示词(点击下方按钮可查看)',
176
+ titleGenPromptReset: '使用默认提示词',
177
+ titleGenSample: '测试消息',
178
+ titleGenTest: '测试生成',
179
+ titleGenTesting: '生成中…',
180
+ titleGenTestOk: '生成结果:',
181
+ titleGenTestFailed: '生成失败',
111
182
  featureWsRunning: '折叠项目运行提示(实验性)',
112
183
  featureWsRunningDesc: '折叠的项目里仍有会话在运行时,项目图标旋转提示;全部结束或展开项目后恢复。期间每 60 秒在后台短暂展开该项目复核运行状态再收起,会话行不显示,仅项目位置可能有约四分之一秒的轻微高度起伏。',
113
184
  tabPerformance: '性能',
@@ -157,7 +228,7 @@ const zh = {
157
228
  featurePinnedExpand: '置顶会话保持项目折叠(实验性)',
158
229
  featurePinnedExpandDesc: '点击折叠项目的置顶会话后将其保持折叠。受限于应用机制,项目会先短暂展开再缩起。',
159
230
  featureAutoUpdatePlugins: '自动更新 zcode-plugins 插件',
160
- featureAutoUpdatePluginsDesc: '启动时自动检查并更新已装的 zcode-plugins 插件(含安装市场里新增的插件),更新在新会话生效。',
231
+ featureAutoUpdatePluginsDesc: '启动时自动检查并更新已安装的 zcode-plugins 插件(只升级不安装,卸载不会被撤销),更新在新会话生效。',
161
232
  pluginsUpdateTitle: '插件更新 · zcode-plugins',
162
233
  pluginsCheckNow: '检查并更新',
163
234
  pluginsUpdating: '正在更新插件…',
@@ -169,7 +240,7 @@ const zh = {
169
240
  pluginsAutoUpdated: 'zcode-plugins 插件已更新',
170
241
  tabVision: 'Vision',
171
242
  visionDesc: '主模型不支持图片输入时(如 glm-5.3),自动把消息里的图片交给下面的视觉模型识别,把描述带给主模型(zcode-vision 插件;/vision-* 命令编辑同一配置)。改动自动保存。',
172
- visionEnabled: '启用图片识别',
243
+ visionEnabled: '启用',
173
244
  visionForceIntercept: '主模型能看图也拦截',
174
245
  visionMode: '链模式',
175
246
  visionModeFallback: '依次尝试',
@@ -182,10 +253,6 @@ const zh = {
182
253
  visionMoveDown: '下移',
183
254
  visionName: '名称',
184
255
  visionUseProvider: '供应商',
185
- visionUseProviderHint: '下拉选择或手动输入:session=跟随当前会话供应商,或供应商名/ID;设置后 baseUrl/API Key/格式自动取该供应商',
186
- visionUseProviderNone: '不跟随(自填地址)',
187
- visionUseProviderSession: '跟随当前会话(session)',
188
- visionUseProviderUnknown: '未找到该供应商,识别时会报错;请从下拉选择,或输入 session',
189
256
  visionSkipAfterFailures: '连续失败次数',
190
257
  visionSkipAfterFailuresHint: '某代理连续失败满次数后暂时跳过它,直接试下一个;0 = 不跳过',
191
258
  visionSkipMinutes: '跳过分钟数',
@@ -194,21 +261,21 @@ const zh = {
194
261
  visionResetChainConfirm: '将链模式与代理列表恢复为默认两级(glm-session → glm-flash),当前对代理的修改会丢失。继续?',
195
262
  visionBaseUrl: '接口地址 baseUrl',
196
263
  visionModel: '模型',
197
- visionFormat: '格式',
198
264
  visionApiKey: 'API Key',
199
265
  visionApiKeyHint: '留空自动取 GLM 订阅 key',
200
266
  visionPrompt: '识别提示词(pipeline 后续步可用 {prev} 引用上一步)',
201
267
  visionTest: '测试',
202
268
  visionTesting: '测试中…',
203
269
  visionTestFailed: '视觉代理测试失败',
204
- visionTestOutput: '测试输出',
205
270
  visionCompressKB: '压缩阈值 KB',
206
271
  visionCompressKBHint: '超过该大小的图先压缩再识别(最长边 2000、JPEG);0 = 不压缩',
207
272
  visionLoadFailed: '读取视觉代理配置失败',
208
273
  tabRtk: 'rtk',
209
274
  rtkDesc: 'rtk 插件:把常见开发命令的输出压缩 60-90% 再进入上下文(/rtk-* 命令编辑同一配置)。改动自动保存并立即生效。',
210
- rtkEnabled: '启用 rtk 压缩',
211
- rtkNotInstalled: '未安装 rtk,以下配置将在安装后生效(会话里可用 /rtk-setup 安装)',
275
+ rtkEnabled: '启用',
276
+ rtkNotInstalled: '未安装 rtk 本体;安装后以下设置生效(会话里执行 /rtk-setup 也可以)',
277
+ rtkInstallBin: '安装 rtk 本体',
278
+ rtkBinInstalled: 'rtk 本体已安装;PATH 需注销重登后对会话生效,插件钩子即时生效',
212
279
  rtkWhitelistTitle: '白名单(不压缩直接放行)',
213
280
  rtkBuiltinLabel: '内置放行(只读,随插件更新):',
214
281
  rtkWhitelistDesc: '每条 name(如 docker)或 git:name(如 git:clone)。输出极小或纯副作用的命令无需压缩,加入后不再压缩;内置的 git add/commit/push、mkdir/cp 等不可移除。删除本文件即恢复默认。',
@@ -221,12 +288,25 @@ const zh = {
221
288
  tabHeadroom: 'Headroom',
222
289
  headroomDesc: 'Headroom 插件:本地压缩代理驻留 127.0.0.1(默认 8787 端口),压缩发往模型的上下文以省 token(/hr-* 命令编辑同一配置)。压缩设备与省电切换保存后立即生效;切换设备会重启代理,正在处理的请求可能中断一次。',
223
290
  headroomBinMissing: '未找到 headroom 程序,代理无法启动;安装 headroom 后以下设置自动生效',
291
+ hrInstallBin: '安装 headroom 本体',
292
+ hrBinInstalled: 'headroom 本体已安装;重新打开会话后代理可用(SessionStart 钩子自动拉起)',
224
293
  headroomInstallTitle: '未安装 headroom 插件',
225
294
  headroomInstallDesc: '从 zcode-plugins 市场安装后即可在此管理压缩代理;建议安装后重启会话生效。',
226
295
  headroomInstall: '安装',
227
296
  headroomInstalling: '安装中…',
228
297
  headroomInstalled: '已安装 headroom 插件',
229
298
  headroomInstallRetry: '安装未生效,请重试或手动在插件市场安装',
299
+ pluginInstallCardTitle: '未安装 {name} 插件',
300
+ pluginInstallCardDesc: '从 zcode-plugins 市场安装后即可在此管理;建议安装后重启会话生效。',
301
+ pluginInstallDone: '已安装 {name} 插件',
302
+ pluginEnable: '启用',
303
+ hrStarting: '正在启动压缩代理…',
304
+ hrStarted: '压缩代理已启动',
305
+ hrStartTimeout: '代理启动超时(90 秒),请检查 ~/.zcode-headroom-proxy.log',
306
+ hrStopping: '正在停止压缩代理…',
307
+ hrRestarting: '正在重启压缩代理…',
308
+ hrStopped: '压缩代理已停止',
309
+ hrUsageNone: '当前没有走 headroom 的供应商,未切换',
230
310
  headroomLoadFailed: '读取 Headroom 配置失败',
231
311
  headroomStatusTitle: '运行状态',
232
312
  headroomStatusLoadFailed: '读取运行状态失败',
@@ -252,7 +332,7 @@ const zh = {
252
332
  headroomRestart: '重启',
253
333
  headroomStopAction: '停止',
254
334
  headroomStopTitle: '停止 Headroom 代理',
255
- headroomStopDesc: '停止后,ZCode 中指向该代理(127.0.0.1)的供应商将无法连接,直至重新启动代理。确认停止?',
335
+ headroomStopDesc: '停止后,ZCode 及其他程序中指向该代理(127.0.0.1)的请求都会失败,直至重新启动代理。headroom 是共享的,其他工具可能正在使用。确认停止?',
256
336
  headroomStoppedWarn: '代理已停止;指向 127.0.0.1 的供应商将无法连接',
257
337
  headroomBackend: '压缩设备',
258
338
  headroomBackendAuto: '自动 · 显卡优先',
@@ -270,8 +350,6 @@ const zh = {
270
350
  headroomInterval: '监视间隔',
271
351
  headroomIntervalDesc: '省电监视器轮询电源状态的间隔(10–3600 秒,默认 60);保存后从下一轮巡检起生效,无需重启。',
272
352
  headroomSecUnit: '秒',
273
- headroomVersionPlugin: '插件',
274
- headroomVersionBin: '程序',
275
353
  upgradeCheck: '检查更新',
276
354
  upgradeChecking: '检查中…',
277
355
  upgradeUpToDate: '已是最新({v})',
@@ -283,7 +361,6 @@ const zh = {
283
361
  upgradeDone: '已更新到 {v}',
284
362
  upgradeFinished: '升级完成',
285
363
  upgradeCheckFailed: '检查更新失败',
286
- version: '版本',
287
364
  close: '关闭',
288
365
  cancel: '取消',
289
366
  pathLabel: '路径',
@@ -328,22 +405,31 @@ const en = {
328
405
  tabFeatures: 'Features',
329
406
  tabStyles: 'Styles',
330
407
  tabProxy: 'Proxy',
408
+ tabBehavior: 'Behavior',
331
409
  tabAgents: 'Global Prompt',
332
410
  agentsDesc: 'Written to ~/.zcode/AGENTS.md and used as default instructions in every session across all projects. Takes effect for new sessions; per-project AGENTS.md can extend or override it. Content over 100 KB is truncated by the app.',
333
411
  agentsPlaceholder: 'Instructions followed by all projects by default; save empty to remove the global prompt',
334
412
  agentsSave: 'Save',
335
413
  agentsSaved: 'Global prompt saved.',
336
414
  agentsLoadFailed: 'Failed to load the global prompt',
337
- proxyDesc: 'Set an HTTP proxy for network access made by the local helper: plugin marketplace updates and installs, headroom update checks and upgrades. Does not affect the ZCode app itself or model requests. Applies immediately.',
415
+ proxyDesc: 'Set an HTTP proxy for network access made by the local helper: plugin marketplace updates and installs, plugin dependency installs and upgrades, and WebDAV sync can all use it — pick the scopes with the toggles below. Does not affect the ZCode app itself or model requests. Applies immediately.',
338
416
  proxyPlaceholder: 'http://127.0.0.1:7890',
339
417
  proxySave: 'Save',
340
418
  proxySaved: 'Proxy settings saved.',
341
419
  proxyHint: 'Save empty to clear the proxy.',
342
420
  proxyTest: 'Test',
343
421
  proxyTesting: 'Testing…',
422
+ proxyTestEmpty: 'Enter a proxy address first',
344
423
  proxyTestFailed: 'Test failed',
424
+ proxyScopePlugins: 'Plugin marketplace',
425
+ proxyScopePluginsDesc: 'Marketplace checks, installs and uninstalls (zcode CLI git operations) go through the proxy.',
426
+ proxyScopeDeps: 'Plugin dependencies',
427
+ proxyScopeDepsDesc: 'headroom and rtk installs, update checks and upgrades (pip and GitHub downloads) go through the proxy.',
428
+ proxyScopeSync: 'Sync',
429
+ proxyScopeSyncDesc: 'WebDAV upload and download go through the proxy. Off by default: domestic WebDAV providers work fine direct, and a stopped proxy breaks sync.',
345
430
  tabSync: 'Sync',
346
- syncDesc: 'Manually back up ZCode Pro settings and model settings to WebDAV, or restore them on a new computer. The two items are stored as separate files, so you can upload or overwrite either one alone; data moves only when you click, never automatically.',
431
+ tabDebug: 'Debug',
432
+ syncDesc: 'Manually back up ZCode Pro settings and model settings to WebDAV, or restore them on a new computer. The two items are stored as separate files, so you can upload or overwrite either one alone; every upload also keeps a timestamped history version and download lets you pick any of them. Data moves only when you click, never automatically.',
347
433
  syncUrlPlaceholder: 'https://dav.example.com/dav/',
348
434
  syncDir: '上传目录',
349
435
  syncDirPlaceholder: 'zcode-pro',
@@ -351,7 +437,7 @@ const en = {
351
437
  syncPassword: 'Password',
352
438
  syncSave: 'Save',
353
439
  syncSaved: 'Sync settings saved.',
354
- syncFormHint: 'Sync files go to zcodepro.json and model.json inside the folder (default zcode-pro, multi-level allowed, created automatically).',
440
+ syncFormHint: 'Sync files go inside the folder (default zcode-pro, multi-level allowed, created automatically): zcodepro.json and model.json are always the latest version; timestamped history versions are kept alongside.',
355
441
  syncRecLink: 'Jianguoyun WebDAV',
356
442
  syncRecSuffix: ' — use the app password, not your account password.',
357
443
  syncIncludeZcp: 'ZCode Pro settings',
@@ -361,16 +447,44 @@ const en = {
361
447
  syncUpload: 'Upload',
362
448
  syncDownload: 'Download',
363
449
  syncUploading: 'Uploading…',
364
- syncDownloading: 'Downloading…',
365
450
  syncUploaded: 'Uploaded to the server.',
366
451
  syncDownloaded: 'Restored from the server.',
367
452
  syncLastPush: 'Last upload',
368
453
  syncLastPull: 'Last download',
369
454
  syncNever: 'never',
370
455
  syncConfirmTitle: 'Download from the server',
371
- syncConfirmDesc: 'Cloud data will overwrite the selected sections locally (a .zcodepro-backup copy is kept next to each file); your local sync config and credentials stay untouched. Restarting ZCode is recommended after restoring model settings. Download now?',
372
- syncConfirmGo: 'Download',
456
+ syncConfirmDesc: 'The selected file will overwrite the matching local section (a .zcodepro-backup copy is kept next to each file); your local sync config and credentials stay untouched. Restarting ZCode is recommended after restoring model settings. Import now?',
457
+ syncConfirmGo: 'Import',
458
+ syncPickDesc: 'Fixed names are always the latest version; timestamped files are the history each upload leaves behind. Import overwrites the matching local section.',
459
+ syncVerDeleteLatestNote: 'Note: this is the "latest" file that older zcode-pro installs download from; deleting it breaks their download. Timestamped history versions are not affected.',
373
460
  syncHint: 'Sync credentials are stored locally in zcodepro.json only; model settings contain the API keys of custom providers and go to your own WebDAV only.',
461
+ syncTest: 'Test',
462
+ syncTesting: 'Testing…',
463
+ syncTestEmpty: 'Enter the WebDAV URL first',
464
+ syncTestFailed: 'Test failed',
465
+ syncTestStepConnect: 'Connect',
466
+ syncTestStepDir: 'Folder',
467
+ syncTestStepList: 'Files',
468
+ syncTestFilesFound: '{n} backup file(s) on the server',
469
+ syncPickTitle: 'Select a file',
470
+ syncPickLoading: 'Loading files from the server…',
471
+ syncPickEmpty: 'No backups on the server yet. Upload from a computer first.',
472
+ syncVerImport: 'Import',
473
+ syncVerImporting: 'Importing…',
474
+ syncVerDelete: 'Delete',
475
+ syncVerSave: 'Save to disk',
476
+ syncVerSaving: 'Saving…',
477
+ syncVerLatest: 'Latest',
478
+ syncVerDeleteTitle: 'Delete server file',
479
+ syncVerDeleteDesc: 'This backup will be deleted from the server and cannot be recovered: ',
480
+ syncVerDeleted: 'Backup deleted from the server.',
481
+ syncVerSaved: 'Saved to',
482
+ devMode: 'Developer mode',
483
+ devModeRowDesc: 'Shows the "Reload ZCode Pro" button; can also be enabled with the ZCODEPRO_DEV=1 environment variable. This tab is visible only while developer mode is active.',
484
+ devModeDesc: 'For development: after changing zcode-pro code, click "Reload ZCode Pro" instead of restarting ZCode. It builds automatically (when running from the source repo), restarts the ZCode Pro launcher process (fresh helper and injected script), and every ZCode window refreshes and re-injects. The ZCode app itself and all sessions stay untouched.',
485
+ devReload: 'Reload ZCode Pro',
486
+ devReloading: 'Reloading…',
487
+ devReloadDesc: 'Every ZCode window refreshes automatically within 2-3 seconds to load the new script.',
374
488
  rowGapName: 'Paragraph spacing',
375
489
  rowGapDesc: 'Vertical spacing between text blocks (turns, paragraphs inside answers).',
376
490
  listSpacingName: 'List spacing',
@@ -387,6 +501,8 @@ const en = {
387
501
  tableCellPaddingDesc: 'Padding inside table cells; left input is vertical, right is horizontal.',
388
502
  lineHeightName: 'Answer line height',
389
503
  lineHeightDesc: 'Line height of answer text (multiplier).',
504
+ thinkingLineHeightName: 'Work-log line height',
505
+ thinkingLineHeightDesc: 'Line height of the “worked for…” history panel (tool entries and reasoning, multiplier).',
390
506
  userLineHeightName: 'Question line height',
391
507
  userLineHeightDesc: 'Line height of question text (multiplier).',
392
508
  contentWidthName: 'Content width',
@@ -401,6 +517,30 @@ const en = {
401
517
  featureSessionSwitchDesc: 'alt+z toggles between the current and the last session; hold alt and press x/c to move the highlight across recently used sessions, release alt to switch (like alt+tab).',
402
518
  featureTitleLock: 'Keep renamed session titles',
403
519
  featureTitleLockDesc: 'Sessions you renamed keep their custom title: after new replies the app may show an auto-generated title instead, which reverts after a restart; this keeps the renamed title in the sidebar.',
520
+ tabTitleGen: 'Task name prompt',
521
+ titleGenShortDesc: 'When a new session starts answering, generates the task name with the chosen provider and prompt and saves it as a manual rename the built-in title never overrides.',
522
+ titleGenEnabled: 'Enable',
523
+ titleGenProvider: 'Provider',
524
+ titleGenProviderNone: 'Custom endpoint (no provider)',
525
+ titleGenProviderSession: 'Follow current session',
526
+ titleGenProviderDeleted: ' (deleted)',
527
+ titleGenModel: 'Model',
528
+ titleGenModelHint: 'Pick from the list, or type a model id',
529
+ titleGenModelEmpty: '(not set)',
530
+ titleGenModelSessionHint: 'Pick from the list; the first entry follows the session model',
531
+ titleGenModelFollowSession: 'Follow the session model',
532
+ titleGenModelManualHint: 'Type a model id',
533
+ titleGenBaseUrl: 'Base URL',
534
+ titleGenApiKey: 'API Key',
535
+ titleGenFormat: 'Protocol',
536
+ titleGenPrompt: 'Prompt',
537
+ titleGenPromptPlaceholder: 'Leave empty for the built-in default prompt (button below shows it)',
538
+ titleGenPromptReset: 'Use default prompt',
539
+ titleGenSample: 'Test message',
540
+ titleGenTest: 'Test',
541
+ titleGenTesting: 'Generating…',
542
+ titleGenTestOk: 'Result: ',
543
+ titleGenTestFailed: 'Generation failed',
404
544
  featureWsRunning: 'Running indicator on collapsed projects (experimental)',
405
545
  featureWsRunningDesc: 'Spins a collapsed project\'s icon while any of its sessions is still running; stops when they all finish or the project is expanded. While spinning, the project is briefly re-expanded in the background every 60 s to re-check and then collapsed — rows stay hidden, with only a subtle quarter-second height ripple at the project.',
406
546
  tabPerformance: 'Performance',
@@ -450,7 +590,7 @@ const en = {
450
590
  featurePinnedExpand: 'Keep projects collapsed for pinned sessions (experimental)',
451
591
  featurePinnedExpandDesc: 'Keeps the project collapsed after clicking a pinned session. Note: it briefly expands first, then collapses.',
452
592
  featureAutoUpdatePlugins: 'Auto-update zcode-plugins plugins',
453
- featureAutoUpdatePluginsDesc: 'Checks and updates installed zcode-plugins plugins on startup (including newly added ones). Updates apply to new sessions.',
593
+ featureAutoUpdatePluginsDesc: 'Checks and updates installed zcode-plugins plugins on startup (updates only — never installs; uninstalled plugins stay uninstalled). Updates apply to new sessions.',
454
594
  pluginsUpdateTitle: 'Plugin updates · zcode-plugins',
455
595
  pluginsCheckNow: 'Check & update',
456
596
  pluginsUpdating: 'Updating plugins…',
@@ -462,7 +602,7 @@ const en = {
462
602
  pluginsAutoUpdated: 'zcode-plugins updated',
463
603
  tabVision: 'Vision',
464
604
  visionDesc: 'When the main model cannot see images (e.g. glm-5.3), images in messages are recognized by the vision models below and passed to the main model as text (zcode-vision plugin; /vision-* commands edit the same file). Changes save automatically.',
465
- visionEnabled: 'Enable image recognition',
605
+ visionEnabled: 'Enable',
466
606
  visionForceIntercept: 'Intercept even if the main model sees images',
467
607
  visionMode: 'Chain mode',
468
608
  visionModeFallback: 'Fallback',
@@ -475,10 +615,6 @@ const en = {
475
615
  visionMoveDown: 'Down',
476
616
  visionName: 'Name',
477
617
  visionUseProvider: 'Provider',
478
- visionUseProviderHint: 'Pick from the list or type: session = follow the current session provider, or a provider name/ID; baseUrl/API key/format follow that provider',
479
- visionUseProviderNone: 'Not following (enter base URL)',
480
- visionUseProviderSession: 'Follow session provider (session)',
481
- visionUseProviderUnknown: 'Unknown provider; recognition will fail. Pick from the list or type session',
482
618
  visionSkipAfterFailures: 'Skip after failures',
483
619
  visionSkipAfterFailuresHint: 'After this many consecutive failures a proxy is skipped and the next one is tried; 0 = never skip',
484
620
  visionSkipMinutes: 'Skip minutes',
@@ -487,21 +623,21 @@ const en = {
487
623
  visionResetChainConfirm: 'Reset chain mode and the proxy list to the default 2-level chain (glm-session → glm-flash)? Current proxy edits will be lost. Continue?',
488
624
  visionBaseUrl: 'Base URL',
489
625
  visionModel: 'Model',
490
- visionFormat: 'Format',
491
626
  visionApiKey: 'API Key',
492
627
  visionApiKeyHint: 'Leave empty to reuse the GLM subscription key',
493
628
  visionPrompt: 'Recognition prompt ({prev} = previous step in pipeline)',
494
629
  visionTest: 'Test',
495
630
  visionTesting: 'Testing…',
496
631
  visionTestFailed: 'Vision proxy test failed',
497
- visionTestOutput: 'Test output',
498
632
  visionCompressKB: 'Compress threshold KB',
499
633
  visionCompressKBHint: 'Images above this size are compressed first (max edge 2000, JPEG); 0 = never',
500
634
  visionLoadFailed: 'Failed to load the vision config',
501
635
  tabRtk: 'rtk',
502
636
  rtkDesc: 'rtk plugin: compresses common dev command output by 60-90% before it reaches the context (/rtk-* commands edit the same files). Changes save automatically and apply immediately.',
503
- rtkEnabled: 'Enable rtk compression',
637
+ rtkEnabled: 'Enable',
504
638
  rtkNotInstalled: 'rtk is not installed. The settings below take effect after installation (/rtk-setup in a session).',
639
+ rtkInstallBin: 'Install rtk binary',
640
+ rtkBinInstalled: 'rtk installed; PATH takes effect for sessions after signing out and back in — the plugin hook works immediately',
505
641
  rtkWhitelistTitle: 'Whitelist (pass through without compression)',
506
642
  rtkBuiltinLabel: 'Built-in exemptions (read-only, follow plugin updates):',
507
643
  rtkWhitelistDesc: 'Each entry is name (e.g. docker) or git:name (e.g. git:clone). Commands with tiny or no output need no compression; adding them skips compression. Built-ins (git add/commit/push, mkdir/cp, …) cannot be removed. Delete the file to reset.',
@@ -514,12 +650,25 @@ const en = {
514
650
  tabHeadroom: 'Headroom',
515
651
  headroomDesc: 'Headroom plugin: a local compression proxy on 127.0.0.1 (port 8787 by default) that compresses context sent to the model to save tokens (/hr-* commands edit the same file). Device and power-save changes apply immediately; switching the device restarts the proxy, so requests in progress may be interrupted once.',
516
652
  headroomBinMissing: 'The headroom program was not found, so the proxy cannot start. The settings below take effect once it is installed.',
653
+ hrInstallBin: 'Install headroom binary',
654
+ hrBinInstalled: 'headroom installed; reopen a session and the hook will start the proxy automatically',
517
655
  headroomInstallTitle: 'headroom plugin not installed',
518
656
  headroomInstallDesc: 'Install it from the zcode-plugins marketplace to manage the compression proxy here; restarting the session afterwards is recommended.',
519
657
  headroomInstall: 'Install',
520
658
  headroomInstalling: 'Installing…',
521
659
  headroomInstalled: 'headroom plugin installed',
522
660
  headroomInstallRetry: 'Installation did not take effect; retry or install it from the marketplace manually',
661
+ pluginInstallCardTitle: '{name} plugin not installed',
662
+ pluginInstallCardDesc: 'Install it from the zcode-plugins marketplace to manage it here; restarting the session afterwards is recommended.',
663
+ pluginInstallDone: '{name} plugin installed',
664
+ pluginEnable: 'Enable',
665
+ hrStarting: 'Starting compression proxy…',
666
+ hrStarted: 'Compression proxy started',
667
+ hrStartTimeout: 'Proxy start timed out (90s); check ~/.zcode-headroom-proxy.log',
668
+ hrStopping: 'Stopping compression proxy…',
669
+ hrRestarting: 'Restarting compression proxy…',
670
+ hrStopped: 'Compression proxy stopped',
671
+ hrUsageNone: 'No providers route through headroom; nothing changed',
523
672
  headroomLoadFailed: 'Failed to load the Headroom config',
524
673
  headroomStatusTitle: 'Status',
525
674
  headroomStatusLoadFailed: 'Failed to load the status',
@@ -545,7 +694,7 @@ const en = {
545
694
  headroomRestart: 'Restart',
546
695
  headroomStopAction: 'Stop',
547
696
  headroomStopTitle: 'Stop the Headroom proxy',
548
- headroomStopDesc: 'Providers in ZCode that point at this proxy (127.0.0.1) will fail to connect until it is started again. Stop it?',
697
+ headroomStopDesc: 'Requests from ZCode and other apps pointing at this proxy (127.0.0.1) will fail until it is started again. headroom is shared — other tools may be using it. Stop it?',
549
698
  headroomStoppedWarn: 'Proxy stopped; providers pointing at 127.0.0.1 cannot connect.',
550
699
  headroomBackend: 'Compression device',
551
700
  headroomBackendAuto: 'Auto · GPU first',
@@ -563,8 +712,6 @@ const en = {
563
712
  headroomInterval: 'Watch interval',
564
713
  headroomIntervalDesc: 'Seconds between power checks (10–3600, default 60); applies from the next round, no restart needed.',
565
714
  headroomSecUnit: 's',
566
- headroomVersionPlugin: 'plugin',
567
- headroomVersionBin: 'program',
568
715
  upgradeCheck: 'Check update',
569
716
  upgradeChecking: 'Checking…',
570
717
  upgradeUpToDate: 'Up to date ({v})',
@@ -576,7 +723,6 @@ const en = {
576
723
  upgradeDone: 'Updated to {v}',
577
724
  upgradeFinished: 'Update finished',
578
725
  upgradeCheckFailed: 'Update check failed',
579
- version: 'Version',
580
726
  close: 'Close',
581
727
  cancel: 'Cancel',
582
728
  pathLabel: 'Path',
@@ -695,6 +841,8 @@ const errEn = {
695
841
  'sync-remote-invalid': 'The URL already holds a different file; use another file path',
696
842
  'sync-request': 'The WebDAV request failed',
697
843
  'sync-run': 'Sync failed',
844
+ 'sync-file-invalid': 'Invalid backup file name',
845
+ 'sync-export': 'Failed to save the backup to disk',
698
846
  };
699
847
 
700
848
  export function errText(res) {
@@ -8,6 +8,7 @@
8
8
  // 触发器/菜单的 React fiber props(OpenSplitButton 场景 target/fileLink/row.path)。
9
9
  import { t, closeRadixMenu, itemsOf, itemText, rpc } from '../core.js';
10
10
  import { getConfig } from '../core.js';
11
+ import { showToast } from '../ui.js';
11
12
 
12
13
  const COPY_ABS_TEXTS = ['复制绝对路径', 'Copy absolute path'];
13
14
  const NO_APPS_TEXTS = ['未找到可用 App', 'No apps found'];
@@ -126,6 +127,12 @@ export function handleFileMenu(content) {
126
127
  const path = resolveTargetPath(content);
127
128
  if (!path) return;
128
129
  const L = t();
130
+ // 打开失败(路径不存在等)弹 toast 报错,不再无声无息
131
+ const fire = (endpoint, label) => {
132
+ rpc(endpoint, { method: 'POST', body: { path } })
133
+ .then((r) => { if (r && r.ok === false) showToast(`${label}失败:${r.error || '未知错误'}`, 'error'); })
134
+ .catch(() => { /* 网络异常时 helper 多半未运行,此时菜单不会注入,静默 */ });
135
+ };
129
136
  // “默认应用打开”锚在编辑器列表末尾(无可用编辑器时即“未找到可用 App”禁用项)之上;
130
137
  // 找不到该组时退而锚在“复制绝对路径”上,保持“打开方式在前、路径操作在后”的次序
131
138
  const noApps = items.find((el) => NO_APPS_TEXTS.some((x) => itemText(el) === x))
@@ -135,13 +142,13 @@ export function handleFileMenu(content) {
135
142
  marker: 'file-open-default',
136
143
  label: L.fileOpenDefault,
137
144
  icon: ICON_OPEN_DEFAULT,
138
- onPick: () => { try { void rpc('/open-path', { method: 'POST', body: { path } }); } catch { /* ignore */ } },
145
+ onPick: () => { void fire('/open-path', L.fileOpenDefault); },
139
146
  });
140
147
  appendMenuItem(content, copyAbs, copyAbs, {
141
148
  marker: 'file-reveal',
142
149
  label: L.fileReveal,
143
150
  icon: ICON_REVEAL,
144
- onPick: () => { try { void rpc('/reveal-path', { method: 'POST', body: { path } }); } catch { /* ignore */ } },
151
+ onPick: () => { void fire('/reveal-path', L.fileReveal); },
145
152
  });
146
153
  })();
147
154
  }
@@ -14,7 +14,7 @@ export async function startPluginUpdateCheck() {
14
14
 
15
15
  const config = await getConfig();
16
16
  if ((config.features || {}).autoUpdatePlugins === true) {
17
- const res = await rpc('/plugins/update', { method: 'POST', body: { installMissing: true } });
17
+ const res = await rpc('/plugins/update', { method: 'POST', body: {} });
18
18
  if (res.ok) showToast(L.pluginsAutoUpdated, 'success');
19
19
  else showToast(L.pluginsUpdateFailed + ': ' + (res.error || ''), 'error');
20
20
  return;