zcode-pro 0.19.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/inject.js CHANGED
@@ -59,12 +59,17 @@
59
59
  proxyScopeSyncDesc: "WebDAV \u4E0A\u4F20\u4E0E\u4E0B\u8F7D\u8D70\u4EE3\u7406\u3002\u9ED8\u8BA4\u5173\u95ED\uFF1A\u575A\u679C\u4E91\u7B49\u56FD\u5185\u7F51\u76D8\u76F4\u8FDE\u5373\u53EF\uFF0C\u4EE3\u7406\u505C\u4E86\u540C\u6B65\u4F1A\u8DDF\u7740\u5931\u8D25\u3002",
60
60
  tabSync: "\u540C\u6B65",
61
61
  tabDebug: "\u8C03\u8BD5",
62
- syncDesc: "\u624B\u52A8\u628A ZCode Pro \u8BBE\u7F6E\u4E0E\u6A21\u578B\u8BBE\u7F6E\u5907\u4EFD\u5230 WebDAV\uFF0C\u6216\u5728\u65B0\u7535\u8111\u4E0A\u6062\u590D\u3002\u4E24\u9879\u5404\u81EA\u72EC\u7ACB\u6210\u6587\u4EF6\uFF0C\u53EF\u53EA\u4E0A\u4F20\u6216\u53EA\u8986\u76D6\u5176\u4E2D\u4E00\u9879\uFF1B\u6BCF\u6B21\u4E0A\u4F20\u4F1A\u989D\u5916\u4FDD\u7559\u4E00\u4EFD\u5E26\u65F6\u95F4\u6233\u7684\u5386\u53F2\u7248\u672C\uFF0C\u4E0B\u8F7D\u65F6\u4EFB\u9009\u4E00\u4E2A\u7248\u672C\u6062\u590D\uFF1B\u4EC5\u5728\u70B9\u51FB\u6309\u94AE\u65F6\u4F20\u8F93\uFF0C\u4E0D\u505A\u81EA\u52A8\u540C\u6B65\u3002",
62
+ testNoSessionHint: "\u9009\u62E9\u201C\u8DDF\u968F\u5F53\u524D\u4F1A\u8BDD[\u5F53\u524D\u6A21\u578B]\u201D\u65F6\uFF0C\u9009\u62E9\u4E0A\u6B21\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u7684\u4F9B\u5E94\u5546[\u6A21\u578B]",
63
+ syncDesc: "\u624B\u52A8\u628A ZCode Pro \u8BBE\u7F6E\u4E0E\u6A21\u578B\u8BBE\u7F6E\u5907\u4EFD\u5230 WebDAV\uFF0C\u6216\u5728\u65B0\u7535\u8111\u4E0A\u6062\u590D\u3002\u4E24\u9879\u5404\u81EA\u72EC\u7ACB\u6210\u6587\u4EF6\uFF0C\u53EF\u53EA\u4E0A\u4F20\u6216\u53EA\u8986\u76D6\u5176\u4E2D\u4E00\u9879\uFF1B\u6BCF\u6B21\u4E0A\u4F20\u4F1A\u989D\u5916\u4FDD\u7559\u4E00\u4EFD\u5E26\u65F6\u95F4\u6233\u7684\u5386\u53F2\u7248\u672C\uFF08\u4FDD\u7559\u591A\u5C11\u4E2A\u89C1\u201C\u5386\u53F2\u7248\u672C\u201D\u4E00\u884C\uFF0C\u4E0A\u4F20\u540E\u81EA\u52A8\u5220\u9664\u8D85\u51FA\u7684\u6700\u65E7\u7248\u672C\uFF09\uFF0C\u4E0B\u8F7D\u65F6\u4EFB\u9009\u4E00\u4E2A\u7248\u672C\u6062\u590D\uFF1B\u4EC5\u5728\u70B9\u51FB\u6309\u94AE\u65F6\u4F20\u8F93\uFF0C\u4E0D\u505A\u81EA\u52A8\u540C\u6B65\u3002",
63
64
  syncUrlPlaceholder: "https://dav.jianguoyun.com/dav/",
64
65
  syncDir: "\u4E0A\u4F20\u76EE\u5F55",
65
66
  syncDirPlaceholder: "zcode-pro",
66
67
  syncLogin: "\u767B\u5F55",
67
68
  syncPassword: "\u5BC6\u7801",
69
+ syncHistoryLimit: "\u5386\u53F2\u7248\u672C",
70
+ syncHistoryLimitUnit: "\u4E2A",
71
+ syncHistoryLimitHint: "\u4E91\u7AEF\u6700\u591A\u4FDD\u7559\u6700\u8FD1\u51E0\u6B21\u4E0A\u4F20\u7559\u4E0B\u7684\u5386\u53F2\u7248\u672C\uFF0C\u4E0A\u4F20\u6210\u529F\u540E\u81EA\u52A8\u5220\u9664\u66F4\u65E9\u7684\uFF1B\u56FA\u5B9A\u540D\u6700\u65B0\u7248\u4E0D\u53D7\u5F71\u54CD\uFF1B0 = \u4E0D\u4FDD\u7559\u5386\u53F2\u7248\u672C",
72
+ syncPruned: "\u5DF2\u6E05\u7406 {n} \u4E2A\u66F4\u65E9\u7684\u5386\u53F2\u7248\u672C",
68
73
  syncSave: "\u4FDD\u5B58",
69
74
  syncSaved: "\u540C\u6B65\u914D\u7F6E\u5DF2\u4FDD\u5B58",
70
75
  syncFormHint: "\u540C\u6B65\u6587\u4EF6\u5B58\u5230\u201C\u4E0A\u4F20\u76EE\u5F55\u201D\uFF08\u9ED8\u8BA4 zcode-pro\uFF0C\u53EF\u591A\u7EA7\uFF0C\u81EA\u52A8\u521B\u5EFA\uFF09\uFF1Azcodepro.json \u4E0E model.json \u59CB\u7EC8\u662F\u6700\u65B0\u4E00\u7248\uFF0C\u65C1\u8FB9\u53E6\u4FDD\u7559\u5E26\u65F6\u95F4\u6233\u7684\u5386\u53F2\u7248\u672C\u3002",
