zcode-pro 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +4 -4
- package/README.md +4 -4
- package/dist/inject.js +1540 -1173
- package/package.json +1 -1
- package/src/host/helper.mjs +10 -1
- package/src/inject/core.js +80 -10
- 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 +138 -3
- package/src/inject/features/ws-running.js +7 -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,40 @@
|
|
|
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
|
+
tabShortcuts: "\u5FEB\u6377\u952E",
|
|
259
|
+
hkTitle: "\u4F1A\u8BDD\u5FEB\u6377\u5207\u6362",
|
|
260
|
+
hkAltZ: "\u5728\u5F53\u524D\u4E0E\u4E0A\u6B21\u4F7F\u7528\u7684\u4F1A\u8BDD\u95F4\u6765\u56DE\u5207\u6362",
|
|
261
|
+
hkAltX: "\u5F39\u7A97\u4E2D\u4E0A\u79FB\u9AD8\u4EAE\uFF08\u66F4\u65E9\u7684\u4F1A\u8BDD\uFF09",
|
|
262
|
+
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",
|
|
263
|
+
hkAltE: "\u6253\u5F00\u6700\u8FD1 10 \u6761\u4EFB\u52A1\u5217\u8868",
|
|
264
|
+
hkAltR: "\u6253\u5F00\u6B63\u5728\u8FD0\u884C\u4E0E\u8FD0\u884C\u5B8C\u672A\u67E5\u770B\u7684\u4EFB\u52A1\u5217\u8868",
|
|
265
|
+
hkArrow: "\u5F39\u7A97\u6253\u5F00\u65F6\u79FB\u52A8\u9AD8\u4EAE\uFF08\u4E0E alt + {prev} / alt + {next} \u540C\u89C4\u5219\uFF09",
|
|
266
|
+
hkEnter: "\u786E\u8BA4\u5207\u6362\u5230\u9AD8\u4EAE\u7684\u4F1A\u8BDD",
|
|
267
|
+
hkEsc: "\u53D6\u6D88\u5E76\u5173\u95ED\u5F39\u7A97",
|
|
268
|
+
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",
|
|
269
|
+
hkReleaseKey: "\u677E\u5F00 alt",
|
|
270
|
+
hkModify: "\u4FEE\u6539",
|
|
271
|
+
hkRecording: "\u6309\u4E0B\u65B0\u952E\u2026",
|
|
272
|
+
hkInvalid: "\u5FEB\u6377\u952E\u53EA\u652F\u6301\u5355\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57",
|
|
273
|
+
hkConflict: "alt+{k} \u5DF2\u7528\u4E8E\u201C{name}\u201D",
|
|
274
|
+
hkSaved: "\u5FEB\u6377\u952E\u5DF2\u66F4\u65B0",
|
|
275
|
+
hkNameLast: "\u5207\u6362\u4E0A\u6B21\u4F1A\u8BDD",
|
|
276
|
+
hkNamePrev: "\u4E0A\u79FB\u9AD8\u4EAE",
|
|
277
|
+
hkNameNext: "\u4E0B\u79FB\u9AD8\u4EAE",
|
|
278
|
+
hkNameRecent: "\u6700\u8FD1 10 \u6761",
|
|
279
|
+
hkNameAttention: "\u8FD0\u884C\u4E2D / \u672A\u67E5\u770B",
|
|
280
|
+
hkEditHint: "\u70B9\u51FB\u201C\u4FEE\u6539\u201D\u540E\u6309\u4E0B\u65B0\u6309\u952E\uFF08\u5B57\u6BCD\u6216\u6570\u5B57\uFF09\uFF0CEsc \u53D6\u6D88",
|
|
281
|
+
hkReset: "\u91CD\u7F6E\u4E3A\u9ED8\u8BA4",
|
|
282
|
+
hkResetDone: "\u5DF2\u6062\u590D\u9ED8\u8BA4\u952E\u4F4D",
|
|
241
283
|
featureFileActions: "\u6587\u4EF6\u83DC\u5355\u589E\u5F3A",
|
|
242
284
|
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
285
|
featureImageCopy: "\u56FE\u7247\u53F3\u952E\u590D\u5236",
|
|
@@ -362,7 +404,7 @@
|
|
|
362
404
|
headroomStoppedWarn: "\u4EE3\u7406\u5DF2\u505C\u6B62\uFF1B\u6307\u5411 127.0.0.1 \u7684\u4F9B\u5E94\u5546\u5C06\u65E0\u6CD5\u8FDE\u63A5",
|
|
363
405
|
headroomBackend: "\u538B\u7F29\u8BBE\u5907",
|
|
364
406
|
headroomBackendAuto: "\u81EA\u52A8 \xB7 \u663E\u5361\u4F18\u5148",
|
|
365
|
-
headroomBackendCpu: "
|
|
407
|
+
headroomBackendCpu: "\u7701\u7535 \xB7 CPU \u4F18\u5148",
|
|
366
408
|
headroomBackendNative: "\uFF08\u539F\u751F\u503C\uFF09",
|
|
367
409
|
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
410
|
headroomPower: "\u7701\u7535\u81EA\u52A8\u5207\u6362",
|
|
@@ -400,7 +442,7 @@
|
|
|
400
442
|
aliasSaved: "\u522B\u540D\u5DF2\u66F4\u65B0",
|
|
401
443
|
aliasCleared: "\u5DF2\u6062\u590D\u771F\u5B9E\u540D\u79F0",
|
|
402
444
|
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\
|
|
445
|
+
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
446
|
aliasMigrateTitle: "\u8FC1\u79FB\u9879\u76EE\u522B\u540D",
|
|
405
447
|
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
448
|
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 +610,7 @@
|
|
|
568
610
|
featureTaskOrder: "Sidebar session drag ordering",
|
|
569
611
|
featureTaskOrderDesc: "Makes session drags in Pinned, Projects and Groups persist across refreshes.",
|
|
570
612
|
featureSessionSwitch: "Session quick switch",
|
|
571
|
-
featureSessionSwitchDesc: "
|
|
613
|
+
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
614
|
featureTitleLock: "Keep renamed session titles",
|
|
573
615
|
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
616
|
tabTitleGen: "Task name prompt",
|
|
@@ -596,7 +638,7 @@
|
|
|
596
638
|
titleGenTestOk: "Result: ",
|
|
597
639
|
titleGenTestFailed: "Generation failed",
|
|
598
640
|
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.
|
|
641
|
+
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
642
|
tabPerformance: "Performance",
|
|
601
643
|
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
644
|
featureIdleReclaim: "Idle project memory reclaim",
|
|
@@ -624,10 +666,40 @@
|
|
|
624
666
|
userFontDesc: 'Font of question text in conversations; "default" follows the UI font.',
|
|
625
667
|
assistantFontName: "Answer font",
|
|
626
668
|
assistantFontDesc: 'Font of answer text in conversations (code blocks stay monospaced); "default" follows the UI font.',
|
|
627
|
-
switcherHint: "
|
|
669
|
+
switcherHint: "{prev} / {next} or \u2191 / \u2193 to choose, Enter or release alt to switch, Esc to cancel",
|
|
628
670
|
switcherCurrent: "current",
|
|
629
671
|
switcherEmpty: "No previous session yet (available after you switch sessions)",
|
|
630
672
|
switcherFailed: "Failed to switch to that session (it may have been deleted)",
|
|
673
|
+
switcherMore: "{n} more \xB7 press c to load",
|
|
674
|
+
switcherRunning: "running",
|
|
675
|
+
switcherUnseen: "unseen",
|
|
676
|
+
switcherAttentionHint: "Running / finished but unseen tasks \xB7 {prev} / {next} or \u2191 / \u2193 to choose, Enter or release alt to switch",
|
|
677
|
+
switcherAttentionEmpty: "No running or unseen tasks",
|
|
678
|
+
tabShortcuts: "Shortcuts",
|
|
679
|
+
hkTitle: "Session quick switch",
|
|
680
|
+
hkAltZ: "Toggle between the current and the last-used session",
|
|
681
|
+
hkAltX: "Move the highlight up (earlier sessions) in the popup",
|
|
682
|
+
hkAltC: "Move the highlight down (recent sessions); at the bottom it loads 5 more and highlights the first newly loaded entry",
|
|
683
|
+
hkAltE: "Open the last 10 tasks",
|
|
684
|
+
hkAltR: "Open running / finished-but-unseen tasks",
|
|
685
|
+
hkArrow: "Move the highlight while the popup is open (same rules as alt + {prev} / alt + {next})",
|
|
686
|
+
hkEnter: "Switch to the highlighted session",
|
|
687
|
+
hkEsc: "Cancel and close the popup",
|
|
688
|
+
hkRelease: "Releasing alt switches once the highlight has moved; otherwise the popup stays open for further selection",
|
|
689
|
+
hkReleaseKey: "release alt",
|
|
690
|
+
hkModify: "Change",
|
|
691
|
+
hkRecording: "press a key\u2026",
|
|
692
|
+
hkInvalid: "Shortcuts accept a single letter or digit only",
|
|
693
|
+
hkConflict: 'alt+{k} is already used by "{name}"',
|
|
694
|
+
hkSaved: "Shortcut updated",
|
|
695
|
+
hkNameLast: "last session",
|
|
696
|
+
hkNamePrev: "move up",
|
|
697
|
+
hkNameNext: "move down",
|
|
698
|
+
hkNameRecent: "last 10 tasks",
|
|
699
|
+
hkNameAttention: "running / unseen",
|
|
700
|
+
hkEditHint: 'Click "Change", press a new key (letter or digit); Esc cancels',
|
|
701
|
+
hkReset: "Reset to defaults",
|
|
702
|
+
hkResetDone: "Shortcuts reset to defaults",
|
|
631
703
|
featureFileActions: "File menu actions",
|
|
632
704
|
featureFileActionsDesc: 'Adds "Open with default app" and "Reveal in file manager" to the right-click menu of file links in chat.',
|
|
633
705
|
featureImageCopy: "Image right-click copy",
|
|
@@ -752,7 +824,7 @@
|
|
|
752
824
|
headroomStoppedWarn: "Proxy stopped; providers pointing at 127.0.0.1 cannot connect.",
|
|
753
825
|
headroomBackend: "Compression device",
|
|
754
826
|
headroomBackendAuto: "Auto \xB7 GPU first",
|
|
755
|
-
headroomBackendCpu: "
|
|
827
|
+
headroomBackendCpu: "Power saving \xB7 CPU first",
|
|
756
828
|
headroomBackendNative: " (native)",
|
|
757
829
|
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
830
|
headroomPower: "Power-save auto switch",
|
|
@@ -790,7 +862,7 @@
|
|
|
790
862
|
aliasSaved: "Alias updated.",
|
|
791
863
|
aliasCleared: "Real name restored.",
|
|
792
864
|
aliasHint: "The directory name on disk is unchanged: terminals, file managers and other path-based UI still show the real name.",
|
|
793
|
-
featureProjectMenuDescNew: '
|
|
865
|
+
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
866
|
aliasMigrateTitle: "Migrate project aliases",
|
|
795
867
|
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
868
|
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 +1673,20 @@
|
|
|
1601
1673
|
background-color: color-mix(in oklab, var(--color-primary, #111) 12%, transparent);
|
|
1602
1674
|
color: var(--color-foreground-subtle, #666);
|
|
1603
1675
|
}
|
|
1676
|
+
/* attention \u5F39\u7A97\uFF08alt+r\uFF09\u7684\u884C\u72B6\u6001\u6807\u7B7E\uFF1A\u8FD0\u884C\u4E2D\u7EFF\u3001\u672A\u67E5\u770B\u7425\u73C0 */
|
|
1677
|
+
.zcodepro-switcher-tag-run {
|
|
1678
|
+
background-color: color-mix(in oklab, var(--color-emerald-500, #10b981) 20%, transparent);
|
|
1679
|
+
}
|
|
1680
|
+
.zcodepro-switcher-tag-new {
|
|
1681
|
+
background-color: color-mix(in oklab, var(--color-amber-500, #f59e0b) 22%, transparent);
|
|
1682
|
+
}
|
|
1683
|
+
/* \u5217\u8868\u5E95\u90E8\u201C\u8FD8\u6709 N \u6761\u201D\u63D0\u793A\u884C */
|
|
1684
|
+
.zcodepro-switcher-more {
|
|
1685
|
+
padding: 6px 12px 2px;
|
|
1686
|
+
font-size: 11px;
|
|
1687
|
+
text-align: center;
|
|
1688
|
+
color: var(--color-muted-foreground, #888);
|
|
1689
|
+
}
|
|
1604
1690
|
.zcodepro-switcher-ws {
|
|
1605
1691
|
font-size: 11px;
|
|
1606
1692
|
color: var(--color-muted-foreground, #888);
|
|
@@ -3845,6 +3931,32 @@
|
|
|
3845
3931
|
}
|
|
3846
3932
|
pluginsStatusLine.textContent = n > 0 ? L.pluginsUpdatesFound.replaceAll("{n}", String(n)) : L.pluginsUpToDate;
|
|
3847
3933
|
})();
|
|
3934
|
+
const HK_ACTIONS = [
|
|
3935
|
+
["switchLast", "hkAltZ"],
|
|
3936
|
+
["switchPrev", "hkAltX"],
|
|
3937
|
+
["switchNext", "hkAltC"],
|
|
3938
|
+
["switchRecent", "hkAltE"],
|
|
3939
|
+
["switchAttention", "hkAltR"]
|
|
3940
|
+
];
|
|
3941
|
+
const hkNames = () => ({
|
|
3942
|
+
switchLast: L.hkNameLast,
|
|
3943
|
+
switchPrev: L.hkNamePrev,
|
|
3944
|
+
switchNext: L.hkNameNext,
|
|
3945
|
+
switchRecent: L.hkNameRecent,
|
|
3946
|
+
switchAttention: L.hkNameAttention
|
|
3947
|
+
});
|
|
3948
|
+
const hkKeys = () => {
|
|
3949
|
+
const sc = config.shortcuts || {};
|
|
3950
|
+
const keys = {};
|
|
3951
|
+
for (const [a] of HK_ACTIONS) {
|
|
3952
|
+
keys[a] = /^[a-z0-9]$/.test(sc[a]) ? sc[a] : DEFAULT_SHORTCUTS[a];
|
|
3953
|
+
}
|
|
3954
|
+
return keys;
|
|
3955
|
+
};
|
|
3956
|
+
const sessionSwitchDesc = () => {
|
|
3957
|
+
const k = hkKeys();
|
|
3958
|
+
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);
|
|
3959
|
+
};
|
|
3848
3960
|
const refreshRows = () => {
|
|
3849
3961
|
const f = config.features || {};
|
|
3850
3962
|
rows.replaceChildren(
|
|
@@ -3860,7 +3972,7 @@
|
|
|
3860
3972
|
if (await setFeature("taskOrder", next)) f.taskOrder = next;
|
|
3861
3973
|
refreshRows();
|
|
3862
3974
|
}),
|
|
3863
|
-
settingRow(L.featureSessionSwitch,
|
|
3975
|
+
settingRow(L.featureSessionSwitch, sessionSwitchDesc(), f.sessionSwitch !== false, async () => {
|
|
3864
3976
|
const next = !(f.sessionSwitch !== false);
|
|
3865
3977
|
if (await setFeature("sessionSwitch", next)) f.sessionSwitch = next;
|
|
3866
3978
|
refreshRows();
|
|
@@ -3972,6 +4084,127 @@
|
|
|
3972
4084
|
h("div", {}, rows),
|
|
3973
4085
|
communityCards
|
|
3974
4086
|
);
|
|
4087
|
+
let hkRecording = null;
|
|
4088
|
+
let hkKeyHandler = null;
|
|
4089
|
+
const hkCard = h("div", { class: "divide-y divide-border rounded-xl border border-border" });
|
|
4090
|
+
const hkCell = (keyLabel, desc, extra) => h(
|
|
4091
|
+
"div",
|
|
4092
|
+
{ class: "flex items-start gap-3 px-3 py-2.5" },
|
|
4093
|
+
h("kbd", {
|
|
4094
|
+
class: "shrink-0 min-w-20 rounded-md border border-border px-2 py-0.5 text-center text-ui-xs text-foreground-subtle",
|
|
4095
|
+
style: "font-family: ui-monospace, SFMono-Regular, Menlo, monospace; line-height: 1.5;"
|
|
4096
|
+
}, keyLabel),
|
|
4097
|
+
h("div", { class: "min-w-0 flex-1 text-ui-sm text-foreground-subtle" }, desc),
|
|
4098
|
+
extra ? h("div", { class: "ml-auto shrink-0 pl-3" }, extra) : null
|
|
4099
|
+
);
|
|
4100
|
+
const renderShortcuts = () => {
|
|
4101
|
+
const keys = hkKeys();
|
|
4102
|
+
const names = hkNames();
|
|
4103
|
+
hkCard.replaceChildren(
|
|
4104
|
+
...HK_ACTIONS.map(([a, descKey]) => {
|
|
4105
|
+
const recording = hkRecording === a;
|
|
4106
|
+
return hkCell(
|
|
4107
|
+
recording ? L.hkRecording : "alt + " + keys[a],
|
|
4108
|
+
L[descKey],
|
|
4109
|
+
btnSmall(recording ? L.hkRecording : L.hkModify, () => {
|
|
4110
|
+
recording ? stopHkRecording() : startHkRecording(a);
|
|
4111
|
+
})
|
|
4112
|
+
);
|
|
4113
|
+
}),
|
|
4114
|
+
hkCell("\u2191 / \u2193", L.hkArrow.replaceAll("{prev}", keys.switchPrev).replaceAll("{next}", keys.switchNext)),
|
|
4115
|
+
hkCell("Enter", L.hkEnter),
|
|
4116
|
+
hkCell("Esc", L.hkEsc),
|
|
4117
|
+
hkCell(L.hkReleaseKey, L.hkRelease)
|
|
4118
|
+
);
|
|
4119
|
+
};
|
|
4120
|
+
const stopHkRecording = () => {
|
|
4121
|
+
hkRecording = null;
|
|
4122
|
+
if (hkKeyHandler) {
|
|
4123
|
+
document.removeEventListener("keydown", hkKeyHandler, true);
|
|
4124
|
+
hkKeyHandler = null;
|
|
4125
|
+
}
|
|
4126
|
+
renderShortcuts();
|
|
4127
|
+
};
|
|
4128
|
+
const startHkRecording = (action) => {
|
|
4129
|
+
hkRecording = action;
|
|
4130
|
+
if (!hkKeyHandler) {
|
|
4131
|
+
const myOverlay = document.querySelector(".zcodepro-overlay");
|
|
4132
|
+
hkKeyHandler = (e) => {
|
|
4133
|
+
if (!myOverlay || !myOverlay.isConnected) {
|
|
4134
|
+
stopHkRecording();
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
if (e.isComposing) return;
|
|
4138
|
+
e.preventDefault();
|
|
4139
|
+
e.stopImmediatePropagation();
|
|
4140
|
+
if (e.key === "Escape") {
|
|
4141
|
+
stopHkRecording();
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
const k = e.key.toLowerCase();
|
|
4145
|
+
if (!/^[a-z0-9]$/.test(k)) {
|
|
4146
|
+
showToast(L.hkInvalid, "error");
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const keys = hkKeys();
|
|
4150
|
+
const names = hkNames();
|
|
4151
|
+
const conflict = HK_ACTIONS.find(([a2]) => a2 !== hkRecording && keys[a2] === k);
|
|
4152
|
+
if (conflict) {
|
|
4153
|
+
showToast(L.hkConflict.replaceAll("{k}", k).replaceAll("{name}", names[conflict[0]]), "error");
|
|
4154
|
+
return;
|
|
4155
|
+
}
|
|
4156
|
+
const a = hkRecording;
|
|
4157
|
+
stopHkRecording();
|
|
4158
|
+
void (async () => {
|
|
4159
|
+
const res = await rpc("/config", { method: "POST", body: { shortcuts: { [a]: k } } });
|
|
4160
|
+
clearConfigCache();
|
|
4161
|
+
window.dispatchEvent(new CustomEvent("zcodepro:config-changed"));
|
|
4162
|
+
if (!res.ok) {
|
|
4163
|
+
showToast(L.failed + ": " + errText(res), "error");
|
|
4164
|
+
renderShortcuts();
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
if (res.config && res.config.shortcuts) config.shortcuts = res.config.shortcuts;
|
|
4168
|
+
showToast(L.hkSaved, "success");
|
|
4169
|
+
refreshRows();
|
|
4170
|
+
renderShortcuts();
|
|
4171
|
+
})();
|
|
4172
|
+
};
|
|
4173
|
+
document.addEventListener("keydown", hkKeyHandler, true);
|
|
4174
|
+
}
|
|
4175
|
+
renderShortcuts();
|
|
4176
|
+
};
|
|
4177
|
+
renderShortcuts();
|
|
4178
|
+
const resetShortcuts = async () => {
|
|
4179
|
+
stopHkRecording();
|
|
4180
|
+
const all = {};
|
|
4181
|
+
for (const [a] of HK_ACTIONS) all[a] = DEFAULT_SHORTCUTS[a];
|
|
4182
|
+
const res = await rpc("/config", { method: "POST", body: { shortcuts: all } });
|
|
4183
|
+
clearConfigCache();
|
|
4184
|
+
window.dispatchEvent(new CustomEvent("zcodepro:config-changed"));
|
|
4185
|
+
if (!res.ok) {
|
|
4186
|
+
showToast(L.failed + ": " + errText(res), "error");
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4189
|
+
if (res.config && res.config.shortcuts) config.shortcuts = res.config.shortcuts;
|
|
4190
|
+
showToast(L.hkResetDone, "success");
|
|
4191
|
+
refreshRows();
|
|
4192
|
+
renderShortcuts();
|
|
4193
|
+
};
|
|
4194
|
+
const paneShortcuts = h(
|
|
4195
|
+
"div",
|
|
4196
|
+
{ role: "tabpanel", class: "mt-4", style: "display:none" },
|
|
4197
|
+
h("div", { class: "mb-2 text-ui-sm font-medium" }, L.hkTitle),
|
|
4198
|
+
h(
|
|
4199
|
+
"div",
|
|
4200
|
+
{ class: "mb-2 flex items-center gap-2" },
|
|
4201
|
+
h("div", { class: "min-w-0 flex-1 text-ui-xs/relaxed text-foreground-subtle" }, L.hkEditHint),
|
|
4202
|
+
h("div", { class: "shrink-0" }, btnSmall(L.hkReset, () => {
|
|
4203
|
+
void resetShortcuts();
|
|
4204
|
+
}))
|
|
4205
|
+
),
|
|
4206
|
+
hkCard
|
|
4207
|
+
);
|
|
3975
4208
|
const paneStyles = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3976
4209
|
const panePerf = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3977
4210
|
const paneAgents = h("div", { role: "tabpanel", class: "mt-2", style: "display:none" });
|
|
@@ -3982,9 +4215,10 @@
|
|
|
3982
4215
|
const paneHeadroom = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3983
4216
|
const paneTitleGen = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
|
|
3984
4217
|
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 };
|
|
4218
|
+
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
4219
|
const tabDefs = [
|
|
3987
4220
|
["features", L.tabFeatures],
|
|
4221
|
+
["shortcuts", L.tabShortcuts],
|
|
3988
4222
|
["agents", L.tabBehavior],
|
|
3989
4223
|
["styles", L.tabStyles],
|
|
3990
4224
|
["perf", L.tabPerformance],
|
|
@@ -4008,6 +4242,7 @@
|
|
|
4008
4242
|
}, label)));
|
|
4009
4243
|
const switchTab = (name) => {
|
|
4010
4244
|
activeTab = name;
|
|
4245
|
+
if (name !== "shortcuts" && hkRecording) stopHkRecording();
|
|
4011
4246
|
for (const [id, pane] of Object.entries(panes)) pane.style.display = id === name ? "" : "none";
|
|
4012
4247
|
renderTabs();
|
|
4013
4248
|
};
|
|
@@ -6077,6 +6312,7 @@
|
|
|
6077
6312
|
statusLine,
|
|
6078
6313
|
tablist,
|
|
6079
6314
|
paneFeatures,
|
|
6315
|
+
paneShortcuts,
|
|
6080
6316
|
paneAgents,
|
|
6081
6317
|
paneStyles,
|
|
6082
6318
|
panePerf,
|
|
@@ -6169,1318 +6405,1449 @@
|
|
|
6169
6405
|
}
|
|
6170
6406
|
}
|
|
6171
6407
|
|
|
6172
|
-
// src/inject/features/
|
|
6173
|
-
var
|
|
6408
|
+
// src/inject/features/ws-running.js
|
|
6409
|
+
var installed2 = false;
|
|
6410
|
+
var enabled2 = true;
|
|
6174
6411
|
var SCAN_DEBOUNCE_MS = 150;
|
|
6175
6412
|
var SCAN_FALLBACK_MS = 5e3;
|
|
6176
|
-
var
|
|
6177
|
-
var
|
|
6178
|
-
var
|
|
6179
|
-
var
|
|
6180
|
-
var
|
|
6181
|
-
var
|
|
6182
|
-
var
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6413
|
+
var PEEK_FIRST_MS = 2e4;
|
|
6414
|
+
var PEEK_REPEAT_MS = 6e4;
|
|
6415
|
+
var PEEK_SETTLE_MS = 160;
|
|
6416
|
+
var PEEK_MAX_MS = 1500;
|
|
6417
|
+
var PEEK_UNMOUNT_WAIT_MS = 800;
|
|
6418
|
+
var CONFIG_POLL_MIN_MS = 5e3;
|
|
6419
|
+
var CONFIG_POLL_MAX_MS = 6e4;
|
|
6420
|
+
var TASK_SEL = "[data-task-item-key]";
|
|
6421
|
+
var WS_SEL = () => projectRowSelector();
|
|
6422
|
+
function findWsRow(ws) {
|
|
6423
|
+
return findProjectRow(ws);
|
|
6424
|
+
}
|
|
6425
|
+
var LOADER_FALLBACK_PATHS = [
|
|
6426
|
+
"M12 2v4",
|
|
6427
|
+
"m16.2 7.8 2.9-2.9",
|
|
6428
|
+
"M18 12h4",
|
|
6429
|
+
"m19.8 16.2-2.9 2.9",
|
|
6430
|
+
"M12 18v4",
|
|
6431
|
+
"m7.8 19.8-2.9-2.9",
|
|
6432
|
+
"M6 12H2",
|
|
6433
|
+
"m4.2 7.8 2.9-2.9"
|
|
6434
|
+
];
|
|
6435
|
+
function makeLoaderSvg(baseClass) {
|
|
6436
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
6437
|
+
const proto = document.querySelector("svg.lucide-loader");
|
|
6438
|
+
if (proto) {
|
|
6439
|
+
const clone = proto.cloneNode(true);
|
|
6440
|
+
const origClass = proto.getAttribute("class") || "";
|
|
6441
|
+
const keep = origClass.split(/\s+/).filter((c) => /^(size-|text-)/.test(c)).join(" ");
|
|
6442
|
+
clone.setAttribute("class", ((keep || baseClass) + " animate-spin zcodepro-ws-loader").trim());
|
|
6443
|
+
return clone;
|
|
6444
|
+
}
|
|
6445
|
+
const svg = document.createElementNS(ns, "svg");
|
|
6446
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
6447
|
+
svg.setAttribute("fill", "none");
|
|
6448
|
+
svg.setAttribute("stroke", "currentColor");
|
|
6449
|
+
svg.setAttribute("stroke-width", "2");
|
|
6450
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
6451
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
6452
|
+
svg.setAttribute("class", (baseClass + " animate-spin zcodepro-ws-loader").trim());
|
|
6453
|
+
for (const d of LOADER_FALLBACK_PATHS) {
|
|
6454
|
+
const path = document.createElementNS(ns, "path");
|
|
6455
|
+
path.setAttribute("d", d);
|
|
6456
|
+
svg.append(path);
|
|
6457
|
+
}
|
|
6458
|
+
return svg;
|
|
6459
|
+
}
|
|
6460
|
+
function setRunningIcon(holder, on) {
|
|
6461
|
+
if (!holder) return;
|
|
6462
|
+
if (on) {
|
|
6463
|
+
if (holder.querySelector(":scope > svg.zcodepro-ws-loader")) return;
|
|
6464
|
+
const orig0 = holder.querySelector(":scope > svg:not(.zcodepro-ws-loader)");
|
|
6465
|
+
const base = (orig0 ? orig0.getAttribute("class") || "" : "size-4").replace(/lucide-[a-z-]*/g, "").trim() || "size-4";
|
|
6466
|
+
holder.append(makeLoaderSvg(base));
|
|
6467
|
+
} else {
|
|
6468
|
+
holder.querySelectorAll(":scope > svg.zcodepro-ws-loader").forEach((el) => el.remove());
|
|
6469
|
+
}
|
|
6470
|
+
}
|
|
6471
|
+
function iconHolderOf(row) {
|
|
6472
|
+
if (row.hasAttribute && row.hasAttribute("data-project-id")) {
|
|
6473
|
+
const toggle2 = row.querySelector('[data-testid="virtual-project-toggle"]');
|
|
6474
|
+
return toggle2 ? toggle2.querySelector(":scope > span") : null;
|
|
6475
|
+
}
|
|
6476
|
+
return row.firstElementChild && row.firstElementChild.querySelector(":scope > span");
|
|
6477
|
+
}
|
|
6478
|
+
function isRunningRow(el) {
|
|
6479
|
+
const scope = el.firstElementChild;
|
|
6480
|
+
if (!scope) return false;
|
|
6481
|
+
const svg = scope.querySelector('svg[class*="lucide-loader"]');
|
|
6482
|
+
return !!svg;
|
|
6483
|
+
}
|
|
6484
|
+
var runningByWs = /* @__PURE__ */ new Map();
|
|
6485
|
+
var peekTimers = /* @__PURE__ */ new Map();
|
|
6486
|
+
var activePeeks = /* @__PURE__ */ new Set();
|
|
6487
|
+
var peekedWs = /* @__PURE__ */ new Set();
|
|
6488
|
+
var wsWithRows = /* @__PURE__ */ new Set();
|
|
6489
|
+
var servicesRef = null;
|
|
6490
|
+
function findServices() {
|
|
6491
|
+
if (servicesRef) return servicesRef;
|
|
6492
|
+
try {
|
|
6493
|
+
const rootEl = document.getElementById("root");
|
|
6494
|
+
const containerKey = rootEl && Object.keys(rootEl).find((k) => k.startsWith("__reactContainer$"));
|
|
6495
|
+
if (!containerKey) return null;
|
|
6496
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6497
|
+
let found = null;
|
|
6498
|
+
const scanObj = (o) => {
|
|
6499
|
+
if (!o || typeof o !== "object" || seen.has(o) || found) return;
|
|
6500
|
+
seen.add(o);
|
|
6501
|
+
const ts = o.zcodeTaskService;
|
|
6502
|
+
if (ts && typeof ts === "object" && typeof ts.releaseWorkspacePreparation === "function") found = o;
|
|
6503
|
+
};
|
|
6504
|
+
let visited = 0;
|
|
6505
|
+
const visit = (f) => {
|
|
6506
|
+
if (!f || found || visited > 6e4) return;
|
|
6507
|
+
visited++;
|
|
6508
|
+
for (const holder of [f.memoizedProps, f.memoizedState]) {
|
|
6509
|
+
if (!holder || typeof holder !== "object") continue;
|
|
6510
|
+
scanObj(holder);
|
|
6511
|
+
for (const v of Object.values(holder)) {
|
|
6512
|
+
if (v && typeof v === "object") scanObj(v);
|
|
6513
|
+
}
|
|
6514
|
+
}
|
|
6515
|
+
visit(f.child);
|
|
6516
|
+
visit(f.sibling);
|
|
6517
|
+
};
|
|
6518
|
+
visit(rootEl[containerKey]);
|
|
6519
|
+
if (found) servicesRef = found;
|
|
6520
|
+
return found;
|
|
6521
|
+
} catch {
|
|
6522
|
+
return null;
|
|
6523
|
+
}
|
|
6524
|
+
}
|
|
6525
|
+
async function authoritativeIdle(ws) {
|
|
6526
|
+
const services = findServices();
|
|
6527
|
+
const ts = services && services.zcodeTaskService;
|
|
6528
|
+
if (!ts || typeof ts.listActiveTaskIds !== "function") return null;
|
|
6529
|
+
try {
|
|
6530
|
+
const base = String(ws).replace(/[\\/]+$/, "");
|
|
6531
|
+
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
6532
|
+
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
6533
|
+
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
6534
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return null;
|
|
6535
|
+
if (!ids.length) return true;
|
|
6536
|
+
const st = await rpc("/task-statuses?ids=" + encodeURIComponent(ids.join(","))).catch(() => null);
|
|
6537
|
+
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
6538
|
+
const live = (id) => {
|
|
6539
|
+
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
6540
|
+
if (rec === void 0) return true;
|
|
6541
|
+
if (!TERMINAL.has(rec.status)) return true;
|
|
6542
|
+
return Date.now() - rec.updatedAt < 3e5;
|
|
6543
|
+
};
|
|
6544
|
+
return !ids.some(live);
|
|
6545
|
+
} catch {
|
|
6546
|
+
return null;
|
|
6547
|
+
}
|
|
6186
6548
|
}
|
|
6187
6549
|
function workspaceOf(key) {
|
|
6188
6550
|
const i = key.indexOf(":sess_");
|
|
6189
6551
|
return i > 0 ? key.slice(0, i) : key;
|
|
6190
6552
|
}
|
|
6191
|
-
function
|
|
6192
|
-
|
|
6553
|
+
function wsHead(row) {
|
|
6554
|
+
return row.matches("[aria-expanded]") ? row : row.querySelector("[aria-expanded]");
|
|
6555
|
+
}
|
|
6556
|
+
function domRowsOf(ws) {
|
|
6557
|
+
return [...document.querySelectorAll(TASK_SEL)].filter((e) => workspaceOf(e.getAttribute("data-task-item-key") || "") === ws);
|
|
6558
|
+
}
|
|
6559
|
+
function currentTaskRow() {
|
|
6560
|
+
for (const el of document.querySelectorAll(TASK_SEL)) {
|
|
6193
6561
|
if ((el.className + "").includes("bg-selected")) return el;
|
|
6194
6562
|
}
|
|
6195
6563
|
return null;
|
|
6196
6564
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
mru.unshift(key);
|
|
6202
|
-
if (mru.length > MRU_LIMIT) mru.length = MRU_LIMIT;
|
|
6565
|
+
var synthClick = (el) => {
|
|
6566
|
+
try {
|
|
6567
|
+
el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
6568
|
+
} catch {
|
|
6203
6569
|
}
|
|
6570
|
+
};
|
|
6571
|
+
function toggleNavSafe(head) {
|
|
6572
|
+
const cur = currentTaskRow();
|
|
6573
|
+
const backKey = cur ? cur.getAttribute("data-task-item-key") : "";
|
|
6574
|
+
synthClick(head);
|
|
6575
|
+
if (!backKey) return;
|
|
6576
|
+
const back = cur && cur.isConnected ? cur : document.querySelector(`${TASK_SEL}[data-task-item-key="${CSS.escape(backKey)}"]`);
|
|
6577
|
+
if (back) synthClick(back);
|
|
6204
6578
|
}
|
|
6205
6579
|
function scan() {
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6580
|
+
wsWithRows = /* @__PURE__ */ new Set();
|
|
6581
|
+
for (const el of document.querySelectorAll(TASK_SEL)) {
|
|
6582
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6583
|
+
const ws = workspaceOf(key);
|
|
6584
|
+
if (!ws) continue;
|
|
6585
|
+
wsWithRows.add(ws);
|
|
6586
|
+
const run = isRunningRow(el);
|
|
6587
|
+
let set = runningByWs.get(ws);
|
|
6588
|
+
if (run) {
|
|
6589
|
+
if (!set) {
|
|
6590
|
+
set = /* @__PURE__ */ new Set();
|
|
6591
|
+
runningByWs.set(ws, set);
|
|
6592
|
+
}
|
|
6593
|
+
set.add(key);
|
|
6594
|
+
} else if (set) {
|
|
6595
|
+
set.delete(key);
|
|
6596
|
+
}
|
|
6210
6597
|
}
|
|
6598
|
+
syncPeeks();
|
|
6599
|
+
apply();
|
|
6211
6600
|
}
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
function taskRowMutations(muts) {
|
|
6601
|
+
function handleRemovals(muts) {
|
|
6602
|
+
const removed = [];
|
|
6215
6603
|
for (const m of muts) {
|
|
6216
|
-
if (m.type
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
if (
|
|
6220
|
-
|
|
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
|
-
}
|
|
6604
|
+
if (m.type !== "childList") continue;
|
|
6605
|
+
for (const n of m.removedNodes) {
|
|
6606
|
+
if (!(n instanceof Element)) continue;
|
|
6607
|
+
if (n.matches(TASK_SEL)) removed.push(n);
|
|
6608
|
+
else for (const r of n.querySelectorAll(TASK_SEL)) removed.push(r);
|
|
6226
6609
|
}
|
|
6227
6610
|
}
|
|
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) {
|
|
6611
|
+
if (!removed.length) return;
|
|
6612
|
+
const infos = removed.map((el) => {
|
|
6613
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6241
6614
|
const ws = workspaceOf(key);
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6615
|
+
return key && ws ? { key, ws, run: isRunningRow(el) } : null;
|
|
6616
|
+
}).filter(Boolean);
|
|
6617
|
+
if (!infos.length) return;
|
|
6618
|
+
setTimeout(() => {
|
|
6619
|
+
for (const info of infos) {
|
|
6620
|
+
const row = findWsRow(info.ws);
|
|
6621
|
+
const head = row && wsHead(row);
|
|
6622
|
+
const collapsed = !row || !head || head.getAttribute("aria-expanded") === "false";
|
|
6623
|
+
let set = runningByWs.get(info.ws);
|
|
6624
|
+
if (collapsed && info.run) {
|
|
6625
|
+
if (!set) {
|
|
6626
|
+
set = /* @__PURE__ */ new Set();
|
|
6627
|
+
runningByWs.set(info.ws, set);
|
|
6628
|
+
}
|
|
6629
|
+
set.add(info.key);
|
|
6630
|
+
} else if (set) {
|
|
6631
|
+
set.delete(info.key);
|
|
6632
|
+
}
|
|
6247
6633
|
}
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
item.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
6252
|
-
return true;
|
|
6634
|
+
syncPeeks();
|
|
6635
|
+
apply();
|
|
6636
|
+
}, 0);
|
|
6253
6637
|
}
|
|
6254
|
-
function
|
|
6255
|
-
|
|
6256
|
-
const
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6638
|
+
function apply() {
|
|
6639
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6640
|
+
for (const row of document.querySelectorAll(WS_SEL())) {
|
|
6641
|
+
const path = rowPath(row);
|
|
6642
|
+
if (!path) continue;
|
|
6643
|
+
seen.add(path);
|
|
6644
|
+
const head = wsHead(row);
|
|
6645
|
+
const collapsed = !head || head.getAttribute("aria-expanded") === "false";
|
|
6646
|
+
const domRunning = !!(runningByWs.get(path) && runningByWs.get(path).size);
|
|
6647
|
+
const normP = (v) => String(v || "").replace(/[\\/]+$/, "");
|
|
6648
|
+
const running = enabled2 && collapsed && (activeProjectPaths.size ? [...activeProjectPaths].some((p2) => normP(p2) === normP(path)) : domRunning);
|
|
6649
|
+
const icon = iconHolderOf(row);
|
|
6650
|
+
icon?.classList.toggle("zcodepro-ws-running", running);
|
|
6651
|
+
setRunningIcon(icon, running);
|
|
6263
6652
|
}
|
|
6653
|
+
applySectionSpin();
|
|
6654
|
+
for (const ws of [...runningByWs.keys()]) if (!seen.has(ws)) runningByWs.delete(ws);
|
|
6264
6655
|
}
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6656
|
+
var headInfoCache = /* @__PURE__ */ new WeakMap();
|
|
6657
|
+
var PROJECT_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u9879\u76EE", "projects"]);
|
|
6658
|
+
var TASK_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u4EFB\u52A1", "tasks"]);
|
|
6659
|
+
function kindFromHeadText(head) {
|
|
6660
|
+
const text = (head.textContent || "").trim().toLowerCase();
|
|
6661
|
+
if (PROJECT_HEAD_TEXTS.has(text)) return "project";
|
|
6662
|
+
if (TASK_HEAD_TEXTS.has(text)) return "task";
|
|
6663
|
+
return null;
|
|
6270
6664
|
}
|
|
6271
|
-
function
|
|
6272
|
-
const
|
|
6273
|
-
|
|
6274
|
-
|
|
6665
|
+
function sectionHeads() {
|
|
6666
|
+
const heads = [];
|
|
6667
|
+
for (const sv of document.querySelectorAll("svg[data-purpose-section-chevron]")) {
|
|
6668
|
+
const btn = sv.closest("button");
|
|
6669
|
+
if (btn) heads.push(btn);
|
|
6670
|
+
}
|
|
6671
|
+
for (const h3 of document.querySelectorAll("h3")) heads.push(h3);
|
|
6672
|
+
return heads.map((head) => {
|
|
6673
|
+
const cached = headInfoCache.get(head);
|
|
6674
|
+
if (cached) return { head, cont: cached.cont, kind: cached.kind };
|
|
6675
|
+
const textKind = head.tagName === "BUTTON" ? kindFromHeadText(head) : "task";
|
|
6676
|
+
let cont = head.parentElement;
|
|
6677
|
+
while (cont && !cont.querySelector("li[data-task-item-key]") && cont !== document.body) cont = cont.parentElement;
|
|
6678
|
+
const contOk = cont && cont !== document.body;
|
|
6679
|
+
const kind = textKind || (contOk ? cont.querySelector("section[data-project-id]") ? "project" : "task" : null);
|
|
6680
|
+
headInfoCache.set(head, { cont: contOk ? cont : null, kind });
|
|
6681
|
+
return { head, cont: contOk ? cont : null, kind };
|
|
6682
|
+
}).filter((x) => x.head);
|
|
6275
6683
|
}
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6684
|
+
var SEC_SPIN_CLASS = "zcodepro-ws-sec-spin";
|
|
6685
|
+
var anyActiveCache = { at: 0, value: null, busy: false };
|
|
6686
|
+
var sectionActive = { task: false, project: false };
|
|
6687
|
+
var activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6688
|
+
setInterval(() => {
|
|
6689
|
+
if (!anyActiveCache.busy && Date.now() - anyActiveCache.at >= 1e4) globalAnyActive();
|
|
6690
|
+
}, 1e4);
|
|
6691
|
+
function globalAnyActive() {
|
|
6692
|
+
if (anyActiveCache.value !== null && Date.now() - anyActiveCache.at < 1e4) return anyActiveCache.value;
|
|
6693
|
+
if (anyActiveCache.busy) return anyActiveCache.value === true;
|
|
6694
|
+
anyActiveCache.busy = true;
|
|
6695
|
+
sectionActive.task = false;
|
|
6696
|
+
sectionActive.project = false;
|
|
6697
|
+
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6698
|
+
void (async () => {
|
|
6699
|
+
let hit = null;
|
|
6700
|
+
try {
|
|
6701
|
+
const res = await rpc("/projects-v2").catch(() => null);
|
|
6702
|
+
const services = findServices();
|
|
6703
|
+
const ts = services && services.zcodeTaskService;
|
|
6704
|
+
if (res && res.ok && res.available && ts && typeof ts.listActiveTaskIds === "function") {
|
|
6705
|
+
hit = false;
|
|
6706
|
+
const projPaths = /* @__PURE__ */ new Set();
|
|
6707
|
+
for (const proj of res.projects || []) {
|
|
6708
|
+
for (const r of proj.roots || []) {
|
|
6709
|
+
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
6710
|
+
if (b) projPaths.add(b);
|
|
6711
|
+
}
|
|
6290
6712
|
}
|
|
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
|
-
|
|
6713
|
+
const taskSidePaths = /* @__PURE__ */ new Set();
|
|
6714
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
6715
|
+
const sec = el.closest("section[data-project-id]");
|
|
6716
|
+
if (sec) continue;
|
|
6717
|
+
const k = el.getAttribute("data-task-item-key") || "";
|
|
6718
|
+
const cut = k.lastIndexOf(":");
|
|
6719
|
+
if (cut > 1) taskSidePaths.add(k.slice(0, cut).replace(/[\\/]+$/, ""));
|
|
6720
|
+
}
|
|
6721
|
+
const scanPaths = /* @__PURE__ */ new Set([...projPaths, ...taskSidePaths]);
|
|
6722
|
+
const byKind = { task: /* @__PURE__ */ new Set(), project: /* @__PURE__ */ new Set() };
|
|
6723
|
+
const byKindByPath = /* @__PURE__ */ new Map();
|
|
6724
|
+
const rootToProject = /* @__PURE__ */ new Map();
|
|
6725
|
+
const projectPaths = /* @__PURE__ */ new Map();
|
|
6726
|
+
for (const proj of res.projects || []) {
|
|
6727
|
+
const names = [];
|
|
6728
|
+
for (const r of proj.roots || []) {
|
|
6729
|
+
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
6730
|
+
if (b) {
|
|
6731
|
+
rootToProject.set(b, proj.name);
|
|
6732
|
+
names.push(b);
|
|
6733
|
+
}
|
|
6734
|
+
}
|
|
6735
|
+
projectPaths.set(proj.name, names);
|
|
6736
|
+
}
|
|
6737
|
+
for (const base of scanPaths) {
|
|
6738
|
+
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
6739
|
+
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
6740
|
+
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
6741
|
+
if (!ids.length) continue;
|
|
6742
|
+
byKindByPath.set(base, ids);
|
|
6743
|
+
const kind = projPaths.has(base) ? "project" : "task";
|
|
6744
|
+
for (const id of ids) byKind[kind].add(id);
|
|
6745
|
+
}
|
|
6746
|
+
const allIds = [...byKind.task, ...byKind.project];
|
|
6747
|
+
const st = allIds.length ? await rpc("/task-statuses?ids=" + encodeURIComponent(allIds.join(","))).catch(() => null) : null;
|
|
6748
|
+
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
6749
|
+
const live = (id) => {
|
|
6750
|
+
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
6751
|
+
if (rec === void 0) return true;
|
|
6752
|
+
if (!TERMINAL.has(rec.status)) return true;
|
|
6753
|
+
return Date.now() - rec.updatedAt < 3e5;
|
|
6754
|
+
};
|
|
6755
|
+
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
6756
|
+
for (const [base, ids] of byKindByPath) {
|
|
6757
|
+
if (!projPaths.has(base)) continue;
|
|
6758
|
+
if (ids.some(live)) {
|
|
6759
|
+
const projName = rootToProject.get(base);
|
|
6760
|
+
if (projName) for (const p2 of projectPaths.get(projName) || []) activeProjectPaths.add(p2);
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6763
|
+
const taskDomRunning = !!document.querySelector('[data-task-item-key]:not(section[data-project-id] *) svg[class*="lucide-loader"]');
|
|
6764
|
+
if (taskDomRunning && [...byKind.task].some(live)) sectionActive.task = true;
|
|
6765
|
+
if ([...byKind.project].some(live)) sectionActive.project = true;
|
|
6766
|
+
hit = sectionActive.task || sectionActive.project;
|
|
6318
6767
|
}
|
|
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" });
|
|
6768
|
+
} catch {
|
|
6769
|
+
}
|
|
6770
|
+
if (hit !== null) anyActiveCache = { at: Date.now(), value: hit, busy: false };
|
|
6771
|
+
else anyActiveCache.busy = false;
|
|
6772
|
+
apply();
|
|
6773
|
+
})();
|
|
6774
|
+
return anyActiveCache.value === true;
|
|
6336
6775
|
}
|
|
6337
|
-
function
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
}
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
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;
|
|
6776
|
+
function applySectionSpin() {
|
|
6777
|
+
if (!enabled2) {
|
|
6778
|
+
document.querySelectorAll("." + SEC_SPIN_CLASS).forEach((el) => el.remove());
|
|
6779
|
+
return;
|
|
6780
|
+
}
|
|
6781
|
+
for (const { head, cont, kind } of sectionHeads()) {
|
|
6782
|
+
const running = !!(cont && cont.querySelector('li[data-task-item-key] svg[class*="lucide-loader"]'));
|
|
6783
|
+
let expanded = true;
|
|
6784
|
+
if (head.tagName === "BUTTON") expanded = head.getAttribute("aria-expanded") !== "false";
|
|
6785
|
+
else {
|
|
6786
|
+
const list = head.nextElementSibling;
|
|
6787
|
+
expanded = !list || list.offsetHeight > 0;
|
|
6358
6788
|
}
|
|
6359
|
-
if (!
|
|
6360
|
-
|
|
6361
|
-
const
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
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;
|
|
6789
|
+
if (!kind) return;
|
|
6790
|
+
const scoped = kind === "project" ? sectionActive.project : sectionActive.task;
|
|
6791
|
+
const want = !expanded && scoped;
|
|
6792
|
+
const existing = head.querySelector(":scope > ." + SEC_SPIN_CLASS);
|
|
6793
|
+
if (want && !existing) {
|
|
6794
|
+
const span = document.createElement("span");
|
|
6795
|
+
span.className = "flex size-4 shrink-0 items-center justify-center " + SEC_SPIN_CLASS;
|
|
6796
|
+
span.append(makeLoaderSvg("size-4"));
|
|
6797
|
+
head.prepend(span);
|
|
6798
|
+
} else if (!want && existing) {
|
|
6799
|
+
existing.remove();
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6415
6802
|
}
|
|
6416
|
-
function
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6803
|
+
function schedulePeek(ws, delay) {
|
|
6804
|
+
clearTimeout(peekTimers.get(ws));
|
|
6805
|
+
peekTimers.set(ws, setTimeout(() => {
|
|
6806
|
+
peekTimers.delete(ws);
|
|
6807
|
+
void peek(ws);
|
|
6808
|
+
}, delay));
|
|
6421
6809
|
}
|
|
6422
|
-
function
|
|
6423
|
-
|
|
6810
|
+
function clearPeek(ws) {
|
|
6811
|
+
const t2 = peekTimers.get(ws);
|
|
6812
|
+
if (t2) {
|
|
6813
|
+
clearTimeout(t2);
|
|
6814
|
+
peekTimers.delete(ws);
|
|
6815
|
+
}
|
|
6424
6816
|
}
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
resolved = true;
|
|
6431
|
-
enabled2 = res.enabled !== false;
|
|
6432
|
-
if (!enabled2) {
|
|
6433
|
-
pinned = null;
|
|
6434
|
-
return null;
|
|
6817
|
+
function syncPeeks() {
|
|
6818
|
+
for (const [ws, set] of runningByWs) {
|
|
6819
|
+
if (!enabled2 || !set.size) {
|
|
6820
|
+
clearPeek(ws);
|
|
6821
|
+
continue;
|
|
6435
6822
|
}
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
if (fetching === p) fetching = null;
|
|
6823
|
+
const row = findWsRow(ws);
|
|
6824
|
+
const head = row && wsHead(row);
|
|
6825
|
+
if (!row || !head || head.getAttribute("aria-expanded") !== "false" || wsWithRows.has(ws)) {
|
|
6826
|
+
clearPeek(ws);
|
|
6827
|
+
continue;
|
|
6828
|
+
}
|
|
6829
|
+
if (!peekTimers.has(ws) && !activePeeks.has(ws)) schedulePeek(ws, peekedWs.has(ws) ? PEEK_REPEAT_MS : PEEK_FIRST_MS);
|
|
6444
6830
|
}
|
|
6445
6831
|
}
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
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);
|
|
6832
|
+
var peekChain = Promise.resolve();
|
|
6833
|
+
async function peek(ws, opts) {
|
|
6834
|
+
if (!opts?.manual) {
|
|
6835
|
+
const auth = await authoritativeIdle(ws);
|
|
6836
|
+
if (auth !== null) {
|
|
6837
|
+
if (auth) {
|
|
6838
|
+
runningByWs.delete(ws);
|
|
6839
|
+
} else {
|
|
6840
|
+
let set = runningByWs.get(ws);
|
|
6841
|
+
if (!set) {
|
|
6842
|
+
set = /* @__PURE__ */ new Set();
|
|
6843
|
+
runningByWs.set(ws, set);
|
|
6470
6844
|
}
|
|
6845
|
+
set.add(ws + ":active");
|
|
6846
|
+
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6471
6847
|
}
|
|
6848
|
+
apply();
|
|
6849
|
+
return true;
|
|
6472
6850
|
}
|
|
6473
6851
|
}
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
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);
|
|
6852
|
+
const run = () => peekInner(ws, opts);
|
|
6853
|
+
const p = peekChain.then(run, run);
|
|
6854
|
+
peekChain = p.catch(() => {
|
|
6855
|
+
});
|
|
6856
|
+
return p;
|
|
6494
6857
|
}
|
|
6495
|
-
async function
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
const
|
|
6499
|
-
if (
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6858
|
+
async function peekInner(ws, opts) {
|
|
6859
|
+
if (!opts?.manual && !enabled2 || document.hidden || activePeeks.has(ws)) return false;
|
|
6860
|
+
const row = findWsRow(ws);
|
|
6861
|
+
const head = row && wsHead(row);
|
|
6862
|
+
if (!row || !head || head.getAttribute("aria-expanded") !== "false") return false;
|
|
6863
|
+
if (!currentTaskRow()) {
|
|
6864
|
+
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6865
|
+
return false;
|
|
6503
6866
|
}
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6867
|
+
activePeeks.add(ws);
|
|
6868
|
+
peekedWs.add(ws);
|
|
6869
|
+
const rect = row.getBoundingClientRect();
|
|
6870
|
+
const frozen = row.cloneNode(true);
|
|
6871
|
+
frozen.classList.add("zcodepro-ws-frozen");
|
|
6872
|
+
frozen.style.left = rect.left + "px";
|
|
6873
|
+
frozen.style.top = rect.top + "px";
|
|
6874
|
+
frozen.style.width = rect.width + "px";
|
|
6875
|
+
frozen.style.height = rect.height + "px";
|
|
6876
|
+
document.body.append(frozen);
|
|
6877
|
+
row.style.visibility = "hidden";
|
|
6878
|
+
const hider = installPeekHider(ws);
|
|
6879
|
+
let readOk = false;
|
|
6880
|
+
try {
|
|
6881
|
+
toggleNavSafe(head);
|
|
6882
|
+
readOk = await settleAndRead(ws);
|
|
6883
|
+
const rowNow = findWsRow(ws) || row;
|
|
6884
|
+
const headNow = wsHead(rowNow);
|
|
6885
|
+
if (headNow && headNow.getAttribute("aria-expanded") === "true" && !userTouched(rowNow)) {
|
|
6886
|
+
toggleNavSafe(headNow);
|
|
6887
|
+
await waitForRowsGone(ws);
|
|
6512
6888
|
}
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6889
|
+
} finally {
|
|
6890
|
+
removePeekHider(hider);
|
|
6891
|
+
row.style.visibility = "";
|
|
6892
|
+
frozen.remove();
|
|
6893
|
+
activePeeks.delete(ws);
|
|
6516
6894
|
}
|
|
6895
|
+
apply();
|
|
6896
|
+
const set = runningByWs.get(ws);
|
|
6897
|
+
if (set && set.size && enabled2) schedulePeek(ws, PEEK_REPEAT_MS);
|
|
6898
|
+
return readOk;
|
|
6517
6899
|
}
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
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;
|
|
6900
|
+
function wsRunningSnapshot() {
|
|
6901
|
+
const curKey = currentTaskRow()?.getAttribute("data-task-item-key") || "";
|
|
6902
|
+
return {
|
|
6903
|
+
running: [...runningByWs.entries()].filter(([, set]) => set.size > 0).map(([ws]) => ws),
|
|
6904
|
+
current: curKey ? workspaceOf(curKey) || null : null
|
|
6905
|
+
};
|
|
6534
6906
|
}
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
scanDebounce2 = 0;
|
|
6540
|
-
scan2();
|
|
6541
|
-
}, SCAN_DEBOUNCE_MS2);
|
|
6907
|
+
function wsRunningKeys() {
|
|
6908
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6909
|
+
for (const set of runningByWs.values()) for (const k of set) keys.add(k);
|
|
6910
|
+
return keys;
|
|
6542
6911
|
}
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6912
|
+
async function verifyWorkspaceNotRunning(ws) {
|
|
6913
|
+
if (!ws || document.hidden) return false;
|
|
6914
|
+
const row = findWsRow(ws);
|
|
6915
|
+
const head = row && wsHead(row);
|
|
6916
|
+
if (!row || !head) return false;
|
|
6917
|
+
if (head.getAttribute("aria-expanded") !== "false") {
|
|
6918
|
+
let run = false;
|
|
6919
|
+
for (const el of domRowsOf(ws)) if (isRunningRow(el)) run = true;
|
|
6920
|
+
return !run;
|
|
6921
|
+
}
|
|
6922
|
+
let verified = false;
|
|
6923
|
+
try {
|
|
6924
|
+
verified = await peek(ws, { manual: true }) === true;
|
|
6925
|
+
} catch {
|
|
6926
|
+
}
|
|
6927
|
+
if (!verified) return false;
|
|
6928
|
+
const set = runningByWs.get(ws);
|
|
6929
|
+
return !(set && set.size);
|
|
6557
6930
|
}
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6931
|
+
function settleAndRead(ws) {
|
|
6932
|
+
return new Promise((resolve) => {
|
|
6933
|
+
const t0 = Date.now();
|
|
6934
|
+
let lastCount = -1;
|
|
6935
|
+
let stableAt = 0;
|
|
6936
|
+
let zeroRows = false;
|
|
6937
|
+
const timer = setInterval(() => {
|
|
6938
|
+
const rows = domRowsOf(ws);
|
|
6939
|
+
const elapsed = Date.now() - t0;
|
|
6940
|
+
if (rows.length !== lastCount) {
|
|
6941
|
+
lastCount = rows.length;
|
|
6942
|
+
stableAt = Date.now();
|
|
6943
|
+
}
|
|
6944
|
+
const settled = rows.length > 0 && rows.length === lastCount && Date.now() - stableAt >= PEEK_SETTLE_MS;
|
|
6945
|
+
if (!settled && elapsed < PEEK_MAX_MS) return;
|
|
6946
|
+
clearInterval(timer);
|
|
6947
|
+
if (lastCount === 0) {
|
|
6948
|
+
zeroRows = true;
|
|
6949
|
+
} else {
|
|
6950
|
+
let set = runningByWs.get(ws);
|
|
6951
|
+
if (!set) {
|
|
6952
|
+
set = /* @__PURE__ */ new Set();
|
|
6953
|
+
runningByWs.set(ws, set);
|
|
6954
|
+
}
|
|
6955
|
+
for (const el of rows) {
|
|
6956
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
6957
|
+
if (isRunningRow(el)) set.add(key);
|
|
6958
|
+
else set.delete(key);
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
resolve(!zeroRows);
|
|
6962
|
+
}, 80);
|
|
6963
|
+
});
|
|
6567
6964
|
}
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6965
|
+
var PEEK_EXEMPT_CLASS = "zcodepro-peek-exempt";
|
|
6966
|
+
var cssAttr = (v) => String(v).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
6967
|
+
function installPeekHider(ws) {
|
|
6968
|
+
const rowSel3 = `${TASK_SEL}[data-task-item-key^="${cssAttr(ws + ":")}"]`;
|
|
6969
|
+
for (const r of document.querySelectorAll(rowSel3)) r.classList.add(PEEK_EXEMPT_CLASS);
|
|
6970
|
+
const style = document.createElement("style");
|
|
6971
|
+
style.textContent = `${rowSel3}:not(.${PEEK_EXEMPT_CLASS}){display:none!important}`;
|
|
6972
|
+
document.head.append(style);
|
|
6973
|
+
return { style, sel: rowSel3 };
|
|
6571
6974
|
}
|
|
6572
|
-
function
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
}
|
|
6975
|
+
function removePeekHider(hider) {
|
|
6976
|
+
hider.style.remove();
|
|
6977
|
+
for (const r of document.querySelectorAll("." + PEEK_EXEMPT_CLASS)) r.classList.remove(PEEK_EXEMPT_CLASS);
|
|
6576
6978
|
}
|
|
6577
|
-
function
|
|
6578
|
-
|
|
6579
|
-
|
|
6979
|
+
function waitForRowsGone(ws) {
|
|
6980
|
+
const sel = `${TASK_SEL}[data-task-item-key^="${cssAttr(ws + ":")}"]:not(.${PEEK_EXEMPT_CLASS})`;
|
|
6981
|
+
return new Promise((resolve) => {
|
|
6982
|
+
const t0 = Date.now();
|
|
6983
|
+
const timer = setInterval(() => {
|
|
6984
|
+
if (!document.querySelector(sel) || Date.now() - t0 >= PEEK_UNMOUNT_WAIT_MS) {
|
|
6985
|
+
clearInterval(timer);
|
|
6986
|
+
resolve();
|
|
6987
|
+
}
|
|
6988
|
+
}, 40);
|
|
6580
6989
|
});
|
|
6581
6990
|
}
|
|
6582
|
-
var
|
|
6583
|
-
var
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
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 }));
|
|
6991
|
+
var TOUCH_WINDOW_MS = 800;
|
|
6992
|
+
var wsTouchAt = /* @__PURE__ */ new WeakMap();
|
|
6993
|
+
function userTouched(row) {
|
|
6994
|
+
const at = wsTouchAt.get(row);
|
|
6995
|
+
return !!at && Date.now() - at < TOUCH_WINDOW_MS;
|
|
6592
6996
|
}
|
|
6593
|
-
function
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6997
|
+
function inSel(node, sel) {
|
|
6998
|
+
return !!(node instanceof Element && node.closest && node.closest(sel));
|
|
6999
|
+
}
|
|
7000
|
+
function relevant(muts) {
|
|
7001
|
+
for (const m of muts) {
|
|
7002
|
+
if (inSel(m.target, TASK_SEL) || inSel(m.target, WS_SEL())) return true;
|
|
7003
|
+
for (const n of m.addedNodes) {
|
|
7004
|
+
if (n instanceof Element && (n.matches(TASK_SEL) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL) || n.querySelector(WS_SEL()))) return true;
|
|
7005
|
+
}
|
|
7006
|
+
for (const n of m.removedNodes) {
|
|
7007
|
+
if (n instanceof Element && (n.matches(TASK_SEL) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL))) return true;
|
|
7008
|
+
}
|
|
6597
7009
|
}
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
7010
|
+
return false;
|
|
7011
|
+
}
|
|
7012
|
+
var pollMs = CONFIG_POLL_MIN_MS;
|
|
7013
|
+
async function refreshConfig() {
|
|
7014
|
+
try {
|
|
7015
|
+
const res = await rpc("/config");
|
|
7016
|
+
if (res && res.ok && res.config && res.config.features) {
|
|
7017
|
+
const next = res.config.features.wsRunningSpin !== false;
|
|
7018
|
+
if (next !== enabled2) {
|
|
7019
|
+
enabled2 = next;
|
|
7020
|
+
if (!next) {
|
|
7021
|
+
for (const ws of [...peekTimers.keys()]) clearPeek(ws);
|
|
7022
|
+
apply();
|
|
7023
|
+
}
|
|
7024
|
+
return true;
|
|
7025
|
+
}
|
|
7026
|
+
}
|
|
7027
|
+
} catch {
|
|
6610
7028
|
}
|
|
7029
|
+
return false;
|
|
6611
7030
|
}
|
|
6612
|
-
function
|
|
7031
|
+
function pollConfig() {
|
|
7032
|
+
setTimeout(async () => {
|
|
7033
|
+
if (document.hidden) pollMs = CONFIG_POLL_MAX_MS;
|
|
7034
|
+
else pollMs = await refreshConfig() ? CONFIG_POLL_MIN_MS : Math.min(Math.round(pollMs * 1.5), CONFIG_POLL_MAX_MS);
|
|
7035
|
+
pollConfig();
|
|
7036
|
+
}, pollMs);
|
|
7037
|
+
}
|
|
7038
|
+
var scanDebounce = 0;
|
|
7039
|
+
function startWsRunningSpin() {
|
|
6613
7040
|
if (installed2 || typeof document === "undefined") return;
|
|
6614
7041
|
installed2 = true;
|
|
6615
|
-
void
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
if (!
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
}, true);
|
|
6626
|
-
document.addEventListener("click", (e) => {
|
|
6627
|
-
if (!renameCtx || renameCtx.armed) return;
|
|
6628
|
-
const item = e.target instanceof Element && e.target.closest('[role="menuitem"], [data-radix-collection-item]');
|
|
6629
|
-
if (item && /重命名|rename/i.test(item.textContent || "")) {
|
|
6630
|
-
renameCtx.armed = true;
|
|
6631
|
-
renameCtx.at = Date.now();
|
|
7042
|
+
void refreshConfig();
|
|
7043
|
+
pollConfig();
|
|
7044
|
+
const observer2 = new MutationObserver((muts) => {
|
|
7045
|
+
if (!relevant(muts)) return;
|
|
7046
|
+
handleRemovals(muts);
|
|
7047
|
+
if (!scanDebounce) {
|
|
7048
|
+
scanDebounce = setTimeout(() => {
|
|
7049
|
+
scanDebounce = 0;
|
|
7050
|
+
scan();
|
|
7051
|
+
}, SCAN_DEBOUNCE_MS);
|
|
6632
7052
|
}
|
|
6633
|
-
}
|
|
6634
|
-
|
|
7053
|
+
});
|
|
7054
|
+
observer2.observe(document.body, { childList: true, subtree: true });
|
|
7055
|
+
scan();
|
|
6635
7056
|
setInterval(() => {
|
|
6636
|
-
if (!document.hidden)
|
|
6637
|
-
},
|
|
7057
|
+
if (!document.hidden && enabled2) scan();
|
|
7058
|
+
}, SCAN_FALLBACK_MS);
|
|
6638
7059
|
document.addEventListener("visibilitychange", () => {
|
|
6639
|
-
if (!document.hidden)
|
|
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
|
-
});
|
|
7060
|
+
if (!document.hidden) scan();
|
|
6657
7061
|
});
|
|
7062
|
+
document.addEventListener("click", (e) => {
|
|
7063
|
+
if (!e.isTrusted) return;
|
|
7064
|
+
const row = e.target instanceof Element && e.target.closest(WS_SEL());
|
|
7065
|
+
if (row) wsTouchAt.set(row, Date.now());
|
|
7066
|
+
}, true);
|
|
6658
7067
|
}
|
|
6659
7068
|
|
|
6660
|
-
// src/inject/features/
|
|
6661
|
-
var
|
|
6662
|
-
var
|
|
6663
|
-
var
|
|
6664
|
-
var
|
|
6665
|
-
var
|
|
6666
|
-
var
|
|
6667
|
-
var
|
|
6668
|
-
var
|
|
6669
|
-
var
|
|
6670
|
-
var
|
|
6671
|
-
var
|
|
6672
|
-
var
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
return
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
return ((el ? el.textContent : r.innerText) || "").trim();
|
|
6687
|
-
}).filter(Boolean);
|
|
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);
|
|
6696
|
-
}
|
|
6697
|
-
function linkDominant(t2) {
|
|
6698
|
-
const raw = t2.replace(/\s+/g, "");
|
|
6699
|
-
if (!raw) return true;
|
|
6700
|
-
const stripped = raw.replace(URL_RE, "");
|
|
6701
|
-
return stripped.length < raw.length / 3;
|
|
6702
|
-
}
|
|
6703
|
-
async function onNewTaskRow(key) {
|
|
6704
|
-
const selDeadline = Date.now() + SELECT_WAIT_MS;
|
|
6705
|
-
while (currentKey() !== key && Date.now() < selDeadline) await sleep2(200);
|
|
6706
|
-
if (currentKey() !== key) return;
|
|
6707
|
-
const cfg = await getConfig().catch(() => null);
|
|
6708
|
-
if (!cfg || !cfg.titleGen || cfg.titleGen.enabled !== true) return;
|
|
6709
|
-
const sessId = sessIdOf2(key);
|
|
6710
|
-
if (!sessId || attempted.has(sessId)) return;
|
|
6711
|
-
attempted.add(sessId);
|
|
6712
|
-
let texts = [];
|
|
6713
|
-
const msgDeadline = Date.now() + MSG_WAIT_MS;
|
|
6714
|
-
while (Date.now() < msgDeadline) {
|
|
6715
|
-
texts = userTexts();
|
|
6716
|
-
if (texts.length) break;
|
|
6717
|
-
await sleep2(400);
|
|
6718
|
-
}
|
|
6719
|
-
if (!texts.length) return;
|
|
6720
|
-
let assistantSeen = false;
|
|
6721
|
-
const convObserver = new MutationObserver((muts) => {
|
|
6722
|
-
if (currentKey() !== key) return;
|
|
6723
|
-
for (const m of muts) {
|
|
6724
|
-
const t2 = m.type === "characterData" ? m.target.parentElement : m.target;
|
|
6725
|
-
if (t2 instanceof Element && t2.closest(USER_ROW)) continue;
|
|
6726
|
-
for (const n of [t2, ...m.addedNodes]) {
|
|
6727
|
-
if (n instanceof Element && n.closest && n.closest(CONV2)) {
|
|
6728
|
-
assistantSeen = true;
|
|
6729
|
-
return;
|
|
6730
|
-
}
|
|
7069
|
+
// src/inject/features/session-switch.js
|
|
7070
|
+
var MRU_LIMIT = 50;
|
|
7071
|
+
var SCAN_DEBOUNCE_MS2 = 150;
|
|
7072
|
+
var SCAN_FALLBACK_MS2 = 5e3;
|
|
7073
|
+
var INITIAL_COUNT = 10;
|
|
7074
|
+
var PAGE_SIZE = 5;
|
|
7075
|
+
var UNSEEN_LIMIT = 50;
|
|
7076
|
+
var mru = [];
|
|
7077
|
+
var current = null;
|
|
7078
|
+
var titles = /* @__PURE__ */ new Map();
|
|
7079
|
+
var popupEl = null;
|
|
7080
|
+
var aliasesCache = {};
|
|
7081
|
+
var highlight = 0;
|
|
7082
|
+
var scanDebounce2 = 0;
|
|
7083
|
+
var popupMode = "mru";
|
|
7084
|
+
var visibleCount = INITIAL_COUNT;
|
|
7085
|
+
var unseen = /* @__PURE__ */ new Set();
|
|
7086
|
+
var lastRunKeys = null;
|
|
7087
|
+
var movedSinceOpen = false;
|
|
7088
|
+
var hotkeys = { ...DEFAULT_SHORTCUTS };
|
|
7089
|
+
function loadHotkeys() {
|
|
7090
|
+
return getConfig(true).then((cfg) => {
|
|
7091
|
+
const sc = cfg && cfg.shortcuts;
|
|
7092
|
+
if (sc && typeof sc === "object") {
|
|
7093
|
+
for (const k of Object.keys(DEFAULT_SHORTCUTS)) {
|
|
7094
|
+
if (typeof sc[k] === "string" && /^[a-z0-9]$/.test(sc[k])) hotkeys[k] = sc[k];
|
|
6731
7095
|
}
|
|
6732
7096
|
}
|
|
7097
|
+
}).catch(() => {
|
|
6733
7098
|
});
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
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;
|
|
6752
|
-
}
|
|
6753
|
-
} finally {
|
|
6754
|
-
convObserver.disconnect();
|
|
6755
|
-
}
|
|
6756
|
-
if (!texts.length) return;
|
|
6757
|
-
if (linkDominant(texts.join("\n"))) {
|
|
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
|
-
}
|
|
6768
|
-
}
|
|
6769
|
-
const callTitleGen = () => rpc("/title-gen/run", { method: "POST", body: { sessId, text: texts.join("\n") } }).catch(() => null);
|
|
6770
|
-
let res = await callTitleGen();
|
|
6771
|
-
for (const delay of [5e3, 2e4]) {
|
|
6772
|
-
if (res && res.ok) break;
|
|
6773
|
-
await sleep2(delay);
|
|
6774
|
-
res = await callTitleGen();
|
|
7099
|
+
}
|
|
7100
|
+
function firstLineOf(item) {
|
|
7101
|
+
const tEl = item.querySelector('[class*="truncate"]');
|
|
7102
|
+
return (tEl ? tEl.textContent : (item.innerText || "").split("\n")[0])?.trim() || "";
|
|
7103
|
+
}
|
|
7104
|
+
function workspaceOf2(key) {
|
|
7105
|
+
const i = key.indexOf(":sess_");
|
|
7106
|
+
return i > 0 ? key.slice(0, i) : key;
|
|
7107
|
+
}
|
|
7108
|
+
function findCurrent() {
|
|
7109
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7110
|
+
if ((el.className + "").includes("bg-selected")) return el;
|
|
6775
7111
|
}
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
7112
|
+
return null;
|
|
7113
|
+
}
|
|
7114
|
+
function record(key) {
|
|
7115
|
+
if (key) unseen.delete(key);
|
|
7116
|
+
if (key && key !== current) {
|
|
7117
|
+
current = key;
|
|
7118
|
+
mru = mru.filter((k) => k !== key);
|
|
7119
|
+
mru.unshift(key);
|
|
7120
|
+
if (mru.length > MRU_LIMIT) mru.length = MRU_LIMIT;
|
|
6779
7121
|
}
|
|
6780
7122
|
}
|
|
6781
|
-
function
|
|
7123
|
+
function scan2() {
|
|
7124
|
+
const cur = findCurrent();
|
|
7125
|
+
if (cur) record(cur.getAttribute("data-task-item-key"));
|
|
6782
7126
|
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
6783
|
-
|
|
6784
|
-
if (!key || knownKeys.has(key)) continue;
|
|
6785
|
-
knownKeys.add(key);
|
|
6786
|
-
void onNewTaskRow(key);
|
|
7127
|
+
titles.set(el.getAttribute("data-task-item-key"), firstLineOf(el));
|
|
6787
7128
|
}
|
|
6788
7129
|
}
|
|
6789
|
-
var
|
|
6790
|
-
var
|
|
6791
|
-
function
|
|
7130
|
+
var rowSel2 = "[data-task-item-key]";
|
|
7131
|
+
var inTaskRow = (node) => node instanceof Element && !!node.closest && !!node.closest(rowSel2);
|
|
7132
|
+
function taskRowMutations(muts) {
|
|
6792
7133
|
for (const m of muts) {
|
|
6793
7134
|
if (m.type === "attributes") {
|
|
6794
|
-
if (
|
|
7135
|
+
if (inTaskRow(m.target)) return true;
|
|
6795
7136
|
} else if (m.type === "characterData") {
|
|
6796
|
-
if (m.target.parentElement &&
|
|
6797
|
-
} else if (
|
|
7137
|
+
if (m.target.parentElement && inTaskRow(m.target.parentElement)) return true;
|
|
7138
|
+
} else if (inTaskRow(m.target)) {
|
|
6798
7139
|
return true;
|
|
6799
7140
|
} else {
|
|
6800
7141
|
for (const n of m.addedNodes) {
|
|
6801
|
-
if (n instanceof Element && (n.matches(
|
|
7142
|
+
if (n instanceof Element && (n.matches(rowSel2) || !!n.querySelector(rowSel2))) return true;
|
|
6802
7143
|
}
|
|
6803
7144
|
}
|
|
6804
7145
|
}
|
|
6805
7146
|
return false;
|
|
6806
7147
|
}
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
}, SCAN_DEBOUNCE_MS3);
|
|
6814
|
-
}
|
|
6815
|
-
function startTitleGen() {
|
|
6816
|
-
if (installed3 || typeof document === "undefined") return;
|
|
6817
|
-
installed3 = true;
|
|
6818
|
-
scanForNewRows();
|
|
6819
|
-
new MutationObserver((muts) => {
|
|
6820
|
-
if (taskRowMutations3(muts)) scheduleScan3();
|
|
6821
|
-
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
|
|
6822
|
-
setInterval(() => {
|
|
6823
|
-
if (!document.hidden) scanForNewRows();
|
|
6824
|
-
}, SCAN_FALLBACK_MS3);
|
|
6825
|
-
document.addEventListener("visibilitychange", () => {
|
|
6826
|
-
if (!document.hidden) scanForNewRows();
|
|
6827
|
-
});
|
|
7148
|
+
function scheduleScan() {
|
|
7149
|
+
if (scanDebounce2) return;
|
|
7150
|
+
scanDebounce2 = setTimeout(() => {
|
|
7151
|
+
scanDebounce2 = 0;
|
|
7152
|
+
scan2();
|
|
7153
|
+
}, SCAN_DEBOUNCE_MS2);
|
|
6828
7154
|
}
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
return findProjectRow(ws);
|
|
7155
|
+
async function switchTo(key) {
|
|
7156
|
+
const find = () => document.querySelector(`[data-task-item-key="${CSS.escape(key)}"]`);
|
|
7157
|
+
let item = find();
|
|
7158
|
+
if (!item) {
|
|
7159
|
+
const ws = workspaceOf2(key);
|
|
7160
|
+
const header = findProjectRow(ws);
|
|
7161
|
+
const expander = header && header.querySelector("[aria-expanded]");
|
|
7162
|
+
if (expander && expander.getAttribute("aria-expanded") === "false") {
|
|
7163
|
+
expander.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
7164
|
+
for (let i = 0; i < 20 && !(item = find()); i++) await new Promise((r) => setTimeout(r, 100));
|
|
7165
|
+
}
|
|
7166
|
+
}
|
|
7167
|
+
if (!item) return false;
|
|
7168
|
+
item.scrollIntoView({ block: "nearest" });
|
|
7169
|
+
item.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
7170
|
+
return true;
|
|
6846
7171
|
}
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
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;
|
|
7172
|
+
function attentionList() {
|
|
7173
|
+
const run = wsRunningKeys();
|
|
7174
|
+
const listed = /* @__PURE__ */ new Set();
|
|
7175
|
+
const head = [];
|
|
7176
|
+
for (const k of mru) {
|
|
7177
|
+
if (run.has(k) || unseen.has(k)) {
|
|
7178
|
+
head.push(k);
|
|
7179
|
+
listed.add(k);
|
|
7180
|
+
}
|
|
6866
7181
|
}
|
|
6867
|
-
const
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
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);
|
|
7182
|
+
const tail = [];
|
|
7183
|
+
for (const k of run) if (!listed.has(k)) {
|
|
7184
|
+
tail.push(k);
|
|
7185
|
+
listed.add(k);
|
|
6879
7186
|
}
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
if (!holder) return;
|
|
6884
|
-
if (on) {
|
|
6885
|
-
if (holder.querySelector(":scope > svg.zcodepro-ws-loader")) return;
|
|
6886
|
-
const orig0 = holder.querySelector(":scope > svg:not(.zcodepro-ws-loader)");
|
|
6887
|
-
const base = (orig0 ? orig0.getAttribute("class") || "" : "size-4").replace(/lucide-[a-z-]*/g, "").trim() || "size-4";
|
|
6888
|
-
holder.append(makeLoaderSvg(base));
|
|
6889
|
-
} else {
|
|
6890
|
-
holder.querySelectorAll(":scope > svg.zcodepro-ws-loader").forEach((el) => el.remove());
|
|
7187
|
+
for (const k of unseen) if (!listed.has(k)) {
|
|
7188
|
+
tail.push(k);
|
|
7189
|
+
listed.add(k);
|
|
6891
7190
|
}
|
|
7191
|
+
return [...head, ...tail];
|
|
6892
7192
|
}
|
|
6893
|
-
function
|
|
6894
|
-
|
|
6895
|
-
const toggle2 = row.querySelector('[data-testid="virtual-project-toggle"]');
|
|
6896
|
-
return toggle2 ? toggle2.querySelector(":scope > span") : null;
|
|
6897
|
-
}
|
|
6898
|
-
return row.firstElementChild && row.firstElementChild.querySelector(":scope > span");
|
|
7193
|
+
function activeList() {
|
|
7194
|
+
return popupMode === "attention" ? attentionList() : mru;
|
|
6899
7195
|
}
|
|
6900
|
-
function
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
const
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
var wsWithRows = /* @__PURE__ */ new Set();
|
|
6911
|
-
var servicesRef = null;
|
|
6912
|
-
function findServices() {
|
|
6913
|
-
if (servicesRef) return servicesRef;
|
|
6914
|
-
try {
|
|
6915
|
-
const rootEl = document.getElementById("root");
|
|
6916
|
-
const containerKey = rootEl && Object.keys(rootEl).find((k) => k.startsWith("__reactContainer$"));
|
|
6917
|
-
if (!containerKey) return null;
|
|
6918
|
-
const seen = /* @__PURE__ */ new Set();
|
|
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
|
-
}
|
|
6936
|
-
}
|
|
6937
|
-
visit(f.child);
|
|
6938
|
-
visit(f.sibling);
|
|
6939
|
-
};
|
|
6940
|
-
visit(rootEl[containerKey]);
|
|
6941
|
-
if (found) servicesRef = found;
|
|
6942
|
-
return found;
|
|
6943
|
-
} catch {
|
|
6944
|
-
return null;
|
|
7196
|
+
function closePopup(commit) {
|
|
7197
|
+
if (!popupEl) return;
|
|
7198
|
+
const idx = highlight;
|
|
7199
|
+
const list = activeList();
|
|
7200
|
+
popupEl.remove();
|
|
7201
|
+
popupEl = null;
|
|
7202
|
+
if (commit && list[idx] && list[idx] !== current) {
|
|
7203
|
+
void switchTo(list[idx]).then((ok) => {
|
|
7204
|
+
if (!ok) showToast(t().switcherFailed, "error");
|
|
7205
|
+
});
|
|
6945
7206
|
}
|
|
6946
7207
|
}
|
|
6947
|
-
|
|
6948
|
-
const
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
const base = String(ws).replace(/[\\/]+$/, "");
|
|
6953
|
-
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
6954
|
-
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
6955
|
-
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
6956
|
-
if (!Array.isArray(a) || !Array.isArray(b)) return null;
|
|
6957
|
-
if (!ids.length) return true;
|
|
6958
|
-
const st = await rpc("/task-statuses?ids=" + encodeURIComponent(ids.join(","))).catch(() => null);
|
|
6959
|
-
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
6960
|
-
const live = (id) => {
|
|
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;
|
|
6969
|
-
}
|
|
7208
|
+
function findTitle(key) {
|
|
7209
|
+
const item = document.querySelector(`[data-task-item-key="${CSS.escape(key)}"]`);
|
|
7210
|
+
if (item) titles.set(key, firstLineOf(item));
|
|
7211
|
+
const id = key.slice(key.indexOf(":sess_") + 1);
|
|
7212
|
+
return titles.get(key) || `sess ${id.slice(0, 8)}`;
|
|
6970
7213
|
}
|
|
6971
|
-
function
|
|
6972
|
-
const
|
|
6973
|
-
|
|
7214
|
+
function projLabelOf(key, aliases2) {
|
|
7215
|
+
const ws = workspaceOf2(key);
|
|
7216
|
+
if (!ws) return "";
|
|
7217
|
+
return aliases2[ws] || ws.replace(/[\\/]+$/, "").split(/[\\/]/).pop();
|
|
6974
7218
|
}
|
|
6975
|
-
function
|
|
6976
|
-
|
|
7219
|
+
function renderPopup() {
|
|
7220
|
+
if (!popupEl) return;
|
|
7221
|
+
const L = t();
|
|
7222
|
+
const list = popupEl.querySelector("[data-zcodepro-switcher-list]");
|
|
7223
|
+
const full = activeList();
|
|
7224
|
+
const shown = full.slice(0, visibleCount);
|
|
7225
|
+
const run = popupMode === "attention" ? wsRunningKeys() : null;
|
|
7226
|
+
list.replaceChildren(...shown.map((key) => {
|
|
7227
|
+
const proj = projLabelOf(key, aliasesCache);
|
|
7228
|
+
return h(
|
|
7229
|
+
"div",
|
|
7230
|
+
{
|
|
7231
|
+
class: "zcodepro-switcher-row",
|
|
7232
|
+
"data-active": full[highlight] === key ? "" : void 0,
|
|
7233
|
+
onClick: () => {
|
|
7234
|
+
highlight = full.indexOf(key);
|
|
7235
|
+
closePopup(true);
|
|
7236
|
+
}
|
|
7237
|
+
},
|
|
7238
|
+
// 标题文本包 span:截断省略作用在文本节点上(flex 容器自身 ellipsis 无效)
|
|
7239
|
+
h(
|
|
7240
|
+
"div",
|
|
7241
|
+
{ class: "zcodepro-switcher-title" },
|
|
7242
|
+
key === current ? h("span", { class: "zcodepro-switcher-tag" }, L.switcherCurrent) : null,
|
|
7243
|
+
run && run.has(key) ? h("span", { class: "zcodepro-switcher-tag zcodepro-switcher-tag-run" }, L.switcherRunning) : null,
|
|
7244
|
+
run && !run.has(key) ? h("span", { class: "zcodepro-switcher-tag zcodepro-switcher-tag-new" }, L.switcherUnseen) : null,
|
|
7245
|
+
h("span", null, findTitle(key))
|
|
7246
|
+
),
|
|
7247
|
+
// 无项目归属(如置顶)时不渲染空行
|
|
7248
|
+
proj ? h("div", { class: "zcodepro-switcher-ws" }, proj) : null
|
|
7249
|
+
);
|
|
7250
|
+
}));
|
|
7251
|
+
if (full.length > shown.length) {
|
|
7252
|
+
list.append(h(
|
|
7253
|
+
"div",
|
|
7254
|
+
{ class: "zcodepro-switcher-more" },
|
|
7255
|
+
L.switcherMore.replaceAll("{n}", String(full.length - shown.length))
|
|
7256
|
+
));
|
|
7257
|
+
}
|
|
6977
7258
|
}
|
|
6978
|
-
function
|
|
6979
|
-
|
|
7259
|
+
async function openPopup(mode = "mru") {
|
|
7260
|
+
if (popupEl) return;
|
|
7261
|
+
popupMode = mode;
|
|
7262
|
+
visibleCount = INITIAL_COUNT;
|
|
7263
|
+
highlight = 0;
|
|
7264
|
+
movedSinceOpen = false;
|
|
7265
|
+
const cfg = await getConfig().catch(() => null);
|
|
7266
|
+
aliasesCache = cfg && cfg.aliases && typeof cfg.aliases === "object" ? cfg.aliases : {};
|
|
7267
|
+
ensureStyle();
|
|
7268
|
+
const L = t();
|
|
7269
|
+
popupEl = h(
|
|
7270
|
+
"div",
|
|
7271
|
+
{
|
|
7272
|
+
class: "zcodepro-switcher-overlay",
|
|
7273
|
+
// 点弹窗外 = 取消(不切)
|
|
7274
|
+
onMousedown: (e) => {
|
|
7275
|
+
if (e.target === popupEl) closePopup(false);
|
|
7276
|
+
}
|
|
7277
|
+
},
|
|
7278
|
+
h(
|
|
7279
|
+
"div",
|
|
7280
|
+
{ class: "zcodepro-switcher" },
|
|
7281
|
+
// 提示行键位跟随当前配置(改键后新开的弹窗即用新键位)
|
|
7282
|
+
h(
|
|
7283
|
+
"div",
|
|
7284
|
+
{ class: "zcodepro-switcher-hint" },
|
|
7285
|
+
(mode === "attention" ? L.switcherAttentionHint : L.switcherHint).replaceAll("{prev}", hotkeys.switchPrev).replaceAll("{next}", hotkeys.switchNext)
|
|
7286
|
+
),
|
|
7287
|
+
h("div", { "data-zcodepro-switcher-list": "1", class: "zcodepro-switcher-list" })
|
|
7288
|
+
)
|
|
7289
|
+
);
|
|
7290
|
+
document.body.append(popupEl);
|
|
7291
|
+
renderPopup();
|
|
6980
7292
|
}
|
|
6981
|
-
function
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
}
|
|
6985
|
-
return null;
|
|
7293
|
+
function scrollHighlight() {
|
|
7294
|
+
const row = popupEl && popupEl.querySelector("[data-active]");
|
|
7295
|
+
if (row) row.scrollIntoView({ block: "nearest" });
|
|
6986
7296
|
}
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
7297
|
+
function moveUp() {
|
|
7298
|
+
const len = Math.min(activeList().length, visibleCount);
|
|
7299
|
+
if (len < 2) return;
|
|
7300
|
+
highlight = highlight > 0 ? highlight - 1 : len - 1;
|
|
7301
|
+
movedSinceOpen = true;
|
|
7302
|
+
renderPopup();
|
|
7303
|
+
scrollHighlight();
|
|
7304
|
+
}
|
|
7305
|
+
function moveDown() {
|
|
7306
|
+
const full = activeList();
|
|
7307
|
+
const len = Math.min(full.length, visibleCount);
|
|
7308
|
+
if (len < 2) return;
|
|
7309
|
+
if (highlight < len - 1) {
|
|
7310
|
+
highlight += 1;
|
|
7311
|
+
} else if (visibleCount < full.length) {
|
|
7312
|
+
visibleCount = Math.min(visibleCount + PAGE_SIZE, full.length);
|
|
7313
|
+
highlight = len;
|
|
7314
|
+
} else {
|
|
7315
|
+
highlight = 0;
|
|
6991
7316
|
}
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
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);
|
|
7317
|
+
movedSinceOpen = true;
|
|
7318
|
+
renderPopup();
|
|
7319
|
+
scrollHighlight();
|
|
7000
7320
|
}
|
|
7001
|
-
function
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7321
|
+
function startSessionSwitch() {
|
|
7322
|
+
scan2();
|
|
7323
|
+
void loadHotkeys();
|
|
7324
|
+
window.addEventListener("zcodepro:config-changed", () => {
|
|
7325
|
+
void loadHotkeys();
|
|
7326
|
+
});
|
|
7327
|
+
new MutationObserver((muts) => {
|
|
7328
|
+
if (taskRowMutations(muts)) scheduleScan();
|
|
7329
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] });
|
|
7330
|
+
setInterval(() => {
|
|
7331
|
+
if (!document.hidden) scan2();
|
|
7332
|
+
}, SCAN_FALLBACK_MS2);
|
|
7333
|
+
document.addEventListener("visibilitychange", () => {
|
|
7334
|
+
if (!document.hidden) scan2();
|
|
7335
|
+
});
|
|
7336
|
+
setInterval(() => {
|
|
7337
|
+
if (document.hidden) return;
|
|
7338
|
+
const now = wsRunningKeys();
|
|
7339
|
+
if (lastRunKeys) {
|
|
7340
|
+
for (const k of lastRunKeys) {
|
|
7341
|
+
if (!now.has(k) && k !== current) unseen.add(k);
|
|
7014
7342
|
}
|
|
7015
|
-
set.add(key);
|
|
7016
|
-
} else if (set) {
|
|
7017
|
-
set.delete(key);
|
|
7018
7343
|
}
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7344
|
+
lastRunKeys = now;
|
|
7345
|
+
if (unseen.size > UNSEEN_LIMIT) unseen = new Set([...unseen].slice(-UNSEEN_LIMIT));
|
|
7346
|
+
}, 1e4);
|
|
7347
|
+
document.addEventListener("click", (e) => {
|
|
7348
|
+
const item = e.target instanceof Element && e.target.closest("[data-task-item-key]");
|
|
7349
|
+
if (item) record(item.getAttribute("data-task-item-key"));
|
|
7350
|
+
}, true);
|
|
7351
|
+
document.addEventListener("keydown", (e) => {
|
|
7352
|
+
if (e.key === "Escape" && popupEl) {
|
|
7353
|
+
e.preventDefault();
|
|
7354
|
+
e.stopImmediatePropagation();
|
|
7355
|
+
closePopup(false);
|
|
7356
|
+
return;
|
|
7031
7357
|
}
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7358
|
+
if (popupEl && (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Enter")) {
|
|
7359
|
+
e.preventDefault();
|
|
7360
|
+
e.stopImmediatePropagation();
|
|
7361
|
+
if (e.key === "ArrowUp") moveUp();
|
|
7362
|
+
else if (e.key === "ArrowDown") moveDown();
|
|
7363
|
+
else if (!e.repeat) closePopup(true);
|
|
7364
|
+
return;
|
|
7365
|
+
}
|
|
7366
|
+
if (!e.altKey || e.ctrlKey || e.metaKey || e.isComposing) return;
|
|
7367
|
+
if (document.querySelector(".zcodepro-overlay")) return;
|
|
7368
|
+
const k = e.key.toLowerCase();
|
|
7369
|
+
const isHot = k === hotkeys.switchLast || k === hotkeys.switchPrev || k === hotkeys.switchNext || k === hotkeys.switchRecent || k === hotkeys.switchAttention;
|
|
7370
|
+
if (!isHot) return;
|
|
7371
|
+
e.preventDefault();
|
|
7372
|
+
e.stopImmediatePropagation();
|
|
7373
|
+
void (async () => {
|
|
7374
|
+
const cfg = await getConfig();
|
|
7375
|
+
if (cfg.features && cfg.features.sessionSwitch === false) return;
|
|
7376
|
+
if (k === hotkeys.switchLast) {
|
|
7377
|
+
if (e.repeat) return;
|
|
7378
|
+
closePopup(false);
|
|
7379
|
+
const live = findCurrent();
|
|
7380
|
+
if (live) record(live.getAttribute("data-task-item-key"));
|
|
7381
|
+
const target = live ? mru[0] === current ? mru[1] : mru.find((mk) => mk !== current) : mru[0];
|
|
7382
|
+
if (!target) {
|
|
7383
|
+
showToast(t().switcherEmpty);
|
|
7384
|
+
return;
|
|
7050
7385
|
}
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7386
|
+
void switchTo(target).then((ok) => {
|
|
7387
|
+
if (!ok) showToast(t().switcherFailed, "error");
|
|
7388
|
+
});
|
|
7389
|
+
return;
|
|
7054
7390
|
}
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7391
|
+
if (k === hotkeys.switchAttention) {
|
|
7392
|
+
if (e.repeat) return;
|
|
7393
|
+
closePopup(false);
|
|
7394
|
+
if (!attentionList().length) {
|
|
7395
|
+
showToast(t().switcherAttentionEmpty);
|
|
7396
|
+
return;
|
|
7397
|
+
}
|
|
7398
|
+
await openPopup("attention");
|
|
7399
|
+
return;
|
|
7400
|
+
}
|
|
7401
|
+
if (mru.length < 2) {
|
|
7402
|
+
showToast(t().switcherEmpty);
|
|
7403
|
+
return;
|
|
7404
|
+
}
|
|
7405
|
+
if (k === hotkeys.switchRecent) {
|
|
7406
|
+
if (!e.repeat && !popupEl) await openPopup("mru");
|
|
7407
|
+
return;
|
|
7408
|
+
}
|
|
7409
|
+
if (!popupEl) await openPopup("mru");
|
|
7410
|
+
if (k === hotkeys.switchPrev) moveUp();
|
|
7411
|
+
else moveDown();
|
|
7412
|
+
})();
|
|
7413
|
+
}, true);
|
|
7414
|
+
document.addEventListener("keyup", (e) => {
|
|
7415
|
+
if (e.key === "Alt" && popupEl && movedSinceOpen) closePopup(true);
|
|
7416
|
+
}, true);
|
|
7417
|
+
window.addEventListener("blur", () => closePopup(false));
|
|
7059
7418
|
}
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7419
|
+
|
|
7420
|
+
// src/inject/features/title-lock.js
|
|
7421
|
+
var TASK_SEL2 = "[data-task-item-key]";
|
|
7422
|
+
var SCAN_DEBOUNCE_MS3 = 150;
|
|
7423
|
+
var SCAN_FALLBACK_MS3 = 5e3;
|
|
7424
|
+
var BOOT_RETRY_MS = 5e3;
|
|
7425
|
+
var RECHECK_DELAY_MS = 1e3;
|
|
7426
|
+
var REVERIFY_MS = 3e3;
|
|
7427
|
+
var MAP_REFRESH_MS = 6e4;
|
|
7428
|
+
var installed3 = false;
|
|
7429
|
+
var seenRows = /* @__PURE__ */ new WeakSet();
|
|
7430
|
+
var enabled3 = true;
|
|
7431
|
+
var pinned = null;
|
|
7432
|
+
var resolved = false;
|
|
7433
|
+
var fetching = null;
|
|
7434
|
+
var pendingKeys = /* @__PURE__ */ new Set();
|
|
7435
|
+
function sessIdOf(key) {
|
|
7436
|
+
const i = key.indexOf(":sess_");
|
|
7437
|
+
return i > 0 ? key.slice(i + 1) : key;
|
|
7077
7438
|
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
if (PROJECT_HEAD_TEXTS.has(text)) return "project";
|
|
7084
|
-
if (TASK_HEAD_TEXTS.has(text)) return "task";
|
|
7085
|
-
return null;
|
|
7439
|
+
function titleElsOf(item) {
|
|
7440
|
+
const copies = item.querySelectorAll("[data-task-title-copy]");
|
|
7441
|
+
if (copies.length) return [...copies];
|
|
7442
|
+
const t2 = item.querySelector('[class*="truncate"]');
|
|
7443
|
+
return t2 ? [t2] : [];
|
|
7086
7444
|
}
|
|
7087
|
-
function
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7445
|
+
function findRows(key) {
|
|
7446
|
+
return [...document.querySelectorAll(`${TASK_SEL2}[data-task-item-key="${CSS.escape(key)}"]`)];
|
|
7447
|
+
}
|
|
7448
|
+
async function fetchPinned() {
|
|
7449
|
+
if (fetching) return fetching;
|
|
7450
|
+
const p = (async () => {
|
|
7451
|
+
const res = await rpc("/pinned-titles");
|
|
7452
|
+
if (!res || !res.ok) return null;
|
|
7453
|
+
resolved = true;
|
|
7454
|
+
enabled3 = res.enabled !== false;
|
|
7455
|
+
if (!enabled3) {
|
|
7456
|
+
pinned = null;
|
|
7457
|
+
return null;
|
|
7458
|
+
}
|
|
7459
|
+
pinned = new Map(Object.entries(res.titles || {}));
|
|
7460
|
+
return pinned;
|
|
7461
|
+
})();
|
|
7462
|
+
fetching = p;
|
|
7463
|
+
try {
|
|
7464
|
+
return await p;
|
|
7465
|
+
} finally {
|
|
7466
|
+
if (fetching === p) fetching = null;
|
|
7092
7467
|
}
|
|
7093
|
-
for (const h3 of document.querySelectorAll("h3")) heads.push(h3);
|
|
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);
|
|
7105
7468
|
}
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
if (
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
const
|
|
7129
|
-
|
|
7130
|
-
for (const r of proj.roots || []) {
|
|
7131
|
-
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
7132
|
-
if (b) projPaths.add(b);
|
|
7133
|
-
}
|
|
7134
|
-
}
|
|
7135
|
-
const taskSidePaths = /* @__PURE__ */ new Set();
|
|
7136
|
-
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7137
|
-
const sec = el.closest("section[data-project-id]");
|
|
7138
|
-
if (sec) continue;
|
|
7139
|
-
const k = el.getAttribute("data-task-item-key") || "";
|
|
7140
|
-
const cut = k.lastIndexOf(":");
|
|
7141
|
-
if (cut > 1) taskSidePaths.add(k.slice(0, cut).replace(/[\\/]+$/, ""));
|
|
7142
|
-
}
|
|
7143
|
-
const scanPaths = /* @__PURE__ */ new Set([...projPaths, ...taskSidePaths]);
|
|
7144
|
-
const byKind = { task: /* @__PURE__ */ new Set(), project: /* @__PURE__ */ new Set() };
|
|
7145
|
-
const byKindByPath = /* @__PURE__ */ new Map();
|
|
7146
|
-
const rootToProject = /* @__PURE__ */ new Map();
|
|
7147
|
-
const projectPaths = /* @__PURE__ */ new Map();
|
|
7148
|
-
for (const proj of res.projects || []) {
|
|
7149
|
-
const names = [];
|
|
7150
|
-
for (const r of proj.roots || []) {
|
|
7151
|
-
const b = String(r.path || "").replace(/[\\/]+$/, "");
|
|
7152
|
-
if (b) {
|
|
7153
|
-
rootToProject.set(b, proj.name);
|
|
7154
|
-
names.push(b);
|
|
7155
|
-
}
|
|
7156
|
-
}
|
|
7157
|
-
projectPaths.set(proj.name, names);
|
|
7158
|
-
}
|
|
7159
|
-
for (const base of scanPaths) {
|
|
7160
|
-
const a = await ts.listActiveTaskIds({ workspacePath: base });
|
|
7161
|
-
const b = await ts.listActiveTaskIds({ workspacePath: base + "/" });
|
|
7162
|
-
const ids = [...Array.isArray(a) ? a : [], ...Array.isArray(b) ? b : []].map(String);
|
|
7163
|
-
if (!ids.length) continue;
|
|
7164
|
-
byKindByPath.set(base, ids);
|
|
7165
|
-
const kind = projPaths.has(base) ? "project" : "task";
|
|
7166
|
-
for (const id of ids) byKind[kind].add(id);
|
|
7167
|
-
}
|
|
7168
|
-
const allIds = [...byKind.task, ...byKind.project];
|
|
7169
|
-
const st = allIds.length ? await rpc("/task-statuses?ids=" + encodeURIComponent(allIds.join(","))).catch(() => null) : null;
|
|
7170
|
-
const TERMINAL = /* @__PURE__ */ new Set(["completed", "error", "interrupted"]);
|
|
7171
|
-
const live = (id) => {
|
|
7172
|
-
const rec = st && st.ok && st.available ? st.statuses[id] : void 0;
|
|
7173
|
-
if (rec === void 0) return true;
|
|
7174
|
-
if (!TERMINAL.has(rec.status)) return true;
|
|
7175
|
-
return Date.now() - rec.updatedAt < 3e5;
|
|
7176
|
-
};
|
|
7177
|
-
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
7178
|
-
for (const [base, ids] of byKindByPath) {
|
|
7179
|
-
if (!projPaths.has(base)) continue;
|
|
7180
|
-
if (ids.some(live)) {
|
|
7181
|
-
const projName = rootToProject.get(base);
|
|
7182
|
-
if (projName) for (const p2 of projectPaths.get(projName) || []) activeProjectPaths.add(p2);
|
|
7183
|
-
}
|
|
7469
|
+
function isMismatch(item) {
|
|
7470
|
+
if (!enabled3 || !pinned) return null;
|
|
7471
|
+
const key = item.getAttribute("data-task-item-key") || "";
|
|
7472
|
+
const want = pinned.get(sessIdOf(key));
|
|
7473
|
+
if (want === void 0) return null;
|
|
7474
|
+
const els = titleElsOf(item);
|
|
7475
|
+
if (!els.length) return null;
|
|
7476
|
+
if ((els[0].textContent || "").trim() === String(want).trim()) return null;
|
|
7477
|
+
if (item.querySelector('input, textarea, [contenteditable="true"]')) return null;
|
|
7478
|
+
return key;
|
|
7479
|
+
}
|
|
7480
|
+
function writeTitle(el, text) {
|
|
7481
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
7482
|
+
const first = walker.nextNode();
|
|
7483
|
+
if (first && !walker.nextNode()) first.nodeValue = text;
|
|
7484
|
+
else el.textContent = text;
|
|
7485
|
+
}
|
|
7486
|
+
function scheduleEnforce(key, { immediate = false } = {}) {
|
|
7487
|
+
if (immediate) {
|
|
7488
|
+
if (enabled3 && pinned) {
|
|
7489
|
+
const want = pinned.get(sessIdOf(key));
|
|
7490
|
+
if (want !== void 0) {
|
|
7491
|
+
for (const item of findRows(key)) {
|
|
7492
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7184
7493
|
}
|
|
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
7494
|
}
|
|
7190
|
-
} catch {
|
|
7191
7495
|
}
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7496
|
+
}
|
|
7497
|
+
if (pendingKeys.has(key)) return;
|
|
7498
|
+
pendingKeys.add(key);
|
|
7499
|
+
setTimeout(() => {
|
|
7500
|
+
pendingKeys.delete(key);
|
|
7501
|
+
void (async () => {
|
|
7502
|
+
const map = await fetchPinned();
|
|
7503
|
+
if (!map) return;
|
|
7504
|
+
const want = map.get(sessIdOf(key));
|
|
7505
|
+
if (want === void 0) return;
|
|
7506
|
+
let wrote = false;
|
|
7507
|
+
for (const item of findRows(key)) {
|
|
7508
|
+
if (isMismatch(item) !== key) continue;
|
|
7509
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7510
|
+
wrote = true;
|
|
7511
|
+
}
|
|
7512
|
+
if (wrote) setTimeout(() => {
|
|
7513
|
+
void enforceKey(key);
|
|
7514
|
+
}, REVERIFY_MS);
|
|
7515
|
+
})();
|
|
7516
|
+
}, RECHECK_DELAY_MS);
|
|
7197
7517
|
}
|
|
7198
|
-
function
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7518
|
+
async function enforceKey(key) {
|
|
7519
|
+
const map = await fetchPinned();
|
|
7520
|
+
if (!map) return;
|
|
7521
|
+
const want = map.get(sessIdOf(key));
|
|
7522
|
+
if (want === void 0) return;
|
|
7523
|
+
for (const item of findRows(key)) {
|
|
7524
|
+
if (isMismatch(item) !== key) continue;
|
|
7525
|
+
for (const el of titleElsOf(item)) writeTitle(el, want);
|
|
7202
7526
|
}
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7527
|
+
}
|
|
7528
|
+
function scan3() {
|
|
7529
|
+
if (!enabled3 || !pinned || pinned.size === 0) return;
|
|
7530
|
+
for (const item of document.querySelectorAll(TASK_SEL2)) {
|
|
7531
|
+
const key = isMismatch(item);
|
|
7532
|
+
if (!key) {
|
|
7533
|
+
seenRows.add(item);
|
|
7534
|
+
continue;
|
|
7210
7535
|
}
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7536
|
+
const fresh = !seenRows.has(item);
|
|
7537
|
+
seenRows.add(item);
|
|
7538
|
+
scheduleEnforce(key, { immediate: fresh });
|
|
7539
|
+
}
|
|
7540
|
+
}
|
|
7541
|
+
var inTaskRow2 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL2));
|
|
7542
|
+
function taskRowMutations2(muts) {
|
|
7543
|
+
for (const m of muts) {
|
|
7544
|
+
if (m.type === "attributes") {
|
|
7545
|
+
if (inTaskRow2(m.target)) return true;
|
|
7546
|
+
} else if (m.type === "characterData") {
|
|
7547
|
+
if (m.target.parentElement && inTaskRow2(m.target.parentElement)) return true;
|
|
7548
|
+
} else if (inTaskRow2(m.target)) {
|
|
7549
|
+
return true;
|
|
7550
|
+
} else {
|
|
7551
|
+
for (const n of m.addedNodes) {
|
|
7552
|
+
if (n instanceof Element && (n.matches(TASK_SEL2) || !!n.querySelector(TASK_SEL2))) return true;
|
|
7553
|
+
}
|
|
7222
7554
|
}
|
|
7223
7555
|
}
|
|
7556
|
+
return false;
|
|
7224
7557
|
}
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7558
|
+
var scanDebounce3 = 0;
|
|
7559
|
+
function scheduleScan2() {
|
|
7560
|
+
if (scanDebounce3) return;
|
|
7561
|
+
scanDebounce3 = setTimeout(() => {
|
|
7562
|
+
scanDebounce3 = 0;
|
|
7563
|
+
scan3();
|
|
7564
|
+
}, SCAN_DEBOUNCE_MS3);
|
|
7231
7565
|
}
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
if (
|
|
7235
|
-
|
|
7236
|
-
|
|
7566
|
+
var mapRefreshTimer = 0;
|
|
7567
|
+
function refreshMapSoon() {
|
|
7568
|
+
if (mapRefreshTimer) return;
|
|
7569
|
+
const tick2 = () => {
|
|
7570
|
+
if (document.hidden) {
|
|
7571
|
+
mapRefreshTimer = setTimeout(tick2, 1e4);
|
|
7572
|
+
return;
|
|
7573
|
+
}
|
|
7574
|
+
mapRefreshTimer = 0;
|
|
7575
|
+
if (enabled3 && resolved) void fetchPinned().then((m) => {
|
|
7576
|
+
if (m) scan3();
|
|
7577
|
+
});
|
|
7578
|
+
};
|
|
7579
|
+
mapRefreshTimer = setTimeout(tick2, MAP_REFRESH_MS);
|
|
7580
|
+
}
|
|
7581
|
+
var editingKey = null;
|
|
7582
|
+
var bootDelay = 0;
|
|
7583
|
+
function scheduleBootRetry() {
|
|
7584
|
+
bootDelay = bootDelay ? Math.min(bootDelay * 2, MAP_REFRESH_MS) : BOOT_RETRY_MS;
|
|
7585
|
+
setTimeout(() => {
|
|
7586
|
+
if (resolved) return;
|
|
7587
|
+
if (!document.hidden) void bootstrap();
|
|
7588
|
+
scheduleBootRetry();
|
|
7589
|
+
}, bootDelay);
|
|
7590
|
+
}
|
|
7591
|
+
async function bootstrap() {
|
|
7592
|
+
const map = await fetchPinned();
|
|
7593
|
+
if (map) scan3();
|
|
7594
|
+
}
|
|
7595
|
+
function setRowTitle(key, text) {
|
|
7596
|
+
for (const item of findRows(key)) {
|
|
7597
|
+
for (const el of titleElsOf(item)) writeTitle(el, text);
|
|
7237
7598
|
}
|
|
7238
7599
|
}
|
|
7239
|
-
function
|
|
7240
|
-
|
|
7241
|
-
if (
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7600
|
+
function refreshPinnedTitles() {
|
|
7601
|
+
return fetchPinned().then((m) => {
|
|
7602
|
+
if (m) scan3();
|
|
7603
|
+
});
|
|
7604
|
+
}
|
|
7605
|
+
var RENAME_CTX_VALID_MS = 15e3;
|
|
7606
|
+
var renameCtx = null;
|
|
7607
|
+
var renamePrefilled = /* @__PURE__ */ new WeakSet();
|
|
7608
|
+
function setNativeValue(el, text) {
|
|
7609
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
7610
|
+
Object.getOwnPropertyDescriptor(el.constructor.prototype, "value").set.call(el, text);
|
|
7611
|
+
} else {
|
|
7612
|
+
el.textContent = text;
|
|
7613
|
+
}
|
|
7614
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
7615
|
+
}
|
|
7616
|
+
function prefillRenameDialog() {
|
|
7617
|
+
if (!renameCtx || !renameCtx.armed || Date.now() - renameCtx.at > RENAME_CTX_VALID_MS) {
|
|
7618
|
+
renameCtx = null;
|
|
7619
|
+
return;
|
|
7620
|
+
}
|
|
7621
|
+
if (!enabled3 || !pinned) return;
|
|
7622
|
+
const want = pinned.get(sessIdOf(renameCtx.key));
|
|
7623
|
+
if (want === void 0) return;
|
|
7624
|
+
for (const el of document.querySelectorAll('[role="dialog"] input, [role="dialog"] textarea, [role="dialog"] [contenteditable="true"]')) {
|
|
7625
|
+
if (renamePrefilled.has(el) || !el.getClientRects().length) continue;
|
|
7626
|
+
if (el.closest(TASK_SEL2) || el.closest(".zcodepro-overlay")) continue;
|
|
7627
|
+
const cur = String(el.value ?? el.textContent ?? "").trim();
|
|
7628
|
+
if (!cur) continue;
|
|
7629
|
+
renamePrefilled.add(el);
|
|
7630
|
+
if (cur !== String(want).trim()) setNativeValue(el, String(want));
|
|
7631
|
+
renameCtx = null;
|
|
7632
|
+
return;
|
|
7633
|
+
}
|
|
7634
|
+
}
|
|
7635
|
+
function startTitleLock() {
|
|
7636
|
+
if (installed3 || typeof document === "undefined") return;
|
|
7637
|
+
installed3 = true;
|
|
7638
|
+
void bootstrap();
|
|
7639
|
+
new MutationObserver((muts) => {
|
|
7640
|
+
if (renameCtx) prefillRenameDialog();
|
|
7641
|
+
if (!taskRowMutations2(muts)) return;
|
|
7642
|
+
refreshMapSoon();
|
|
7643
|
+
scheduleScan2();
|
|
7644
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
|
|
7645
|
+
document.addEventListener("contextmenu", (e) => {
|
|
7646
|
+
const row = e.target instanceof Element && e.target.closest(TASK_SEL2);
|
|
7647
|
+
renameCtx = row ? { key: row.getAttribute("data-task-item-key") || "", at: 0, armed: false } : null;
|
|
7648
|
+
}, true);
|
|
7649
|
+
document.addEventListener("click", (e) => {
|
|
7650
|
+
if (!renameCtx || renameCtx.armed) return;
|
|
7651
|
+
const item = e.target instanceof Element && e.target.closest('[role="menuitem"], [data-radix-collection-item]');
|
|
7652
|
+
if (item && /重命名|rename/i.test(item.textContent || "")) {
|
|
7653
|
+
renameCtx.armed = true;
|
|
7654
|
+
renameCtx.at = Date.now();
|
|
7250
7655
|
}
|
|
7251
|
-
|
|
7656
|
+
}, true);
|
|
7657
|
+
scheduleBootRetry();
|
|
7658
|
+
setInterval(() => {
|
|
7659
|
+
if (!document.hidden) scan3();
|
|
7660
|
+
}, SCAN_FALLBACK_MS3);
|
|
7661
|
+
document.addEventListener("visibilitychange", () => {
|
|
7662
|
+
if (!document.hidden) scan3();
|
|
7663
|
+
});
|
|
7664
|
+
window.addEventListener("zcodepro:config-changed", () => {
|
|
7665
|
+
void bootstrap();
|
|
7666
|
+
});
|
|
7667
|
+
document.addEventListener("focusin", (e) => {
|
|
7668
|
+
const el = e.target;
|
|
7669
|
+
if (!(el instanceof Element)) return;
|
|
7670
|
+
if (!el.matches('input, textarea, [contenteditable="true"]')) return;
|
|
7671
|
+
const row = el.closest(TASK_SEL2);
|
|
7672
|
+
editingKey = row ? row.getAttribute("data-task-item-key") || "" : null;
|
|
7673
|
+
});
|
|
7674
|
+
document.addEventListener("focusout", () => {
|
|
7675
|
+
if (editingKey === null) return;
|
|
7676
|
+
editingKey = null;
|
|
7677
|
+
void fetchPinned().then((m) => {
|
|
7678
|
+
if (m) scan3();
|
|
7679
|
+
});
|
|
7680
|
+
});
|
|
7681
|
+
}
|
|
7682
|
+
|
|
7683
|
+
// src/inject/features/title-gen.js
|
|
7684
|
+
var CONV2 = '[class*="@md/conversation"]';
|
|
7685
|
+
var USER_ROW = '[class*="user-row"]';
|
|
7686
|
+
var SCAN_DEBOUNCE_MS4 = 300;
|
|
7687
|
+
var SCAN_FALLBACK_MS4 = 5e3;
|
|
7688
|
+
var SELECT_WAIT_MS = 2e3;
|
|
7689
|
+
var MSG_WAIT_MS = 1e4;
|
|
7690
|
+
var QUIET_FALLBACK_MS = 12e4;
|
|
7691
|
+
var COLLECT_MAX_MS = 6e5;
|
|
7692
|
+
var installed4 = false;
|
|
7693
|
+
var knownKeys = /* @__PURE__ */ new Set();
|
|
7694
|
+
var attempted = /* @__PURE__ */ new Set();
|
|
7695
|
+
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
7696
|
+
function sessIdOf2(key) {
|
|
7697
|
+
const i = key.indexOf(":sess_");
|
|
7698
|
+
return i > 0 ? key.slice(i + 1) : "";
|
|
7699
|
+
}
|
|
7700
|
+
function currentKey() {
|
|
7701
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7702
|
+
if ((el.className + "").includes("bg-selected")) return el.getAttribute("data-task-item-key") || "";
|
|
7252
7703
|
}
|
|
7704
|
+
return "";
|
|
7253
7705
|
}
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7706
|
+
function userTexts() {
|
|
7707
|
+
return [...document.querySelectorAll(`${CONV2} ${USER_ROW}`)].map((r) => {
|
|
7708
|
+
const el = r.querySelector(".whitespace-pre-wrap");
|
|
7709
|
+
return ((el ? el.textContent : r.innerText) || "").trim();
|
|
7710
|
+
}).filter(Boolean);
|
|
7711
|
+
}
|
|
7712
|
+
var URL_RE = /https?:\/\/[^\s\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+/g;
|
|
7713
|
+
function assistantText() {
|
|
7714
|
+
const els = [...document.querySelectorAll('[class*="@md/conversation"] [class*="assistant-row"]')].filter((e) => !e.querySelector("[data-is-streaming]"));
|
|
7715
|
+
const last = els[els.length - 1];
|
|
7716
|
+
if (!last) return "";
|
|
7717
|
+
const text = (last.innerText || "").replace(URL_RE, "").trim();
|
|
7718
|
+
return text.slice(0, 600);
|
|
7719
|
+
}
|
|
7720
|
+
function linkDominant(t2) {
|
|
7721
|
+
const raw = t2.replace(/\s+/g, "");
|
|
7722
|
+
if (!raw) return true;
|
|
7723
|
+
const stripped = raw.replace(URL_RE, "");
|
|
7724
|
+
return stripped.length < raw.length / 3;
|
|
7725
|
+
}
|
|
7726
|
+
async function onNewTaskRow(key) {
|
|
7727
|
+
const selDeadline = Date.now() + SELECT_WAIT_MS;
|
|
7728
|
+
while (currentKey() !== key && Date.now() < selDeadline) await sleep2(200);
|
|
7729
|
+
if (currentKey() !== key) return;
|
|
7730
|
+
const cfg = await getConfig().catch(() => null);
|
|
7731
|
+
if (!cfg || !cfg.titleGen || cfg.titleGen.enabled !== true) return;
|
|
7732
|
+
const sessId = sessIdOf2(key);
|
|
7733
|
+
if (!sessId || attempted.has(sessId)) return;
|
|
7734
|
+
attempted.add(sessId);
|
|
7735
|
+
let texts = [];
|
|
7736
|
+
const msgDeadline = Date.now() + MSG_WAIT_MS;
|
|
7737
|
+
while (Date.now() < msgDeadline) {
|
|
7738
|
+
texts = userTexts();
|
|
7739
|
+
if (texts.length) break;
|
|
7740
|
+
await sleep2(400);
|
|
7741
|
+
}
|
|
7742
|
+
if (!texts.length) return;
|
|
7743
|
+
let assistantSeen = false;
|
|
7744
|
+
const convObserver = new MutationObserver((muts) => {
|
|
7745
|
+
if (currentKey() !== key) return;
|
|
7746
|
+
for (const m of muts) {
|
|
7747
|
+
const t2 = m.type === "characterData" ? m.target.parentElement : m.target;
|
|
7748
|
+
if (t2 instanceof Element && t2.closest(USER_ROW)) continue;
|
|
7749
|
+
for (const n of [t2, ...m.addedNodes]) {
|
|
7750
|
+
if (n instanceof Element && n.closest && n.closest(CONV2)) {
|
|
7751
|
+
assistantSeen = true;
|
|
7752
|
+
return;
|
|
7266
7753
|
}
|
|
7267
|
-
set.add(ws + ":active");
|
|
7268
|
-
schedulePeek(ws, PEEK_REPEAT_MS);
|
|
7269
7754
|
}
|
|
7270
|
-
apply();
|
|
7271
|
-
return true;
|
|
7272
7755
|
}
|
|
7273
|
-
}
|
|
7274
|
-
const run = () => peekInner(ws, opts);
|
|
7275
|
-
const p = peekChain.then(run, run);
|
|
7276
|
-
peekChain = p.catch(() => {
|
|
7277
7756
|
});
|
|
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;
|
|
7757
|
+
convObserver.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
7758
|
+
const startAt = Date.now();
|
|
7759
|
+
let lastCount = texts.length;
|
|
7760
|
+
let lastChange = Date.now();
|
|
7302
7761
|
try {
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7762
|
+
while (Date.now() - startAt < COLLECT_MAX_MS) {
|
|
7763
|
+
await sleep2(500);
|
|
7764
|
+
if (currentKey() !== key) {
|
|
7765
|
+
lastChange = Date.now();
|
|
7766
|
+
continue;
|
|
7767
|
+
}
|
|
7768
|
+
texts = userTexts();
|
|
7769
|
+
if (texts.length !== lastCount) {
|
|
7770
|
+
lastCount = texts.length;
|
|
7771
|
+
lastChange = Date.now();
|
|
7772
|
+
}
|
|
7773
|
+
if (assistantSeen) break;
|
|
7774
|
+
if (Date.now() - lastChange >= QUIET_FALLBACK_MS) break;
|
|
7310
7775
|
}
|
|
7311
7776
|
} finally {
|
|
7312
|
-
|
|
7313
|
-
row.style.visibility = "";
|
|
7314
|
-
frozen.remove();
|
|
7315
|
-
activePeeks.delete(ws);
|
|
7777
|
+
convObserver.disconnect();
|
|
7316
7778
|
}
|
|
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;
|
|
7779
|
+
if (!texts.length) return;
|
|
7780
|
+
if (linkDominant(texts.join("\n"))) {
|
|
7781
|
+
const deadline = Date.now() + 6e4;
|
|
7782
|
+
while (Date.now() < deadline) {
|
|
7783
|
+
await sleep2(2e3);
|
|
7784
|
+
if (currentKey() !== key) continue;
|
|
7785
|
+
const a = assistantText();
|
|
7786
|
+
if (a && a.length > 80) {
|
|
7787
|
+
texts.push(`\uFF08\u9996\u8F6E\u56DE\u7B54\u6458\u8981\uFF09${a}`);
|
|
7788
|
+
break;
|
|
7789
|
+
}
|
|
7790
|
+
}
|
|
7338
7791
|
}
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7792
|
+
const callTitleGen = () => rpc("/title-gen/run", { method: "POST", body: { sessId, text: texts.join("\n") } }).catch(() => null);
|
|
7793
|
+
let res = await callTitleGen();
|
|
7794
|
+
for (const delay of [5e3, 2e4]) {
|
|
7795
|
+
if (res && res.ok) break;
|
|
7796
|
+
await sleep2(delay);
|
|
7797
|
+
res = await callTitleGen();
|
|
7798
|
+
}
|
|
7799
|
+
if (res && res.ok && res.written && res.title) {
|
|
7800
|
+
setRowTitle(key, res.title);
|
|
7801
|
+
void refreshPinnedTitles();
|
|
7343
7802
|
}
|
|
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
7803
|
}
|
|
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
|
-
}
|
|
7804
|
+
function scanForNewRows() {
|
|
7805
|
+
for (const el of document.querySelectorAll("[data-task-item-key]")) {
|
|
7806
|
+
const key = el.getAttribute("data-task-item-key") || "";
|
|
7807
|
+
if (!key || knownKeys.has(key)) continue;
|
|
7808
|
+
knownKeys.add(key);
|
|
7809
|
+
void onNewTaskRow(key);
|
|
7426
7810
|
}
|
|
7427
|
-
return false;
|
|
7428
7811
|
}
|
|
7429
|
-
var
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
if (
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
return true;
|
|
7812
|
+
var TASK_SEL3 = "[data-task-item-key]";
|
|
7813
|
+
var inTaskRow3 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL3));
|
|
7814
|
+
function taskRowMutations3(muts) {
|
|
7815
|
+
for (const m of muts) {
|
|
7816
|
+
if (m.type === "attributes") {
|
|
7817
|
+
if (inTaskRow3(m.target)) return true;
|
|
7818
|
+
} else if (m.type === "characterData") {
|
|
7819
|
+
if (m.target.parentElement && inTaskRow3(m.target.parentElement)) return true;
|
|
7820
|
+
} else if (inTaskRow3(m.target)) {
|
|
7821
|
+
return true;
|
|
7822
|
+
} else {
|
|
7823
|
+
for (const n of m.addedNodes) {
|
|
7824
|
+
if (n instanceof Element && (n.matches(TASK_SEL3) || !!n.querySelector(TASK_SEL3))) return true;
|
|
7442
7825
|
}
|
|
7443
7826
|
}
|
|
7444
|
-
} catch {
|
|
7445
7827
|
}
|
|
7446
7828
|
return false;
|
|
7447
7829
|
}
|
|
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
7830
|
var scanDebounce4 = 0;
|
|
7456
|
-
function
|
|
7831
|
+
function scheduleScan3() {
|
|
7832
|
+
if (scanDebounce4) return;
|
|
7833
|
+
scanDebounce4 = setTimeout(() => {
|
|
7834
|
+
scanDebounce4 = 0;
|
|
7835
|
+
scanForNewRows();
|
|
7836
|
+
}, SCAN_DEBOUNCE_MS4);
|
|
7837
|
+
}
|
|
7838
|
+
function startTitleGen() {
|
|
7457
7839
|
if (installed4 || typeof document === "undefined") return;
|
|
7458
7840
|
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();
|
|
7841
|
+
scanForNewRows();
|
|
7842
|
+
new MutationObserver((muts) => {
|
|
7843
|
+
if (taskRowMutations3(muts)) scheduleScan3();
|
|
7844
|
+
}).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"], characterData: true });
|
|
7473
7845
|
setInterval(() => {
|
|
7474
|
-
if (!document.hidden
|
|
7846
|
+
if (!document.hidden) scanForNewRows();
|
|
7475
7847
|
}, SCAN_FALLBACK_MS4);
|
|
7476
7848
|
document.addEventListener("visibilitychange", () => {
|
|
7477
|
-
if (!document.hidden)
|
|
7849
|
+
if (!document.hidden) scanForNewRows();
|
|
7478
7850
|
});
|
|
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
7851
|
}
|
|
7485
7852
|
|
|
7486
7853
|
// src/inject/features/idle-reclaim.js
|