zcode-pro 1.0.0 → 1.2.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.
- package/README.en.md +5 -4
- package/README.md +5 -4
- package/dist/inject.js +1775 -1206
- package/package.json +1 -1
- package/src/host/helper.mjs +10 -1
- package/src/inject/core.js +88 -10
- package/src/inject/features/newtab-panels.js +224 -0
- package/src/inject/features/sandbox-reclaim.js +121 -0
- package/src/inject/features/session-switch.js +159 -24
- package/src/inject/features/settings-dialog.js +143 -3
- package/src/inject/features/ws-running.js +7 -0
- package/src/inject/index.js +2 -0
- package/src/inject/ui.js +14 -0
package/dist/inject.js
CHANGED
|
@@ -30,6 +30,18 @@
|
|
|
30
30
|
function clearConfigCache() {
|
|
31
31
|
configCache = { value: null, at: 0 };
|
|
32
32
|
}
|
|
33
|
+
var DEFAULT_SHORTCUTS = {
|
|
34
|
+
switchLast: "z",
|
|
35
|
+
// 立即切到上次会话
|
|
36
|
+
switchPrev: "x",
|
|
37
|
+
// 弹窗中上移
|
|
38
|
+
switchNext: "c",
|
|
39
|
+
// 弹窗中下移
|
|
40
|
+
switchRecent: "e",
|
|
41
|
+
// 打开最近 10 条
|
|
42
|
+
switchAttention: "r"
|
|
43
|
+
// 打开运行中 / 未查看
|
|
44
|
+
};
|
|
33
45
|
function zcodeAppVersion() {
|
|
34
46
|
const v = liveBoot().zcodeVersion;
|
|
35
47
|
return typeof v === "string" && v ? v : "";
|
|
@@ -178,7 +190,7 @@
|
|
|
178
190
|
featureTaskOrder: "\u4FA7\u8FB9\u680F\u4F1A\u8BDD\u62D6\u52A8\u6392\u5E8F",
|
|
179
191
|
featureTaskOrderDesc: "\u8BA9\u7F6E\u9876\u3001\u9879\u76EE\u4E0E\u5206\u7EC4\u4E2D\u7684\u4F1A\u8BDD\u62D6\u52A8\u540E\u8BB0\u4F4F\u987A\u5E8F\uFF0C\u5237\u65B0\u540E\u4FDD\u6301\u3002",
|
|
180
192
|
featureSessionSwitch: "\u4F1A\u8BDD\u5FEB\u6377\u5207\u6362",
|
|
181
|
-
featureSessionSwitchDesc: "
|
|
193
|
+
featureSessionSwitchDesc: "{last} \u5728\u5F53\u524D\u4E0E\u4E0A\u6B21\u4F1A\u8BDD\u95F4\u6765\u56DE\u5207\u6362\uFF1B\u6309\u4F4F alt \u518D\u6309 {prev}/{next} \u5F39\u51FA\u6700\u8FD1\u4F1A\u8BDD\u5217\u8868\u524D\u540E\u9009\u62E9\uFF08\u521D\u59CB 10 \u6761\uFF0C{next} \u5230\u5E95\u518D\u52A0\u8F7D 5 \u6761\uFF09\uFF0C{recent} \u76F4\u63A5\u6253\u5F00\u6700\u8FD1 10 \u6761\uFF0C{attention} \u6253\u5F00\u8FD0\u884C\u4E2D\u4E0E\u8FD0\u884C\u5B8C\u672A\u67E5\u770B\u7684\u4EFB\u52A1\uFF1B\u65B9\u5411\u952E\u540C\u6837\u53EF\u9009\uFF0CEnter \u6216\u677E\u5F00 alt \u5207\u6362\uFF08\u7C7B alt+tab\uFF09",
|
|
182
194
|
featureTitleLock: "\u91CD\u547D\u540D\u4F1A\u8BDD\u540D\u9501\u5B9A",
|
|
183
195
|
featureTitleLockDesc: "\u624B\u52A8\u91CD\u547D\u540D\u8FC7\u7684\u4F1A\u8BDD\u4E0D\u518D\u88AB\u81EA\u52A8\u6807\u9898\u8986\u76D6\uFF1A\u4F1A\u8BDD\u6709\u65B0\u56DE\u7B54\u540E\u754C\u9762\u53EF\u80FD\u6539\u663E\u81EA\u52A8\u6807\u9898\uFF0C\u91CD\u542F\u540E\u53C8\u53D8\u56DE\uFF0C\u672C\u529F\u80FD\u8BA9\u4FA7\u680F\u59CB\u7EC8\u663E\u793A\u91CD\u547D\u540D\u540E\u7684\u540D\u5B57\u3002",
|
|
184
196
|
tabTitleGen: "\u4EFB\u52A1\u540D\u63D0\u793A\u8BCD",
|
|
@@ -206,7 +218,7 @@
|
|
|
206
218
|
titleGenTestOk: "\u751F\u6210\u7ED3\u679C\uFF1A",
|
|
207
219
|
titleGenTestFailed: "\u751F\u6210\u5931\u8D25",
|
|
208
220
|
featureWsRunning: "\u6298\u53E0\u65F6\u4EFB\u52A1\u8FD0\u884C\u4E2D\u63D0\u793A",
|
|
209
|
-
featureWsRunningDesc: "\u6709\u4F1A\u8BDD\u5728\u8FD0\u884C\u65F6\uFF0C\u6298\u53E0\u7684\u9879\u76EE\u4E0E\u201C\u4EFB\u52A1\u201D\u201C\u5DF2\u7F6E\u9876\u201D\u7B49\u5206\u533A\u5934\u663E\u793A\u4E0E\u4EFB\u52A1\u8FD0\u884C\u4E2D\u540C\u6B3E\u7684\u52A0\u8F7D\u56FE\u6807\uFF0C\u5168\u90E8\u7ED3\u675F\u540E\u6D88\u5931\
|
|
221
|
+
featureWsRunningDesc: "\u6709\u4F1A\u8BDD\u5728\u8FD0\u884C\u65F6\uFF0C\u6298\u53E0\u7684\u9879\u76EE\u4E0E\u201C\u4EFB\u52A1\u201D\u201C\u5DF2\u7F6E\u9876\u201D\u7B49\u5206\u533A\u5934\u663E\u793A\u4E0E\u4EFB\u52A1\u8FD0\u884C\u4E2D\u540C\u6B3E\u7684\u52A0\u8F7D\u56FE\u6807\uFF0C\u5168\u90E8\u7ED3\u675F\u540E\u6D88\u5931\u3002",
|
|
210
222
|
tabPerformance: "\u6027\u80FD",
|
|
211
223
|
perfDesc: "ZCode \u4E3A\u6BCF\u4E2A\u6253\u5F00\u8FC7\u7684\u9879\u76EE\u5E38\u9A7B\u4E00\u4E2A\u4F1A\u8BDD\u8FDB\u7A0B\uFF0C\u5E94\u7528\u81EA\u8EAB\u4E0D\u4F1A\u56DE\u6536\uFF0C\u9879\u76EE\u591A\u4E86\u5185\u5B58\u5360\u7528\u5C31\u9AD8\u3002\u5F00\u542F\u540E\uFF0C\u957F\u65F6\u95F4\u672A\u4F7F\u7528\u4E14\u6CA1\u6709\u4EFB\u52A1\u5728\u8DD1\u7684\u9879\u76EE\u4F1A\u88AB\u81EA\u52A8\u91CA\u653E\uFF1A\u4F1A\u8BDD\u8BB0\u5F55\u4E0D\u53D7\u5F71\u54CD\uFF0C\u518D\u6B21\u6253\u5F00\u65F6\u81EA\u52A8\u6062\u590D\uFF0C\u4EC5\u9996\u6B21\u56DE\u590D\u6709\u51E0\u79D2\u7B49\u5F85\u3002\u6B63\u5728\u4F7F\u7528\u7684\u9879\u76EE\u3001\u8FD0\u884C\u4E2D\u7684\u4F1A\u8BDD\u4E0E\u540E\u53F0\u547D\u4EE4\u3001\u5B9A\u65F6\u4EFB\u52A1\u90FD\u4E0D\u4F1A\u88AB\u56DE\u6536\u3002\u540E\u53F0\u547D\u4EE4\u68C0\u6D4B\u4F9D\u8D56\u7CFB\u7EDF\u8FDB\u7A0B\u4FE1\u606F\uFF08Linux / macOS / Windows \u5404\u8D70\u7CFB\u7EDF\u81EA\u5E26\u5DE5\u5177\uFF09\uFF0C\u68C0\u6D4B\u4E0D\u53EF\u7528\u65F6\u529F\u80FD\u81EA\u52A8\u505C\u7528\u3002",
|
|
212
224
|
featureIdleReclaim: "\u7A7A\u95F2\u9879\u76EE\u5185\u5B58\u56DE\u6536",
|
|
@@ -234,10 +246,44 @@
|
|
|
234
246
|
userFontDesc: "\u4F1A\u8BDD\u4E2D\u63D0\u95EE\u5185\u5BB9\u7684\u5B57\u4F53\uFF1B\u9009\u201C\u9ED8\u8BA4\u201D\u65F6\u8DDF\u968F\u754C\u9762\u5B57\u4F53\u3002",
|
|
235
247
|
assistantFontName: "\u56DE\u7B54\u5B57\u4F53",
|
|
236
248
|
assistantFontDesc: "\u4F1A\u8BDD\u4E2D\u56DE\u7B54\u6B63\u6587\u7684\u5B57\u4F53\uFF08\u4EE3\u7801\u5757\u4ECD\u7528\u7B49\u5BBD\u5B57\u4F53\uFF09\uFF1B\u9009\u201C\u9ED8\u8BA4\u201D\u65F6\u8DDF\u968F\u754C\u9762\u5B57\u4F53\u3002",
|
|
237
|
-
switcherHint: "
|
|
249
|
+
switcherHint: "{prev} / {next} \u6216 \u2191 / \u2193 \u9009\u62E9\uFF0CEnter \u6216\u677E\u5F00 alt \u5207\u6362\uFF0CEsc \u53D6\u6D88",
|
|
238
250
|
switcherCurrent: "\u5F53\u524D",
|
|
239
251
|
switcherEmpty: "\u6682\u65E0\u4E0A\u6B21\u4F1A\u8BDD\uFF08\u5207\u6362\u8FC7\u4F1A\u8BDD\u540E\u53EF\u7528\uFF09",
|
|
240
252
|
switcherFailed: "\u672A\u80FD\u5207\u6362\u5230\u8BE5\u4F1A\u8BDD\uFF08\u53EF\u80FD\u5DF2\u5220\u9664\uFF09",
|
|
253
|
+
switcherMore: "\u8FD8\u6709 {n} \u6761 \xB7 \u6309 c \u52A0\u8F7D",
|
|
254
|
+
switcherRunning: "\u8FD0\u884C\u4E2D",
|
|
255
|
+
switcherUnseen: "\u672A\u67E5\u770B",
|
|
256
|
+
switcherAttentionHint: "\u8FD0\u884C\u4E2D / \u8FD0\u884C\u5B8C\u672A\u67E5\u770B\u7684\u4EFB\u52A1 \xB7 {prev} / {next} \u6216 \u2191 / \u2193 \u9009\u62E9\uFF0CEnter \u6216\u677E\u5F00 alt \u5207\u6362",
|
|
257
|
+
switcherAttentionEmpty: "\u6682\u65E0\u8FD0\u884C\u4E2D\u6216\u672A\u67E5\u770B\u7684\u4EFB\u52A1",
|
|
258
|
+
featureNewtabPanels: "\u65B0\u6807\u7B7E\u9875\u63D2\u4EF6\u9762\u677F\u5165\u53E3",
|
|
259
|
+
featureNewtabPanelsDesc: "\u5B98\u65B9\u201C\u65B0\u6807\u7B7E\u9875\u201D\u53EA\u5217\u5B98\u65B9\u9762\u677F\u4E0E\u63A8\u8350\u7684\u5B98\u65B9\u63D2\u4EF6\uFF0C\u6B64\u529F\u80FD\u628A\u7B2C\u4E09\u65B9\u5E02\u573A\u63D2\u4EF6\uFF08headroom\u3001rtk \u7B49\uFF09\u7684\u9762\u677F\u5361\u7247\u52A0\u8FDB\u53BB\uFF0C\u70B9\u51FB\u5728\u4FA7\u8FB9\u9762\u677F\u6253\u5F00\u3002",
|
|
260
|
+
ntpDescSuffix: "\u63D2\u4EF6\u9762\u677F",
|
|
261
|
+
ntpNeedSession: "\u5148\u6253\u5F00\u4E00\u4E2A\u4EFB\u52A1\u4F1A\u8BDD\uFF0C\u518D\u4ECE\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u63D2\u4EF6\u9762\u677F",
|
|
262
|
+
tabShortcuts: "\u5FEB\u6377\u952E",
|
|
263
|
+
hkTitle: "\u4F1A\u8BDD\u5FEB\u6377\u5207\u6362",
|
|
264
|
+
hkAltZ: "\u5728\u5F53\u524D\u4E0E\u4E0A\u6B21\u4F7F\u7528\u7684\u4F1A\u8BDD\u95F4\u6765\u56DE\u5207\u6362",
|
|
265
|
+
hkAltX: "\u5F39\u7A97\u4E2D\u4E0A\u79FB\u9AD8\u4EAE\uFF08\u66F4\u65E9\u7684\u4F1A\u8BDD\uFF09",
|
|
266
|
+
hkAltC: "\u5F39\u7A97\u4E2D\u4E0B\u79FB\u9AD8\u4EAE\uFF08\u66F4\u65B0\u7684\u4F1A\u8BDD\uFF09\uFF1B\u5230\u5E95\u4E14\u8FD8\u6709\u66F4\u591A\u65F6\u52A0\u8F7D 5 \u6761\u5E76\u9009\u4E2D\u65B0\u52A0\u8F7D\u7684\u7B2C\u4E00\u6761",
|
|
267
|
+
hkAltE: "\u6253\u5F00\u6700\u8FD1 10 \u6761\u4EFB\u52A1\u5217\u8868",
|
|
268
|
+
hkAltR: "\u6253\u5F00\u6B63\u5728\u8FD0\u884C\u4E0E\u8FD0\u884C\u5B8C\u672A\u67E5\u770B\u7684\u4EFB\u52A1\u5217\u8868",
|
|
269
|
+
hkArrow: "\u5F39\u7A97\u6253\u5F00\u65F6\u79FB\u52A8\u9AD8\u4EAE\uFF08\u4E0E alt + {prev} / alt + {next} \u540C\u89C4\u5219\uFF09",
|
|
270
|
+
hkEnter: "\u786E\u8BA4\u5207\u6362\u5230\u9AD8\u4EAE\u7684\u4F1A\u8BDD",
|
|
271
|
+
hkEsc: "\u53D6\u6D88\u5E76\u5173\u95ED\u5F39\u7A97",
|
|
272
|
+
hkRelease: "\u79FB\u52A8\u8FC7\u9AD8\u4EAE\u65F6\u677E\u5F00\u5373\u5207\u6362\uFF1B\u4ECE\u672A\u79FB\u52A8\u5219\u5F39\u7A97\u4FDD\u6301\u6253\u5F00\uFF0C\u7EE7\u7EED\u9009\u62E9",
|
|
273
|
+
hkReleaseKey: "\u677E\u5F00 alt",
|
|
274
|
+
hkModify: "\u4FEE\u6539",
|
|
275
|
+
hkRecording: "\u6309\u4E0B\u65B0\u952E\u2026",
|
|
276
|
+
hkInvalid: "\u5FEB\u6377\u952E\u53EA\u652F\u6301\u5355\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57",
|
|
277
|
+
hkConflict: "alt+{k} \u5DF2\u7528\u4E8E\u201C{name}\u201D",
|
|
278
|
+
hkSaved: "\u5FEB\u6377\u952E\u5DF2\u66F4\u65B0",
|
|
279
|
+
hkNameLast: "\u5207\u6362\u4E0A\u6B21\u4F1A\u8BDD",
|
|
280
|
+
hkNamePrev: "\u4E0A\u79FB\u9AD8\u4EAE",
|
|
281
|
+
hkNameNext: "\u4E0B\u79FB\u9AD8\u4EAE",
|
|
282
|
+
hkNameRecent: "\u6700\u8FD1 10 \u6761",
|
|
283
|
+
hkNameAttention: "\u8FD0\u884C\u4E2D / \u672A\u67E5\u770B",
|
|
284
|
+
hkEditHint: "\u70B9\u51FB\u201C\u4FEE\u6539\u201D\u540E\u6309\u4E0B\u65B0\u6309\u952E\uFF08\u5B57\u6BCD\u6216\u6570\u5B57\uFF09\uFF0CEsc \u53D6\u6D88",
|
|
285
|
+
hkReset: "\u91CD\u7F6E\u4E3A\u9ED8\u8BA4",
|
|
286
|
+
hkResetDone: "\u5DF2\u6062\u590D\u9ED8\u8BA4\u952E\u4F4D",
|
|
241
287
|
featureFileActions: "\u6587\u4EF6\u83DC\u5355\u589E\u5F3A",
|
|
242
288
|
featureFileActionsDesc: "\u5728\u4F1A\u8BDD\u4E2D\u6587\u4EF6\u94FE\u63A5\u7684\u53F3\u952E\u83DC\u5355\u91CC\u65B0\u589E\u201C\u9ED8\u8BA4\u5E94\u7528\u6253\u5F00\u201D\u4E0E\u201C\u6253\u5F00\u6240\u5728\u76EE\u5F55\u201D\u3002",
|
|
243
289
|
featureImageCopy: "\u56FE\u7247\u53F3\u952E\u590D\u5236",
|
|
@@ -362,7 +408,7 @@
|
|
|
362
408
|
headroomStoppedWarn: "\u4EE3\u7406\u5DF2\u505C\u6B62\uFF1B\u6307\u5411 127.0.0.1 \u7684\u4F9B\u5E94\u5546\u5C06\u65E0\u6CD5\u8FDE\u63A5",
|
|
363
409
|
headroomBackend: "\u538B\u7F29\u8BBE\u5907",
|
|
364
410
|
headroomBackendAuto: "\u81EA\u52A8 \xB7 \u663E\u5361\u4F18\u5148",
|
|
365
|
-
headroomBackendCpu: "
|
|
411
|
+
headroomBackendCpu: "\u7701\u7535 \xB7 CPU \u4F18\u5148",
|
|
366
412
|
headroomBackendNative: "\uFF08\u539F\u751F\u503C\uFF09",
|
|
367
413
|
headroomBackendDesc: "\u81EA\u52A8\uFF1Aheadroom \u9009\u6700\u5FEB\u8BBE\u5907\uFF08CUDA/MPS \u663E\u5361\u4F18\u5148\uFF09\uFF1BCPU\uFF1A\u5F3A\u5236 CPU \u538B\u7F29\uFF0C\u7701\u7535\u4E14\u4E0D\u5360\u663E\u5B58\u3002\u4E5F\u652F\u6301 headroom \u539F\u751F\u503C\uFF08onnx\u3001pytorch_mps \u7B49\uFF09\u3002\u5207\u6362\u4F1A\u91CD\u542F\u4EE3\u7406\u7ACB\u5373\u751F\u6548\u3002",
|
|
368
414
|
headroomPower: "\u7701\u7535\u81EA\u52A8\u5207\u6362",
|
|
@@ -400,7 +446,7 @@
|
|
|
400
446
|
aliasSaved: "\u522B\u540D\u5DF2\u66F4\u65B0",
|
|
401
447
|
aliasCleared: "\u5DF2\u6062\u590D\u771F\u5B9E\u540D\u79F0",
|
|
402
448
|
aliasHint: "\u78C1\u76D8\u76EE\u5F55\u540D\u4E0D\u53D8\uFF1A\u7EC8\u7AEF\u3001\u6587\u4EF6\u7BA1\u7406\u5668\u4E0E\u5176\u4ED6\u5F15\u7528\u771F\u5B9E\u8DEF\u5F84\u7684\u754C\u9762\u4ECD\u663E\u793A\u539F\u540D\u3002",
|
|
403
|
-
featureProjectMenuDescNew: "\u9879\u76EE\u201C\u66F4\u591A\u201D\u83DC\u5355\u4E2D\u7684\
|
|
449
|
+
featureProjectMenuDescNew: "\u9879\u76EE\u201C\u66F4\u591A\u201D\u83DC\u5355\u4E2D\u7684\u6253\u5F00\u6587\u4EF6\u5939\u4E0E\u590D\u5236\u8DEF\u5F84\u3002\u5B98\u65B9\u5DF2\u652F\u6301\u4FEE\u6539\u9879\u76EE\u540D\u79F0\uFF08\u7F16\u8F91\u9879\u76EE\uFF09\uFF0C\u81EA\u5B9A\u4E49\u522B\u540D\u5DF2\u505C\u7528\u3002",
|
|
404
450
|
aliasMigrateTitle: "\u8FC1\u79FB\u9879\u76EE\u522B\u540D",
|
|
405
451
|
aliasMigrateDesc: "\u5F53\u524D ZCode \u5DF2\u652F\u6301\u4FEE\u6539\u9879\u76EE\u540D\u79F0\uFF08\u9879\u76EE\u201C\u66F4\u591A\u201D\u83DC\u5355 \u2192 \u7F16\u8F91\u9879\u76EE\uFF09\uFF0C\u81EA\u5B9A\u4E49\u522B\u540D\u529F\u80FD\u5DF2\u505C\u7528\u3002\u53EF\u628A\u5DF2\u4FDD\u5B58\u7684\u522B\u540D\u5199\u5165\u5B98\u65B9\u9879\u76EE\u540D\u79F0\uFF0C\u52FE\u9009\u8981\u8FC1\u79FB\u7684\u9879\u76EE\uFF1B\u8FC1\u79FB\u53EA\u6539\u9879\u76EE\u540D\u79F0\uFF0C\u78C1\u76D8\u76EE\u5F55\u4E0D\u53D7\u5F71\u54CD\u3002",
|
|
406
452
|
aliasMigrateItemHint: "\u8FC1\u79FB\u540E\u5C06\u4F5C\u4E3A\u9879\u76EE\u540D\u79F0\u4FDD\u5B58\uFF08\u53EF\u968F\u65F6\u5728\u201C\u7F16\u8F91\u9879\u76EE\u201D\u4E2D\u518D\u6539\uFF09\u3002\u4EC5\u65E0\u6807\u8BB0\u7684\u6761\u76EE\u53EF\u52FE\u9009\uFF1B\u5DF2\u8FC1\u79FB\u3001\u5DF2\u5E76\u5165\u3001\u9879\u76EE\u5DF2\u5220\u9664\u3001\u672C\u673A\u4E0D\u5B58\u5728\uFF08\u65E7\u673A\u5668\u8DEF\u5F84\uFF09\u4EE5\u53CA\u9879\u76EE\u5DF2\u91CD\u547D\u540D\u7684\u90FD\u4E0D\u53EF\u52FE\u9009\u2014\u2014\u8981\u6539\u8FD9\u4E9B\u9879\u76EE\u7684\u540D\u5B57\uFF0C\u76F4\u63A5\u7528\u9879\u76EE\u201C\u66F4\u591A\u201D\u83DC\u5355\u91CC\u7684\u201C\u7F16\u8F91\u9879\u76EE\u201D\u3002",
|
|
@@ -568,7 +614,7 @@
|
|
|
568
614
|
featureTaskOrder: "Sidebar session drag ordering",
|
|
569
615
|
featureTaskOrderDesc: "Makes session drags in Pinned, Projects and Groups persist across refreshes.",
|
|
570
616
|
featureSessionSwitch: "Session quick switch",
|
|
571
|
-
featureSessionSwitchDesc: "
|
|
617
|
+
featureSessionSwitchDesc: "{last} toggles between the current and the last session; hold alt and press {prev}/{next} to move the highlight across recently used sessions (10 shown initially, pressing {next} at the bottom loads 5 more), {recent} opens the last 10 directly, {attention} opens running / finished-but-unseen tasks; arrow keys also move the highlight, Enter or release alt to switch (like alt+tab)",
|
|
572
618
|
featureTitleLock: "Keep renamed session titles",
|
|
573
619
|
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.",
|
|
574
620
|
tabTitleGen: "Task name prompt",
|
|
@@ -596,7 +642,7 @@
|
|
|
596
642
|
titleGenTestOk: "Result: ",
|
|
597
643
|
titleGenTestFailed: "Generation failed",
|
|
598
644
|
featureWsRunning: "Running indicator when collapsed",
|
|
599
|
-
featureWsRunningDesc: "Shows the same spinning loader as running tasks on collapsed projects and on section headers (\u201CTasks\u201D, \u201CPinned\u201D) while any session is running; clears when they all finish.
|
|
645
|
+
featureWsRunningDesc: "Shows the same spinning loader as running tasks on collapsed projects and on section headers (\u201CTasks\u201D, \u201CPinned\u201D) while any session is running; clears when they all finish.",
|
|
600
646
|
tabPerformance: "Performance",
|
|
601
647
|
perfDesc: "ZCode keeps a session process resident for every project you have opened and never reclaims it, so memory grows with projects. When enabled, projects unused for a while with nothing running release their memory automatically: sessions are untouched and reload when reopened, with a few seconds wait on the first reply. The project in use, running sessions, background commands and scheduled tasks are never reclaimed. Background-command detection reads system process info via built-in tools (Linux / macOS / Windows); when unavailable, the feature disables itself.",
|
|
602
648
|
featureIdleReclaim: "Idle project memory reclaim",
|
|
@@ -624,10 +670,44 @@
|
|
|
624
670
|
userFontDesc: 'Font of question text in conversations; "default" follows the UI font.',
|
|
625
671
|
assistantFontName: "Answer font",
|
|
626
672
|
assistantFontDesc: 'Font of answer text in conversations (code blocks stay monospaced); "default" follows the UI font.',
|
|
627
|
-
switcherHint: "
|
|
673
|
+
switcherHint: "{prev} / {next} or \u2191 / \u2193 to choose, Enter or release alt to switch, Esc to cancel",
|
|
628
674
|
switcherCurrent: "current",
|
|
629
675
|
switcherEmpty: "No previous session yet (available after you switch sessions)",
|
|
630
676
|
switcherFailed: "Failed to switch to that session (it may have been deleted)",
|
|
677
|
+
switcherMore: "{n} more \xB7 press c to load",
|
|
678
|
+
switcherRunning: "running",
|
|
679
|
+
switcherUnseen: "unseen",
|
|
680
|
+
switcherAttentionHint: "Running / finished but unseen tasks \xB7 {prev} / {next} or \u2191 / \u2193 to choose, Enter or release alt to switch",
|
|
681
|
+
switcherAttentionEmpty: "No running or unseen tasks",
|
|
682
|
+
featureNewtabPanels: "Plugin panels on the new tab page",
|
|
683
|
+
featureNewtabPanelsDesc: 'The built-in "new tab page" only lists built-in panels and recommended official plugins; this adds cards for third-party marketplace plugin panels (headroom, rtk, \u2026) that open in the side pane.',
|
|
684
|
+
ntpDescSuffix: "plugin panel",
|
|
685
|
+
ntpNeedSession: "Open a task session first, then open plugin panels from the new tab page",
|
|
686
|
+
tabShortcuts: "Shortcuts",
|
|
687
|
+
hkTitle: "Session quick switch",
|
|
688
|
+
hkAltZ: "Toggle between the current and the last-used session",
|
|
689
|
+
hkAltX: "Move the highlight up (earlier sessions) in the popup",
|
|
690
|
+
hkAltC: "Move the highlight down (recent sessions); at the bottom it loads 5 more and highlights the first newly loaded entry",
|
|
691
|
+
hkAltE: "Open the last 10 tasks",
|
|
692
|
+
hkAltR: "Open running / finished-but-unseen tasks",
|
|
693
|
+
hkArrow: "Move the highlight while the popup is open (same rules as alt + {prev} / alt + {next})",
|
|
694
|
+
hkEnter: "Switch to the highlighted session",
|
|
695
|
+
hkEsc: "Cancel and close the popup",
|
|
696
|
+
hkRelease: "Releasing alt switches once the highlight has moved; otherwise the popup stays open for further selection",
|
|
697
|
+
hkReleaseKey: "release alt",
|
|
698
|
+
hkModify: "Change",
|
|
699
|
+
hkRecording: "press a key\u2026",
|
|
700
|
+
hkInvalid: "Shortcuts accept a single letter or digit only",
|
|
701
|
+
hkConflict: 'alt+{k} is already used by "{name}"',
|
|
702
|
+
hkSaved: "Shortcut updated",
|
|
703
|
+
hkNameLast: "last session",
|
|
704
|
+
hkNamePrev: "move up",
|
|
705
|
+
hkNameNext: "move down",
|
|
706
|
+
hkNameRecent: "last 10 tasks",
|
|
707
|
+
hkNameAttention: "running / unseen",
|
|
708
|
+
hkEditHint: 'Click "Change", press a new key (letter or digit); Esc cancels',
|
|
709
|
+
hkReset: "Reset to defaults",
|
|
710
|
+
hkResetDone: "Shortcuts reset to defaults",
|
|
631
711
|
featureFileActions: "File menu actions",
|
|
632
712
|
featureFileActionsDesc: 'Adds "Open with default app" and "Reveal in file manager" to the right-click menu of file links in chat.',
|
|
633
713
|
featureImageCopy: "Image right-click copy",
|
|
@@ -752,7 +832,7 @@
|
|
|
752
832
|
headroomStoppedWarn: "Proxy stopped; providers pointing at 127.0.0.1 cannot connect.",
|
|
753
833
|
headroomBackend: "Compression device",
|
|
754
834
|
headroomBackendAuto: "Auto \xB7 GPU first",
|
|
755
|
-
headroomBackendCpu: "
|
|
835
|
+
headroomBackendCpu: "Power saving \xB7 CPU first",
|
|
756
836
|
headroomBackendNative: " (native)",
|
|
757
837
|
headroomBackendDesc: "Auto lets headroom pick the fastest device (CUDA/MPS); CPU forces CPU compression (power saving, no VRAM). Native headroom values (onnx, pytorch_mps, \u2026) also work. Switching restarts the proxy to apply.",
|
|
758
838
|
headroomPower: "Power-save auto switch",
|
|
@@ -790,7 +870,7 @@
|
|
|
790
870
|
aliasSaved: "Alias updated.",
|
|
791
871
|
aliasCleared: "Real name restored.",
|
|
792
872
|
aliasHint: "The directory name on disk is unchanged: terminals, file managers and other path-based UI still show the real name.",
|
|
793
|
-
featureProjectMenuDescNew: '
|
|
873
|
+
featureProjectMenuDescNew: 'Open folder and copy path in the project "More" menu. Renaming is built in since ZCode 3.16.1 ("Edit project"), so the custom alias is retired.',
|
|
794
874
|
aliasMigrateTitle: "Migrate project aliases",
|
|
795
875
|
aliasMigrateDesc: 'This ZCode supports renaming projects (project "More" menu \u2192 Edit project), so the custom alias feature is retired. Write your saved aliases into the official project names by picking the projects below; only the project name changes, folders on disk are untouched.',
|
|
796
876
|
aliasMigrateItemHint: 'The alias becomes the project name (re-editable anytime via "Edit project"). Only unmarked entries can be checked; migrated, merged, deleted, not-on-this-machine and manually-renamed ones cannot \u2014 to rename those projects, use "Edit project" in the project "More" menu directly.',
|
|
@@ -1601,6 +1681,20 @@
|
|
|
1601
1681
|
background-color: color-mix(in oklab, var(--color-primary, #111) 12%, transparent);
|
|
1602
1682
|
color: var(--color-foreground-subtle, #666);
|
|
1603
1683
|
}
|
|
1684
|
+
/* attention \u5F39\u7A97\uFF08alt+r\uFF09\u7684\u884C\u72B6\u6001\u6807\u7B7E\uFF1A\u8FD0\u884C\u4E2D\u7EFF\u3001\u672A\u67E5\u770B\u7425\u73C0 */
|
|
1685
|
+
.zcodepro-switcher-tag-run {
|
|
1686
|
+
background-color: color-mix(in oklab, var(--color-emerald-500, #10b981) 20%, transparent);
|
|
1687
|
+
}
|
|
1688
|
+
.zcodepro-switcher-tag-new {
|
|
1689
|
+
background-color: color-mix(in oklab, var(--color-amber-500, #f59e0b) 22%, transparent);
|
|
1690
|
+
}
|
|
1691
|
+
/* \u5217\u8868\u5E95\u90E8\u201C\u8FD8\u6709 N \u6761\u201D\u63D0\u793A\u884C */
|
|
1692
|
+
.zcodepro-switcher-more {
|
|
1693
|
+
padding: 6px 12px 2px;
|
|
1694
|
+
font-size: 11px;
|
|
1695
|
+
text-align: center;
|
|
1696
|
+
color: var(--color-muted-foreground, #888);
|
|
1697
|
+
}
|
|
1604
1698
|
.zcodepro-switcher-ws {
|
|
1605
1699
|
font-size: 11px;
|
|
1606
1700
|
color: var(--color-muted-foreground, #888);
|
|
@@ -2756,10 +2850,10 @@
|
|
|
2756
2850
|
function startImageMenu() {
|
|
2757
2851
|
if (typeof window === "undefined") return;
|
|
2758
2852
|
if (typeof navigator.clipboard?.write !== "function" || typeof window.ClipboardItem === "undefined") return;
|
|
2759
|
-
let
|
|
2853
|
+
let enabled7 = true;
|
|
2760
2854
|
const refresh = () => {
|
|
2761
2855
|
void getConfig().then((c) => {
|
|
2762
|
-
|
|
2856
|
+
enabled7 = !(c.features && c.features.imageCopy === false);
|
|
2763
2857
|
});
|
|
2764
2858
|
};
|
|
2765
2859
|
refresh();
|
|
@@ -2768,7 +2862,7 @@
|
|
|
2768
2862
|
const img = copyTargetOf(e.target, e.clientX, e.clientY);
|
|
2769
2863
|
if (!img) return;
|
|
2770
2864
|
e.preventDefault();
|
|
2771
|
-
if (
|
|
2865
|
+
if (enabled7) showMenu(e.clientX, e.clientY, img);
|
|
2772
2866
|
refresh();
|
|
2773
2867
|
}, true);
|
|
2774
2868
|
}
|
|
@@ -3845,6 +3939,32 @@
|
|
|
3845
3939
|
}
|
|
3846
3940
|
pluginsStatusLine.textContent = n > 0 ? L.pluginsUpdatesFound.replaceAll("{n}", String(n)) : L.pluginsUpToDate;
|
|
3847
3941
|
})();
|
|
3942
|
+
const HK_ACTIONS = [
|
|
3943
|
+
["switchLast", "hkAltZ"],
|
|
3944
|
+
["switchPrev", "hkAltX"],
|
|
3945
|
+
["switchNext", "hkAltC"],
|
|
3946
|
+
["switchRecent", "hkAltE"],
|
|
3947
|
+
["switchAttention", "hkAltR"]
|
|
3948
|
+
];
|
|
3949
|
+
const hkNames = () => ({
|
|
3950
|
+
switchLast: L.hkNameLast,
|
|
3951
|
+
switchPrev: L.hkNamePrev,
|
|
3952
|
+
switchNext: L.hkNameNext,
|
|
3953
|
+
switchRecent: L.hkNameRecent,
|
|
3954
|
+
switchAttention: L.hkNameAttention
|
|
3955
|
+
});
|
|
3956
|
+
const hkKeys = () => {
|
|
3957
|
+
const sc = config.shortcuts || {};
|
|
3958
|
+
const keys = {};
|
|
3959
|
+
for (const [a] of HK_ACTIONS) {
|
|
3960
|
+
keys[a] = /^[a-z0-9]$/.test(sc[a]) ? sc[a] : DEFAULT_SHORTCUTS[a];
|
|
3961
|
+
}
|
|
3962
|
+
return keys;
|
|
3963
|
+
};
|
|
3964
|
+
const sessionSwitchDesc = () => {
|
|
3965
|
+
const k = hkKeys();
|
|
3966
|
+
return L.featureSessionSwitchDesc.replaceAll("{last}", "alt+" + k.switchLast).replaceAll("{prev}", k.switchPrev).replaceAll("{next}", k.switchNext).replaceAll("{recent}", "alt+" + k.switchRecent).replaceAll("{attention}", "alt+" + k.switchAttention);
|
|
3967
|
+
};
|
|
3848
3968
|
const refreshRows = () => {
|
|
3849
3969
|
const f = config.features || {};
|
|
3850
3970
|
rows.replaceChildren(
|
|
@@ -3860,7 +3980,7 @@
|
|
|
3860
3980
|
if (await setFeature("taskOrder", next)) f.taskOrder = next;
|
|
3861
3981
|
refreshRows();
|
|
3862
3982
|
}),
|
|
3863
|
-
settingRow(L.featureSessionSwitch,
|
|
3983
|
+
settingRow(L.featureSessionSwitch, sessionSwitchDesc(), f.sessionSwitch !== false, async () => {
|
|
3864
3984
|
const next = !(f.sessionSwitch !== false);
|
|
3865
3985
|
if (await setFeature("sessionSwitch", next)) f.sessionSwitch = next;
|
|
3866
3986
|
refreshRows();
|
|
@@ -3890,6 +4010,11 @@
|
|
|
3890
4010
|
if (await setFeature("wsRunningSpin", next)) f.wsRunningSpin = next;
|
|
3891
4011
|
refreshRows();
|
|
3892
4012
|
}),
|
|
4013
|
+
settingRow(L.featureNewtabPanels, L.featureNewtabPanelsDesc, f.newtabPanels !== false, async () => {
|
|
4014
|
+
const next = !(f.newtabPanels !== false);
|
|
4015
|
+
if (await setFeature("newtabPanels", next)) f.newtabPanels = next;
|
|
4016
|
+
refreshRows();
|
|
4017
|
+
}),
|
|
3893
4018
|
(() => {
|
|
3894
4019
|
const repoLink = h("span", {
|
|
3895
4020
|
class: "cursor-pointer underline-offset-4 hover:underline",
|
|
@@ -3972,6 +4097,127 @@
|
|
|
3972
4097
|
h("div", {}, rows),
|
|
3973
4098
|
communityCards
|
|
3974
4099
|
);
|
|
4100
|
+
let hkRecording = null;
|
|
4101
|
+
let hkKeyHandler = null;
|
|
4102
|
+
const hkCard = h("div", { class: "divide-y divide-border rounded-xl border border-border" });
|
|
4103
|
+
const hkCell = (keyLabel, desc, extra) => h(
|
|
4104
|
+
"div",
|
|
4105
|
+
{ class: "flex items-start gap-3 px-3 py-2.5" },
|
|
4106
|
+
h("kbd", {
|
|
4107
|
+
class: "shrink-0 min-w-20 rounded-md border border-border px-2 py-0.5 text-center text-ui-xs text-foreground-subtle",
|
|
4108
|
+
style: "font-family: ui-monospace, SFMono-Regular, Menlo, monospace; line-height: 1.5;"
|
|
4109
|
+
}, keyLabel),
|
|
4110
|
+
h("div", { class: "min-w-0 flex-1 text-ui-sm text-foreground-subtle" }, desc),
|
|
4111
|
+
extra ? h("div", { class: "ml-auto shrink-0 pl-3" }, extra) : null
|
|
4112
|
+
);
|
|
4113
|
+
const renderShortcuts = () => {
|
|
4114
|
+
const keys = hkKeys();
|
|
4115
|
+
const names = hkNames();
|
|
4116
|
+
hkCard.replaceChildren(
|
|
4117
|
+
...HK_ACTIONS.map(([a, descKey]) => {
|
|
4118
|
+
const recording = hkRecording === a;
|
|
4119
|
+
return hkCell(
|
|
4120
|
+
recording ? L.hkRecording : "alt + " + keys[a],
|
|
4121
|
+
L[descKey],
|
|
4122
|
+
btnSmall(recording ? L.hkRecording : L.hkModify, () => {
|
|
4123
|
+
recording ? stopHkRecording() : startHkRecording(a);
|
|
4124
|
+
})
|
|
4125
|
+
);
|
|
4126
|
+
}),
|
|
4127
|
+
hkCell("\u2191 / \u2193", L.hkArrow.replaceAll("{prev}", keys.switchPrev).replaceAll("{next}", keys.switchNext)),
|
|
4128
|
+
hkCell("Enter", L.hkEnter),
|
|
4129
|
+
hkCell("Esc", L.hkEsc),
|
|
4130
|
+
hkCell(L.hkReleaseKey, L.hkRelease)
|
|
4131
|
+
);
|
|
4132
|
+
};
|
|
4133
|
+
const stopHkRecording = () => {
|
|
4134
|
+
hkRecording = null;
|
|
4135
|
+
if (hkKeyHandler) {
|
|
4136
|
+
document.removeEventListener("keydown", hkKeyHandler, true);
|
|
4137
|
+
hkKeyHandler = null;
|
|
4138
|
+
}
|
|
4139
|
+
renderShortcuts();
|
|
4140
|
+
};
|
|
4141
|
+
const startHkRecording = (action) => {
|
|
4142
|
+
hkRecording = action;
|
|
4143
|
+
if (!hkKeyHandler) {
|
|
4144
|
+
const myOverlay = document.querySelector(".zcodepro-overlay");
|
|
4145
|
+
hkKeyHandler = (e) => {
|
|
4146
|
+
if (!myOverlay || !myOverlay.isConnected) {
|
|
4147
|
+
stopHkRecording();
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4150
|
+
if (e.isComposing) return;
|
|
4151
|
+
e.preventDefault();
|
|
4152
|
+
e.stopImmediatePropagation();
|
|
4153
|
+
if (e.key === "Escape") {
|
|
4154
|
+
stopHkRecording();
|
|
4155
|
+
return;
|
|
4156
|
+
}
|
|
4157
|
+
const k = e.key.toLowerCase();
|
|
4158
|
+
if (!/^[a-z0-9]$/.test(k)) {
|
|
4159
|
+
showToast(L.hkInvalid, "error");
|
|
4160
|
+
return;
|
|
4161
|
+
}
|
|
4162
|
+
const keys = hkKeys();
|
|
4163
|
+
const names = hkNames();
|
|
4164
|
+
const conflict = HK_ACTIONS.find(([a2]) => a2 !== hkRecording && keys[a2] === k);
|
|
4165
|
+
if (conflict) {
|
|
4166
|
+
showToast(L.hkConflict.replaceAll("{k}", k).replaceAll("{name}", names[conflict[0]]), "error");
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4169
|
+
const a = hkRecording;
|
|
4170
|
+
stopHkRecording();
|
|
4171
|
+
void (async () => {
|
|
4172
|
+
const res = await rpc("/config", { method: "POST", body: { shortcuts: { [a]: k } } });
|
|
4173
|
+
clearConfigCache();
|
|
4174
|
+
window.dispatchEvent(new CustomEvent("zcodepro:config-changed"));
|
|
4175
|
+
if (!res.ok) {
|
|
4176
|
+
showToast(L.failed + ": " + errText(res), "error");
|
|
4177
|
+
renderShortcuts();
|
|
4178
|
+
return;
|
|
4179
|
+
}
|
|
4180
|
+
if (res.config && res.config.shortcuts) config.shortcuts = res.config.shortcuts;
|
|
4181
|
+
showToast(L.hkSaved, "success");
|
|
4182
|
+
refreshRows();
|
|
4183
|
+
renderShortcuts();
|
|
4184
|
+
})();
|
|
4185
|
+
};
|
|
4186
|
+
document.addEventListener("keydown", hkKeyHandler, true);
|
|
4187
|
+
}
|
|
4188
|
+
renderShortcuts();
|
|
4189
|
+
};
|
|
4190
|
+
renderShortcuts();
|
|
4191
|
+
const resetShortcuts = async () => {
|
|
4192
|
+
stopHkRecording();
|
|
4193
|
+
const all = {};
|
|
4194
|
+
for (const [a] of HK_ACTIONS) all[a] = DEFAULT_SHORTCUTS[a];
|
|
4195
|
+
const res = await rpc("/config", { method: "POST", body: { shortcuts: all } });
|
|
4196
|
+
clearConfigCache();
|
|
4197
|
+
window.dispatchEvent(new CustomEvent("zcodepro:config-changed"));
|
|
4198
|
+
if (!res.ok) {
|
|
4199
|
+
showToast(L.failed + ": " + errText(res), "error");
|
|
4200
|
+
return;
|
|
4201
|
+
}
|
|
4202
|
+
if (res.config && res.config.shortcuts) config.shortcuts = res.config.shortcuts;
|
|
4203
|
+
showToast(L.hkResetDone, "success");
|
|
4204
|
+
refreshRows();
|
|
4205
|
+
renderShortcuts();
|
|
4206
|
+
};
|
|
4207
|
+
const paneShortcuts = h(
|
|
4208
|
+
"div",
|
|
4209
|
+
{ role: "tabpanel", class: "mt-4", style: "display:none" },
|
|
4210
|
+
h("div", { class: "mb-2 text-ui-sm font-medium" }, L.hkTitle),
|
|
4211
|
+
h(
|
|
4212
|
+
"div",
|
|
4213
|
+
{ class: "mb-2 flex items-center gap-2" },
|
|
4214
|
+
h("div", { class: "min-w-0 flex-1 text-ui-xs/relaxed text-foreground-subtle" }, L.hkEditHint),
|
|
4215
|
+
h("div", { class: "shrink-0" }, btnSmall(L.hkReset, () => {
|
|
4216
|
+
void resetShortcuts();
|
|
4217
|
+
}))
|
|
4218
|
+
),
|
|
4219
|
+
hkCard
|
|
4220
|
+
);
|
|
3975
4221
|
const paneStyles = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3976
4222
|
const panePerf = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3977
4223
|
const paneAgents = h("div", { role: "tabpanel", class: "mt-2", style: "display:none" });
|
|
@@ -3982,9 +4228,10 @@
|
|
|
3982
4228
|
const paneHeadroom = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3983
4229
|
const paneTitleGen = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3984
4230
|
const paneDebug = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3985
|
-
const panes = { features: paneFeatures, styles: paneStyles, perf: panePerf, agents: paneAgents, proxy: paneProxy, sync: paneSync, vision: paneVision, headroom: paneHeadroom, rtk: paneRtk, debug: paneDebug };
|
|
4231
|
+
const panes = { features: paneFeatures, shortcuts: paneShortcuts, styles: paneStyles, perf: panePerf, agents: paneAgents, proxy: paneProxy, sync: paneSync, vision: paneVision, headroom: paneHeadroom, rtk: paneRtk, debug: paneDebug };
|
|
3986
4232
|
const tabDefs = [
|
|
3987
4233
|
["features", L.tabFeatures],
|
|
4234
|
+
["shortcuts", L.tabShortcuts],
|
|
3988
4235
|
["agents", L.tabBehavior],
|
|
3989
4236
|
["styles", L.tabStyles],
|
|
3990
4237
|
["perf", L.tabPerformance],
|
|
@@ -4008,6 +4255,7 @@
|
|
|
4008
4255
|
}, label)));
|
|
4009
4256
|
const switchTab = (name) => {
|
|
4010
4257
|
activeTab = name;
|
|
4258
|
+
if (name !== "shortcuts" && hkRecording) stopHkRecording();
|
|
4011
4259
|
for (const [id, pane] of Object.entries(panes)) pane.style.display = id === name ? "" : "none";
|
|
4012
4260
|
renderTabs();
|
|
4013
4261
|
};
|
|
@@ -6077,6 +6325,7 @@
|
|
|
6077
6325
|
statusLine,
|
|
6078
6326
|
tablist,
|
|
6079
6327
|
paneFeatures,
|
|
6328
|
+
paneShortcuts,
|
|
6080
6329
|
paneAgents,
|
|
6081
6330
|
paneStyles,
|
|
6082
6331
|
panePerf,
|
|
@@ -6169,1318 +6418,1634 @@
|
|
|
6169
6418
|
}
|
|
6170
6419
|
}
|
|
6171
6420
|
|
|
6172
|
-
// src/inject/features/
|
|
6173
|
-
var
|
|
6421
|
+
// src/inject/features/ws-running.js
|
|
6422
|
+
var installed2 = false;
|
|
6423
|
+
var enabled2 = true;
|
|
6174
6424
|
var SCAN_DEBOUNCE_MS = 150;
|
|
6175
6425
|
var SCAN_FALLBACK_MS = 5e3;
|
|
6176
|
-
var
|
|
6177
|
-
var
|
|
6178
|
-
var
|
|
6179
|
-
var
|
|
6180
|
-
var
|
|
6181
|
-
var
|
|
6182
|
-
var
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6426
|
+
var PEEK_FIRST_MS = 2e4;
|
|
6427
|
+
var PEEK_REPEAT_MS = 6e4;
|
|
6428
|
+
var PEEK_SETTLE_MS = 160;
|
|
6429
|
+
var PEEK_MAX_MS = 1500;
|
|
6430
|
+
var PEEK_UNMOUNT_WAIT_MS = 800;
|
|
6431
|
+
var CONFIG_POLL_MIN_MS = 5e3;
|
|
6432
|
+
var CONFIG_POLL_MAX_MS = 6e4;
|
|
6433
|
+
var TASK_SEL = "[data-task-item-key]";
|
|
6434
|
+
var WS_SEL = () => projectRowSelector();
|
|
6435
|
+
function findWsRow(ws) {
|
|
6436
|
+
return findProjectRow(ws);
|
|
6437
|
+
}
|
|
6438
|
+
var LOADER_FALLBACK_PATHS = [
|
|
6439
|
+
"M12 2v4",
|
|
6440
|
+
"m16.2 7.8 2.9-2.9",
|
|
6441
|
+
"M18 12h4",
|
|
6442
|
+
"m19.8 16.2-2.9 2.9",
|
|
6443
|
+
"M12 18v4",
|
|
6444
|
+
"m7.8 19.8-2.9-2.9",
|
|
6445
|
+
"M6 12H2",
|
|
6446
|
+
"m4.2 7.8 2.9-2.9"
|
|
6447
|
+
];
|
|
6448
|
+
function makeLoaderSvg(baseClass) {
|
|
6449
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
6450
|
+
const proto = document.querySelector("svg.lucide-loader");
|
|
6451
|
+
if (proto) {
|
|
6452
|
+
const clone = proto.cloneNode(true);
|
|
6453
|
+
const origClass = proto.getAttribute("class") || "";
|
|
6454
|
+
const keep = origClass.split(/\s+/).filter((c) => /^(size-|text-)/.test(c)).join(" ");
|
|
6455
|
+
clone.setAttribute("class", ((keep || baseClass) + " animate-spin zcodepro-ws-loader").trim());
|
|
6456
|
+
return clone;
|
|
6457
|
+
}
|
|
6458
|
+
const svg = document.createElementNS(ns, "svg");
|
|
6459
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
6460
|
+
svg.setAttribute("fill", "none");
|
|
6461
|
+
svg.setAttribute("stroke", "currentColor");
|
|
6462
|
+
svg.setAttribute("stroke-width", "2");
|
|
6463
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
6464
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
6465
|
+
svg.setAttribute("class", (baseClass + " animate-spin zcodepro-ws-loader").trim());
|
|
6466
|
+
for (const d of LOADER_FALLBACK_PATHS) {
|
|
6467
|
+
const path = document.createElementNS(ns, "path");
|
|
6468
|
+
path.setAttribute("d", d);
|
|
6469
|
+
svg.append(path);
|
|
6470
|
+
}
|
|
6471
|
+
return svg;
|
|
6472
|
+
}
|
|
6473
|
+
function setRunningIcon(holder, on) {
|
|
6474
|
+
if (!holder) return;
|
|
6475
|
+
if (on) {
|
|
6476
|
+
if (holder.querySelector(":scope > svg.zcodepro-ws-loader")) return;
|
|
6477
|
+
const orig0 = holder.querySelector(":scope > svg:not(.zcodepro-ws-loader)");
|
|
6478
|
+
const base = (orig0 ? orig0.getAttribute("class") || "" : "size-4").replace(/lucide-[a-z-]*/g, "").trim() || "size-4";
|
|
6479
|
+
holder.append(makeLoaderSvg(base));
|
|
6480
|
+
} else {
|
|
6481
|
+
holder.querySelectorAll(":scope > svg.zcodepro-ws-loader").forEach((el) => el.remove());
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
function iconHolderOf(row) {
|
|
6485
|
+
if (row.hasAttribute && row.hasAttribute("data-project-id")) {
|
|
6486
|
+
const toggle2 = row.querySelector('[data-testid="virtual-project-toggle"]');
|
|
6487
|
+
return toggle2 ? toggle2.querySelector(":scope > span") : null;
|
|
6488
|
+
}
|
|
6489
|
+
return row.firstElementChild && row.firstElementChild.querySelector(":scope > span");
|
|
6490
|
+
}
|
|
6491
|
+
function isRunningRow(el) {
|
|
6492
|
+
const scope = el.firstElementChild;
|
|
6493
|
+
if (!scope) return false;
|
|
6494
|
+
const svg = scope.querySelector('svg[class*="lucide-loader"]');
|
|
6495
|
+
return !!svg;
|
|
6496
|
+
}
|
|
6497
|
+
var runningByWs = /* @__PURE__ */ new Map();
|
|
6498
|
+
var peekTimers = /* @__PURE__ */ new Map();
|
|
6499
|
+
var activePeeks = /* @__PURE__ */ new Set();
|
|
6500
|
+
var peekedWs = /* @__PURE__ */ new Set();
|
|
6501
|
+
var wsWithRows = /* @__PURE__ */ new Set();
|
|
6502
|
+
var servicesRef = null;
|
|
6503
|
+
function findServices() {
|
|
6504
|
+
if (servicesRef) return servicesRef;
|
|
6505
|
+
try {
|
|
6506
|
+
const rootEl = document.getElementById("root");
|
|
6507
|
+
const containerKey = rootEl && Object.keys(rootEl).find((k) => k.startsWith("__reactContainer$"));
|
|
6508
|
+
if (!containerKey) return null;
|
|
6509
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6510
|
+
let found = null;
|
|
6511
|
+
const scanObj = (o) => {
|
|
6512
|
+
if (!o || typeof o !== "object" || seen.has(o) || found) return;
|
|
6513
|
+
seen.add(o);
|
|
6514
|
+
const ts = o.zcodeTaskService;
|
|
6515
|
+
if (ts && typeof ts === "object" && typeof ts.releaseWorkspacePreparation === "function") found = o;
|
|
6516
|
+
};
|
|
6517
|
+
let visited = 0;
|
|
6518
|
+
const visit = (f) => {
|
|
6519
|
+
if (!f || found || visited > 6e4) return;
|
|
6520
|
+
visited++;
|
|
6521
|
+
for (const holder of [f.memoizedProps, f.memoizedState]) {
|
|
6522
|
+
if (!holder || typeof holder !== "object") continue;
|
|
6523
|
+
scanObj(holder);
|
|
6524
|
+
for (const v of Object.values(holder)) {
|
|
6525
|
+
if (v && typeof v === "object") scanObj(v);
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
visit(f.child);
|
|
6529
|
+
visit(f.sibling);
|
|
6530
|
+
};
|
|
6531
|
+
visit(rootEl[containerKey]);
|
|
6532
|
+
if (found) servicesRef = found;
|
|
6533
|
+
return found;
|
|
6534
|
+
} catch {
|
|
6535
|
+
return null;
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6538
|
+
async function authoritativeIdle(ws) {
|
|
6539
|
+
const services = findServices();
|
|
6540
|
+
const ts = services && services.zcodeTaskService;
|
|
6541
|
+
if (!ts || typeof ts.listActiveTaskIds !== "function") return null;
|
|
6542
|
+
try {
|
|
6543
|
+
const base = String(ws).replace(/[\\/]+$/, "");
|
|
6544
|
+
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
6545
|
+
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
6546
|
+
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
6547
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return null;
|
|
6548
|
+
if (!ids.length) return true;
|
|
6549
|
+
const st = await rpc("/task-statuses?ids=" + encodeURIComponent(ids.join(","))).catch(() => null);
|
|
6550
|
+
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
6551
|
+
const live = (id) => {
|
|
6552
|
+
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
6553
|
+
if (rec === void 0) return true;
|
|
6554
|
+
if (!TERMINAL.has(rec.status)) return true;
|
|
6555
|
+
return Date.now() - rec.updatedAt < 3e5;
|
|
6556
|
+
};
|
|
6557
|
+
return !ids.some(live);
|
|
6558
|
+
} catch {
|
|
6559
|
+
return null;
|
|
6560
|
+
}
|
|
6186
6561
|
}
|
|
6187
6562
|
function workspaceOf(key) {
|
|
6188
6563
|
const i = key.indexOf(":sess_");
|
|
6189
6564
|
return i > 0 ? key.slice(0, i) : key;
|
|
6190
6565
|
}
|
|
6191
|
-
function
|
|
6192
|
-
|
|
6566
|
+
function wsHead(row) {
|
|
6567
|
+
return row.matches("[aria-expanded]") ? row : row.querySelector("[aria-expanded]");
|
|
6568
|
+
}
|
|
6569
|
+
function domRowsOf(ws) {
|
|
6570
|
+
return [...document.querySelectorAll(TASK_SEL)].filter((e) => workspaceOf(e.getAttribute("data-task-item-key") || "") === ws);
|
|
6571
|
+
}
|
|
6572
|
+
function currentTaskRow() {
|
|
6573
|
+
for (const el of document.querySelectorAll(TASK_SEL)) {
|
|
6193
6574
|
if ((el.className + "").includes("bg-selected")) return el;
|
|
6194
6575
|
}
|
|
6195
6576
|
return null;
|
|
6196
6577
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
mru.unshift(key);
|
|
6202
|
-
if (mru.length > MRU_LIMIT) mru.length = MRU_LIMIT;
|
|
6578
|
+
var synthClick = (el) => {
|
|
6579
|
+
try {
|
|
6580
|
+
el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
6581
|
+
} catch {
|
|
6203
6582
|
}
|
|
6583
|
+
};
|
|
6584
|
+
function toggleNavSafe(head) {
|
|
6585
|
+
const cur = currentTaskRow();
|
|
6586
|
+
const backKey = cur ? cur.getAttribute("data-task-item-key") : "";
|
|
6587
|
+
synthClick(head);
|
|
6588
|
+
if (!backKey) return;
|
|
6589
|
+
const back = cur && cur.isConnected ? cur : document.querySelector(`${TASK_SEL}[data-task-item-key="${CSS.escape(backKey)}"]`);
|
|
6590
|
+
if (back) synthClick(back);
|
|
6204
6591
|
}
|
|
6205
6592
|
function scan() {
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6593
|
+
wsWithRows = /* @__PURE__ */ new Set();
|
|
6594
|
+
for (const el of document.querySelectorAll(TASK_SEL)) {
|
|
6595
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6596
|
+
const ws = workspaceOf(key);
|
|
6597
|
+
if (!ws) continue;
|
|
6598
|
+
wsWithRows.add(ws);
|
|
6599
|
+
const run = isRunningRow(el);
|
|
6600
|
+
let set = runningByWs.get(ws);
|
|
6601
|
+
if (run) {
|
|
6602
|
+
if (!set) {
|
|
6603
|
+
set = /* @__PURE__ */ new Set();
|
|
6604
|
+
runningByWs.set(ws, set);
|
|
6605
|
+
}
|
|
6606
|
+
set.add(key);
|
|
6607
|
+
} else if (set) {
|
|
6608
|
+
set.delete(key);
|
|
6609
|
+
}
|
|
6210
6610
|
}
|
|
6611
|
+
syncPeeks();
|
|
6612
|
+
apply();
|
|
6211
6613
|
}
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
if (
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
} else if (inTaskRow(m.target)) {
|
|
6221
|
-
return true;
|
|
6222
|
-
} else {
|
|
6223
|
-
for (const n of m.addedNodes) {
|
|
6224
|
-
if (n instanceof Element && (n.matches(rowSel2) || !!n.querySelector(rowSel2))) return true;
|
|
6225
|
-
}
|
|
6614
|
+
function handleRemovals(muts) {
|
|
6615
|
+
const removed = [];
|
|
6616
|
+
for (const m of muts) {
|
|
6617
|
+
if (m.type !== "childList") continue;
|
|
6618
|
+
for (const n of m.removedNodes) {
|
|
6619
|
+
if (!(n instanceof Element)) continue;
|
|
6620
|
+
if (n.matches(TASK_SEL)) removed.push(n);
|
|
6621
|
+
else for (const r of n.querySelectorAll(TASK_SEL)) removed.push(r);
|
|
6226
6622
|
}
|
|
6227
6623
|
}
|
|
6228
|
-
return
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
if (scanDebounce) return;
|
|
6232
|
-
scanDebounce = setTimeout(() => {
|
|
6233
|
-
scanDebounce = 0;
|
|
6234
|
-
scan();
|
|
6235
|
-
}, SCAN_DEBOUNCE_MS);
|
|
6236
|
-
}
|
|
6237
|
-
async function switchTo(key) {
|
|
6238
|
-
const find = () => document.querySelector(`[data-task-item-key="${CSS.escape(key)}"]`);
|
|
6239
|
-
let item = find();
|
|
6240
|
-
if (!item) {
|
|
6624
|
+
if (!removed.length) return;
|
|
6625
|
+
const infos = removed.map((el) => {
|
|
6626
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6241
6627
|
const ws = workspaceOf(key);
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6628
|
+
return key && ws ? { key, ws, run: isRunningRow(el) } : null;
|
|
6629
|
+
}).filter(Boolean);
|
|
6630
|
+
if (!infos.length) return;
|
|
6631
|
+
setTimeout(() => {
|
|
6632
|
+
for (const info of infos) {
|
|
6633
|
+
const row = findWsRow(info.ws);
|
|
6634
|
+
const head = row && wsHead(row);
|
|
6635
|
+
const collapsed = !row || !head || head.getAttribute("aria-expanded") === "false";
|
|
6636
|
+
let set = runningByWs.get(info.ws);
|
|
6637
|
+
if (collapsed && info.run) {
|
|
6638
|
+
if (!set) {
|
|
6639
|
+
set = /* @__PURE__ */ new Set();
|
|
6640
|
+
runningByWs.set(info.ws, set);
|
|
6641
|
+
}
|
|
6642
|
+
set.add(info.key);
|
|
6643
|
+
} else if (set) {
|
|
6644
|
+
set.delete(info.key);
|
|
6645
|
+
}
|
|
6247
6646
|
}
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
item.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
6252
|
-
return true;
|
|
6647
|
+
syncPeeks();
|
|
6648
|
+
apply();
|
|
6649
|
+
}, 0);
|
|
6253
6650
|
}
|
|
6254
|
-
function
|
|
6255
|
-
|
|
6256
|
-
const
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6651
|
+
function apply() {
|
|
6652
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6653
|
+
for (const row of document.querySelectorAll(WS_SEL())) {
|
|
6654
|
+
const path = rowPath(row);
|
|
6655
|
+
if (!path) continue;
|
|
6656
|
+
seen.add(path);
|
|
6657
|
+
const head = wsHead(row);
|
|
6658
|
+
const collapsed = !head || head.getAttribute("aria-expanded") === "false";
|
|
6659
|
+
const domRunning = !!(runningByWs.get(path) && runningByWs.get(path).size);
|
|
6660
|
+
const normP = (v) => String(v || "").replace(/[\\/]+$/, "");
|
|
6661
|
+
const running = enabled2 && collapsed && (activeProjectPaths.size ? [...activeProjectPaths].some((p2) => normP(p2) === normP(path)) : domRunning);
|
|
6662
|
+
const icon = iconHolderOf(row);
|
|
6663
|
+
icon?.classList.toggle("zcodepro-ws-running", running);
|
|
6664
|
+
setRunningIcon(icon, running);
|
|
6263
6665
|
}
|
|
6666
|
+
applySectionSpin();
|
|
6667
|
+
for (const ws of [...runningByWs.keys()]) if (!seen.has(ws)) runningByWs.delete(ws);
|
|
6264
6668
|
}
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6669
|
+
var headInfoCache = /* @__PURE__ */ new WeakMap();
|
|
6670
|
+
var PROJECT_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u9879\u76EE", "projects"]);
|
|
6671
|
+
var TASK_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u4EFB\u52A1", "tasks"]);
|
|
6672
|
+
function kindFromHeadText(head) {
|
|
6673
|
+
const text = (head.textContent || "").trim().toLowerCase();
|
|
6674
|
+
if (PROJECT_HEAD_TEXTS.has(text)) return "project";
|
|
6675
|
+
if (TASK_HEAD_TEXTS.has(text)) return "task";
|
|
6676
|
+
return null;
|
|
6270
6677
|
}
|
|
6271
|
-
function
|
|
6272
|
-
const
|
|
6273
|
-
|
|
6274
|
-
|
|
6678
|
+
function sectionHeads() {
|
|
6679
|
+
const heads = [];
|
|
6680
|
+
for (const sv of document.querySelectorAll("svg[data-purpose-section-chevron]")) {
|
|
6681
|
+
const btn = sv.closest("button");
|
|
6682
|
+
if (btn) heads.push(btn);
|
|
6683
|
+
}
|
|
6684
|
+
for (const h3 of document.querySelectorAll("h3")) heads.push(h3);
|
|
6685
|
+
return heads.map((head) => {
|
|
6686
|
+
const cached = headInfoCache.get(head);
|
|
6687
|
+
if (cached) return { head, cont: cached.cont, kind: cached.kind };
|
|
6688
|
+
const textKind = head.tagName === "BUTTON" ? kindFromHeadText(head) : "task";
|
|
6689
|
+
let cont = head.parentElement;
|
|
6690
|
+
while (cont && !cont.querySelector("li[data-task-item-key]") && cont !== document.body) cont = cont.parentElement;
|
|
6691
|
+
const contOk = cont && cont !== document.body;
|
|
6692
|
+
const kind = textKind || (contOk ? cont.querySelector("section[data-project-id]") ? "project" : "task" : null);
|
|
6693
|
+
headInfoCache.set(head, { cont: contOk ? cont : null, kind });
|
|
6694
|
+
return { head, cont: contOk ? cont : null, kind };
|
|
6695
|
+
}).filter((x) => x.head);
|
|
6275
6696
|
}
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6697
|
+
var SEC_SPIN_CLASS = "zcodepro-ws-sec-spin";
|
|
6698
|
+
var anyActiveCache = { at: 0, value: null, busy: false };
|
|
6699
|
+
var sectionActive = { task: false, project: false };
|
|
6700
|
+
var activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6701
|
+
setInterval(() => {
|
|
6702
|
+
if (!anyActiveCache.busy && Date.now() - anyActiveCache.at >= 1e4) globalAnyActive();
|
|
6703
|
+
}, 1e4);
|
|
6704
|
+
function globalAnyActive() {
|
|
6705
|
+
if (anyActiveCache.value !== null && Date.now() - anyActiveCache.at < 1e4) return anyActiveCache.value;
|
|
6706
|
+
if (anyActiveCache.busy) return anyActiveCache.value === true;
|
|
6707
|
+
anyActiveCache.busy = true;
|
|
6708
|
+
sectionActive.task = false;
|
|
6709
|
+
sectionActive.project = false;
|
|
6710
|
+
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6711
|
+
void (async () => {
|
|
6712
|
+
let hit = null;
|
|
6713
|
+
try {
|
|
6714
|
+
const res = await rpc("/projects-v2").catch(() => null);
|
|
6715
|
+
const services = findServices();
|
|
6716
|
+
const ts = services && services.zcodeTaskService;
|
|
6717
|
+
if (res && res.ok && res.available && ts && typeof ts.listActiveTaskIds === "function") {
|
|
6718
|
+
hit = false;
|
|
6719
|
+
const projPaths = /* @__PURE__ */ new Set();
|
|
6720
|
+
for (const proj of res.projects || []) {
|
|
6721
|
+
for (const r of proj.roots || []) {
|
|
6722
|
+
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
6723
|
+
if (b) projPaths.add(b);
|
|
6724
|
+
}
|
|
6290
6725
|
}
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6726
|
+
const taskSidePaths = /* @__PURE__ */ new Set();
|
|
6727
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
6728
|
+
const sec = el.closest("section[data-project-id]");
|
|
6729
|
+
if (sec) continue;
|
|
6730
|
+
const k = el.getAttribute("data-task-item-key") || "";
|
|
6731
|
+
const cut = k.lastIndexOf(":");
|
|
6732
|
+
if (cut > 1) taskSidePaths.add(k.slice(0, cut).replace(/[\\/]+$/, ""));
|
|
6733
|
+
}
|
|
6734
|
+
const scanPaths = /* @__PURE__ */ new Set([...projPaths, ...taskSidePaths]);
|
|
6735
|
+
const byKind = { task: /* @__PURE__ */ new Set(), project: /* @__PURE__ */ new Set() };
|
|
6736
|
+
const byKindByPath = /* @__PURE__ */ new Map();
|
|
6737
|
+
const rootToProject = /* @__PURE__ */ new Map();
|
|
6738
|
+
const projectPaths = /* @__PURE__ */ new Map();
|
|
6739
|
+
for (const proj of res.projects || []) {
|
|
6740
|
+
const names = [];
|
|
6741
|
+
for (const r of proj.roots || []) {
|
|
6742
|
+
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
6743
|
+
if (b) {
|
|
6744
|
+
rootToProject.set(b, proj.name);
|
|
6745
|
+
names.push(b);
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
projectPaths.set(proj.name, names);
|
|
6749
|
+
}
|
|
6750
|
+
for (const base of scanPaths) {
|
|
6751
|
+
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
6752
|
+
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
6753
|
+
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
6754
|
+
if (!ids.length) continue;
|
|
6755
|
+
byKindByPath.set(base, ids);
|
|
6756
|
+
const kind = projPaths.has(base) ? "project" : "task";
|
|
6757
|
+
for (const id of ids) byKind[kind].add(id);
|
|
6758
|
+
}
|
|
6759
|
+
const allIds = [...byKind.task, ...byKind.project];
|
|
6760
|
+
const st = allIds.length ? await rpc("/task-statuses?ids=" + encodeURIComponent(allIds.join(","))).catch(() => null) : null;
|
|
6761
|
+
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
6762
|
+
const live = (id) => {
|
|
6763
|
+
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
6764
|
+
if (rec === void 0) return true;
|
|
6765
|
+
if (!TERMINAL.has(rec.status)) return true;
|
|
6766
|
+
return Date.now() - rec.updatedAt < 3e5;
|
|
6767
|
+
};
|
|
6768
|
+
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6769
|
+
for (const [base, ids] of byKindByPath) {
|
|
6770
|
+
if (!projPaths.has(base)) continue;
|
|
6771
|
+
if (ids.some(live)) {
|
|
6772
|
+
const projName = rootToProject.get(base);
|
|
6773
|
+
if (projName) for (const p2 of projectPaths.get(projName) || []) activeProjectPaths.add(p2);
|
|
6774
|
+
}
|
|
6775
|
+
}
|
|
6776
|
+
const taskDomRunning = !!document.querySelector('[data-task-item-key]:not(section[data-project-id] *) svg[class*="lucide-loader"]');
|
|
6777
|
+
if (taskDomRunning && [...byKind.task].some(live)) sectionActive.task = true;
|
|
6778
|
+
if ([...byKind.project].some(live)) sectionActive.project = true;
|
|
6779
|
+
hit = sectionActive.task || sectionActive.project;
|
|
6318
6780
|
}
|
|
6319
|
-
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
);
|
|
6327
|
-
document.body.append(popupEl);
|
|
6328
|
-
renderPopup();
|
|
6329
|
-
}
|
|
6330
|
-
function moveHighlight(delta) {
|
|
6331
|
-
if (!popupEl || mru.length < 2) return;
|
|
6332
|
-
highlight = (highlight + delta + mru.length) % mru.length;
|
|
6333
|
-
renderPopup();
|
|
6334
|
-
const row = popupEl.querySelector("[data-active]");
|
|
6335
|
-
if (row) row.scrollIntoView({ block: "nearest" });
|
|
6781
|
+
} catch {
|
|
6782
|
+
}
|
|
6783
|
+
if (hit !== null) anyActiveCache = { at: Date.now(), value: hit, busy: false };
|
|
6784
|
+
else anyActiveCache.busy = false;
|
|
6785
|
+
apply();
|
|
6786
|
+
})();
|
|
6787
|
+
return anyActiveCache.value === true;
|
|
6336
6788
|
}
|
|
6337
|
-
function
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
if (taskRowMutations(muts)) scheduleScan();
|
|
6341
|
-
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] });
|
|
6342
|
-
setInterval(() => {
|
|
6343
|
-
if (!document.hidden) scan();
|
|
6344
|
-
}, SCAN_FALLBACK_MS);
|
|
6345
|
-
document.addEventListener("visibilitychange", () => {
|
|
6346
|
-
if (!document.hidden) scan();
|
|
6347
|
-
});
|
|
6348
|
-
document.addEventListener("click", (e) => {
|
|
6349
|
-
const item = e.target instanceof Element && e.target.closest("[data-task-item-key]");
|
|
6350
|
-
if (item) record(item.getAttribute("data-task-item-key"));
|
|
6351
|
-
}, true);
|
|
6352
|
-
document.addEventListener("keydown", (e) => {
|
|
6353
|
-
if (e.key === "Escape" && popupEl) {
|
|
6354
|
-
e.preventDefault();
|
|
6355
|
-
e.stopImmediatePropagation();
|
|
6356
|
-
closePopup(false);
|
|
6357
|
-
return;
|
|
6358
|
-
}
|
|
6359
|
-
if (!e.altKey || e.ctrlKey || e.metaKey || e.isComposing) return;
|
|
6360
|
-
if (document.querySelector(".zcodepro-overlay")) return;
|
|
6361
|
-
const k = e.key.toLowerCase();
|
|
6362
|
-
if (k !== "z" && k !== "x" && k !== "c") return;
|
|
6363
|
-
e.preventDefault();
|
|
6364
|
-
e.stopImmediatePropagation();
|
|
6365
|
-
void (async () => {
|
|
6366
|
-
const cfg = await getConfig();
|
|
6367
|
-
if (cfg.features && cfg.features.sessionSwitch === false) return;
|
|
6368
|
-
if (k === "z") {
|
|
6369
|
-
if (e.repeat) return;
|
|
6370
|
-
closePopup(false);
|
|
6371
|
-
const live = findCurrent();
|
|
6372
|
-
if (live) record(live.getAttribute("data-task-item-key"));
|
|
6373
|
-
const target = live ? mru[0] === current ? mru[1] : mru.find((mk) => mk !== current) : mru[0];
|
|
6374
|
-
if (!target) {
|
|
6375
|
-
showToast(t().switcherEmpty);
|
|
6376
|
-
return;
|
|
6377
|
-
}
|
|
6378
|
-
void switchTo(target).then((ok) => {
|
|
6379
|
-
if (!ok) showToast(t().switcherFailed, "error");
|
|
6380
|
-
});
|
|
6381
|
-
return;
|
|
6382
|
-
}
|
|
6383
|
-
if (mru.length < 2) {
|
|
6384
|
-
showToast(t().switcherEmpty);
|
|
6385
|
-
return;
|
|
6386
|
-
}
|
|
6387
|
-
if (!popupEl) await openPopup();
|
|
6388
|
-
moveHighlight(k === "x" ? -1 : 1);
|
|
6389
|
-
})();
|
|
6390
|
-
}, true);
|
|
6391
|
-
document.addEventListener("keyup", (e) => {
|
|
6392
|
-
if (e.key === "Alt" && popupEl) closePopup(true);
|
|
6393
|
-
}, true);
|
|
6394
|
-
window.addEventListener("blur", () => closePopup(false));
|
|
6395
|
-
}
|
|
6396
|
-
|
|
6397
|
-
// src/inject/features/title-lock.js
|
|
6398
|
-
var TASK_SEL = "[data-task-item-key]";
|
|
6399
|
-
var SCAN_DEBOUNCE_MS2 = 150;
|
|
6400
|
-
var SCAN_FALLBACK_MS2 = 5e3;
|
|
6401
|
-
var BOOT_RETRY_MS = 5e3;
|
|
6402
|
-
var RECHECK_DELAY_MS = 1e3;
|
|
6403
|
-
var REVERIFY_MS = 3e3;
|
|
6404
|
-
var MAP_REFRESH_MS = 6e4;
|
|
6405
|
-
var installed2 = false;
|
|
6406
|
-
var seenRows = /* @__PURE__ */ new WeakSet();
|
|
6407
|
-
var enabled2 = true;
|
|
6408
|
-
var pinned = null;
|
|
6409
|
-
var resolved = false;
|
|
6410
|
-
var fetching = null;
|
|
6411
|
-
var pendingKeys = /* @__PURE__ */ new Set();
|
|
6412
|
-
function sessIdOf(key) {
|
|
6413
|
-
const i = key.indexOf(":sess_");
|
|
6414
|
-
return i > 0 ? key.slice(i + 1) : key;
|
|
6415
|
-
}
|
|
6416
|
-
function titleElsOf(item) {
|
|
6417
|
-
const copies = item.querySelectorAll("[data-task-title-copy]");
|
|
6418
|
-
if (copies.length) return [...copies];
|
|
6419
|
-
const t2 = item.querySelector('[class*="truncate"]');
|
|
6420
|
-
return t2 ? [t2] : [];
|
|
6421
|
-
}
|
|
6422
|
-
function findRows(key) {
|
|
6423
|
-
return [...document.querySelectorAll(`${TASK_SEL}[data-task-item-key="${CSS.escape(key)}"]`)];
|
|
6424
|
-
}
|
|
6425
|
-
async function fetchPinned() {
|
|
6426
|
-
if (fetching) return fetching;
|
|
6427
|
-
const p = (async () => {
|
|
6428
|
-
const res = await rpc("/pinned-titles");
|
|
6429
|
-
if (!res || !res.ok) return null;
|
|
6430
|
-
resolved = true;
|
|
6431
|
-
enabled2 = res.enabled !== false;
|
|
6432
|
-
if (!enabled2) {
|
|
6433
|
-
pinned = null;
|
|
6434
|
-
return null;
|
|
6435
|
-
}
|
|
6436
|
-
pinned = new Map(Object.entries(res.titles || {}));
|
|
6437
|
-
return pinned;
|
|
6438
|
-
})();
|
|
6439
|
-
fetching = p;
|
|
6440
|
-
try {
|
|
6441
|
-
return await p;
|
|
6442
|
-
} finally {
|
|
6443
|
-
if (fetching === p) fetching = null;
|
|
6444
|
-
}
|
|
6445
|
-
}
|
|
6446
|
-
function isMismatch(item) {
|
|
6447
|
-
if (!enabled2 || !pinned) return null;
|
|
6448
|
-
const key = item.getAttribute("data-task-item-key") || "";
|
|
6449
|
-
const want = pinned.get(sessIdOf(key));
|
|
6450
|
-
if (want === void 0) return null;
|
|
6451
|
-
const els = titleElsOf(item);
|
|
6452
|
-
if (!els.length) return null;
|
|
6453
|
-
if ((els[0].textContent || "").trim() === String(want).trim()) return null;
|
|
6454
|
-
if (item.querySelector('input, textarea, [contenteditable="true"]')) return null;
|
|
6455
|
-
return key;
|
|
6456
|
-
}
|
|
6457
|
-
function writeTitle(el, text) {
|
|
6458
|
-
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
6459
|
-
const first = walker.nextNode();
|
|
6460
|
-
if (first && !walker.nextNode()) first.nodeValue = text;
|
|
6461
|
-
else el.textContent = text;
|
|
6462
|
-
}
|
|
6463
|
-
function scheduleEnforce(key, { immediate = false } = {}) {
|
|
6464
|
-
if (immediate) {
|
|
6465
|
-
if (enabled2 && pinned) {
|
|
6466
|
-
const want = pinned.get(sessIdOf(key));
|
|
6467
|
-
if (want !== void 0) {
|
|
6468
|
-
for (const item of findRows(key)) {
|
|
6469
|
-
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
6470
|
-
}
|
|
6471
|
-
}
|
|
6472
|
-
}
|
|
6473
|
-
}
|
|
6474
|
-
if (pendingKeys.has(key)) return;
|
|
6475
|
-
pendingKeys.add(key);
|
|
6476
|
-
setTimeout(() => {
|
|
6477
|
-
pendingKeys.delete(key);
|
|
6478
|
-
void (async () => {
|
|
6479
|
-
const map = await fetchPinned();
|
|
6480
|
-
if (!map) return;
|
|
6481
|
-
const want = map.get(sessIdOf(key));
|
|
6482
|
-
if (want === void 0) return;
|
|
6483
|
-
let wrote = false;
|
|
6484
|
-
for (const item of findRows(key)) {
|
|
6485
|
-
if (isMismatch(item) !== key) continue;
|
|
6486
|
-
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
6487
|
-
wrote = true;
|
|
6488
|
-
}
|
|
6489
|
-
if (wrote) setTimeout(() => {
|
|
6490
|
-
void enforceKey(key);
|
|
6491
|
-
}, REVERIFY_MS);
|
|
6492
|
-
})();
|
|
6493
|
-
}, RECHECK_DELAY_MS);
|
|
6494
|
-
}
|
|
6495
|
-
async function enforceKey(key) {
|
|
6496
|
-
const map = await fetchPinned();
|
|
6497
|
-
if (!map) return;
|
|
6498
|
-
const want = map.get(sessIdOf(key));
|
|
6499
|
-
if (want === void 0) return;
|
|
6500
|
-
for (const item of findRows(key)) {
|
|
6501
|
-
if (isMismatch(item) !== key) continue;
|
|
6502
|
-
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
6503
|
-
}
|
|
6504
|
-
}
|
|
6505
|
-
function scan2() {
|
|
6506
|
-
if (!enabled2 || !pinned || pinned.size === 0) return;
|
|
6507
|
-
for (const item of document.querySelectorAll(TASK_SEL)) {
|
|
6508
|
-
const key = isMismatch(item);
|
|
6509
|
-
if (!key) {
|
|
6510
|
-
seenRows.add(item);
|
|
6511
|
-
continue;
|
|
6512
|
-
}
|
|
6513
|
-
const fresh = !seenRows.has(item);
|
|
6514
|
-
seenRows.add(item);
|
|
6515
|
-
scheduleEnforce(key, { immediate: fresh });
|
|
6516
|
-
}
|
|
6517
|
-
}
|
|
6518
|
-
var inTaskRow2 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL));
|
|
6519
|
-
function taskRowMutations2(muts) {
|
|
6520
|
-
for (const m of muts) {
|
|
6521
|
-
if (m.type === "attributes") {
|
|
6522
|
-
if (inTaskRow2(m.target)) return true;
|
|
6523
|
-
} else if (m.type === "characterData") {
|
|
6524
|
-
if (m.target.parentElement && inTaskRow2(m.target.parentElement)) return true;
|
|
6525
|
-
} else if (inTaskRow2(m.target)) {
|
|
6526
|
-
return true;
|
|
6527
|
-
} else {
|
|
6528
|
-
for (const n of m.addedNodes) {
|
|
6529
|
-
if (n instanceof Element && (n.matches(TASK_SEL) || !!n.querySelector(TASK_SEL))) return true;
|
|
6530
|
-
}
|
|
6531
|
-
}
|
|
6532
|
-
}
|
|
6533
|
-
return false;
|
|
6534
|
-
}
|
|
6535
|
-
var scanDebounce2 = 0;
|
|
6536
|
-
function scheduleScan2() {
|
|
6537
|
-
if (scanDebounce2) return;
|
|
6538
|
-
scanDebounce2 = setTimeout(() => {
|
|
6539
|
-
scanDebounce2 = 0;
|
|
6540
|
-
scan2();
|
|
6541
|
-
}, SCAN_DEBOUNCE_MS2);
|
|
6542
|
-
}
|
|
6543
|
-
var mapRefreshTimer = 0;
|
|
6544
|
-
function refreshMapSoon() {
|
|
6545
|
-
if (mapRefreshTimer) return;
|
|
6546
|
-
const tick2 = () => {
|
|
6547
|
-
if (document.hidden) {
|
|
6548
|
-
mapRefreshTimer = setTimeout(tick2, 1e4);
|
|
6549
|
-
return;
|
|
6550
|
-
}
|
|
6551
|
-
mapRefreshTimer = 0;
|
|
6552
|
-
if (enabled2 && resolved) void fetchPinned().then((m) => {
|
|
6553
|
-
if (m) scan2();
|
|
6554
|
-
});
|
|
6555
|
-
};
|
|
6556
|
-
mapRefreshTimer = setTimeout(tick2, MAP_REFRESH_MS);
|
|
6557
|
-
}
|
|
6558
|
-
var editingKey = null;
|
|
6559
|
-
var bootDelay = 0;
|
|
6560
|
-
function scheduleBootRetry() {
|
|
6561
|
-
bootDelay = bootDelay ? Math.min(bootDelay * 2, MAP_REFRESH_MS) : BOOT_RETRY_MS;
|
|
6562
|
-
setTimeout(() => {
|
|
6563
|
-
if (resolved) return;
|
|
6564
|
-
if (!document.hidden) void bootstrap();
|
|
6565
|
-
scheduleBootRetry();
|
|
6566
|
-
}, bootDelay);
|
|
6567
|
-
}
|
|
6568
|
-
async function bootstrap() {
|
|
6569
|
-
const map = await fetchPinned();
|
|
6570
|
-
if (map) scan2();
|
|
6571
|
-
}
|
|
6572
|
-
function setRowTitle(key, text) {
|
|
6573
|
-
for (const item of findRows(key)) {
|
|
6574
|
-
for (const el of titleElsOf(item)) writeTitle(el, text);
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
function refreshPinnedTitles() {
|
|
6578
|
-
return fetchPinned().then((m) => {
|
|
6579
|
-
if (m) scan2();
|
|
6580
|
-
});
|
|
6581
|
-
}
|
|
6582
|
-
var RENAME_CTX_VALID_MS = 15e3;
|
|
6583
|
-
var renameCtx = null;
|
|
6584
|
-
var renamePrefilled = /* @__PURE__ */ new WeakSet();
|
|
6585
|
-
function setNativeValue(el, text) {
|
|
6586
|
-
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
6587
|
-
Object.getOwnPropertyDescriptor(el.constructor.prototype, "value").set.call(el, text);
|
|
6588
|
-
} else {
|
|
6589
|
-
el.textContent = text;
|
|
6590
|
-
}
|
|
6591
|
-
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6592
|
-
}
|
|
6593
|
-
function prefillRenameDialog() {
|
|
6594
|
-
if (!renameCtx || !renameCtx.armed || Date.now() - renameCtx.at > RENAME_CTX_VALID_MS) {
|
|
6595
|
-
renameCtx = null;
|
|
6596
|
-
return;
|
|
6597
|
-
}
|
|
6598
|
-
if (!enabled2 || !pinned) return;
|
|
6599
|
-
const want = pinned.get(sessIdOf(renameCtx.key));
|
|
6600
|
-
if (want === void 0) return;
|
|
6601
|
-
for (const el of document.querySelectorAll('[role="dialog"] input, [role="dialog"] textarea, [role="dialog"] [contenteditable="true"]')) {
|
|
6602
|
-
if (renamePrefilled.has(el) || !el.getClientRects().length) continue;
|
|
6603
|
-
if (el.closest(TASK_SEL) || el.closest(".zcodepro-overlay")) continue;
|
|
6604
|
-
const cur = String(el.value ?? el.textContent ?? "").trim();
|
|
6605
|
-
if (!cur) continue;
|
|
6606
|
-
renamePrefilled.add(el);
|
|
6607
|
-
if (cur !== String(want).trim()) setNativeValue(el, String(want));
|
|
6608
|
-
renameCtx = null;
|
|
6789
|
+
function applySectionSpin() {
|
|
6790
|
+
if (!enabled2) {
|
|
6791
|
+
document.querySelectorAll("." + SEC_SPIN_CLASS).forEach((el) => el.remove());
|
|
6609
6792
|
return;
|
|
6610
6793
|
}
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
renameCtx.at = Date.now();
|
|
6632
|
-
}
|
|
6633
|
-
}, true);
|
|
6634
|
-
scheduleBootRetry();
|
|
6635
|
-
setInterval(() => {
|
|
6636
|
-
if (!document.hidden) scan2();
|
|
6637
|
-
}, SCAN_FALLBACK_MS2);
|
|
6638
|
-
document.addEventListener("visibilitychange", () => {
|
|
6639
|
-
if (!document.hidden) scan2();
|
|
6640
|
-
});
|
|
6641
|
-
window.addEventListener("zcodepro:config-changed", () => {
|
|
6642
|
-
void bootstrap();
|
|
6643
|
-
});
|
|
6644
|
-
document.addEventListener("focusin", (e) => {
|
|
6645
|
-
const el = e.target;
|
|
6646
|
-
if (!(el instanceof Element)) return;
|
|
6647
|
-
if (!el.matches('input, textarea, [contenteditable="true"]')) return;
|
|
6648
|
-
const row = el.closest(TASK_SEL);
|
|
6649
|
-
editingKey = row ? row.getAttribute("data-task-item-key") || "" : null;
|
|
6650
|
-
});
|
|
6651
|
-
document.addEventListener("focusout", () => {
|
|
6652
|
-
if (editingKey === null) return;
|
|
6653
|
-
editingKey = null;
|
|
6654
|
-
void fetchPinned().then((m) => {
|
|
6655
|
-
if (m) scan2();
|
|
6656
|
-
});
|
|
6657
|
-
});
|
|
6658
|
-
}
|
|
6659
|
-
|
|
6660
|
-
// src/inject/features/title-gen.js
|
|
6661
|
-
var CONV2 = '[class*="@md/conversation"]';
|
|
6662
|
-
var USER_ROW = '[class*="user-row"]';
|
|
6663
|
-
var SCAN_DEBOUNCE_MS3 = 300;
|
|
6664
|
-
var SCAN_FALLBACK_MS3 = 5e3;
|
|
6665
|
-
var SELECT_WAIT_MS = 2e3;
|
|
6666
|
-
var MSG_WAIT_MS = 1e4;
|
|
6667
|
-
var QUIET_FALLBACK_MS = 12e4;
|
|
6668
|
-
var COLLECT_MAX_MS = 6e5;
|
|
6669
|
-
var installed3 = false;
|
|
6670
|
-
var knownKeys = /* @__PURE__ */ new Set();
|
|
6671
|
-
var attempted = /* @__PURE__ */ new Set();
|
|
6672
|
-
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
6673
|
-
function sessIdOf2(key) {
|
|
6674
|
-
const i = key.indexOf(":sess_");
|
|
6675
|
-
return i > 0 ? key.slice(i + 1) : "";
|
|
6676
|
-
}
|
|
6677
|
-
function currentKey() {
|
|
6678
|
-
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
6679
|
-
if ((el.className + "").includes("bg-selected")) return el.getAttribute("data-task-item-key") || "";
|
|
6794
|
+
for (const { head, cont, kind } of sectionHeads()) {
|
|
6795
|
+
const running = !!(cont && cont.querySelector('li[data-task-item-key] svg[class*="lucide-loader"]'));
|
|
6796
|
+
let expanded = true;
|
|
6797
|
+
if (head.tagName === "BUTTON") expanded = head.getAttribute("aria-expanded") !== "false";
|
|
6798
|
+
else {
|
|
6799
|
+
const list = head.nextElementSibling;
|
|
6800
|
+
expanded = !list || list.offsetHeight > 0;
|
|
6801
|
+
}
|
|
6802
|
+
if (!kind) return;
|
|
6803
|
+
const scoped = kind === "project" ? sectionActive.project : sectionActive.task;
|
|
6804
|
+
const want = !expanded && scoped;
|
|
6805
|
+
const existing = head.querySelector(":scope > ." + SEC_SPIN_CLASS);
|
|
6806
|
+
if (want && !existing) {
|
|
6807
|
+
const span = document.createElement("span");
|
|
6808
|
+
span.className = "flex size-4 shrink-0 items-center justify-center " + SEC_SPIN_CLASS;
|
|
6809
|
+
span.append(makeLoaderSvg("size-4"));
|
|
6810
|
+
head.prepend(span);
|
|
6811
|
+
} else if (!want && existing) {
|
|
6812
|
+
existing.remove();
|
|
6813
|
+
}
|
|
6680
6814
|
}
|
|
6681
|
-
return "";
|
|
6682
6815
|
}
|
|
6683
|
-
function
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
var URL_RE = /https?:\/\/[^\s\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+/g;
|
|
6690
|
-
function assistantText() {
|
|
6691
|
-
const els = [...document.querySelectorAll('[class*="@md/conversation"] [class*="assistant-row"]')].filter((e) => !e.querySelector("[data-is-streaming]"));
|
|
6692
|
-
const last = els[els.length - 1];
|
|
6693
|
-
if (!last) return "";
|
|
6694
|
-
const text = (last.innerText || "").replace(URL_RE, "").trim();
|
|
6695
|
-
return text.slice(0, 600);
|
|
6816
|
+
function schedulePeek(ws, delay) {
|
|
6817
|
+
clearTimeout(peekTimers.get(ws));
|
|
6818
|
+
peekTimers.set(ws, setTimeout(() => {
|
|
6819
|
+
peekTimers.delete(ws);
|
|
6820
|
+
void peek(ws);
|
|
6821
|
+
}, delay));
|
|
6696
6822
|
}
|
|
6697
|
-
function
|
|
6698
|
-
const
|
|
6699
|
-
if (
|
|
6700
|
-
|
|
6701
|
-
|
|
6823
|
+
function clearPeek(ws) {
|
|
6824
|
+
const t2 = peekTimers.get(ws);
|
|
6825
|
+
if (t2) {
|
|
6826
|
+
clearTimeout(t2);
|
|
6827
|
+
peekTimers.delete(ws);
|
|
6828
|
+
}
|
|
6702
6829
|
}
|
|
6703
|
-
|
|
6704
|
-
const
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
if (texts.length) break;
|
|
6717
|
-
await sleep2(400);
|
|
6830
|
+
function syncPeeks() {
|
|
6831
|
+
for (const [ws, set] of runningByWs) {
|
|
6832
|
+
if (!enabled2 || !set.size) {
|
|
6833
|
+
clearPeek(ws);
|
|
6834
|
+
continue;
|
|
6835
|
+
}
|
|
6836
|
+
const row = findWsRow(ws);
|
|
6837
|
+
const head = row && wsHead(row);
|
|
6838
|
+
if (!row || !head || head.getAttribute("aria-expanded") !== "false" || wsWithRows.has(ws)) {
|
|
6839
|
+
clearPeek(ws);
|
|
6840
|
+
continue;
|
|
6841
|
+
}
|
|
6842
|
+
if (!peekTimers.has(ws) && !activePeeks.has(ws)) schedulePeek(ws, peekedWs.has(ws) ? PEEK_REPEAT_MS : PEEK_FIRST_MS);
|
|
6718
6843
|
}
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
if (
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6844
|
+
}
|
|
6845
|
+
var peekChain = Promise.resolve();
|
|
6846
|
+
async function peek(ws, opts) {
|
|
6847
|
+
if (!opts?.manual) {
|
|
6848
|
+
const auth = await authoritativeIdle(ws);
|
|
6849
|
+
if (auth !== null) {
|
|
6850
|
+
if (auth) {
|
|
6851
|
+
runningByWs.delete(ws);
|
|
6852
|
+
} else {
|
|
6853
|
+
let set = runningByWs.get(ws);
|
|
6854
|
+
if (!set) {
|
|
6855
|
+
set = /* @__PURE__ */ new Set();
|
|
6856
|
+
runningByWs.set(ws, set);
|
|
6730
6857
|
}
|
|
6858
|
+
set.add(ws + ":active");
|
|
6859
|
+
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6731
6860
|
}
|
|
6861
|
+
apply();
|
|
6862
|
+
return true;
|
|
6732
6863
|
}
|
|
6864
|
+
}
|
|
6865
|
+
const run = () => peekInner(ws, opts);
|
|
6866
|
+
const p = peekChain.then(run, run);
|
|
6867
|
+
peekChain = p.catch(() => {
|
|
6733
6868
|
});
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6869
|
+
return p;
|
|
6870
|
+
}
|
|
6871
|
+
async function peekInner(ws, opts) {
|
|
6872
|
+
if (!opts?.manual && !enabled2 || document.hidden || activePeeks.has(ws)) return false;
|
|
6873
|
+
const row = findWsRow(ws);
|
|
6874
|
+
const head = row && wsHead(row);
|
|
6875
|
+
if (!row || !head || head.getAttribute("aria-expanded") !== "false") return false;
|
|
6876
|
+
if (!currentTaskRow()) {
|
|
6877
|
+
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6878
|
+
return false;
|
|
6879
|
+
}
|
|
6880
|
+
activePeeks.add(ws);
|
|
6881
|
+
peekedWs.add(ws);
|
|
6882
|
+
const rect = row.getBoundingClientRect();
|
|
6883
|
+
const frozen = row.cloneNode(true);
|
|
6884
|
+
frozen.classList.add("zcodepro-ws-frozen");
|
|
6885
|
+
frozen.style.left = rect.left + "px";
|
|
6886
|
+
frozen.style.top = rect.top + "px";
|
|
6887
|
+
frozen.style.width = rect.width + "px";
|
|
6888
|
+
frozen.style.height = rect.height + "px";
|
|
6889
|
+
document.body.append(frozen);
|
|
6890
|
+
row.style.visibility = "hidden";
|
|
6891
|
+
const hider = installPeekHider(ws);
|
|
6892
|
+
let readOk = false;
|
|
6738
6893
|
try {
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
if (texts.length !== lastCount) {
|
|
6747
|
-
lastCount = texts.length;
|
|
6748
|
-
lastChange = Date.now();
|
|
6749
|
-
}
|
|
6750
|
-
if (assistantSeen) break;
|
|
6751
|
-
if (Date.now() - lastChange >= QUIET_FALLBACK_MS) break;
|
|
6894
|
+
toggleNavSafe(head);
|
|
6895
|
+
readOk = await settleAndRead(ws);
|
|
6896
|
+
const rowNow = findWsRow(ws) || row;
|
|
6897
|
+
const headNow = wsHead(rowNow);
|
|
6898
|
+
if (headNow && headNow.getAttribute("aria-expanded") === "true" && !userTouched(rowNow)) {
|
|
6899
|
+
toggleNavSafe(headNow);
|
|
6900
|
+
await waitForRowsGone(ws);
|
|
6752
6901
|
}
|
|
6753
6902
|
} finally {
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
const deadline = Date.now() + 6e4;
|
|
6759
|
-
while (Date.now() < deadline) {
|
|
6760
|
-
await sleep2(2e3);
|
|
6761
|
-
if (currentKey() !== key) continue;
|
|
6762
|
-
const a = assistantText();
|
|
6763
|
-
if (a && a.length > 80) {
|
|
6764
|
-
texts.push(`\uFF08\u9996\u8F6E\u56DE\u7B54\u6458\u8981\uFF09${a}`);
|
|
6765
|
-
break;
|
|
6766
|
-
}
|
|
6767
|
-
}
|
|
6903
|
+
removePeekHider(hider);
|
|
6904
|
+
row.style.visibility = "";
|
|
6905
|
+
frozen.remove();
|
|
6906
|
+
activePeeks.delete(ws);
|
|
6768
6907
|
}
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6908
|
+
apply();
|
|
6909
|
+
const set = runningByWs.get(ws);
|
|
6910
|
+
if (set && set.size && enabled2) schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6911
|
+
return readOk;
|
|
6912
|
+
}
|
|
6913
|
+
function wsRunningSnapshot() {
|
|
6914
|
+
const curKey = currentTaskRow()?.getAttribute("data-task-item-key") || "";
|
|
6915
|
+
return {
|
|
6916
|
+
running: [...runningByWs.entries()].filter(([, set]) => set.size > 0).map(([ws]) => ws),
|
|
6917
|
+
current: curKey ? workspaceOf(curKey) || null : null
|
|
6918
|
+
};
|
|
6919
|
+
}
|
|
6920
|
+
function wsRunningKeys() {
|
|
6921
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6922
|
+
for (const set of runningByWs.values()) for (const k of set) keys.add(k);
|
|
6923
|
+
return keys;
|
|
6924
|
+
}
|
|
6925
|
+
async function verifyWorkspaceNotRunning(ws) {
|
|
6926
|
+
if (!ws || document.hidden) return false;
|
|
6927
|
+
const row = findWsRow(ws);
|
|
6928
|
+
const head = row && wsHead(row);
|
|
6929
|
+
if (!row || !head) return false;
|
|
6930
|
+
if (head.getAttribute("aria-expanded") !== "false") {
|
|
6931
|
+
let run = false;
|
|
6932
|
+
for (const el of domRowsOf(ws)) if (isRunningRow(el)) run = true;
|
|
6933
|
+
return !run;
|
|
6775
6934
|
}
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6935
|
+
let verified = false;
|
|
6936
|
+
try {
|
|
6937
|
+
verified = await peek(ws, { manual: true }) === true;
|
|
6938
|
+
} catch {
|
|
6779
6939
|
}
|
|
6940
|
+
if (!verified) return false;
|
|
6941
|
+
const set = runningByWs.get(ws);
|
|
6942
|
+
return !(set && set.size);
|
|
6943
|
+
}
|
|
6944
|
+
function settleAndRead(ws) {
|
|
6945
|
+
return new Promise((resolve) => {
|
|
6946
|
+
const t0 = Date.now();
|
|
6947
|
+
let lastCount = -1;
|
|
6948
|
+
let stableAt = 0;
|
|
6949
|
+
let zeroRows = false;
|
|
6950
|
+
const timer = setInterval(() => {
|
|
6951
|
+
const rows = domRowsOf(ws);
|
|
6952
|
+
const elapsed = Date.now() - t0;
|
|
6953
|
+
if (rows.length !== lastCount) {
|
|
6954
|
+
lastCount = rows.length;
|
|
6955
|
+
stableAt = Date.now();
|
|
6956
|
+
}
|
|
6957
|
+
const settled = rows.length > 0 && rows.length === lastCount && Date.now() - stableAt >= PEEK_SETTLE_MS;
|
|
6958
|
+
if (!settled && elapsed < PEEK_MAX_MS) return;
|
|
6959
|
+
clearInterval(timer);
|
|
6960
|
+
if (lastCount === 0) {
|
|
6961
|
+
zeroRows = true;
|
|
6962
|
+
} else {
|
|
6963
|
+
let set = runningByWs.get(ws);
|
|
6964
|
+
if (!set) {
|
|
6965
|
+
set = /* @__PURE__ */ new Set();
|
|
6966
|
+
runningByWs.set(ws, set);
|
|
6967
|
+
}
|
|
6968
|
+
for (const el of rows) {
|
|
6969
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6970
|
+
if (isRunningRow(el)) set.add(key);
|
|
6971
|
+
else set.delete(key);
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
resolve(!zeroRows);
|
|
6975
|
+
}, 80);
|
|
6976
|
+
});
|
|
6977
|
+
}
|
|
6978
|
+
var PEEK_EXEMPT_CLASS = "zcodepro-peek-exempt";
|
|
6979
|
+
var cssAttr = (v) => String(v).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
6980
|
+
function installPeekHider(ws) {
|
|
6981
|
+
const rowSel3 = `${TASK_SEL}[data-task-item-key^="${cssAttr(ws + ":")}"]`;
|
|
6982
|
+
for (const r of document.querySelectorAll(rowSel3)) r.classList.add(PEEK_EXEMPT_CLASS);
|
|
6983
|
+
const style = document.createElement("style");
|
|
6984
|
+
style.textContent = `${rowSel3}:not(.${PEEK_EXEMPT_CLASS}){display:none!important}`;
|
|
6985
|
+
document.head.append(style);
|
|
6986
|
+
return { style, sel: rowSel3 };
|
|
6987
|
+
}
|
|
6988
|
+
function removePeekHider(hider) {
|
|
6989
|
+
hider.style.remove();
|
|
6990
|
+
for (const r of document.querySelectorAll("." + PEEK_EXEMPT_CLASS)) r.classList.remove(PEEK_EXEMPT_CLASS);
|
|
6991
|
+
}
|
|
6992
|
+
function waitForRowsGone(ws) {
|
|
6993
|
+
const sel = `${TASK_SEL}[data-task-item-key^="${cssAttr(ws + ":")}"]:not(.${PEEK_EXEMPT_CLASS})`;
|
|
6994
|
+
return new Promise((resolve) => {
|
|
6995
|
+
const t0 = Date.now();
|
|
6996
|
+
const timer = setInterval(() => {
|
|
6997
|
+
if (!document.querySelector(sel) || Date.now() - t0 >= PEEK_UNMOUNT_WAIT_MS) {
|
|
6998
|
+
clearInterval(timer);
|
|
6999
|
+
resolve();
|
|
7000
|
+
}
|
|
7001
|
+
}, 40);
|
|
7002
|
+
});
|
|
6780
7003
|
}
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
void onNewTaskRow(key);
|
|
6787
|
-
}
|
|
7004
|
+
var TOUCH_WINDOW_MS = 800;
|
|
7005
|
+
var wsTouchAt = /* @__PURE__ */ new WeakMap();
|
|
7006
|
+
function userTouched(row) {
|
|
7007
|
+
const at = wsTouchAt.get(row);
|
|
7008
|
+
return !!at && Date.now() - at < TOUCH_WINDOW_MS;
|
|
6788
7009
|
}
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
7010
|
+
function inSel(node, sel) {
|
|
7011
|
+
return !!(node instanceof Element && node.closest && node.closest(sel));
|
|
7012
|
+
}
|
|
7013
|
+
function relevant(muts) {
|
|
6792
7014
|
for (const m of muts) {
|
|
6793
|
-
if (m.
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
return true;
|
|
6799
|
-
}
|
|
6800
|
-
|
|
6801
|
-
|
|
7015
|
+
if (inSel(m.target, TASK_SEL) || inSel(m.target, WS_SEL())) return true;
|
|
7016
|
+
for (const n of m.addedNodes) {
|
|
7017
|
+
if (n instanceof Element && (n.matches(TASK_SEL) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL) || n.querySelector(WS_SEL()))) return true;
|
|
7018
|
+
}
|
|
7019
|
+
for (const n of m.removedNodes) {
|
|
7020
|
+
if (n instanceof Element && (n.matches(TASK_SEL) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL))) return true;
|
|
7021
|
+
}
|
|
7022
|
+
}
|
|
7023
|
+
return false;
|
|
7024
|
+
}
|
|
7025
|
+
var pollMs = CONFIG_POLL_MIN_MS;
|
|
7026
|
+
async function refreshConfig() {
|
|
7027
|
+
try {
|
|
7028
|
+
const res = await rpc("/config");
|
|
7029
|
+
if (res && res.ok && res.config && res.config.features) {
|
|
7030
|
+
const next = res.config.features.wsRunningSpin !== false;
|
|
7031
|
+
if (next !== enabled2) {
|
|
7032
|
+
enabled2 = next;
|
|
7033
|
+
if (!next) {
|
|
7034
|
+
for (const ws of [...peekTimers.keys()]) clearPeek(ws);
|
|
7035
|
+
apply();
|
|
7036
|
+
}
|
|
7037
|
+
return true;
|
|
6802
7038
|
}
|
|
6803
7039
|
}
|
|
7040
|
+
} catch {
|
|
6804
7041
|
}
|
|
6805
7042
|
return false;
|
|
6806
7043
|
}
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
}, SCAN_DEBOUNCE_MS3);
|
|
7044
|
+
function pollConfig() {
|
|
7045
|
+
setTimeout(async () => {
|
|
7046
|
+
if (document.hidden) pollMs = CONFIG_POLL_MAX_MS;
|
|
7047
|
+
else pollMs = await refreshConfig() ? CONFIG_POLL_MIN_MS : Math.min(Math.round(pollMs * 1.5), CONFIG_POLL_MAX_MS);
|
|
7048
|
+
pollConfig();
|
|
7049
|
+
}, pollMs);
|
|
6814
7050
|
}
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
7051
|
+
var scanDebounce = 0;
|
|
7052
|
+
function startWsRunningSpin() {
|
|
7053
|
+
if (installed2 || typeof document === "undefined") return;
|
|
7054
|
+
installed2 = true;
|
|
7055
|
+
void refreshConfig();
|
|
7056
|
+
pollConfig();
|
|
7057
|
+
const observer2 = new MutationObserver((muts) => {
|
|
7058
|
+
if (!relevant(muts)) return;
|
|
7059
|
+
handleRemovals(muts);
|
|
7060
|
+
if (!scanDebounce) {
|
|
7061
|
+
scanDebounce = setTimeout(() => {
|
|
7062
|
+
scanDebounce = 0;
|
|
7063
|
+
scan();
|
|
7064
|
+
}, SCAN_DEBOUNCE_MS);
|
|
7065
|
+
}
|
|
7066
|
+
});
|
|
7067
|
+
observer2.observe(document.body, { childList: true, subtree: true });
|
|
7068
|
+
scan();
|
|
6822
7069
|
setInterval(() => {
|
|
6823
|
-
if (!document.hidden)
|
|
6824
|
-
},
|
|
7070
|
+
if (!document.hidden && enabled2) scan();
|
|
7071
|
+
}, SCAN_FALLBACK_MS);
|
|
6825
7072
|
document.addEventListener("visibilitychange", () => {
|
|
6826
|
-
if (!document.hidden)
|
|
7073
|
+
if (!document.hidden) scan();
|
|
6827
7074
|
});
|
|
7075
|
+
document.addEventListener("click", (e) => {
|
|
7076
|
+
if (!e.isTrusted) return;
|
|
7077
|
+
const row = e.target instanceof Element && e.target.closest(WS_SEL());
|
|
7078
|
+
if (row) wsTouchAt.set(row, Date.now());
|
|
7079
|
+
}, true);
|
|
6828
7080
|
}
|
|
6829
7081
|
|
|
6830
|
-
// src/inject/features/
|
|
6831
|
-
var
|
|
6832
|
-
var
|
|
6833
|
-
var
|
|
6834
|
-
var
|
|
6835
|
-
var
|
|
6836
|
-
var
|
|
6837
|
-
var
|
|
6838
|
-
var
|
|
6839
|
-
var
|
|
6840
|
-
var
|
|
6841
|
-
var
|
|
6842
|
-
var
|
|
6843
|
-
var
|
|
6844
|
-
|
|
6845
|
-
|
|
7082
|
+
// src/inject/features/session-switch.js
|
|
7083
|
+
var MRU_LIMIT = 50;
|
|
7084
|
+
var SCAN_DEBOUNCE_MS2 = 150;
|
|
7085
|
+
var SCAN_FALLBACK_MS2 = 5e3;
|
|
7086
|
+
var INITIAL_COUNT = 10;
|
|
7087
|
+
var PAGE_SIZE = 5;
|
|
7088
|
+
var UNSEEN_LIMIT = 50;
|
|
7089
|
+
var mru = [];
|
|
7090
|
+
var current = null;
|
|
7091
|
+
var titles = /* @__PURE__ */ new Map();
|
|
7092
|
+
var popupEl = null;
|
|
7093
|
+
var aliasesCache = {};
|
|
7094
|
+
var highlight = 0;
|
|
7095
|
+
var scanDebounce2 = 0;
|
|
7096
|
+
var popupMode = "mru";
|
|
7097
|
+
var visibleCount = INITIAL_COUNT;
|
|
7098
|
+
var unseen = /* @__PURE__ */ new Set();
|
|
7099
|
+
var lastRunKeys = null;
|
|
7100
|
+
var movedSinceOpen = false;
|
|
7101
|
+
var hotkeys = { ...DEFAULT_SHORTCUTS };
|
|
7102
|
+
function loadHotkeys() {
|
|
7103
|
+
return getConfig(true).then((cfg) => {
|
|
7104
|
+
const sc = cfg && cfg.shortcuts;
|
|
7105
|
+
if (sc && typeof sc === "object") {
|
|
7106
|
+
for (const k of Object.keys(DEFAULT_SHORTCUTS)) {
|
|
7107
|
+
if (typeof sc[k] === "string" && /^[a-z0-9]$/.test(sc[k])) hotkeys[k] = sc[k];
|
|
7108
|
+
}
|
|
7109
|
+
}
|
|
7110
|
+
}).catch(() => {
|
|
7111
|
+
});
|
|
6846
7112
|
}
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
"M18 12h4",
|
|
6851
|
-
"m19.8 16.2-2.9 2.9",
|
|
6852
|
-
"M12 18v4",
|
|
6853
|
-
"m7.8 19.8-2.9-2.9",
|
|
6854
|
-
"M6 12H2",
|
|
6855
|
-
"m4.2 7.8 2.9-2.9"
|
|
6856
|
-
];
|
|
6857
|
-
function makeLoaderSvg(baseClass) {
|
|
6858
|
-
const ns = "http://www.w3.org/2000/svg";
|
|
6859
|
-
const proto = document.querySelector("svg.lucide-loader");
|
|
6860
|
-
if (proto) {
|
|
6861
|
-
const clone = proto.cloneNode(true);
|
|
6862
|
-
const origClass = proto.getAttribute("class") || "";
|
|
6863
|
-
const keep = origClass.split(/\s+/).filter((c) => /^(size-|text-)/.test(c)).join(" ");
|
|
6864
|
-
clone.setAttribute("class", ((keep || baseClass) + " animate-spin zcodepro-ws-loader").trim());
|
|
6865
|
-
return clone;
|
|
6866
|
-
}
|
|
6867
|
-
const svg = document.createElementNS(ns, "svg");
|
|
6868
|
-
svg.setAttribute("viewBox", "0 0 24 24");
|
|
6869
|
-
svg.setAttribute("fill", "none");
|
|
6870
|
-
svg.setAttribute("stroke", "currentColor");
|
|
6871
|
-
svg.setAttribute("stroke-width", "2");
|
|
6872
|
-
svg.setAttribute("stroke-linecap", "round");
|
|
6873
|
-
svg.setAttribute("stroke-linejoin", "round");
|
|
6874
|
-
svg.setAttribute("class", (baseClass + " animate-spin zcodepro-ws-loader").trim());
|
|
6875
|
-
for (const d of LOADER_FALLBACK_PATHS) {
|
|
6876
|
-
const path = document.createElementNS(ns, "path");
|
|
6877
|
-
path.setAttribute("d", d);
|
|
6878
|
-
svg.append(path);
|
|
6879
|
-
}
|
|
6880
|
-
return svg;
|
|
7113
|
+
function firstLineOf(item) {
|
|
7114
|
+
const tEl = item.querySelector('[class*="truncate"]');
|
|
7115
|
+
return (tEl ? tEl.textContent : (item.innerText || "").split("\n")[0])?.trim() || "";
|
|
6881
7116
|
}
|
|
6882
|
-
function
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
} else {
|
|
6890
|
-
holder.querySelectorAll(":scope > svg.zcodepro-ws-loader").forEach((el) => el.remove());
|
|
7117
|
+
function workspaceOf2(key) {
|
|
7118
|
+
const i = key.indexOf(":sess_");
|
|
7119
|
+
return i > 0 ? key.slice(0, i) : key;
|
|
7120
|
+
}
|
|
7121
|
+
function findCurrent() {
|
|
7122
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7123
|
+
if ((el.className + "").includes("bg-selected")) return el;
|
|
6891
7124
|
}
|
|
7125
|
+
return null;
|
|
6892
7126
|
}
|
|
6893
|
-
function
|
|
6894
|
-
if (
|
|
6895
|
-
|
|
6896
|
-
|
|
7127
|
+
function record(key) {
|
|
7128
|
+
if (key) unseen.delete(key);
|
|
7129
|
+
if (key && key !== current) {
|
|
7130
|
+
current = key;
|
|
7131
|
+
mru = mru.filter((k) => k !== key);
|
|
7132
|
+
mru.unshift(key);
|
|
7133
|
+
if (mru.length > MRU_LIMIT) mru.length = MRU_LIMIT;
|
|
6897
7134
|
}
|
|
6898
|
-
return row.firstElementChild && row.firstElementChild.querySelector(":scope > span");
|
|
6899
7135
|
}
|
|
6900
|
-
function
|
|
6901
|
-
const
|
|
6902
|
-
if (
|
|
6903
|
-
const
|
|
6904
|
-
|
|
7136
|
+
function scan2() {
|
|
7137
|
+
const cur = findCurrent();
|
|
7138
|
+
if (cur) record(cur.getAttribute("data-task-item-key"));
|
|
7139
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7140
|
+
titles.set(el.getAttribute("data-task-item-key"), firstLineOf(el));
|
|
7141
|
+
}
|
|
6905
7142
|
}
|
|
6906
|
-
var
|
|
6907
|
-
var
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
let found = null;
|
|
6920
|
-
const scanObj = (o) => {
|
|
6921
|
-
if (!o || typeof o !== "object" || seen.has(o) || found) return;
|
|
6922
|
-
seen.add(o);
|
|
6923
|
-
const ts = o.zcodeTaskService;
|
|
6924
|
-
if (ts && typeof ts === "object" && typeof ts.releaseWorkspacePreparation === "function") found = o;
|
|
6925
|
-
};
|
|
6926
|
-
let visited = 0;
|
|
6927
|
-
const visit = (f) => {
|
|
6928
|
-
if (!f || found || visited > 6e4) return;
|
|
6929
|
-
visited++;
|
|
6930
|
-
for (const holder of [f.memoizedProps, f.memoizedState]) {
|
|
6931
|
-
if (!holder || typeof holder !== "object") continue;
|
|
6932
|
-
scanObj(holder);
|
|
6933
|
-
for (const v of Object.values(holder)) {
|
|
6934
|
-
if (v && typeof v === "object") scanObj(v);
|
|
6935
|
-
}
|
|
7143
|
+
var rowSel2 = "[data-task-item-key]";
|
|
7144
|
+
var inTaskRow = (node) => node instanceof Element && !!node.closest && !!node.closest(rowSel2);
|
|
7145
|
+
function taskRowMutations(muts) {
|
|
7146
|
+
for (const m of muts) {
|
|
7147
|
+
if (m.type === "attributes") {
|
|
7148
|
+
if (inTaskRow(m.target)) return true;
|
|
7149
|
+
} else if (m.type === "characterData") {
|
|
7150
|
+
if (m.target.parentElement && inTaskRow(m.target.parentElement)) return true;
|
|
7151
|
+
} else if (inTaskRow(m.target)) {
|
|
7152
|
+
return true;
|
|
7153
|
+
} else {
|
|
7154
|
+
for (const n of m.addedNodes) {
|
|
7155
|
+
if (n instanceof Element && (n.matches(rowSel2) || !!n.querySelector(rowSel2))) return true;
|
|
6936
7156
|
}
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
return false;
|
|
7160
|
+
}
|
|
7161
|
+
function scheduleScan() {
|
|
7162
|
+
if (scanDebounce2) return;
|
|
7163
|
+
scanDebounce2 = setTimeout(() => {
|
|
7164
|
+
scanDebounce2 = 0;
|
|
7165
|
+
scan2();
|
|
7166
|
+
}, SCAN_DEBOUNCE_MS2);
|
|
7167
|
+
}
|
|
7168
|
+
async function switchTo(key) {
|
|
7169
|
+
const find = () => document.querySelector(`[data-task-item-key="${CSS.escape(key)}"]`);
|
|
7170
|
+
let item = find();
|
|
7171
|
+
if (!item) {
|
|
7172
|
+
const ws = workspaceOf2(key);
|
|
7173
|
+
const header = findProjectRow(ws);
|
|
7174
|
+
const expander = header && header.querySelector("[aria-expanded]");
|
|
7175
|
+
if (expander && expander.getAttribute("aria-expanded") === "false") {
|
|
7176
|
+
expander.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
7177
|
+
for (let i = 0; i < 20 && !(item = find()); i++) await new Promise((r) => setTimeout(r, 100));
|
|
7178
|
+
}
|
|
6945
7179
|
}
|
|
7180
|
+
if (!item) return false;
|
|
7181
|
+
item.scrollIntoView({ block: "nearest" });
|
|
7182
|
+
item.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
7183
|
+
return true;
|
|
6946
7184
|
}
|
|
6947
|
-
|
|
6948
|
-
const
|
|
6949
|
-
const
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
6962
|
-
if (rec === void 0) return true;
|
|
6963
|
-
if (!TERMINAL.has(rec.status)) return true;
|
|
6964
|
-
return Date.now() - rec.updatedAt < 3e5;
|
|
6965
|
-
};
|
|
6966
|
-
return !ids.some(live);
|
|
6967
|
-
} catch {
|
|
6968
|
-
return null;
|
|
7185
|
+
function attentionList() {
|
|
7186
|
+
const run = wsRunningKeys();
|
|
7187
|
+
const listed = /* @__PURE__ */ new Set();
|
|
7188
|
+
const head = [];
|
|
7189
|
+
for (const k of mru) {
|
|
7190
|
+
if (run.has(k) || unseen.has(k)) {
|
|
7191
|
+
head.push(k);
|
|
7192
|
+
listed.add(k);
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
const tail = [];
|
|
7196
|
+
for (const k of run) if (!listed.has(k)) {
|
|
7197
|
+
tail.push(k);
|
|
7198
|
+
listed.add(k);
|
|
6969
7199
|
}
|
|
7200
|
+
for (const k of unseen) if (!listed.has(k)) {
|
|
7201
|
+
tail.push(k);
|
|
7202
|
+
listed.add(k);
|
|
7203
|
+
}
|
|
7204
|
+
return [...head, ...tail];
|
|
6970
7205
|
}
|
|
6971
|
-
function
|
|
6972
|
-
|
|
6973
|
-
return i > 0 ? key.slice(0, i) : key;
|
|
7206
|
+
function activeList() {
|
|
7207
|
+
return popupMode === "attention" ? attentionList() : mru;
|
|
6974
7208
|
}
|
|
6975
|
-
function
|
|
6976
|
-
|
|
7209
|
+
function closePopup(commit) {
|
|
7210
|
+
if (!popupEl) return;
|
|
7211
|
+
const idx = highlight;
|
|
7212
|
+
const list = activeList();
|
|
7213
|
+
popupEl.remove();
|
|
7214
|
+
popupEl = null;
|
|
7215
|
+
if (commit && list[idx] && list[idx] !== current) {
|
|
7216
|
+
void switchTo(list[idx]).then((ok) => {
|
|
7217
|
+
if (!ok) showToast(t().switcherFailed, "error");
|
|
7218
|
+
});
|
|
7219
|
+
}
|
|
6977
7220
|
}
|
|
6978
|
-
function
|
|
6979
|
-
|
|
7221
|
+
function findTitle(key) {
|
|
7222
|
+
const item = document.querySelector(`[data-task-item-key="${CSS.escape(key)}"]`);
|
|
7223
|
+
if (item) titles.set(key, firstLineOf(item));
|
|
7224
|
+
const id = key.slice(key.indexOf(":sess_") + 1);
|
|
7225
|
+
return titles.get(key) || `sess ${id.slice(0, 8)}`;
|
|
6980
7226
|
}
|
|
6981
|
-
function
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
return null;
|
|
7227
|
+
function projLabelOf(key, aliases2) {
|
|
7228
|
+
const ws = workspaceOf2(key);
|
|
7229
|
+
if (!ws) return "";
|
|
7230
|
+
return aliases2[ws] || ws.replace(/[\\/]+$/, "").split(/[\\/]/).pop();
|
|
6986
7231
|
}
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
7232
|
+
function renderPopup() {
|
|
7233
|
+
if (!popupEl) return;
|
|
7234
|
+
const L = t();
|
|
7235
|
+
const list = popupEl.querySelector("[data-zcodepro-switcher-list]");
|
|
7236
|
+
const full = activeList();
|
|
7237
|
+
const shown = full.slice(0, visibleCount);
|
|
7238
|
+
const run = popupMode === "attention" ? wsRunningKeys() : null;
|
|
7239
|
+
list.replaceChildren(...shown.map((key) => {
|
|
7240
|
+
const proj = projLabelOf(key, aliasesCache);
|
|
7241
|
+
return h(
|
|
7242
|
+
"div",
|
|
7243
|
+
{
|
|
7244
|
+
class: "zcodepro-switcher-row",
|
|
7245
|
+
"data-active": full[highlight] === key ? "" : void 0,
|
|
7246
|
+
onClick: () => {
|
|
7247
|
+
highlight = full.indexOf(key);
|
|
7248
|
+
closePopup(true);
|
|
7249
|
+
}
|
|
7250
|
+
},
|
|
7251
|
+
// 标题文本包 span:截断省略作用在文本节点上(flex 容器自身 ellipsis 无效)
|
|
7252
|
+
h(
|
|
7253
|
+
"div",
|
|
7254
|
+
{ class: "zcodepro-switcher-title" },
|
|
7255
|
+
key === current ? h("span", { class: "zcodepro-switcher-tag" }, L.switcherCurrent) : null,
|
|
7256
|
+
run && run.has(key) ? h("span", { class: "zcodepro-switcher-tag zcodepro-switcher-tag-run" }, L.switcherRunning) : null,
|
|
7257
|
+
run && !run.has(key) ? h("span", { class: "zcodepro-switcher-tag zcodepro-switcher-tag-new" }, L.switcherUnseen) : null,
|
|
7258
|
+
h("span", null, findTitle(key))
|
|
7259
|
+
),
|
|
7260
|
+
// 无项目归属(如置顶)时不渲染空行
|
|
7261
|
+
proj ? h("div", { class: "zcodepro-switcher-ws" }, proj) : null
|
|
7262
|
+
);
|
|
7263
|
+
}));
|
|
7264
|
+
if (full.length > shown.length) {
|
|
7265
|
+
list.append(h(
|
|
7266
|
+
"div",
|
|
7267
|
+
{ class: "zcodepro-switcher-more" },
|
|
7268
|
+
L.switcherMore.replaceAll("{n}", String(full.length - shown.length))
|
|
7269
|
+
));
|
|
6991
7270
|
}
|
|
6992
|
-
};
|
|
6993
|
-
function toggleNavSafe(head) {
|
|
6994
|
-
const cur = currentTaskRow();
|
|
6995
|
-
const backKey = cur ? cur.getAttribute("data-task-item-key") : "";
|
|
6996
|
-
synthClick(head);
|
|
6997
|
-
if (!backKey) return;
|
|
6998
|
-
const back = cur && cur.isConnected ? cur : document.querySelector(`${TASK_SEL3}[data-task-item-key="${CSS.escape(backKey)}"]`);
|
|
6999
|
-
if (back) synthClick(back);
|
|
7000
7271
|
}
|
|
7001
|
-
function
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7272
|
+
async function openPopup(mode = "mru") {
|
|
7273
|
+
if (popupEl) return;
|
|
7274
|
+
popupMode = mode;
|
|
7275
|
+
visibleCount = INITIAL_COUNT;
|
|
7276
|
+
highlight = 0;
|
|
7277
|
+
movedSinceOpen = false;
|
|
7278
|
+
const cfg = await getConfig().catch(() => null);
|
|
7279
|
+
aliasesCache = cfg && cfg.aliases && typeof cfg.aliases === "object" ? cfg.aliases : {};
|
|
7280
|
+
ensureStyle();
|
|
7281
|
+
const L = t();
|
|
7282
|
+
popupEl = h(
|
|
7283
|
+
"div",
|
|
7284
|
+
{
|
|
7285
|
+
class: "zcodepro-switcher-overlay",
|
|
7286
|
+
// 点弹窗外 = 取消(不切)
|
|
7287
|
+
onMousedown: (e) => {
|
|
7288
|
+
if (e.target === popupEl) closePopup(false);
|
|
7014
7289
|
}
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7290
|
+
},
|
|
7291
|
+
h(
|
|
7292
|
+
"div",
|
|
7293
|
+
{ class: "zcodepro-switcher" },
|
|
7294
|
+
// 提示行键位跟随当前配置(改键后新开的弹窗即用新键位)
|
|
7295
|
+
h(
|
|
7296
|
+
"div",
|
|
7297
|
+
{ class: "zcodepro-switcher-hint" },
|
|
7298
|
+
(mode === "attention" ? L.switcherAttentionHint : L.switcherHint).replaceAll("{prev}", hotkeys.switchPrev).replaceAll("{next}", hotkeys.switchNext)
|
|
7299
|
+
),
|
|
7300
|
+
h("div", { "data-zcodepro-switcher-list": "1", class: "zcodepro-switcher-list" })
|
|
7301
|
+
)
|
|
7302
|
+
);
|
|
7303
|
+
document.body.append(popupEl);
|
|
7304
|
+
renderPopup();
|
|
7305
|
+
}
|
|
7306
|
+
function scrollHighlight() {
|
|
7307
|
+
const row = popupEl && popupEl.querySelector("[data-active]");
|
|
7308
|
+
if (row) row.scrollIntoView({ block: "nearest" });
|
|
7309
|
+
}
|
|
7310
|
+
function moveUp() {
|
|
7311
|
+
const len = Math.min(activeList().length, visibleCount);
|
|
7312
|
+
if (len < 2) return;
|
|
7313
|
+
highlight = highlight > 0 ? highlight - 1 : len - 1;
|
|
7314
|
+
movedSinceOpen = true;
|
|
7315
|
+
renderPopup();
|
|
7316
|
+
scrollHighlight();
|
|
7317
|
+
}
|
|
7318
|
+
function moveDown() {
|
|
7319
|
+
const full = activeList();
|
|
7320
|
+
const len = Math.min(full.length, visibleCount);
|
|
7321
|
+
if (len < 2) return;
|
|
7322
|
+
if (highlight < len - 1) {
|
|
7323
|
+
highlight += 1;
|
|
7324
|
+
} else if (visibleCount < full.length) {
|
|
7325
|
+
visibleCount = Math.min(visibleCount + PAGE_SIZE, full.length);
|
|
7326
|
+
highlight = len;
|
|
7327
|
+
} else {
|
|
7328
|
+
highlight = 0;
|
|
7019
7329
|
}
|
|
7020
|
-
|
|
7021
|
-
|
|
7330
|
+
movedSinceOpen = true;
|
|
7331
|
+
renderPopup();
|
|
7332
|
+
scrollHighlight();
|
|
7022
7333
|
}
|
|
7023
|
-
function
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7334
|
+
function startSessionSwitch() {
|
|
7335
|
+
scan2();
|
|
7336
|
+
void loadHotkeys();
|
|
7337
|
+
window.addEventListener("zcodepro:config-changed", () => {
|
|
7338
|
+
void loadHotkeys();
|
|
7339
|
+
});
|
|
7340
|
+
new MutationObserver((muts) => {
|
|
7341
|
+
if (taskRowMutations(muts)) scheduleScan();
|
|
7342
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] });
|
|
7343
|
+
setInterval(() => {
|
|
7344
|
+
if (!document.hidden) scan2();
|
|
7345
|
+
}, SCAN_FALLBACK_MS2);
|
|
7346
|
+
document.addEventListener("visibilitychange", () => {
|
|
7347
|
+
if (!document.hidden) scan2();
|
|
7348
|
+
});
|
|
7349
|
+
setInterval(() => {
|
|
7350
|
+
if (document.hidden) return;
|
|
7351
|
+
const now = wsRunningKeys();
|
|
7352
|
+
if (lastRunKeys) {
|
|
7353
|
+
for (const k of lastRunKeys) {
|
|
7354
|
+
if (!now.has(k) && k !== current) unseen.add(k);
|
|
7355
|
+
}
|
|
7031
7356
|
}
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
const
|
|
7037
|
-
|
|
7038
|
-
})
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7357
|
+
lastRunKeys = now;
|
|
7358
|
+
if (unseen.size > UNSEEN_LIMIT) unseen = new Set([...unseen].slice(-UNSEEN_LIMIT));
|
|
7359
|
+
}, 1e4);
|
|
7360
|
+
document.addEventListener("click", (e) => {
|
|
7361
|
+
const item = e.target instanceof Element && e.target.closest("[data-task-item-key]");
|
|
7362
|
+
if (item) record(item.getAttribute("data-task-item-key"));
|
|
7363
|
+
}, true);
|
|
7364
|
+
document.addEventListener("keydown", (e) => {
|
|
7365
|
+
if (e.key === "Escape" && popupEl) {
|
|
7366
|
+
e.preventDefault();
|
|
7367
|
+
e.stopImmediatePropagation();
|
|
7368
|
+
closePopup(false);
|
|
7369
|
+
return;
|
|
7370
|
+
}
|
|
7371
|
+
if (popupEl && (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Enter")) {
|
|
7372
|
+
e.preventDefault();
|
|
7373
|
+
e.stopImmediatePropagation();
|
|
7374
|
+
if (e.key === "ArrowUp") moveUp();
|
|
7375
|
+
else if (e.key === "ArrowDown") moveDown();
|
|
7376
|
+
else if (!e.repeat) closePopup(true);
|
|
7377
|
+
return;
|
|
7378
|
+
}
|
|
7379
|
+
if (!e.altKey || e.ctrlKey || e.metaKey || e.isComposing) return;
|
|
7380
|
+
if (document.querySelector(".zcodepro-overlay")) return;
|
|
7381
|
+
const k = e.key.toLowerCase();
|
|
7382
|
+
const isHot = k === hotkeys.switchLast || k === hotkeys.switchPrev || k === hotkeys.switchNext || k === hotkeys.switchRecent || k === hotkeys.switchAttention;
|
|
7383
|
+
if (!isHot) return;
|
|
7384
|
+
e.preventDefault();
|
|
7385
|
+
e.stopImmediatePropagation();
|
|
7386
|
+
void (async () => {
|
|
7387
|
+
const cfg = await getConfig();
|
|
7388
|
+
if (cfg.features && cfg.features.sessionSwitch === false) return;
|
|
7389
|
+
if (k === hotkeys.switchLast) {
|
|
7390
|
+
if (e.repeat) return;
|
|
7391
|
+
closePopup(false);
|
|
7392
|
+
const live = findCurrent();
|
|
7393
|
+
if (live) record(live.getAttribute("data-task-item-key"));
|
|
7394
|
+
const target = live ? mru[0] === current ? mru[1] : mru.find((mk) => mk !== current) : mru[0];
|
|
7395
|
+
if (!target) {
|
|
7396
|
+
showToast(t().switcherEmpty);
|
|
7397
|
+
return;
|
|
7050
7398
|
}
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7399
|
+
void switchTo(target).then((ok) => {
|
|
7400
|
+
if (!ok) showToast(t().switcherFailed, "error");
|
|
7401
|
+
});
|
|
7402
|
+
return;
|
|
7403
|
+
}
|
|
7404
|
+
if (k === hotkeys.switchAttention) {
|
|
7405
|
+
if (e.repeat) return;
|
|
7406
|
+
closePopup(false);
|
|
7407
|
+
if (!attentionList().length) {
|
|
7408
|
+
showToast(t().switcherAttentionEmpty);
|
|
7409
|
+
return;
|
|
7410
|
+
}
|
|
7411
|
+
await openPopup("attention");
|
|
7412
|
+
return;
|
|
7413
|
+
}
|
|
7414
|
+
if (mru.length < 2) {
|
|
7415
|
+
showToast(t().switcherEmpty);
|
|
7416
|
+
return;
|
|
7417
|
+
}
|
|
7418
|
+
if (k === hotkeys.switchRecent) {
|
|
7419
|
+
if (!e.repeat && !popupEl) await openPopup("mru");
|
|
7420
|
+
return;
|
|
7421
|
+
}
|
|
7422
|
+
if (!popupEl) await openPopup("mru");
|
|
7423
|
+
if (k === hotkeys.switchPrev) moveUp();
|
|
7424
|
+
else moveDown();
|
|
7425
|
+
})();
|
|
7426
|
+
}, true);
|
|
7427
|
+
document.addEventListener("keyup", (e) => {
|
|
7428
|
+
if (e.key === "Alt" && popupEl && movedSinceOpen) closePopup(true);
|
|
7429
|
+
}, true);
|
|
7430
|
+
window.addEventListener("blur", () => closePopup(false));
|
|
7431
|
+
}
|
|
7432
|
+
|
|
7433
|
+
// src/inject/features/newtab-panels.js
|
|
7434
|
+
var GRID_HINTS = ["\u8FD0\u884C\u547D\u4EE4\u548C\u67E5\u770B\u8F93\u51FA", "Run commands and view output"];
|
|
7435
|
+
var OFFICIAL_SUFFIX = "@zcode-plugins-official";
|
|
7436
|
+
var OPEN_FN_MARK = "\u6253\u5F00\u63D2\u4EF6 UI";
|
|
7437
|
+
var enabled3 = true;
|
|
7438
|
+
var injectTimer = 0;
|
|
7439
|
+
function eachFiber(visit) {
|
|
7440
|
+
const rootEl = document.getElementById("root");
|
|
7441
|
+
const key = rootEl && Object.keys(rootEl).find((k) => k.startsWith("__reactContainer$"));
|
|
7442
|
+
if (!key) return;
|
|
7443
|
+
let visited = 0;
|
|
7444
|
+
const walk = (f) => {
|
|
7445
|
+
if (!f || visited > 2e5) return;
|
|
7446
|
+
visited++;
|
|
7447
|
+
if (visit(f)) return true;
|
|
7448
|
+
return walk(f.child) || walk(f.sibling);
|
|
7449
|
+
};
|
|
7450
|
+
walk(rootEl[key]);
|
|
7451
|
+
}
|
|
7452
|
+
function findOpenSidePane() {
|
|
7453
|
+
let found = null;
|
|
7454
|
+
eachFiber((f) => {
|
|
7455
|
+
const et = f.elementType;
|
|
7456
|
+
if (et && typeof et === "object" && typeof et.$$typeof === "symbol" && String(et.$$typeof).includes("react.context")) {
|
|
7457
|
+
const val = f.memoizedProps && f.memoizedProps.value;
|
|
7458
|
+
if (typeof val === "function" && val.toString().includes(OPEN_FN_MARK)) {
|
|
7459
|
+
found = val;
|
|
7460
|
+
return true;
|
|
7054
7461
|
}
|
|
7055
7462
|
}
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7463
|
+
return false;
|
|
7464
|
+
});
|
|
7465
|
+
return found;
|
|
7059
7466
|
}
|
|
7060
|
-
function
|
|
7467
|
+
function findBridge() {
|
|
7468
|
+
let holder = null;
|
|
7061
7469
|
const seen = /* @__PURE__ */ new Set();
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
const
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7470
|
+
const scan4 = (o) => {
|
|
7471
|
+
if (!o || typeof o !== "object" || seen.has(o) || holder) return;
|
|
7472
|
+
seen.add(o);
|
|
7473
|
+
if (typeof o.pluginUiBridgeService === "object" && o.pluginUiBridgeService) {
|
|
7474
|
+
holder = o.pluginUiBridgeService;
|
|
7475
|
+
return;
|
|
7476
|
+
}
|
|
7477
|
+
for (const v of Object.values(o)) if (v && typeof v === "object") scan4(v);
|
|
7478
|
+
};
|
|
7479
|
+
eachFiber((f) => {
|
|
7480
|
+
for (const h2 of [f.memoizedProps, f.memoizedState]) {
|
|
7481
|
+
if (!h2 || typeof h2 !== "object") continue;
|
|
7482
|
+
scan4(h2);
|
|
7483
|
+
if (holder) return true;
|
|
7484
|
+
}
|
|
7485
|
+
return false;
|
|
7486
|
+
});
|
|
7487
|
+
return holder;
|
|
7488
|
+
}
|
|
7489
|
+
function sessionScope() {
|
|
7490
|
+
const rows = [...document.querySelectorAll("[data-task-item-key]")];
|
|
7491
|
+
const cur = rows.find((e) => (e.className + "").includes("bg-selected")) || rows[rows.length - 1];
|
|
7492
|
+
const key = cur ? cur.getAttribute("data-task-item-key") : "";
|
|
7493
|
+
if (!key) return null;
|
|
7494
|
+
const i = key.indexOf(":sess_");
|
|
7495
|
+
return i > 0 ? { workspacePath: key.slice(0, i), sessionId: key.slice(i + 1) } : null;
|
|
7496
|
+
}
|
|
7497
|
+
async function thirdPartySurfaces(bridge, workspacePath) {
|
|
7498
|
+
try {
|
|
7499
|
+
const list = await bridge.listSurfaces({ workspacePath });
|
|
7500
|
+
return (list || []).filter((s) => !String(s.pluginId || "").endsWith(OFFICIAL_SUFFIX));
|
|
7501
|
+
} catch {
|
|
7502
|
+
return [];
|
|
7074
7503
|
}
|
|
7075
|
-
applySectionSpin();
|
|
7076
|
-
for (const ws of [...runningByWs.keys()]) if (!seen.has(ws)) runningByWs.delete(ws);
|
|
7077
7504
|
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
if (
|
|
7085
|
-
|
|
7505
|
+
function surfaceTitle(s, locale) {
|
|
7506
|
+
const title = s.title;
|
|
7507
|
+
const pick = (obj) => {
|
|
7508
|
+
const lang = (locale || "").split("-")[0];
|
|
7509
|
+
return obj[locale] || lang && obj[lang] || Object.entries(obj).find(([k]) => k.toLowerCase().startsWith(lang || "\0"))?.[1] || obj.en || Object.values(obj)[0] || "";
|
|
7510
|
+
};
|
|
7511
|
+
if (typeof title === "string") return title;
|
|
7512
|
+
if (title && typeof title === "object") {
|
|
7513
|
+
return pick(title) || s.pluginName || s.id;
|
|
7514
|
+
}
|
|
7515
|
+
return s.pluginName || s.id;
|
|
7516
|
+
}
|
|
7517
|
+
var PANEL_ICON_PATHS = ['<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>'];
|
|
7518
|
+
function findNewTabGrid() {
|
|
7519
|
+
const item = document.querySelector("[data-side-pane-open-tab-item]");
|
|
7520
|
+
if (!item || item.offsetParent === null) return null;
|
|
7521
|
+
const grid = item.parentElement;
|
|
7522
|
+
if (!grid || grid === document.body) return null;
|
|
7523
|
+
const text = grid.textContent || "";
|
|
7524
|
+
return GRID_HINTS.some((h2) => text.includes(h2)) ? grid : null;
|
|
7525
|
+
}
|
|
7526
|
+
async function injectPanels(grid) {
|
|
7527
|
+
if (grid.dataset.zcodeproPanels) return;
|
|
7528
|
+
const template = grid.querySelector("[data-side-pane-open-tab-item]");
|
|
7529
|
+
if (!template) return;
|
|
7530
|
+
const scope = sessionScope();
|
|
7531
|
+
if (!scope) return;
|
|
7532
|
+
const bridge = findBridge();
|
|
7533
|
+
if (!bridge) return;
|
|
7534
|
+
const surfaces = await thirdPartySurfaces(bridge, scope.workspacePath);
|
|
7535
|
+
if (!surfaces.length) {
|
|
7536
|
+
grid.dataset.zcodeproPanels = "1";
|
|
7537
|
+
return;
|
|
7538
|
+
}
|
|
7539
|
+
grid.dataset.zcodeproPanels = "1";
|
|
7540
|
+
const L = t();
|
|
7541
|
+
const locale = isZhLocale() ? "zh-CN" : "en-US";
|
|
7542
|
+
for (const s of surfaces) {
|
|
7543
|
+
const card = template.cloneNode(true);
|
|
7544
|
+
card.removeAttribute("data-side-pane-open-tab-item");
|
|
7545
|
+
card.setAttribute("data-zcodepro-panel", s.id);
|
|
7546
|
+
card.setAttribute("data-zcodepro-panel-name", s.pluginName || "");
|
|
7547
|
+
const title = surfaceTitle(s, locale);
|
|
7548
|
+
const desc = (s.pluginName || "") + " \xB7 " + L.ntpDescSuffix;
|
|
7549
|
+
const titleEl = card.querySelector("span.font-semibold");
|
|
7550
|
+
if (titleEl) titleEl.textContent = title;
|
|
7551
|
+
const descEl = card.querySelector("span[title]");
|
|
7552
|
+
if (descEl) {
|
|
7553
|
+
descEl.textContent = desc;
|
|
7554
|
+
descEl.setAttribute("title", desc);
|
|
7555
|
+
}
|
|
7556
|
+
const svg = card.querySelector("svg");
|
|
7557
|
+
if (svg) {
|
|
7558
|
+
svg.innerHTML = PANEL_ICON_PATHS[0];
|
|
7559
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
7560
|
+
}
|
|
7561
|
+
card.addEventListener("click", (ev) => {
|
|
7562
|
+
ev.stopPropagation();
|
|
7563
|
+
const sc = sessionScope();
|
|
7564
|
+
const open = findOpenSidePane();
|
|
7565
|
+
if (!sc || !open) {
|
|
7566
|
+
showToast(L.ntpNeedSession, "error");
|
|
7567
|
+
return;
|
|
7568
|
+
}
|
|
7569
|
+
try {
|
|
7570
|
+
open({
|
|
7571
|
+
parentSessionId: sc.sessionId,
|
|
7572
|
+
pluginId: s.pluginId,
|
|
7573
|
+
surfaceId: s.id,
|
|
7574
|
+
serverName: s.server,
|
|
7575
|
+
resourceUri: s.resourceUri,
|
|
7576
|
+
remoteSessionId: null,
|
|
7577
|
+
title,
|
|
7578
|
+
workspacePath: sc.workspacePath
|
|
7579
|
+
});
|
|
7580
|
+
} catch (e) {
|
|
7581
|
+
console.warn("[zcodepro] \u6253\u5F00\u63D2\u4EF6\u9762\u677F\u5931\u8D25", e);
|
|
7582
|
+
showToast(L.ntpNeedSession, "error");
|
|
7583
|
+
}
|
|
7584
|
+
});
|
|
7585
|
+
grid.append(card);
|
|
7586
|
+
}
|
|
7086
7587
|
}
|
|
7087
|
-
function
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7588
|
+
function tryInject() {
|
|
7589
|
+
if (!enabled3 || document.hidden) return;
|
|
7590
|
+
const grid = findNewTabGrid();
|
|
7591
|
+
if (!grid) return;
|
|
7592
|
+
if (grid.dataset.zcodeproPanels && !grid.querySelector("[data-zcodepro-panel]")) {
|
|
7593
|
+
delete grid.dataset.zcodeproPanels;
|
|
7092
7594
|
}
|
|
7093
|
-
|
|
7094
|
-
return heads.map((head) => {
|
|
7095
|
-
const cached = headInfoCache.get(head);
|
|
7096
|
-
if (cached) return { head, cont: cached.cont, kind: cached.kind };
|
|
7097
|
-
const textKind = head.tagName === "BUTTON" ? kindFromHeadText(head) : "task";
|
|
7098
|
-
let cont = head.parentElement;
|
|
7099
|
-
while (cont && !cont.querySelector("li[data-task-item-key]") && cont !== document.body) cont = cont.parentElement;
|
|
7100
|
-
const contOk = cont && cont !== document.body;
|
|
7101
|
-
const kind = textKind || (contOk ? cont.querySelector("section[data-project-id]") ? "project" : "task" : null);
|
|
7102
|
-
headInfoCache.set(head, { cont: contOk ? cont : null, kind });
|
|
7103
|
-
return { head, cont: contOk ? cont : null, kind };
|
|
7104
|
-
}).filter((x) => x.head);
|
|
7595
|
+
void injectPanels(grid);
|
|
7105
7596
|
}
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7597
|
+
function startNewtabPanels() {
|
|
7598
|
+
ensureStyle();
|
|
7599
|
+
const refreshEnabled = () => {
|
|
7600
|
+
void getConfig().then((cfg) => {
|
|
7601
|
+
enabled3 = cfg.features ? cfg.features.newtabPanels !== false : true;
|
|
7602
|
+
}).catch(() => {
|
|
7603
|
+
});
|
|
7604
|
+
};
|
|
7605
|
+
refreshEnabled();
|
|
7606
|
+
window.addEventListener("zcodepro:config-changed", refreshEnabled);
|
|
7607
|
+
const observer2 = new MutationObserver(() => {
|
|
7608
|
+
if (injectTimer) return;
|
|
7609
|
+
injectTimer = setTimeout(() => {
|
|
7610
|
+
injectTimer = 0;
|
|
7611
|
+
tryInject();
|
|
7612
|
+
}, 300);
|
|
7613
|
+
});
|
|
7614
|
+
observer2.observe(document.body, { childList: true, subtree: true });
|
|
7615
|
+
setInterval(tryInject, 5e3);
|
|
7616
|
+
}
|
|
7617
|
+
|
|
7618
|
+
// src/inject/features/title-lock.js
|
|
7619
|
+
var TASK_SEL2 = "[data-task-item-key]";
|
|
7620
|
+
var SCAN_DEBOUNCE_MS3 = 150;
|
|
7621
|
+
var SCAN_FALLBACK_MS3 = 5e3;
|
|
7622
|
+
var BOOT_RETRY_MS = 5e3;
|
|
7623
|
+
var RECHECK_DELAY_MS = 1e3;
|
|
7624
|
+
var REVERIFY_MS = 3e3;
|
|
7625
|
+
var MAP_REFRESH_MS = 6e4;
|
|
7626
|
+
var installed3 = false;
|
|
7627
|
+
var seenRows = /* @__PURE__ */ new WeakSet();
|
|
7628
|
+
var enabled4 = true;
|
|
7629
|
+
var pinned = null;
|
|
7630
|
+
var resolved = false;
|
|
7631
|
+
var fetching = null;
|
|
7632
|
+
var pendingKeys = /* @__PURE__ */ new Set();
|
|
7633
|
+
function sessIdOf(key) {
|
|
7634
|
+
const i = key.indexOf(":sess_");
|
|
7635
|
+
return i > 0 ? key.slice(i + 1) : key;
|
|
7636
|
+
}
|
|
7637
|
+
function titleElsOf(item) {
|
|
7638
|
+
const copies = item.querySelectorAll("[data-task-title-copy]");
|
|
7639
|
+
if (copies.length) return [...copies];
|
|
7640
|
+
const t2 = item.querySelector('[class*="truncate"]');
|
|
7641
|
+
return t2 ? [t2] : [];
|
|
7642
|
+
}
|
|
7643
|
+
function findRows(key) {
|
|
7644
|
+
return [...document.querySelectorAll(`${TASK_SEL2}[data-task-item-key="${CSS.escape(key)}"]`)];
|
|
7645
|
+
}
|
|
7646
|
+
async function fetchPinned() {
|
|
7647
|
+
if (fetching) return fetching;
|
|
7648
|
+
const p = (async () => {
|
|
7649
|
+
const res = await rpc("/pinned-titles");
|
|
7650
|
+
if (!res || !res.ok) return null;
|
|
7651
|
+
resolved = true;
|
|
7652
|
+
enabled4 = res.enabled !== false;
|
|
7653
|
+
if (!enabled4) {
|
|
7654
|
+
pinned = null;
|
|
7655
|
+
return null;
|
|
7656
|
+
}
|
|
7657
|
+
pinned = new Map(Object.entries(res.titles || {}));
|
|
7658
|
+
return pinned;
|
|
7659
|
+
})();
|
|
7660
|
+
fetching = p;
|
|
7661
|
+
try {
|
|
7662
|
+
return await p;
|
|
7663
|
+
} finally {
|
|
7664
|
+
if (fetching === p) fetching = null;
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
function isMismatch(item) {
|
|
7668
|
+
if (!enabled4 || !pinned) return null;
|
|
7669
|
+
const key = item.getAttribute("data-task-item-key") || "";
|
|
7670
|
+
const want = pinned.get(sessIdOf(key));
|
|
7671
|
+
if (want === void 0) return null;
|
|
7672
|
+
const els = titleElsOf(item);
|
|
7673
|
+
if (!els.length) return null;
|
|
7674
|
+
if ((els[0].textContent || "").trim() === String(want).trim()) return null;
|
|
7675
|
+
if (item.querySelector('input, textarea, [contenteditable="true"]')) return null;
|
|
7676
|
+
return key;
|
|
7677
|
+
}
|
|
7678
|
+
function writeTitle(el, text) {
|
|
7679
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
7680
|
+
const first = walker.nextNode();
|
|
7681
|
+
if (first && !walker.nextNode()) first.nodeValue = text;
|
|
7682
|
+
else el.textContent = text;
|
|
7683
|
+
}
|
|
7684
|
+
function scheduleEnforce(key, { immediate = false } = {}) {
|
|
7685
|
+
if (immediate) {
|
|
7686
|
+
if (enabled4 && pinned) {
|
|
7687
|
+
const want = pinned.get(sessIdOf(key));
|
|
7688
|
+
if (want !== void 0) {
|
|
7689
|
+
for (const item of findRows(key)) {
|
|
7690
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7184
7691
|
}
|
|
7185
|
-
const taskDomRunning = !!document.querySelector('[data-task-item-key]:not(section[data-project-id] *) svg[class*="lucide-loader"]');
|
|
7186
|
-
if (taskDomRunning && [...byKind.task].some(live)) sectionActive.task = true;
|
|
7187
|
-
if ([...byKind.project].some(live)) sectionActive.project = true;
|
|
7188
|
-
hit = sectionActive.task || sectionActive.project;
|
|
7189
7692
|
}
|
|
7190
|
-
} catch {
|
|
7191
7693
|
}
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7694
|
+
}
|
|
7695
|
+
if (pendingKeys.has(key)) return;
|
|
7696
|
+
pendingKeys.add(key);
|
|
7697
|
+
setTimeout(() => {
|
|
7698
|
+
pendingKeys.delete(key);
|
|
7699
|
+
void (async () => {
|
|
7700
|
+
const map = await fetchPinned();
|
|
7701
|
+
if (!map) return;
|
|
7702
|
+
const want = map.get(sessIdOf(key));
|
|
7703
|
+
if (want === void 0) return;
|
|
7704
|
+
let wrote = false;
|
|
7705
|
+
for (const item of findRows(key)) {
|
|
7706
|
+
if (isMismatch(item) !== key) continue;
|
|
7707
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7708
|
+
wrote = true;
|
|
7709
|
+
}
|
|
7710
|
+
if (wrote) setTimeout(() => {
|
|
7711
|
+
void enforceKey(key);
|
|
7712
|
+
}, REVERIFY_MS);
|
|
7713
|
+
})();
|
|
7714
|
+
}, RECHECK_DELAY_MS);
|
|
7715
|
+
}
|
|
7716
|
+
async function enforceKey(key) {
|
|
7717
|
+
const map = await fetchPinned();
|
|
7718
|
+
if (!map) return;
|
|
7719
|
+
const want = map.get(sessIdOf(key));
|
|
7720
|
+
if (want === void 0) return;
|
|
7721
|
+
for (const item of findRows(key)) {
|
|
7722
|
+
if (isMismatch(item) !== key) continue;
|
|
7723
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7724
|
+
}
|
|
7197
7725
|
}
|
|
7198
|
-
function
|
|
7199
|
-
if (!
|
|
7200
|
-
|
|
7201
|
-
|
|
7726
|
+
function scan3() {
|
|
7727
|
+
if (!enabled4 || !pinned || pinned.size === 0) return;
|
|
7728
|
+
for (const item of document.querySelectorAll(TASK_SEL2)) {
|
|
7729
|
+
const key = isMismatch(item);
|
|
7730
|
+
if (!key) {
|
|
7731
|
+
seenRows.add(item);
|
|
7732
|
+
continue;
|
|
7733
|
+
}
|
|
7734
|
+
const fresh = !seenRows.has(item);
|
|
7735
|
+
seenRows.add(item);
|
|
7736
|
+
scheduleEnforce(key, { immediate: fresh });
|
|
7202
7737
|
}
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7738
|
+
}
|
|
7739
|
+
var inTaskRow2 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL2));
|
|
7740
|
+
function taskRowMutations2(muts) {
|
|
7741
|
+
for (const m of muts) {
|
|
7742
|
+
if (m.type === "attributes") {
|
|
7743
|
+
if (inTaskRow2(m.target)) return true;
|
|
7744
|
+
} else if (m.type === "characterData") {
|
|
7745
|
+
if (m.target.parentElement && inTaskRow2(m.target.parentElement)) return true;
|
|
7746
|
+
} else if (inTaskRow2(m.target)) {
|
|
7747
|
+
return true;
|
|
7748
|
+
} else {
|
|
7749
|
+
for (const n of m.addedNodes) {
|
|
7750
|
+
if (n instanceof Element && (n.matches(TASK_SEL2) || !!n.querySelector(TASK_SEL2))) return true;
|
|
7751
|
+
}
|
|
7210
7752
|
}
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7753
|
+
}
|
|
7754
|
+
return false;
|
|
7755
|
+
}
|
|
7756
|
+
var scanDebounce3 = 0;
|
|
7757
|
+
function scheduleScan2() {
|
|
7758
|
+
if (scanDebounce3) return;
|
|
7759
|
+
scanDebounce3 = setTimeout(() => {
|
|
7760
|
+
scanDebounce3 = 0;
|
|
7761
|
+
scan3();
|
|
7762
|
+
}, SCAN_DEBOUNCE_MS3);
|
|
7763
|
+
}
|
|
7764
|
+
var mapRefreshTimer = 0;
|
|
7765
|
+
function refreshMapSoon() {
|
|
7766
|
+
if (mapRefreshTimer) return;
|
|
7767
|
+
const tick2 = () => {
|
|
7768
|
+
if (document.hidden) {
|
|
7769
|
+
mapRefreshTimer = setTimeout(tick2, 1e4);
|
|
7770
|
+
return;
|
|
7222
7771
|
}
|
|
7772
|
+
mapRefreshTimer = 0;
|
|
7773
|
+
if (enabled4 && resolved) void fetchPinned().then((m) => {
|
|
7774
|
+
if (m) scan3();
|
|
7775
|
+
});
|
|
7776
|
+
};
|
|
7777
|
+
mapRefreshTimer = setTimeout(tick2, MAP_REFRESH_MS);
|
|
7778
|
+
}
|
|
7779
|
+
var editingKey = null;
|
|
7780
|
+
var bootDelay = 0;
|
|
7781
|
+
function scheduleBootRetry() {
|
|
7782
|
+
bootDelay = bootDelay ? Math.min(bootDelay * 2, MAP_REFRESH_MS) : BOOT_RETRY_MS;
|
|
7783
|
+
setTimeout(() => {
|
|
7784
|
+
if (resolved) return;
|
|
7785
|
+
if (!document.hidden) void bootstrap();
|
|
7786
|
+
scheduleBootRetry();
|
|
7787
|
+
}, bootDelay);
|
|
7788
|
+
}
|
|
7789
|
+
async function bootstrap() {
|
|
7790
|
+
const map = await fetchPinned();
|
|
7791
|
+
if (map) scan3();
|
|
7792
|
+
}
|
|
7793
|
+
function setRowTitle(key, text) {
|
|
7794
|
+
for (const item of findRows(key)) {
|
|
7795
|
+
for (const el of titleElsOf(item)) writeTitle(el, text);
|
|
7223
7796
|
}
|
|
7224
7797
|
}
|
|
7225
|
-
function
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
void peek(ws);
|
|
7230
|
-
}, delay));
|
|
7798
|
+
function refreshPinnedTitles() {
|
|
7799
|
+
return fetchPinned().then((m) => {
|
|
7800
|
+
if (m) scan3();
|
|
7801
|
+
});
|
|
7231
7802
|
}
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7803
|
+
var RENAME_CTX_VALID_MS = 15e3;
|
|
7804
|
+
var renameCtx = null;
|
|
7805
|
+
var renamePrefilled = /* @__PURE__ */ new WeakSet();
|
|
7806
|
+
function setNativeValue(el, text) {
|
|
7807
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
7808
|
+
Object.getOwnPropertyDescriptor(el.constructor.prototype, "value").set.call(el, text);
|
|
7809
|
+
} else {
|
|
7810
|
+
el.textContent = text;
|
|
7237
7811
|
}
|
|
7812
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
7238
7813
|
}
|
|
7239
|
-
function
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7814
|
+
function prefillRenameDialog() {
|
|
7815
|
+
if (!renameCtx || !renameCtx.armed || Date.now() - renameCtx.at > RENAME_CTX_VALID_MS) {
|
|
7816
|
+
renameCtx = null;
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
if (!enabled4 || !pinned) return;
|
|
7820
|
+
const want = pinned.get(sessIdOf(renameCtx.key));
|
|
7821
|
+
if (want === void 0) return;
|
|
7822
|
+
for (const el of document.querySelectorAll('[role="dialog"] input, [role="dialog"] textarea, [role="dialog"] [contenteditable="true"]')) {
|
|
7823
|
+
if (renamePrefilled.has(el) || !el.getClientRects().length) continue;
|
|
7824
|
+
if (el.closest(TASK_SEL2) || el.closest(".zcodepro-overlay")) continue;
|
|
7825
|
+
const cur = String(el.value ?? el.textContent ?? "").trim();
|
|
7826
|
+
if (!cur) continue;
|
|
7827
|
+
renamePrefilled.add(el);
|
|
7828
|
+
if (cur !== String(want).trim()) setNativeValue(el, String(want));
|
|
7829
|
+
renameCtx = null;
|
|
7830
|
+
return;
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
function startTitleLock() {
|
|
7834
|
+
if (installed3 || typeof document === "undefined") return;
|
|
7835
|
+
installed3 = true;
|
|
7836
|
+
void bootstrap();
|
|
7837
|
+
new MutationObserver((muts) => {
|
|
7838
|
+
if (renameCtx) prefillRenameDialog();
|
|
7839
|
+
if (!taskRowMutations2(muts)) return;
|
|
7840
|
+
refreshMapSoon();
|
|
7841
|
+
scheduleScan2();
|
|
7842
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
|
|
7843
|
+
document.addEventListener("contextmenu", (e) => {
|
|
7844
|
+
const row = e.target instanceof Element && e.target.closest(TASK_SEL2);
|
|
7845
|
+
renameCtx = row ? { key: row.getAttribute("data-task-item-key") || "", at: 0, armed: false } : null;
|
|
7846
|
+
}, true);
|
|
7847
|
+
document.addEventListener("click", (e) => {
|
|
7848
|
+
if (!renameCtx || renameCtx.armed) return;
|
|
7849
|
+
const item = e.target instanceof Element && e.target.closest('[role="menuitem"], [data-radix-collection-item]');
|
|
7850
|
+
if (item && /重命名|rename/i.test(item.textContent || "")) {
|
|
7851
|
+
renameCtx.armed = true;
|
|
7852
|
+
renameCtx.at = Date.now();
|
|
7250
7853
|
}
|
|
7251
|
-
|
|
7854
|
+
}, true);
|
|
7855
|
+
scheduleBootRetry();
|
|
7856
|
+
setInterval(() => {
|
|
7857
|
+
if (!document.hidden) scan3();
|
|
7858
|
+
}, SCAN_FALLBACK_MS3);
|
|
7859
|
+
document.addEventListener("visibilitychange", () => {
|
|
7860
|
+
if (!document.hidden) scan3();
|
|
7861
|
+
});
|
|
7862
|
+
window.addEventListener("zcodepro:config-changed", () => {
|
|
7863
|
+
void bootstrap();
|
|
7864
|
+
});
|
|
7865
|
+
document.addEventListener("focusin", (e) => {
|
|
7866
|
+
const el = e.target;
|
|
7867
|
+
if (!(el instanceof Element)) return;
|
|
7868
|
+
if (!el.matches('input, textarea, [contenteditable="true"]')) return;
|
|
7869
|
+
const row = el.closest(TASK_SEL2);
|
|
7870
|
+
editingKey = row ? row.getAttribute("data-task-item-key") || "" : null;
|
|
7871
|
+
});
|
|
7872
|
+
document.addEventListener("focusout", () => {
|
|
7873
|
+
if (editingKey === null) return;
|
|
7874
|
+
editingKey = null;
|
|
7875
|
+
void fetchPinned().then((m) => {
|
|
7876
|
+
if (m) scan3();
|
|
7877
|
+
});
|
|
7878
|
+
});
|
|
7879
|
+
}
|
|
7880
|
+
|
|
7881
|
+
// src/inject/features/title-gen.js
|
|
7882
|
+
var CONV2 = '[class*="@md/conversation"]';
|
|
7883
|
+
var USER_ROW = '[class*="user-row"]';
|
|
7884
|
+
var SCAN_DEBOUNCE_MS4 = 300;
|
|
7885
|
+
var SCAN_FALLBACK_MS4 = 5e3;
|
|
7886
|
+
var SELECT_WAIT_MS = 2e3;
|
|
7887
|
+
var MSG_WAIT_MS = 1e4;
|
|
7888
|
+
var QUIET_FALLBACK_MS = 12e4;
|
|
7889
|
+
var COLLECT_MAX_MS = 6e5;
|
|
7890
|
+
var installed4 = false;
|
|
7891
|
+
var knownKeys = /* @__PURE__ */ new Set();
|
|
7892
|
+
var attempted = /* @__PURE__ */ new Set();
|
|
7893
|
+
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
7894
|
+
function sessIdOf2(key) {
|
|
7895
|
+
const i = key.indexOf(":sess_");
|
|
7896
|
+
return i > 0 ? key.slice(i + 1) : "";
|
|
7897
|
+
}
|
|
7898
|
+
function currentKey() {
|
|
7899
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7900
|
+
if ((el.className + "").includes("bg-selected")) return el.getAttribute("data-task-item-key") || "";
|
|
7252
7901
|
}
|
|
7902
|
+
return "";
|
|
7253
7903
|
}
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7904
|
+
function userTexts() {
|
|
7905
|
+
return [...document.querySelectorAll(`${CONV2} ${USER_ROW}`)].map((r) => {
|
|
7906
|
+
const el = r.querySelector(".whitespace-pre-wrap");
|
|
7907
|
+
return ((el ? el.textContent : r.innerText) || "").trim();
|
|
7908
|
+
}).filter(Boolean);
|
|
7909
|
+
}
|
|
7910
|
+
var URL_RE = /https?:\/\/[^\s\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+/g;
|
|
7911
|
+
function assistantText() {
|
|
7912
|
+
const els = [...document.querySelectorAll('[class*="@md/conversation"] [class*="assistant-row"]')].filter((e) => !e.querySelector("[data-is-streaming]"));
|
|
7913
|
+
const last = els[els.length - 1];
|
|
7914
|
+
if (!last) return "";
|
|
7915
|
+
const text = (last.innerText || "").replace(URL_RE, "").trim();
|
|
7916
|
+
return text.slice(0, 600);
|
|
7917
|
+
}
|
|
7918
|
+
function linkDominant(t2) {
|
|
7919
|
+
const raw = t2.replace(/\s+/g, "");
|
|
7920
|
+
if (!raw) return true;
|
|
7921
|
+
const stripped = raw.replace(URL_RE, "");
|
|
7922
|
+
return stripped.length < raw.length / 3;
|
|
7923
|
+
}
|
|
7924
|
+
async function onNewTaskRow(key) {
|
|
7925
|
+
const selDeadline = Date.now() + SELECT_WAIT_MS;
|
|
7926
|
+
while (currentKey() !== key && Date.now() < selDeadline) await sleep2(200);
|
|
7927
|
+
if (currentKey() !== key) return;
|
|
7928
|
+
const cfg = await getConfig().catch(() => null);
|
|
7929
|
+
if (!cfg || !cfg.titleGen || cfg.titleGen.enabled !== true) return;
|
|
7930
|
+
const sessId = sessIdOf2(key);
|
|
7931
|
+
if (!sessId || attempted.has(sessId)) return;
|
|
7932
|
+
attempted.add(sessId);
|
|
7933
|
+
let texts = [];
|
|
7934
|
+
const msgDeadline = Date.now() + MSG_WAIT_MS;
|
|
7935
|
+
while (Date.now() < msgDeadline) {
|
|
7936
|
+
texts = userTexts();
|
|
7937
|
+
if (texts.length) break;
|
|
7938
|
+
await sleep2(400);
|
|
7939
|
+
}
|
|
7940
|
+
if (!texts.length) return;
|
|
7941
|
+
let assistantSeen = false;
|
|
7942
|
+
const convObserver = new MutationObserver((muts) => {
|
|
7943
|
+
if (currentKey() !== key) return;
|
|
7944
|
+
for (const m of muts) {
|
|
7945
|
+
const t2 = m.type === "characterData" ? m.target.parentElement : m.target;
|
|
7946
|
+
if (t2 instanceof Element && t2.closest(USER_ROW)) continue;
|
|
7947
|
+
for (const n of [t2, ...m.addedNodes]) {
|
|
7948
|
+
if (n instanceof Element && n.closest && n.closest(CONV2)) {
|
|
7949
|
+
assistantSeen = true;
|
|
7950
|
+
return;
|
|
7266
7951
|
}
|
|
7267
|
-
set.add(ws + ":active");
|
|
7268
|
-
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
7269
7952
|
}
|
|
7270
|
-
apply();
|
|
7271
|
-
return true;
|
|
7272
7953
|
}
|
|
7273
|
-
}
|
|
7274
|
-
const run = () => peekInner(ws, opts);
|
|
7275
|
-
const p = peekChain.then(run, run);
|
|
7276
|
-
peekChain = p.catch(() => {
|
|
7277
7954
|
});
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
const row = findWsRow(ws);
|
|
7283
|
-
const head = row && wsHead(row);
|
|
7284
|
-
if (!row || !head || head.getAttribute("aria-expanded") !== "false") return false;
|
|
7285
|
-
if (!currentTaskRow()) {
|
|
7286
|
-
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
7287
|
-
return false;
|
|
7288
|
-
}
|
|
7289
|
-
activePeeks.add(ws);
|
|
7290
|
-
peekedWs.add(ws);
|
|
7291
|
-
const rect = row.getBoundingClientRect();
|
|
7292
|
-
const frozen = row.cloneNode(true);
|
|
7293
|
-
frozen.classList.add("zcodepro-ws-frozen");
|
|
7294
|
-
frozen.style.left = rect.left + "px";
|
|
7295
|
-
frozen.style.top = rect.top + "px";
|
|
7296
|
-
frozen.style.width = rect.width + "px";
|
|
7297
|
-
frozen.style.height = rect.height + "px";
|
|
7298
|
-
document.body.append(frozen);
|
|
7299
|
-
row.style.visibility = "hidden";
|
|
7300
|
-
const hider = installPeekHider(ws);
|
|
7301
|
-
let readOk = false;
|
|
7955
|
+
convObserver.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
7956
|
+
const startAt = Date.now();
|
|
7957
|
+
let lastCount = texts.length;
|
|
7958
|
+
let lastChange = Date.now();
|
|
7302
7959
|
try {
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7960
|
+
while (Date.now() - startAt < COLLECT_MAX_MS) {
|
|
7961
|
+
await sleep2(500);
|
|
7962
|
+
if (currentKey() !== key) {
|
|
7963
|
+
lastChange = Date.now();
|
|
7964
|
+
continue;
|
|
7965
|
+
}
|
|
7966
|
+
texts = userTexts();
|
|
7967
|
+
if (texts.length !== lastCount) {
|
|
7968
|
+
lastCount = texts.length;
|
|
7969
|
+
lastChange = Date.now();
|
|
7970
|
+
}
|
|
7971
|
+
if (assistantSeen) break;
|
|
7972
|
+
if (Date.now() - lastChange >= QUIET_FALLBACK_MS) break;
|
|
7310
7973
|
}
|
|
7311
7974
|
} finally {
|
|
7312
|
-
|
|
7313
|
-
row.style.visibility = "";
|
|
7314
|
-
frozen.remove();
|
|
7315
|
-
activePeeks.delete(ws);
|
|
7975
|
+
convObserver.disconnect();
|
|
7316
7976
|
}
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
async function verifyWorkspaceNotRunning(ws) {
|
|
7330
|
-
if (!ws || document.hidden) return false;
|
|
7331
|
-
const row = findWsRow(ws);
|
|
7332
|
-
const head = row && wsHead(row);
|
|
7333
|
-
if (!row || !head) return false;
|
|
7334
|
-
if (head.getAttribute("aria-expanded") !== "false") {
|
|
7335
|
-
let run = false;
|
|
7336
|
-
for (const el of domRowsOf(ws)) if (isRunningRow(el)) run = true;
|
|
7337
|
-
return !run;
|
|
7977
|
+
if (!texts.length) return;
|
|
7978
|
+
if (linkDominant(texts.join("\n"))) {
|
|
7979
|
+
const deadline = Date.now() + 6e4;
|
|
7980
|
+
while (Date.now() < deadline) {
|
|
7981
|
+
await sleep2(2e3);
|
|
7982
|
+
if (currentKey() !== key) continue;
|
|
7983
|
+
const a = assistantText();
|
|
7984
|
+
if (a && a.length > 80) {
|
|
7985
|
+
texts.push(`\uFF08\u9996\u8F6E\u56DE\u7B54\u6458\u8981\uFF09${a}`);
|
|
7986
|
+
break;
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7338
7989
|
}
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7990
|
+
const callTitleGen = () => rpc("/title-gen/run", { method: "POST", body: { sessId, text: texts.join("\n") } }).catch(() => null);
|
|
7991
|
+
let res = await callTitleGen();
|
|
7992
|
+
for (const delay of [5e3, 2e4]) {
|
|
7993
|
+
if (res && res.ok) break;
|
|
7994
|
+
await sleep2(delay);
|
|
7995
|
+
res = await callTitleGen();
|
|
7996
|
+
}
|
|
7997
|
+
if (res && res.ok && res.written && res.title) {
|
|
7998
|
+
setRowTitle(key, res.title);
|
|
7999
|
+
void refreshPinnedTitles();
|
|
7343
8000
|
}
|
|
7344
|
-
if (!verified) return false;
|
|
7345
|
-
const set = runningByWs.get(ws);
|
|
7346
|
-
return !(set && set.size);
|
|
7347
|
-
}
|
|
7348
|
-
function settleAndRead(ws) {
|
|
7349
|
-
return new Promise((resolve) => {
|
|
7350
|
-
const t0 = Date.now();
|
|
7351
|
-
let lastCount = -1;
|
|
7352
|
-
let stableAt = 0;
|
|
7353
|
-
let zeroRows = false;
|
|
7354
|
-
const timer = setInterval(() => {
|
|
7355
|
-
const rows = domRowsOf(ws);
|
|
7356
|
-
const elapsed = Date.now() - t0;
|
|
7357
|
-
if (rows.length !== lastCount) {
|
|
7358
|
-
lastCount = rows.length;
|
|
7359
|
-
stableAt = Date.now();
|
|
7360
|
-
}
|
|
7361
|
-
const settled = rows.length > 0 && rows.length === lastCount && Date.now() - stableAt >= PEEK_SETTLE_MS;
|
|
7362
|
-
if (!settled && elapsed < PEEK_MAX_MS) return;
|
|
7363
|
-
clearInterval(timer);
|
|
7364
|
-
if (lastCount === 0) {
|
|
7365
|
-
zeroRows = true;
|
|
7366
|
-
} else {
|
|
7367
|
-
let set = runningByWs.get(ws);
|
|
7368
|
-
if (!set) {
|
|
7369
|
-
set = /* @__PURE__ */ new Set();
|
|
7370
|
-
runningByWs.set(ws, set);
|
|
7371
|
-
}
|
|
7372
|
-
for (const el of rows) {
|
|
7373
|
-
const key = el.getAttribute("data-task-item-key") || "";
|
|
7374
|
-
if (isRunningRow(el)) set.add(key);
|
|
7375
|
-
else set.delete(key);
|
|
7376
|
-
}
|
|
7377
|
-
}
|
|
7378
|
-
resolve(!zeroRows);
|
|
7379
|
-
}, 80);
|
|
7380
|
-
});
|
|
7381
|
-
}
|
|
7382
|
-
var PEEK_EXEMPT_CLASS = "zcodepro-peek-exempt";
|
|
7383
|
-
var cssAttr = (v) => String(v).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
7384
|
-
function installPeekHider(ws) {
|
|
7385
|
-
const rowSel3 = `${TASK_SEL3}[data-task-item-key^="${cssAttr(ws + ":")}"]`;
|
|
7386
|
-
for (const r of document.querySelectorAll(rowSel3)) r.classList.add(PEEK_EXEMPT_CLASS);
|
|
7387
|
-
const style = document.createElement("style");
|
|
7388
|
-
style.textContent = `${rowSel3}:not(.${PEEK_EXEMPT_CLASS}){display:none!important}`;
|
|
7389
|
-
document.head.append(style);
|
|
7390
|
-
return { style, sel: rowSel3 };
|
|
7391
|
-
}
|
|
7392
|
-
function removePeekHider(hider) {
|
|
7393
|
-
hider.style.remove();
|
|
7394
|
-
for (const r of document.querySelectorAll("." + PEEK_EXEMPT_CLASS)) r.classList.remove(PEEK_EXEMPT_CLASS);
|
|
7395
|
-
}
|
|
7396
|
-
function waitForRowsGone(ws) {
|
|
7397
|
-
const sel = `${TASK_SEL3}[data-task-item-key^="${cssAttr(ws + ":")}"]:not(.${PEEK_EXEMPT_CLASS})`;
|
|
7398
|
-
return new Promise((resolve) => {
|
|
7399
|
-
const t0 = Date.now();
|
|
7400
|
-
const timer = setInterval(() => {
|
|
7401
|
-
if (!document.querySelector(sel) || Date.now() - t0 >= PEEK_UNMOUNT_WAIT_MS) {
|
|
7402
|
-
clearInterval(timer);
|
|
7403
|
-
resolve();
|
|
7404
|
-
}
|
|
7405
|
-
}, 40);
|
|
7406
|
-
});
|
|
7407
|
-
}
|
|
7408
|
-
var TOUCH_WINDOW_MS = 800;
|
|
7409
|
-
var wsTouchAt = /* @__PURE__ */ new WeakMap();
|
|
7410
|
-
function userTouched(row) {
|
|
7411
|
-
const at = wsTouchAt.get(row);
|
|
7412
|
-
return !!at && Date.now() - at < TOUCH_WINDOW_MS;
|
|
7413
|
-
}
|
|
7414
|
-
function inSel(node, sel) {
|
|
7415
|
-
return !!(node instanceof Element && node.closest && node.closest(sel));
|
|
7416
8001
|
}
|
|
7417
|
-
function
|
|
7418
|
-
for (const
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
for (const n of m.removedNodes) {
|
|
7424
|
-
if (n instanceof Element && (n.matches(TASK_SEL3) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL3))) return true;
|
|
7425
|
-
}
|
|
8002
|
+
function scanForNewRows() {
|
|
8003
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
8004
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
8005
|
+
if (!key || knownKeys.has(key)) continue;
|
|
8006
|
+
knownKeys.add(key);
|
|
8007
|
+
void onNewTaskRow(key);
|
|
7426
8008
|
}
|
|
7427
|
-
return false;
|
|
7428
8009
|
}
|
|
7429
|
-
var
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
if (
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
return true;
|
|
8010
|
+
var TASK_SEL3 = "[data-task-item-key]";
|
|
8011
|
+
var inTaskRow3 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL3));
|
|
8012
|
+
function taskRowMutations3(muts) {
|
|
8013
|
+
for (const m of muts) {
|
|
8014
|
+
if (m.type === "attributes") {
|
|
8015
|
+
if (inTaskRow3(m.target)) return true;
|
|
8016
|
+
} else if (m.type === "characterData") {
|
|
8017
|
+
if (m.target.parentElement && inTaskRow3(m.target.parentElement)) return true;
|
|
8018
|
+
} else if (inTaskRow3(m.target)) {
|
|
8019
|
+
return true;
|
|
8020
|
+
} else {
|
|
8021
|
+
for (const n of m.addedNodes) {
|
|
8022
|
+
if (n instanceof Element && (n.matches(TASK_SEL3) || !!n.querySelector(TASK_SEL3))) return true;
|
|
7442
8023
|
}
|
|
7443
8024
|
}
|
|
7444
|
-
} catch {
|
|
7445
8025
|
}
|
|
7446
8026
|
return false;
|
|
7447
8027
|
}
|
|
7448
|
-
function pollConfig() {
|
|
7449
|
-
setTimeout(async () => {
|
|
7450
|
-
if (document.hidden) pollMs = CONFIG_POLL_MAX_MS;
|
|
7451
|
-
else pollMs = await refreshConfig() ? CONFIG_POLL_MIN_MS : Math.min(Math.round(pollMs * 1.5), CONFIG_POLL_MAX_MS);
|
|
7452
|
-
pollConfig();
|
|
7453
|
-
}, pollMs);
|
|
7454
|
-
}
|
|
7455
8028
|
var scanDebounce4 = 0;
|
|
7456
|
-
function
|
|
8029
|
+
function scheduleScan3() {
|
|
8030
|
+
if (scanDebounce4) return;
|
|
8031
|
+
scanDebounce4 = setTimeout(() => {
|
|
8032
|
+
scanDebounce4 = 0;
|
|
8033
|
+
scanForNewRows();
|
|
8034
|
+
}, SCAN_DEBOUNCE_MS4);
|
|
8035
|
+
}
|
|
8036
|
+
function startTitleGen() {
|
|
7457
8037
|
if (installed4 || typeof document === "undefined") return;
|
|
7458
8038
|
installed4 = true;
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
handleRemovals(muts);
|
|
7464
|
-
if (!scanDebounce4) {
|
|
7465
|
-
scanDebounce4 = setTimeout(() => {
|
|
7466
|
-
scanDebounce4 = 0;
|
|
7467
|
-
scan3();
|
|
7468
|
-
}, SCAN_DEBOUNCE_MS4);
|
|
7469
|
-
}
|
|
7470
|
-
});
|
|
7471
|
-
observer2.observe(document.body, { childList: true, subtree: true });
|
|
7472
|
-
scan3();
|
|
8039
|
+
scanForNewRows();
|
|
8040
|
+
new MutationObserver((muts) => {
|
|
8041
|
+
if (taskRowMutations3(muts)) scheduleScan3();
|
|
8042
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
|
|
7473
8043
|
setInterval(() => {
|
|
7474
|
-
if (!document.hidden
|
|
8044
|
+
if (!document.hidden) scanForNewRows();
|
|
7475
8045
|
}, SCAN_FALLBACK_MS4);
|
|
7476
8046
|
document.addEventListener("visibilitychange", () => {
|
|
7477
|
-
if (!document.hidden)
|
|
8047
|
+
if (!document.hidden) scanForNewRows();
|
|
7478
8048
|
});
|
|
7479
|
-
document.addEventListener("click", (e) => {
|
|
7480
|
-
if (!e.isTrusted) return;
|
|
7481
|
-
const row = e.target instanceof Element && e.target.closest(WS_SEL());
|
|
7482
|
-
if (row) wsTouchAt.set(row, Date.now());
|
|
7483
|
-
}, true);
|
|
7484
8049
|
}
|
|
7485
8050
|
|
|
7486
8051
|
// src/inject/features/idle-reclaim.js
|
|
@@ -7614,7 +8179,7 @@
|
|
|
7614
8179
|
var SCAN_FALLBACK_MS5 = 5e3;
|
|
7615
8180
|
var ROW_SEL = "[data-task-item-key]";
|
|
7616
8181
|
var MENU_SEL = '[data-testid="task-new-button"], [data-testid="automations-open"], [data-testid="plugin-store-sidebar-open"], [data-testid="sidebar-search-open"], [data-slot="command"], [data-testid="desktop-top-nav-back"]';
|
|
7617
|
-
var
|
|
8182
|
+
var enabled5 = true;
|
|
7618
8183
|
var rowEl = null;
|
|
7619
8184
|
var origs = null;
|
|
7620
8185
|
var syncTimer = 0;
|
|
@@ -7757,7 +8322,7 @@
|
|
|
7757
8322
|
return scroll.getBoundingClientRect().width < NARROW_SIDEBAR_PX;
|
|
7758
8323
|
}
|
|
7759
8324
|
function sync() {
|
|
7760
|
-
if (!
|
|
8325
|
+
if (!enabled5) return;
|
|
7761
8326
|
const parts = findParts();
|
|
7762
8327
|
if (!parts) {
|
|
7763
8328
|
if (rowEl) rowEl.style.display = "none";
|
|
@@ -7819,8 +8384,8 @@
|
|
|
7819
8384
|
}
|
|
7820
8385
|
async function refreshConfig2() {
|
|
7821
8386
|
const cfg = await getConfig(true).catch(() => null);
|
|
7822
|
-
|
|
7823
|
-
if (
|
|
8387
|
+
enabled5 = !cfg || !cfg.features || cfg.features.toolbarIcons !== false;
|
|
8388
|
+
if (enabled5) sync();
|
|
7824
8389
|
else teardown();
|
|
7825
8390
|
}
|
|
7826
8391
|
function startToolbarIcons() {
|
|
@@ -7846,7 +8411,7 @@
|
|
|
7846
8411
|
var STORE_KEY = "zcodepro:pinned-collapsed";
|
|
7847
8412
|
var SYNC_DEBOUNCE_MS2 = 300;
|
|
7848
8413
|
var SCAN_FALLBACK_MS6 = 5e3;
|
|
7849
|
-
var
|
|
8414
|
+
var enabled6 = true;
|
|
7850
8415
|
var syncTimer2 = 0;
|
|
7851
8416
|
function findPinnedHeader() {
|
|
7852
8417
|
for (const h3 of document.querySelectorAll("h3")) {
|
|
@@ -7903,7 +8468,7 @@
|
|
|
7903
8468
|
}
|
|
7904
8469
|
h3.classList.add(HEAD_CLASS);
|
|
7905
8470
|
h3.addEventListener("click", () => {
|
|
7906
|
-
if (
|
|
8471
|
+
if (enabled6) toggle();
|
|
7907
8472
|
});
|
|
7908
8473
|
const btn = h("button", {
|
|
7909
8474
|
type: "button",
|
|
@@ -7912,7 +8477,7 @@
|
|
|
7912
8477
|
"aria-expanded": collapsed ? "false" : "true",
|
|
7913
8478
|
onClick: (e) => {
|
|
7914
8479
|
e.stopPropagation();
|
|
7915
|
-
if (
|
|
8480
|
+
if (enabled6) toggle();
|
|
7916
8481
|
}
|
|
7917
8482
|
});
|
|
7918
8483
|
btn.append(chevronSvg());
|
|
@@ -7920,7 +8485,7 @@
|
|
|
7920
8485
|
return true;
|
|
7921
8486
|
}
|
|
7922
8487
|
function sync2() {
|
|
7923
|
-
if (
|
|
8488
|
+
if (enabled6) apply2();
|
|
7924
8489
|
}
|
|
7925
8490
|
function scheduleSync2() {
|
|
7926
8491
|
if (syncTimer2) return;
|
|
@@ -7949,8 +8514,8 @@
|
|
|
7949
8514
|
}
|
|
7950
8515
|
async function refreshConfig3() {
|
|
7951
8516
|
const cfg = await getConfig(true).catch(() => null);
|
|
7952
|
-
|
|
7953
|
-
if (
|
|
8517
|
+
enabled6 = !cfg || !cfg.features || cfg.features.pinnedCollapse !== false;
|
|
8518
|
+
if (enabled6) sync2();
|
|
7954
8519
|
else teardown2();
|
|
7955
8520
|
}
|
|
7956
8521
|
function startPinnedCollapse() {
|
|
@@ -8069,6 +8634,10 @@
|
|
|
8069
8634
|
startToolbarIcons();
|
|
8070
8635
|
} catch {
|
|
8071
8636
|
}
|
|
8637
|
+
try {
|
|
8638
|
+
startNewtabPanels();
|
|
8639
|
+
} catch {
|
|
8640
|
+
}
|
|
8072
8641
|
try {
|
|
8073
8642
|
startPinnedCollapse();
|
|
8074
8643
|
} catch {
|