@@ -85,8 +90,8 @@
85
90
  syncConfirmTitle: "\u4ECE\u4E91\u7AEF\u4E0B\u8F7D",
86
91
  syncConfirmDesc: "\u5C06\u7528\u6240\u9009\u6587\u4EF6\u8986\u76D6\u672C\u673A\u5BF9\u5E94\u7684\u4E00\u9879\uFF08\u8986\u76D6\u524D\u4F1A\u5728\u539F\u6587\u4EF6\u65C1\u7559\u4E0B .zcodepro-backup \u5907\u4EFD\uFF09\uFF1B\u672C\u673A\u7684\u540C\u6B65\u914D\u7F6E\u4E0E\u767B\u5F55\u51ED\u636E\u4E0D\u53D7\u5F71\u54CD\u3002\u6A21\u578B\u8BBE\u7F6E\u6062\u590D\u540E\u5EFA\u8BAE\u91CD\u542F ZCode \u751F\u6548\u3002\u786E\u8BA4\u5BFC\u5165\uFF1F",
87
92
  syncConfirmGo: "\u786E\u8BA4\u5BFC\u5165",
88
- syncPickDesc: "\u56FA\u5B9A\u540D\u6587\u4EF6\u59CB\u7EC8\u662F\u6700\u65B0\u4E00\u7248\uFF0C\u5E26\u65F6\u95F4\u6233\u7684\u662F\u6BCF\u6B21\u4E0A\u4F20\u7559\u4E0B\u7684\u5386\u53F2\u7248\u672C\uFF1B\u300C\u5BFC\u5165\u300D\u7528\u6240\u9009\u6587\u4EF6\u8986\u76D6\u672C\u673A\u5BF9\u5E94\u7684\u4E00\u9879\u3002",
89
- syncVerDeleteLatestNote: "\u6CE8\u610F\uFF1A\u8FD9\u662F\u201C\u6700\u65B0\u201D\u6587\u4EF6\uFF0C\u65E7\u7248 zcode-pro \u7684\u300C\u4ECE\u4E91\u7AEF\u4E0B\u8F7D\u300D\u4F9D\u8D56\u5B83\uFF0C\u5220\u9664\u540E\u65E7\u7248\u673A\u5668\u5C06\u65E0\u6CD5\u4E0B\u8F7D\uFF1B\u5E26\u65F6\u95F4\u6233\u7684\u5386\u53F2\u7248\u672C\u4E0D\u53D7\u5F71\u54CD\u3002",
93
+ syncPickDesc: "\u56FA\u5B9A\u540D\u6587\u4EF6\u59CB\u7EC8\u662F\u6700\u65B0\u4E00\u7248\uFF0C\u5E26\u65F6\u95F4\u6233\u7684\u662F\u6BCF\u6B21\u4E0A\u4F20\u7559\u4E0B\u7684\u5386\u53F2\u7248\u672C\uFF1B\u201C\u5BFC\u5165\u201D\u7528\u6240\u9009\u6587\u4EF6\u8986\u76D6\u672C\u673A\u5BF9\u5E94\u7684\u4E00\u9879\u3002",
94
+ syncVerDeleteLatestNote: "\u6CE8\u610F\uFF1A\u8FD9\u662F\u201C\u6700\u65B0\u201D\u6587\u4EF6\uFF0C\u65E7\u7248 zcode-pro \u7684\u201C\u4ECE\u4E91\u7AEF\u4E0B\u8F7D\u201D\u4F9D\u8D56\u5B83\uFF0C\u5220\u9664\u540E\u65E7\u7248\u673A\u5668\u5C06\u65E0\u6CD5\u4E0B\u8F7D\uFF1B\u5E26\u65F6\u95F4\u6233\u7684\u5386\u53F2\u7248\u672C\u4E0D\u53D7\u5F71\u54CD\u3002",
90
95
  syncHint: "\u540C\u6B65\u767B\u5F55\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A zcodepro.json\uFF1B\u6A21\u578B\u8BBE\u7F6E\u5305\u542B\u81EA\u5B9A\u4E49\u4F9B\u5E94\u5546\u7684 API Key\uFF0C\u53EA\u4F1A\u4E0A\u4F20\u5230\u4F60\u81EA\u5DF1\u7684 WebDAV\u3002",
91
96
  syncTest: "\u6D4B\u8BD5",
92
97
  syncTesting: "\u6D4B\u8BD5\u4E2D\u2026",
@@ -110,8 +115,8 @@
110
115
  syncVerDeleted: "\u5DF2\u5220\u9664\u4E91\u7AEF\u5907\u4EFD",
111
116
  syncVerSaved: "\u5DF2\u4FDD\u5B58\u5230",
112
117
  devMode: "\u5F00\u53D1\u6A21\u5F0F",
113
- devModeRowDesc: "\u5F00\u542F\u540E\u51FA\u73B0\u300C\u91CD\u8F7D ZCode Pro\u300D\u6309\u94AE\uFF1B\u4E5F\u53EF\u7ED9\u542F\u52A8\u5668\u8BBE\u73AF\u5883\u53D8\u91CF ZCODEPRO_DEV=1 \u542F\u7528\u3002\u6B64\u6807\u7B7E\u9875\u4EC5\u5728\u5F00\u53D1\u6A21\u5F0F\u751F\u6548\u65F6\u663E\u793A\u3002",
114
- devModeDesc: "\u5F00\u53D1\u8C03\u8BD5\u7528\uFF1A\u6539\u5B8C zcode-pro \u4EE3\u7801\u540E\u4E0D\u5FC5\u91CD\u542F ZCode\uFF0C\u70B9\u300C\u91CD\u8F7D ZCode Pro\u300D\u5373\u53EF\u52A0\u8F7D\u65B0\u4EE3\u7801\u3002\u6D41\u7A0B\u4E3A\u81EA\u52A8\u6784\u5EFA\uFF08\u9700\u5728\u6E90\u7801\u76EE\u5F55\u8FD0\u884C\uFF09\u2192 \u4EE5\u65B0\u8FDB\u7A0B\u91CD\u542F ZCode Pro\uFF08\u672C\u5730\u52A9\u624B\u4E0E\u6CE8\u5165\u811A\u672C\u90FD\u6362\u65B0\uFF09\u2192 \u6240\u6709 ZCode \u7A97\u53E3\u81EA\u52A8\u5237\u65B0\u5E76\u91CD\u65B0\u6CE8\u5165\uFF1BZCode \u672C\u4F53\u4E0E\u5DF2\u6253\u5F00\u7684\u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\u3002",
118
+ devModeRowDesc: "\u5F00\u542F\u540E\u51FA\u73B0\u201C\u91CD\u8F7D ZCode Pro\u201D\u6309\u94AE\uFF1B\u4E5F\u53EF\u7ED9\u542F\u52A8\u5668\u8BBE\u73AF\u5883\u53D8\u91CF ZCODEPRO_DEV=1 \u542F\u7528\u3002\u6B64\u6807\u7B7E\u9875\u4EC5\u5728\u5F00\u53D1\u6A21\u5F0F\u751F\u6548\u65F6\u663E\u793A\u3002",
119
+ devModeDesc: "\u5F00\u53D1\u8C03\u8BD5\u7528\uFF1A\u6539\u5B8C zcode-pro \u4EE3\u7801\u540E\u4E0D\u5FC5\u91CD\u542F ZCode\uFF0C\u70B9\u201C\u91CD\u8F7D ZCode Pro\u201D\u5373\u53EF\u52A0\u8F7D\u65B0\u4EE3\u7801\u3002\u6D41\u7A0B\u4E3A\u81EA\u52A8\u6784\u5EFA\uFF08\u9700\u5728\u6E90\u7801\u76EE\u5F55\u8FD0\u884C\uFF09\u2192 \u4EE5\u65B0\u8FDB\u7A0B\u91CD\u542F ZCode Pro\uFF08\u672C\u5730\u52A9\u624B\u4E0E\u6CE8\u5165\u811A\u672C\u90FD\u6362\u65B0\uFF09\u2192 \u6240\u6709 ZCode \u7A97\u53E3\u81EA\u52A8\u5237\u65B0\u5E76\u91CD\u65B0\u6CE8\u5165\uFF1BZCode \u672C\u4F53\u4E0E\u5DF2\u6253\u5F00\u7684\u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\u3002",
115
120
  devReload: "\u91CD\u8F7D ZCode Pro",
116
121
  devReloading: "\u91CD\u8F7D\u4E2D\u2026",
117
122
  devReloadDesc: "\u70B9\u51FB\u540E\u7EA6 2-3 \u79D2\u5185\u6240\u6709 ZCode \u7A97\u53E3\u81EA\u52A8\u5237\u65B0\u4E00\u6B21\u5E76\u52A0\u8F7D\u65B0\u811A\u672C\u3002",
@@ -132,7 +137,7 @@
132
137
  lineHeightName: "\u56DE\u7B54\u884C\u9AD8",
133
138
  lineHeightDesc: "\u56DE\u7B54\u6B63\u6587\u7684\u884C\u9AD8\uFF08\u500D\u6570\uFF09\u3002",
134
139
  thinkingLineHeightName: "\u601D\u8003\u884C\u9AD8",
135
- thinkingLineHeightDesc: "\u300C\u5DF2\u5DE5\u4F5C/\u5DE5\u4F5C\u4E2D\u300D\u8FC7\u7A0B\u8BB0\u5F55\uFF08\u8BFB\u53D6/\u7F16\u8F91/\u67E5\u9605/\u7EC8\u7AEF\u6761\u76EE\u4E0E\u601D\u8003\u5185\u5BB9\uFF09\u7684\u884C\u9AD8\uFF08\u500D\u6570\uFF09\u3002",
140
+ thinkingLineHeightDesc: "\u201C\u5DF2\u5DE5\u4F5C/\u5DE5\u4F5C\u4E2D\u201D\u8FC7\u7A0B\u8BB0\u5F55\uFF08\u8BFB\u53D6/\u7F16\u8F91/\u67E5\u9605/\u7EC8\u7AEF\u6761\u76EE\u4E0E\u601D\u8003\u5185\u5BB9\uFF09\u7684\u884C\u9AD8\uFF08\u500D\u6570\uFF09\u3002",
136
141
  userLineHeightName: "\u63D0\u95EE\u884C\u9AD8",
137
142
  userLineHeightDesc: "\u63D0\u95EE\u5185\u5BB9\u7684\u884C\u9AD8\uFF08\u500D\u6570\uFF09\u3002",
138
143
  contentWidthName: "\u5185\u5BB9\u5BBD\u5EA6",
@@ -250,11 +255,10 @@
250
255
  visionSkipMinutes: "\u8DF3\u8FC7\u5206\u949F\u6570",
251
256
  visionSkipMinutesHint: "\u8DF3\u8FC7\u591A\u4E45\u540E\u81EA\u52A8\u6062\u590D\u5C1D\u8BD5\uFF1B\u671F\u95F4\u4EFB\u4E00\u6B21\u6210\u529F\u5373\u6E05\u96F6\u8BA1\u6570",
252
257
  visionResetChain: "\u6062\u590D\u9ED8\u8BA4\u94FE",
253
- visionResetChainConfirm: "\u5C06\u94FE\u6A21\u5F0F\u4E0E\u4EE3\u7406\u5217\u8868\u6062\u590D\u4E3A\u9ED8\u8BA4\u4E24\u7EA7\uFF08glm-session \u2192 glm-flash\uFF09\uFF0C\u5F53\u524D\u5BF9\u4EE3\u7406\u7684\u4FEE\u6539\u4F1A\u4E22\u5931\u3002\u7EE7\u7EED\uFF1F",
254
- visionBaseUrl: "\u63A5\u53E3\u5730\u5740 baseUrl",
258
+ visionResetChainConfirm: "\u5C06\u94FE\u6A21\u5F0F\u4E0E\u4EE3\u7406\u5217\u8868\u6062\u590D\u4E3A\u9ED8\u8BA4\u5355\u7EA7\uFF08session\uFF1A\u8DDF\u968F\u4F1A\u8BDD\u4E0E\u5176\u5F53\u524D\u6A21\u578B\uFF09\uFF0C\u5F53\u524D\u5BF9\u4EE3\u7406\u7684\u4FEE\u6539\u4F1A\u4E22\u5931\u3002\u7EE7\u7EED\uFF1F",
259
+ visionBaseUrl: "\u63A5\u53E3\u5730\u5740",
255
260
  visionModel: "\u6A21\u578B",
256
261
  visionApiKey: "API Key",
257
- visionApiKeyHint: "\u7559\u7A7A\u81EA\u52A8\u53D6 GLM \u8BA2\u9605 key",
258
262
  visionPrompt: "\u8BC6\u522B\u63D0\u793A\u8BCD\uFF08pipeline \u540E\u7EED\u6B65\u53EF\u7528 {prev} \u5F15\u7528\u4E0A\u4E00\u6B65\uFF09",
259
263
  visionTest: "\u6D4B\u8BD5",
260
264
  visionTesting: "\u6D4B\u8BD5\u4E2D\u2026",
@@ -420,12 +424,17 @@
420
424
  proxyScopeSyncDesc: "WebDAV upload and download go through the proxy. Off by default: domestic WebDAV providers work fine direct, and a stopped proxy breaks sync.",
421
425
  tabSync: "Sync",
422
426
  tabDebug: "Debug",
423
- 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.",
427
+ testNoSessionHint: "With \u201Cfollow current session [current model]\u201D selected, the provider [model] of the last session is used.",
428
+ 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 (how many to keep is set in the "History" row; older ones are removed automatically after upload) and download lets you pick any of them. Data moves only when you click, never automatically.',
424
429
  syncUrlPlaceholder: "https://dav.example.com/dav/",
425
- syncDir: "\u4E0A\u4F20\u76EE\u5F55",
430
+ syncDir: "Folder",
426
431
  syncDirPlaceholder: "zcode-pro",
427
432
  syncLogin: "Login",
428
433
  syncPassword: "Password",
434
+ syncHistoryLimit: "History",
435
+ syncHistoryLimitUnit: "versions",
436
+ syncHistoryLimitHint: "How many recent uploads keep their history versions on the server; older ones are removed automatically after a successful upload. The fixed-name latest file is never removed. 0 = keep no history versions.",
437
+ syncPruned: "removed {n} older history versions",
429
438
  syncSave: "Save",
430
439
  syncSaved: "Sync settings saved.",
431
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.",
@@ -611,11 +620,10 @@
611
620
  visionSkipMinutes: "Skip minutes",
612
621
  visionSkipMinutesHint: "How long a skipped proxy rests before being retried; any success resets the counter",
613
622
  visionResetChain: "Reset default chain",
614
- visionResetChainConfirm: "Reset chain mode and the proxy list to the default 2-level chain (glm-session \u2192 glm-flash)? Current proxy edits will be lost. Continue?",
615
- visionBaseUrl: "Base URL",
623
+ visionResetChainConfirm: "Reset chain mode and the proxy list to the default single-level chain (session: follow session and its current model)? Current proxy edits will be lost. Continue?",
624
+ visionBaseUrl: "API URL",
616
625
  visionModel: "Model",
617
626
  visionApiKey: "API Key",
618
- visionApiKeyHint: "Leave empty to reuse the GLM subscription key",
619
627
  visionPrompt: "Recognition prompt ({prev} = previous step in pipeline)",
620
628
  visionTest: "Test",
621
629
  visionTesting: "Testing\u2026",
@@ -3654,17 +3662,34 @@
3654
3662
  )
3655
3663
  );
3656
3664
  const savedSync = config.sync && typeof config.sync === "object" ? config.sync : { url: "", dir: "zcode-pro", login: "", password: "", include: { zcodepro: true, model: true }, lastPushAt: null, lastPullAt: null };
3657
- const syncInputCls = "h-8 w-full rounded-lg border border-border bg-input px-2.5 text-ui-sm text-foreground outline-none transition-shadow placeholder:text-foreground-subtle focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40";
3665
+ const syncInputBase = "h-8 rounded-lg border border-border bg-input px-2.5 text-ui-sm text-foreground outline-none transition-shadow placeholder:text-foreground-subtle focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40";
3666
+ const syncInputCls = syncInputBase + " w-full";
3667
+ const syncLabel = (text) => h("span", { class: "w-20 shrink-0 text-ui-sm font-medium text-foreground" }, text);
3658
3668
  const syncFormRow = (labelText, node) => h(
3659
3669
  "div",
3660
3670
  { class: "flex items-center gap-3 px-2 py-1.5" },
3661
- h("span", { class: "w-20 shrink-0 text-ui-sm font-medium text-foreground" }, labelText),
3671
+ syncLabel(labelText),
3662
3672
  node
3663
3673
  );
3664
3674
  const syncUrlInput = h("input", { type: "text", value: savedSync.url || "", placeholder: L.syncUrlPlaceholder, spellcheck: "false", autocomplete: "off", class: syncInputCls + " min-w-0 flex-1" });
3665
3675
  const syncDirInput = h("input", { type: "text", value: savedSync.dir || "zcode-pro", placeholder: L.syncDirPlaceholder, spellcheck: "false", autocomplete: "off", class: syncInputCls + " min-w-0 flex-1" });
3666
3676
  const syncLoginInput = h("input", { type: "text", value: savedSync.login || "", spellcheck: "false", autocomplete: "off", class: syncInputCls + " min-w-0 flex-1" });
3667
3677
  const syncPasswordInput = h("input", { type: "password", value: savedSync.password || "", autocomplete: "new-password", class: syncInputCls + " min-w-0 flex-1" });
3678
+ const syncHistoryInput = h("input", {
3679
+ type: "number",
3680
+ min: "0",
3681
+ max: "100",
3682
+ step: "1",
3683
+ value: Number.isInteger(savedSync.historyLimit) ? savedSync.historyLimit : 10,
3684
+ title: L.syncHistoryLimitHint,
3685
+ class: syncInputBase + " w-20 shrink-0 text-center"
3686
+ });
3687
+ const syncHistoryValue = () => {
3688
+ const s = syncHistoryInput.value.trim();
3689
+ if (!s) return 10;
3690
+ const n = Number(s);
3691
+ return Number.isFinite(n) ? Math.min(100, Math.max(0, Math.round(n))) : 10;
3692
+ };
3668
3693
  let syncFormOriginal = null;
3669
3694
  const syncSaveBtn = btnSmall(L.syncSave, () => {
3670
3695
  void saveSyncForm();
@@ -3673,15 +3698,16 @@
3673
3698
  url: syncUrlInput.value.trim(),
3674
3699
  dir: syncDirInput.value.trim(),
3675
3700
  login: syncLoginInput.value.trim(),
3676
- password: syncPasswordInput.value
3701
+ password: syncPasswordInput.value,
3702
+ historyLimit: syncHistoryValue()
3677
3703
  });
3678
3704
  const syncCheckDirty = () => {
3679
3705
  const c = syncFormValues();
3680
- syncSaveBtn.disabled = c.url === syncFormOriginal.url && c.dir === syncFormOriginal.dir && c.login === syncFormOriginal.login && c.password === syncFormOriginal.password;
3706
+ syncSaveBtn.disabled = c.url === syncFormOriginal.url && c.dir === syncFormOriginal.dir && c.login === syncFormOriginal.login && c.password === syncFormOriginal.password && c.historyLimit === syncFormOriginal.historyLimit;
3681
3707
  };
3682
3708
  syncFormOriginal = syncFormValues();
3683
3709
  syncSaveBtn.disabled = true;
3684
- for (const el of [syncUrlInput, syncDirInput, syncLoginInput, syncPasswordInput]) {
3710
+ for (const el of [syncUrlInput, syncDirInput, syncLoginInput, syncPasswordInput, syncHistoryInput]) {
3685
3711
  el.addEventListener("input", syncCheckDirty);
3686
3712
  }
3687
3713
  const saveSyncForm = async () => {
@@ -3692,12 +3718,14 @@
3692
3718
  url: res.sync.url,
3693
3719
  dir: res.sync.dir,
3694
3720
  login: res.sync.login,
3695
- password: res.sync.password
3721
+ password: res.sync.password,
3722
+ historyLimit: Number.isInteger(res.sync.historyLimit) ? res.sync.historyLimit : 10
3696
3723
  };
3697
3724
  syncUrlInput.value = res.sync.url;
3698
3725
  syncDirInput.value = res.sync.dir;
3699
3726
  syncLoginInput.value = res.sync.login;
3700
3727
  syncPasswordInput.value = res.sync.password;
3728
+ syncHistoryInput.value = syncFormOriginal.historyLimit;
3701
3729
  showToast(L.syncSaved);
3702
3730
  } else {
3703
3731
  showToast(L.failed + ": " + errText(res), "error");
@@ -3993,7 +4021,7 @@
3993
4021
  return;
3994
4022
  }
3995
4023
  renderSyncStatus(res.sync || {});
3996
- showToast(L.syncUploaded, "success");
4024
+ showToast(res.pruned ? L.syncUploaded + (isZhLocale() ? "\uFF1B" : "; ") + L.syncPruned.replace("{n}", res.pruned) : L.syncUploaded, "success");
3997
4025
  };
3998
4026
  paneSync.append(
3999
4027
  h("p", { class: "text-ui-sm/relaxed text-foreground-subtle" }, L.syncDesc),
@@ -4001,12 +4029,27 @@
4001
4029
  "div",
4002
4030
  { class: "mt-3 rounded-xl border border-border p-1" },
4003
4031
  syncFormRow("URL", syncUrlInput),
4004
- syncFormRow(L.syncDir, syncDirInput),
4005
- syncFormRow(L.syncLogin, syncLoginInput),
4006
- syncFormRow(L.syncPassword, syncPasswordInput),
4032
+ // 登录与密码一行、上传目录与历史版本一行:短字段成对排,少占纵向空间
4033
+ h(
4034
+ "div",
4035
+ { class: "flex items-center gap-3 px-2 py-1.5" },
4036
+ syncLabel(L.syncLogin),
4037
+ syncLoginInput,
4038
+ syncLabel(L.syncPassword),
4039
+ syncPasswordInput
4040
+ ),
4007
4041
  h(
4008
4042
  "div",
4009
- { class: "flex items-start justify-between gap-2 px-2 py-1.5" },
4043
+ { class: "flex items-center gap-3 px-2 py-1.5" },
4044
+ syncLabel(L.syncDir),
4045
+ syncDirInput,
4046
+ syncLabel(L.syncHistoryLimit),
4047
+ syncHistoryInput,
4048
+ h("span", { class: "shrink-0 text-ui-xs text-foreground-subtle" }, L.syncHistoryLimitUnit)
4049
+ ),
4050
+ h(
4051
+ "div",
4052
+ { class: "flex items-center justify-between gap-2 px-2 py-1.5" },
4010
4053
  h(
4011
4054
  "div",
4012
4055
  { class: "min-w-0" },
@@ -4083,16 +4126,15 @@
4083
4126
  const VISION_DEFAULT_CFG = {
4084
4127
  enabled: true,
4085
4128
  chainMode: "fallback",
4086
- chain: ["glm-session", "glm-flash"],
4129
+ chain: ["session"],
4087
4130
  proxies: [
4088
- { name: "glm-session", useProvider: "session", model: "glm-5.3-flash", prompt: VISION_DEFAULT_PROMPT },
4089
- { name: "glm-flash", baseUrl: "https://open.bigmodel.cn/api/anthropic", model: "glm-5.3-flash", apiKey: "", format: "anthropic", prompt: VISION_DEFAULT_PROMPT }
4131
+ { name: "session", useProvider: "session", model: "", prompt: VISION_DEFAULT_PROMPT }
4090
4132
  ],
4091
4133
  pollMs: 3e3,
4092
4134
  apiTimeoutMs: 12e4,
4093
4135
  // 视觉上游冷启动可能近 2 分钟,与插件 DEFAULT_CONFIG 一致
4094
4136
  compressThresholdKB: 1024,
4095
- skipAfterFailures: 4,
4137
+ skipAfterFailures: 2,
4096
4138
  skipMinutes: 30,
4097
4139
  forceIntercept: true
4098
4140
  };
@@ -4236,26 +4278,22 @@
4236
4278
  n
4237
4279
  );
4238
4280
  };
4239
- const cards = visionCfg.proxies.map((p, i) => h(
4240
- "div",
4241
- { class: "mt-2 rounded-xl border border-border p-2" },
4242
- h(
4281
+ const cards = visionCfg.proxies.map((p, i) => {
4282
+ const manualConnCard = isManualConn(p.useProvider, titleGenProviders) ? [h(
4243
4283
  "div",
4244
- { class: "flex flex-wrap items-center gap-2" },
4245
- h("span", { class: "shrink-0 rounded-md bg-surface px-1.5 py-0.5 text-ui-xs tabular-nums text-foreground-subtle" }, String(i + 1)),
4246
- // 名称输入框用 flex-1 占剩余宽度,与序号同行;textIn 的 w-full 会把序号挤成单独一行
4247
- (() => {
4248
- const n = h("input", { type: "text", value: p.name || "", placeholder: L.visionName, class: visionInputCls + " min-w-0 flex-1" });
4249
- n.addEventListener("input", () => {
4250
- p.name = n.value;
4251
- saveVisionSoon();
4252
- });
4253
- return n;
4254
- })(),
4255
- (() => {
4284
+ { class: "mt-2 grid grid-cols-1 gap-2 rounded-xl border border-border p-2 sm:grid-cols-3" },
4285
+ field(L.visionBaseUrl, textIn(p.baseUrl, (v) => {
4286
+ p.baseUrl = v;
4287
+ saveVisionSoon();
4288
+ })),
4289
+ field(L.visionApiKey, textIn(p.apiKey, (v) => {
4290
+ p.apiKey = v;
4291
+ saveVisionSoon();
4292
+ }, { type: "password" })),
4293
+ field(L.titleGenFormat, (() => {
4256
4294
  const sel = h(
4257
4295
  "select",
4258
- { class: "h-7 shrink-0 rounded-lg border border-border bg-input px-1.5 text-ui-xs text-foreground outline-none" },
4296
+ { class: "h-8 w-full rounded-lg border border-border bg-input px-2 text-ui-sm text-foreground outline-none" },
4259
4297
  h("option", { value: "anthropic" }, "anthropic"),
4260
4298
  h("option", { value: "openai" }, "openai")
4261
4299
  );
@@ -4265,78 +4303,85 @@
4265
4303
  void persistVision();
4266
4304
  });
4267
4305
  return sel;
4268
- })(),
4269
- smallBtn(L.visionMoveUp, () => {
4270
- if (i <= 0) return;
4271
- visionCfg.proxies.splice(i - 1, 0, visionCfg.proxies.splice(i, 1)[0]);
4272
- void persistVision();
4273
- renderVision();
4274
- }, i === 0 ? "pointer-events-none opacity-40" : ""),
4275
- smallBtn(L.visionMoveDown, () => {
4276
- if (i >= visionCfg.proxies.length - 1) return;
4277
- visionCfg.proxies.splice(i + 1, 0, visionCfg.proxies.splice(i, 1)[0]);
4278
- void persistVision();
4279
- renderVision();
4280
- }, i === visionCfg.proxies.length - 1 ? "pointer-events-none opacity-40" : ""),
4281
- smallBtn(L.visionRemove, () => {
4282
- visionCfg.proxies.splice(i, 1);
4283
- void persistVision();
4284
- renderVision();
4285
- })
4286
- ),
4287
- h(
4288
- "div",
4289
- { class: "mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2" },
4290
- // 供应商与模型走 provider-fields 共用逻辑:跟随会话时模型下拉为
4291
- // 全部供应商模型汇总,具体供应商为其模型列表;已删 id 标注「已删除」
4292
- field(L.visionUseProvider, comboField(
4293
- p.useProvider || "",
4294
- providerOptionsOf(titleGenProviders, L),
4295
- (v, src) => {
4296
- p.useProvider = v;
4297
- saveVisionSoon();
4298
- if (src === "select") renderVision();
4299
- },
4300
- { placeholder: L.titleGenProviderSession, staleLabel: L.titleGenProviderDeleted }
4301
- )),
4302
- // 跟随会话时模型下拉头部有「跟随当前会话当前模型」(值为空,
4303
- // 插件 ≥1.6.1 在调用时解析为会话当前模型);具体供应商为其模型列表
4304
- field(L.visionModel, comboField(
4305
- p.model || "",
4306
- modelOptionsOf(p.useProvider, titleGenProviders, {
4307
- followSession: (p.useProvider || "").trim() === "session",
4308
- followSessionLabel: L.titleGenModelFollowSession
4309
- }),
4310
- (v) => {
4311
- p.model = v;
4312
- saveVisionSoon();
4313
- },
4314
- {
4315
- placeholder: modelPlaceholderOf(p.useProvider, L),
4316
- emptyLabel: (p.useProvider || "").trim() === "session" ? L.titleGenModelFollowSession : L.titleGenModelEmpty
4317
- }
4318
- )),
4319
- ...isManualConn(p.useProvider, titleGenProviders) ? [
4320
- field(L.visionBaseUrl, textIn(p.baseUrl, (v) => {
4321
- p.baseUrl = v;
4322
- saveVisionSoon();
4323
- })),
4324
- field(L.visionApiKey + " \xB7 " + L.visionApiKeyHint, textIn(p.apiKey, (v) => {
4325
- p.apiKey = v;
4306
+ })())
4307
+ )] : [];
4308
+ return h("div", { class: "mt-2 rounded-xl border border-border p-2" }, [
4309
+ h(
4310
+ "div",
4311
+ { class: "flex flex-wrap items-center gap-2" },
4312
+ h("span", { class: "shrink-0 rounded-md bg-surface px-1.5 py-0.5 text-ui-xs tabular-nums text-foreground-subtle" }, String(i + 1)),
4313
+ // 名称输入框用 flex-1 占剩余宽度,与序号同行;textIn 的 w-full 会把序号挤成单独一行
4314
+ (() => {
4315
+ const n = h("input", { type: "text", value: p.name || "", placeholder: L.visionName, class: visionInputCls + " min-w-0 flex-1" });
4316
+ n.addEventListener("input", () => {
4317
+ p.name = n.value;
4318
+ saveVisionSoon();
4319
+ });
4320
+ return n;
4321
+ })(),
4322
+ smallBtn(L.visionMoveUp, () => {
4323
+ if (i <= 0) return;
4324
+ visionCfg.proxies.splice(i - 1, 0, visionCfg.proxies.splice(i, 1)[0]);
4325
+ void persistVision();
4326
+ renderVision();
4327
+ }, i === 0 ? "pointer-events-none opacity-40" : ""),
4328
+ smallBtn(L.visionMoveDown, () => {
4329
+ if (i >= visionCfg.proxies.length - 1) return;
4330
+ visionCfg.proxies.splice(i + 1, 0, visionCfg.proxies.splice(i, 1)[0]);
4331
+ void persistVision();
4332
+ renderVision();
4333
+ }, i === visionCfg.proxies.length - 1 ? "pointer-events-none opacity-40" : ""),
4334
+ smallBtn(L.visionRemove, () => {
4335
+ visionCfg.proxies.splice(i, 1);
4336
+ void persistVision();
4337
+ renderVision();
4338
+ })
4339
+ ),
4340
+ h(
4341
+ "div",
4342
+ { class: "mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2" },
4343
+ // 供应商与模型走 provider-fields 共用逻辑:跟随会话时模型下拉为
4344
+ // 全部供应商模型汇总,具体供应商为其模型列表;已删 id 标注“已删除”
4345
+ field(L.visionUseProvider, comboField(
4346
+ p.useProvider || "",
4347
+ providerOptionsOf(titleGenProviders, L),
4348
+ (v, src) => {
4349
+ p.useProvider = v;
4350
+ saveVisionSoon();
4351
+ if (src === "select") renderVision();
4352
+ },
4353
+ { placeholder: L.titleGenProviderSession, staleLabel: L.titleGenProviderDeleted }
4354
+ )),
4355
+ // 跟随会话时模型下拉头部有“跟随当前会话当前模型”(值为空,
4356
+ // 插件 ≥1.6.1 在调用时解析为会话当前模型);具体供应商为其模型列表
4357
+ field(L.visionModel, comboField(
4358
+ p.model || "",
4359
+ modelOptionsOf(p.useProvider, titleGenProviders, {
4360
+ followSession: (p.useProvider || "").trim() === "session",
4361
+ followSessionLabel: L.titleGenModelFollowSession
4362
+ }),
4363
+ (v) => {
4364
+ p.model = v;
4365
+ saveVisionSoon();
4366
+ },
4367
+ {
4368
+ placeholder: modelPlaceholderOf(p.useProvider, L),
4369
+ emptyLabel: (p.useProvider || "").trim() === "session" ? L.titleGenModelFollowSession : L.titleGenModelEmpty
4370
+ }
4371
+ ))
4372
+ ),
4373
+ ...manualConnCard,
4374
+ (() => {
4375
+ const n = h("textarea", { class: "zcodepro-textarea zcodepro-textarea-sm", rows: "3", placeholder: L.visionPrompt });
4376
+ n.value = p.prompt || "";
4377
+ n.addEventListener("input", () => {
4378
+ p.prompt = n.value;
4326
4379
  saveVisionSoon();
4327
- }, { type: "password" }))
4328
- ] : []
4329
- ),
4330
- (() => {
4331
- const n = h("textarea", { class: "zcodepro-textarea zcodepro-textarea-sm", rows: "3", placeholder: L.visionPrompt });
4332
- n.value = p.prompt || "";
4333
- n.addEventListener("input", () => {
4334
- p.prompt = n.value;
4335
- saveVisionSoon();
4336
- });
4337
- return field(L.visionPrompt, n);
4338
- })()
4339
- ));
4380
+ });
4381
+ return field(L.visionPrompt, n);
4382
+ })()
4383
+ ]);
4384
+ });
4340
4385
  let testBtn;
4341
4386
  testBtn = smallBtn(L.visionTest, async () => {
4342
4387
  testBtn.disabled = true;
@@ -4347,7 +4392,6 @@
4347
4392
  testBtn.disabled = false;
4348
4393
  testBtn.textContent = L.visionTest;
4349
4394
  visionTestPre.textContent = res.output || res.error || "";
4350
- if (!res.ok) showToast(L.visionTestFailed + ": " + errText(res), "error");
4351
4395
  });
4352
4396
  paneVision.replaceChildren(
4353
4397
  h("p", { class: "text-ui-sm/relaxed text-foreground-subtle" }, L.visionDesc),
@@ -4412,7 +4456,7 @@
4412
4456
  n
4413
4457
  );
4414
4458
  })(),
4415
- numIn(visionCfg.skipAfterFailures, { min: 0, dflt: 4, title: L.visionSkipAfterFailuresHint, label: L.visionSkipAfterFailures, commit: (v) => {
4459
+ numIn(visionCfg.skipAfterFailures, { min: 0, dflt: 2, title: L.visionSkipAfterFailuresHint, label: L.visionSkipAfterFailures, commit: (v) => {
4416
4460
  visionCfg.skipAfterFailures = v;
4417
4461
  } }),
4418
4462
  numIn(visionCfg.skipMinutes, { min: 1, dflt: 30, title: L.visionSkipMinutesHint, label: L.visionSkipMinutes, commit: (v) => {
@@ -4427,7 +4471,7 @@
4427
4471
  "div",
4428
4472
  { class: "flex items-center gap-1.5" },
4429
4473
  smallBtn("+ " + L.visionAddProxy, () => {
4430
- visionCfg.proxies.push({ name: "", baseUrl: "https://open.bigmodel.cn/api/anthropic", model: "glm-5.3-flash", apiKey: "", format: "anthropic", prompt: "" });
4474
+ visionCfg.proxies.push({ name: "", baseUrl: "https://open.bigmodel.cn/api/anthropic", model: "glm-5.3-flash", apiKey: "", format: "anthropic", prompt: VISION_DEFAULT_PROMPT });
4431
4475
  renderVision();
4432
4476
  }),
4433
4477
  smallBtn(L.visionResetChain, () => {
@@ -4438,7 +4482,12 @@
4438
4482
  renderVision();
4439
4483
  })
4440
4484
  ),
4441
- testBtn
4485
+ h(
4486
+ "div",
4487
+ { class: "flex min-w-0 items-center justify-end gap-2" },
4488
+ h("span", { class: "min-w-0 text-right text-ui-xs/relaxed text-foreground-subtle" }, L.testNoSessionHint),
4489
+ testBtn
4490
+ )
4442
4491
  ),
4443
4492
  visionTestPre
4444
4493
  );
@@ -5188,11 +5237,9 @@
5188
5237
  testBtn.textContent = L.titleGenTest;
5189
5238
  if (res && res.ok) {
5190
5239
  testState.textContent = L.titleGenTestOk + res.title;
5191
- showToast(res.title, "success");
5192
5240
  } else {
5193
5241
  testState.textContent = res && errText(res) || L.titleGenTestFailed;
5194
5242
  testState.className = "min-w-0 flex-1 truncate text-ui-xs/relaxed text-destructive";
5195
- showToast(L.titleGenTestFailed + ": " + (res ? errText(res) : ""), "error");
5196
5243
  }
5197
5244
  }, "shrink-0");
5198
5245
  paneTitleGen.replaceChildren(
@@ -5232,12 +5279,18 @@
5232
5279
  ),
5233
5280
  promptArea
5234
5281
  ),
5235
- // 测试
5282
+ // 测试(两行:输入框整行;说明 + 按钮一行。结果只显示在本区下方,
5283
+ // 不弹窗;从没对话过时的引导见 testState 错误文案)
5236
5284
  h(
5237
5285
  "div",
5238
- { class: "mt-2 flex items-center gap-2 rounded-xl border border-border p-2" },
5286
+ { class: "mt-2 rounded-xl border border-border p-2" },
5239
5287
  sampleInput,
5240
- testBtn
5288
+ h(
5289
+ "div",
5290
+ { class: "mt-2 flex items-center justify-between gap-2" },
5291
+ h("span", { class: "min-w-0 text-ui-xs/relaxed text-foreground-subtle" }, L.testNoSessionHint),
5292
+ testBtn
5293
+ )
5241
5294
  ),
5242
5295
  testState
5243
5296
  );
@@ -5732,15 +5785,58 @@
5732
5785
  if (m) scan2();
5733
5786
  });
5734
5787
  }
5788
+ var RENAME_CTX_VALID_MS = 15e3;
5789
+ var renameCtx = null;
5790
+ var renamePrefilled = /* @__PURE__ */ new WeakSet();
5791
+ function setNativeValue(el, text) {
5792
+ if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
5793
+ Object.getOwnPropertyDescriptor(el.constructor.prototype, "value").set.call(el, text);
5794
+ } else {
5795
+ el.textContent = text;
5796
+ }
5797
+ el.dispatchEvent(new Event("input", { bubbles: true }));
5798
+ }
5799
+ function prefillRenameDialog() {
5800
+ if (!renameCtx || !renameCtx.armed || Date.now() - renameCtx.at > RENAME_CTX_VALID_MS) {
5801
+ renameCtx = null;
5802
+ return;
5803
+ }
5804
+ if (!enabled2 || !pinned) return;
5805
+ const want = pinned.get(sessIdOf(renameCtx.key));
5806
+ if (want === void 0) return;
5807
+ for (const el of document.querySelectorAll('[role="dialog"] input, [role="dialog"] textarea, [role="dialog"] [contenteditable="true"]')) {
5808
+ if (renamePrefilled.has(el) || !el.getClientRects().length) continue;
5809
+ if (el.closest(TASK_SEL) || el.closest(".zcodepro-overlay")) continue;
5810
+ const cur = String(el.value ?? el.textContent ?? "").trim();
5811
+ if (!cur) continue;
5812
+ renamePrefilled.add(el);
5813
+ if (cur !== String(want).trim()) setNativeValue(el, String(want));
5814
+ renameCtx = null;
5815
+ return;
5816
+ }
5817
+ }
5735
5818
  function startTitleLock() {
5736
5819
  if (installed2 || typeof document === "undefined") return;
5737
5820
  installed2 = true;
5738
5821
  void bootstrap();
5739
5822
  new MutationObserver((muts) => {
5823
+ if (renameCtx) prefillRenameDialog();
5740
5824
  if (!taskRowMutations2(muts)) return;
5741
5825
  refreshMapSoon();
5742
5826
  scheduleScan2();
5743
5827
  }).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
5828
+ document.addEventListener("contextmenu", (e) => {
5829
+ const row = e.target instanceof Element && e.target.closest(TASK_SEL);
5830
+ renameCtx = row ? { key: row.getAttribute("data-task-item-key") || "", at: 0, armed: false } : null;
5831
+ }, true);
5832
+ document.addEventListener("click", (e) => {
5833
+ if (!renameCtx || renameCtx.armed) return;
5834
+ const item = e.target instanceof Element && e.target.closest('[role="menuitem"], [data-radix-collection-item]');
5835
+ if (item && /重命名|rename/i.test(item.textContent || "")) {
5836
+ renameCtx.armed = true;
5837
+ renameCtx.at = Date.now();
5838
+ }
5839
+ }, true);
5744
5840
  scheduleBootRetry();
5745
5841
  setInterval(() => {
5746
5842
  if (!document.hidden) scan2();
@@ -5850,7 +5946,13 @@
5850
5946
  convObserver.disconnect();
5851
5947
  }
5852
5948
  if (!texts.length) return;
5853
- const res = await rpc("/title-gen/run", { method: "POST", body: { sessId, text: texts.join("\n") } }).catch(() => null);
5949
+ const callTitleGen = () => rpc("/title-gen/run", { method: "POST", body: { sessId, text: texts.join("\n") } }).catch(() => null);
5950
+ let res = await callTitleGen();
5951
+ for (const delay of [5e3, 2e4]) {
5952
+ if (res && res.ok) break;
5953
+ await sleep(delay);
5954
+ res = await callTitleGen();
5955
+ }
5854
5956
  if (res && res.ok && res.written && res.title) {
5855
5957
  setRowTitle(key, res.title);
5856
5958
  void refreshPinnedTitles();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zcode-pro",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "ZCode Pro — 为 ZCode 桌面版增加界面增强(不修改客户端文件,通过 ZCode Pro 快捷方式启动即可),核心功能:项目自定义别名",
5
5
  "type": "module",
6
6
  "bin": {