zcode-pro 0.20.3 → 1.0.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/dist/inject.js CHANGED
@@ -30,6 +30,35 @@
30
30
  function clearConfigCache() {
31
31
  configCache = { value: null, at: 0 };
32
32
  }
33
+ function zcodeAppVersion() {
34
+ const v = liveBoot().zcodeVersion;
35
+ return typeof v === "string" && v ? v : "";
36
+ }
37
+ function zcodeVersionGte(version, major, minor, patch = 0) {
38
+ const m = String(version || "").match(/^(\d+)\.(\d+)\.(\d+)/);
39
+ if (!m) return false;
40
+ const a = Number(m[1]), b = Number(m[2]), c = Number(m[3]);
41
+ return a > major || a === major && (b > minor || b === minor && c >= patch);
42
+ }
43
+ function officialRenameSupported() {
44
+ return zcodeVersionGte(zcodeAppVersion(), 3, 16, 1);
45
+ }
46
+ var newSidebarCached = false;
47
+ function isNewProjectSidebar() {
48
+ if (newSidebarCached) return true;
49
+ if (officialRenameSupported()) {
50
+ newSidebarCached = true;
51
+ return true;
52
+ }
53
+ try {
54
+ if (document.querySelector("section[data-project-id]")) {
55
+ newSidebarCached = true;
56
+ return true;
57
+ }
58
+ } catch {
59
+ }
60
+ return false;
61
+ }
33
62
  var zh = {
34
63
  settingsTitle: "ZCode Pro",
35
64
  tabFeatures: "\u529F\u80FD",
@@ -76,7 +105,7 @@
76
105
  syncRecLink: "\u575A\u679C\u4E91 WebDAV",
77
106
  syncRecSuffix: "\uFF1A\u767B\u5F55\u4E0E\u5BC6\u7801\u586B\u201C\u5E94\u7528\u5BC6\u7801\u201D\uFF0C\u4E0D\u662F\u8D26\u53F7\u5BC6\u7801\u3002",
78
107
  syncIncludeZcp: "ZCode Pro \u8BBE\u7F6E",
79
- syncIncludeZcpDesc: "\u529F\u80FD\u5F00\u5173\u3001\u6837\u5F0F\u8C03\u6574\u3001\u9879\u76EE\u522B\u540D\u4E0E\u4EE3\u7406\u8BBE\u7F6E\uFF1B\u540C\u6B65\u914D\u7F6E\u4E0E\u51ED\u636E\u672C\u8EAB\u4E0D\u53C2\u4E0E\u540C\u6B65\u3002",
108
+ syncIncludeZcpDesc: "\u529F\u80FD\u5F00\u5173\u3001\u6837\u5F0F\u8C03\u6574\u4E0E\u4EE3\u7406\u8BBE\u7F6E\uFF1B\u540C\u6B65\u914D\u7F6E\u4E0E\u51ED\u636E\u672C\u8EAB\u4E0D\u53C2\u4E0E\u540C\u6B65\u3002\u9879\u76EE\u522B\u540D\u4E0D\u540C\u6B65\uFF08\u5B98\u65B9\u5DF2\u652F\u6301\u6539\u9879\u76EE\u540D\uFF09\u3002",
80
109
  syncIncludeModel: "\u6A21\u578B\u8BBE\u7F6E",
81
110
  syncIncludeModelDesc: "\u81EA\u5B9A\u4E49\u4F9B\u5E94\u5546\u4E0E\u6A21\u578B\u914D\u7F6E\uFF08config.json \u4E0E provider_config.json\uFF0C\u542B API Key\uFF09\u3002\u8D26\u53F7\u767B\u5F55\u7684\u51ED\u636E\uFF08\u5982 BigModel \u8BA2\u9605\uFF09\u4E0D\u53C2\u4E0E\u540C\u6B65\uFF0C\u5404\u673A\u5668\u7528\u5404\u81EA\u8D26\u53F7\u767B\u5F55\u3002",
82
111
  syncUpload: "\u4E0A\u4F20\u5230\u4E91\u7AEF",
@@ -176,8 +205,8 @@
176
205
  titleGenTesting: "\u751F\u6210\u4E2D\u2026",
177
206
  titleGenTestOk: "\u751F\u6210\u7ED3\u679C\uFF1A",
178
207
  titleGenTestFailed: "\u751F\u6210\u5931\u8D25",
179
- featureWsRunning: "\u6298\u53E0\u9879\u76EE\u8FD0\u884C\u63D0\u793A\uFF08\u5B9E\u9A8C\u6027\uFF09",
180
- featureWsRunningDesc: "\u6298\u53E0\u7684\u9879\u76EE\u91CC\u4ECD\u6709\u4F1A\u8BDD\u5728\u8FD0\u884C\u65F6\uFF0C\u9879\u76EE\u56FE\u6807\u65CB\u8F6C\u63D0\u793A\uFF1B\u5168\u90E8\u7ED3\u675F\u6216\u5C55\u5F00\u9879\u76EE\u540E\u6062\u590D\u3002\u671F\u95F4\u6BCF 60 \u79D2\u5728\u540E\u53F0\u77ED\u6682\u5C55\u5F00\u8BE5\u9879\u76EE\u590D\u6838\u8FD0\u884C\u72B6\u6001\u518D\u6536\u8D77\uFF0C\u4F1A\u8BDD\u884C\u4E0D\u663E\u793A\uFF0C\u4EC5\u9879\u76EE\u4F4D\u7F6E\u53EF\u80FD\u6709\u7EA6\u56DB\u5206\u4E4B\u4E00\u79D2\u7684\u8F7B\u5FAE\u9AD8\u5EA6\u8D77\u4F0F\u3002",
208
+ 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\uFF1B3.16.1 \u4E4B\u524D\u6BCF 60 \u79D2\u4F1A\u5728\u540E\u53F0\u77ED\u6682\u5C55\u5F00\u9879\u76EE\u590D\u6838\u518D\u6536\u8D77\u3002",
181
210
  tabPerformance: "\u6027\u80FD",
182
211
  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",
183
212
  featureIdleReclaim: "\u7A7A\u95F2\u9879\u76EE\u5185\u5B58\u56DE\u6536",
@@ -217,17 +246,16 @@
217
246
  imageCopied: "\u56FE\u7247\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",
218
247
  imageCopyFailed: "\u590D\u5236\u56FE\u7247\u5931\u8D25",
219
248
  openFolderItem: "\u6253\u5F00\u6587\u4EF6\u5939",
249
+ openFolderPrimary: "\u4E3B\u76EE\u5F55",
220
250
  copyPathItem: "\u590D\u5236\u8DEF\u5F84",
221
251
  pathCopied: "\u8DEF\u5F84\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",
222
252
  pathCopyFailed: "\u590D\u5236\u8DEF\u5F84\u5931\u8D25",
223
253
  fileOpenDefault: "\u9ED8\u8BA4\u5E94\u7528\u6253\u5F00",
224
254
  fileReveal: "\u6253\u5F00\u6240\u5728\u76EE\u5F55",
225
- featurePinnedExpand: "\u7F6E\u9876\u4F1A\u8BDD\u4FDD\u6301\u9879\u76EE\u6298\u53E0\uFF08\u5B9E\u9A8C\u6027\uFF09",
226
- featurePinnedExpandDesc: "\u70B9\u51FB\u6298\u53E0\u9879\u76EE\u7684\u7F6E\u9876\u4F1A\u8BDD\u540E\u5C06\u5176\u4FDD\u6301\u6298\u53E0\u3002\u53D7\u9650\u4E8E\u5E94\u7528\u673A\u5236\uFF0C\u9879\u76EE\u4F1A\u5148\u77ED\u6682\u5C55\u5F00\u518D\u7F29\u8D77\u3002",
227
- featureAutoUpdatePlugins: "\u81EA\u52A8\u66F4\u65B0 zcode-plugins \u63D2\u4EF6",
228
- featureAutoUpdatePluginsDesc: "\u542F\u52A8\u65F6\u81EA\u52A8\u68C0\u67E5\u5E76\u66F4\u65B0\u5DF2\u5B89\u88C5\u7684 zcode-plugins \u63D2\u4EF6\uFF08\u53EA\u5347\u7EA7\u4E0D\u5B89\u88C5\uFF0C\u5378\u8F7D\u4E0D\u4F1A\u88AB\u64A4\u9500\uFF09\uFF0C\u66F4\u65B0\u5728\u65B0\u4F1A\u8BDD\u751F\u6548\u3002",
229
- pluginsUpdateTitle: "\u63D2\u4EF6\u66F4\u65B0 \xB7 zcode-plugins",
230
- pluginsCheckNow: "\u68C0\u67E5\u5E76\u66F4\u65B0",
255
+ featureAutoUpdatePlugins: "\u81EA\u52A8\u66F4\u65B0",
256
+ featureAutoUpdatePluginsRepo: "duanluan/zcode-plugins",
257
+ featureAutoUpdatePluginsDesc: "",
258
+ pluginsCheckNow: "\u68C0\u67E5\u66F4\u65B0",
231
259
  pluginsUpdating: "\u6B63\u5728\u66F4\u65B0\u63D2\u4EF6\u2026",
232
260
  pluginsUpToDate: "\u63D2\u4EF6\u5DF2\u662F\u6700\u65B0",
233
261
  pluginsUpdatesFound: "{n} \u4E2A\u63D2\u4EF6\u53EF\u66F4\u65B0",
@@ -305,6 +333,8 @@
305
333
  hrUsageNone: "\u5F53\u524D\u6CA1\u6709\u8D70 headroom \u7684\u4F9B\u5E94\u5546\uFF0C\u672A\u5207\u6362",
306
334
  headroomLoadFailed: "\u8BFB\u53D6 Headroom \u914D\u7F6E\u5931\u8D25",
307
335
  headroomStatusTitle: "\u8FD0\u884C\u72B6\u6001",
336
+ hrInstRunning: "\u8FD0\u884C\u4E2D",
337
+ hrInstStopped: "\u672A\u8FD0\u884C",
308
338
  headroomStatusLoadFailed: "\u8BFB\u53D6\u8FD0\u884C\u72B6\u6001\u5931\u8D25",
309
339
  headroomProxyUp: "\u4EE3\u7406\u8FD0\u884C\u4E2D",
310
340
  headroomProxyDown: "\u4EE3\u7406\u672A\u8FD0\u884C",
@@ -370,6 +400,30 @@
370
400
  aliasSaved: "\u522B\u540D\u5DF2\u66F4\u65B0",
371
401
  aliasCleared: "\u5DF2\u6062\u590D\u771F\u5B9E\u540D\u79F0",
372
402
  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\u5207\u6362\u6587\u4EF6\u5939\u3001\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
+ aliasMigrateTitle: "\u8FC1\u79FB\u9879\u76EE\u522B\u540D",
405
+ 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
+ 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",
407
+ aliasMigrateStateDone: "\u5DF2\u8FC1\u79FB",
408
+ aliasMigrateStateMerged: "\u5DF2\u5E76\u5165\u300C{name}\u300D",
409
+ aliasMigrateStateDeleted: "\u9879\u76EE\u5DF2\u5220\u9664",
410
+ aliasMigrateStateMissing: "\u672C\u673A\u4E0D\u5B58\u5728",
411
+ aliasMigrateStateRenamed: "\u9879\u76EE\u5DF2\u91CD\u547D\u540D",
412
+ aliasMigrateDeadSummary: "\u5DF2\u5931\u6548 {n} \u6761\uFF08\u672C\u673A\u4E0D\u5B58\u5728 / \u9879\u76EE\u5DF2\u5220\u9664\uFF0C\u591A\u4E3A\u8BBE\u7F6E\u540C\u6B65\u5E26\u6765\u7684\u65E7\u673A\u5668\u8DEF\u5F84\uFF09",
413
+ aliasMigrateClearDead: "\u6E05\u9664\u5931\u6548\u6761\u76EE",
414
+ aliasMigrateDeadCleared: "\u5DF2\u6E05\u9664 {n} \u6761\u5931\u6548\u522B\u540D",
415
+ aliasMigrateDeadClearFailed: "\u90E8\u5206\u5931\u6548\u522B\u540D\u672A\u80FD\u6E05\u9664\uFF0C\u8BF7\u91CD\u8BD5",
416
+ aliasMigrateGo: "\u8FC1\u79FB\u6240\u9009",
417
+ aliasMigrateRunning: "\u8FC1\u79FB\u4E2D\u2026",
418
+ aliasMigrateProgress: "\u6B63\u5728\u8FC1\u79FB {i}/{n}\uFF1A{name}",
419
+ aliasMigrateStateFailed: "\u5931\u8D25",
420
+ aliasMigrateSkip: "\u6682\u4E0D\u8FC1\u79FB",
421
+ aliasMigrateDone: "\u5DF2\u8FC1\u79FB {n} \u4E2A\u522B\u540D",
422
+ aliasMigratePartial: "{n} \u4E2A\u5DF2\u8FC1\u79FB\uFF0C{m} \u4E2A\u672A\u6210\u529F\uFF1B\u672A\u6210\u529F\u7684\u53EF\u7A0D\u540E\u5728 ZCode Pro \u8BBE\u7F6E\u4E2D\u91CD\u8BD5",
423
+ aliasMigrateAllFailed: "\u522B\u540D\u8FC1\u79FB\u672A\u6210\u529F\uFF0C\u53EF\u7A0D\u540E\u5728 ZCode Pro \u8BBE\u7F6E\u4E2D\u91CD\u8BD5",
424
+ aliasMigrateCardName: "\u522B\u540D\u8FC1\u79FB",
425
+ aliasMigrateCardDesc: "\u5B98\u65B9\u5DF2\u652F\u6301\u4FEE\u6539\u9879\u76EE\u540D\u79F0\uFF0C\u8FD8\u6709 {n} \u4E2A\u81EA\u5B9A\u4E49\u522B\u540D\u672A\u8FC1\u79FB\u3002",
426
+ aliasMigrateRun: "\u8FC1\u79FB",
373
427
  taskOrderSaved: "\u987A\u5E8F\u5DF2\u66F4\u65B0",
374
428
  qqGroupTitle: "QQ \u7FA4\uFF1A428403354",
375
429
  qqGroupDesc: "\u95EE\u9898\u53CD\u9988\u4E0E\u4EA4\u6D41",
@@ -441,7 +495,7 @@
441
495
  syncRecLink: "Jianguoyun WebDAV",
442
496
  syncRecSuffix: " \u2014 use the app password, not your account password.",
443
497
  syncIncludeZcp: "ZCode Pro settings",
444
- syncIncludeZcpDesc: "Feature toggles, style adjustments, project aliases and the proxy setting; the sync config and credentials themselves are never synced.",
498
+ syncIncludeZcpDesc: "Feature toggles, style adjustments and the proxy setting; the sync config and credentials themselves are never synced. Project aliases are not synced (renaming is built in now).",
445
499
  syncIncludeModel: "Model settings",
446
500
  syncIncludeModelDesc: "Custom providers and model config (config.json and provider_config.json, API keys included). Account sign-in credentials (e.g. the BigModel subscription) are not synced; each computer signs in with its own account.",
447
501
  syncUpload: "Upload",
@@ -541,8 +595,8 @@
541
595
  titleGenTesting: "Generating\u2026",
542
596
  titleGenTestOk: "Result: ",
543
597
  titleGenTestFailed: "Generation failed",
544
- featureWsRunning: "Running indicator on collapsed projects (experimental)",
545
- featureWsRunningDesc: "Spins a collapsed project's icon while any of its sessions is still running; stops when they all finish or the project is expanded. While spinning, the project is briefly re-expanded in the background every 60 s to re-check and then collapsed \u2014 rows stay hidden, with only a subtle quarter-second height ripple at the project.",
598
+ 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. Before ZCode 3.16.1 the project is briefly re-expanded in the background every 60 s to re-check.",
546
600
  tabPerformance: "Performance",
547
601
  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.",
548
602
  featureIdleReclaim: "Idle project memory reclaim",
@@ -582,17 +636,16 @@
582
636
  imageCopied: "Image copied to the clipboard.",
583
637
  imageCopyFailed: "Failed to copy the image.",
584
638
  openFolderItem: "Open folder",
639
+ openFolderPrimary: "primary",
585
640
  copyPathItem: "Copy path",
586
641
  pathCopied: "Path copied to the clipboard.",
587
642
  pathCopyFailed: "Failed to copy the path.",
588
643
  fileOpenDefault: "Open with default app",
589
644
  fileReveal: "Reveal in file manager",
590
- featurePinnedExpand: "Keep projects collapsed for pinned sessions (experimental)",
591
- featurePinnedExpandDesc: "Keeps the project collapsed after clicking a pinned session. Note: it briefly expands first, then collapses.",
592
- featureAutoUpdatePlugins: "Auto-update zcode-plugins plugins",
593
- featureAutoUpdatePluginsDesc: "Checks and updates installed zcode-plugins plugins on startup (updates only \u2014 never installs; uninstalled plugins stay uninstalled). Updates apply to new sessions.",
594
- pluginsUpdateTitle: "Plugin updates \xB7 zcode-plugins",
595
- pluginsCheckNow: "Check & update",
645
+ featureAutoUpdatePlugins: "Auto-update",
646
+ featureAutoUpdatePluginsRepo: "duanluan/zcode-plugins",
647
+ featureAutoUpdatePluginsDesc: "",
648
+ pluginsCheckNow: "Check for updates",
596
649
  pluginsUpdating: "Updating plugins\u2026",
597
650
  pluginsUpToDate: "Plugins are up to date",
598
651
  pluginsUpdatesFound: "{n} plugin(s) can be updated",
@@ -670,6 +723,8 @@
670
723
  hrUsageNone: "No providers route through headroom; nothing changed",
671
724
  headroomLoadFailed: "Failed to load the Headroom config",
672
725
  headroomStatusTitle: "Status",
726
+ hrInstRunning: "running",
727
+ hrInstStopped: "down",
673
728
  headroomStatusLoadFailed: "Failed to load the status",
674
729
  headroomProxyUp: "Proxy running",
675
730
  headroomProxyDown: "Proxy down",
@@ -735,6 +790,30 @@
735
790
  aliasSaved: "Alias updated.",
736
791
  aliasCleared: "Real name restored.",
737
792
  aliasHint: "The directory name on disk is unchanged: terminals, file managers and other path-based UI still show the real name.",
793
+ featureProjectMenuDescNew: 'Switch folder, 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
+ aliasMigrateTitle: "Migrate project aliases",
795
+ 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
+ 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.',
797
+ aliasMigrateStateDone: "Migrated",
798
+ aliasMigrateStateMerged: 'Merged into "{name}"',
799
+ aliasMigrateStateDeleted: "Project deleted",
800
+ aliasMigrateStateMissing: "Not on this machine",
801
+ aliasMigrateStateRenamed: "Project renamed",
802
+ aliasMigrateDeadSummary: "{n} stale entries (not on this machine / project deleted \u2014 usually old-machine paths from settings sync)",
803
+ aliasMigrateClearDead: "Clear stale entries",
804
+ aliasMigrateDeadCleared: "Removed {n} stale alias(es)",
805
+ aliasMigrateDeadClearFailed: "Some stale aliases could not be removed; please retry",
806
+ aliasMigrateGo: "Migrate selected",
807
+ aliasMigrateRunning: "Migrating\u2026",
808
+ aliasMigrateProgress: "Migrating {i}/{n}: {name}",
809
+ aliasMigrateStateFailed: "Failed",
810
+ aliasMigrateSkip: "Not now",
811
+ aliasMigrateDone: "Migrated {n} alias(es)",
812
+ aliasMigratePartial: "{n} migrated, {m} failed; retry the rest later in ZCode Pro settings",
813
+ aliasMigrateAllFailed: "Alias migration failed; retry later in ZCode Pro settings",
814
+ aliasMigrateCardName: "Alias migration",
815
+ aliasMigrateCardDesc: "Project renaming is built in now; {n} custom alias(es) are not migrated yet.",
816
+ aliasMigrateRun: "Migrate",
738
817
  taskOrderSaved: "Order updated.",
739
818
  qqGroupTitle: "QQ group: 428403354",
740
819
  qqGroupDesc: "Feedback & discussion",
@@ -918,7 +997,7 @@
918
997
  var overlayClassBare = "fixed inset-0 isolate z-50 flex items-center justify-center duration-100 p-4 platform-linux-desktop:top-12";
919
998
  var contentClass = "w-full sm:max-w-md rounded-2xl border-none bg-popover/98 p-5 text-ui-base/relaxed text-foreground ring-border shadow-2xl";
920
999
  var dialogStack = [];
921
- function openDialog({ title, description, onMount, onClose, width = "sm:max-w-md", overlay = "dim", draggable = false, posKey = "", dismissOnOutside = true, bodyClass = "" }) {
1000
+ function openDialog({ title, description, onMount, onClose, width = "sm:max-w-md", overlay = "dim", draggable = false, posKey = "", dismissOnOutside = true, bodyClass = "", closable = false }) {
922
1001
  const L = t();
923
1002
  const prevActive = document.activeElement;
924
1003
  let cleanupDrag = null;
@@ -958,8 +1037,25 @@
958
1037
  content.style.pointerEvents = "auto";
959
1038
  }
960
1039
  const titleEl = h("h2", { class: "text-lg font-semibold leading-none tracking-tight text-foreground" }, title);
961
- content.append(
1040
+ const titleRow = closable ? h(
1041
+ "div",
1042
+ { class: "flex items-start justify-between gap-2" },
962
1043
  titleEl,
1044
+ h("button", {
1045
+ type: "button",
1046
+ class: "zcodepro-close",
1047
+ title: L.close,
1048
+ "aria-label": L.close,
1049
+ onMousedown: (e) => {
1050
+ e.stopPropagation();
1051
+ },
1052
+ onClick: () => {
1053
+ close();
1054
+ }
1055
+ }, "\u2715")
1056
+ ) : titleEl;
1057
+ content.append(
1058
+ titleRow,
963
1059
  ...description ? [h("p", { class: "mt-2 text-ui-sm/relaxed text-foreground-subtle" }, description)] : []
964
1060
  );
965
1061
  const body = h("div", { class: "zcodepro-dialog-body " + (bodyClass || "mt-4") });
@@ -1154,13 +1250,13 @@
1154
1250
  }
1155
1251
  function unitField({ value = null, fallback = { value: 100, unit: "%" }, step = { px: 10, "%": 1 }, onCommit }) {
1156
1252
  const RANGES = { px: [320, 3840], "%": [20, 100] };
1157
- const norm2 = (v) => {
1253
+ const norm3 = (v) => {
1158
1254
  if (!v || !RANGES[v.unit]) return null;
1159
1255
  const [min, max] = RANGES[v.unit];
1160
1256
  const n = v.unit === "px" ? Math.round(v.value) : Math.round(v.value * 10) / 10;
1161
1257
  return Number.isFinite(n) ? { value: Math.min(max, Math.max(min, n)), unit: v.unit } : null;
1162
1258
  };
1163
- let current2 = norm2(value) || norm2(fallback) || { value: 100, unit: "%" };
1259
+ let current2 = norm3(value) || norm3(fallback) || { value: 100, unit: "%" };
1164
1260
  const input = h("input", {
1165
1261
  type: "text",
1166
1262
  inputmode: "decimal",
@@ -1171,7 +1267,7 @@
1171
1267
  input.value = `${current2.value}${current2.unit}`;
1172
1268
  };
1173
1269
  const commit = (v) => {
1174
- const next = norm2(v);
1270
+ const next = norm3(v);
1175
1271
  if (!next || next.value === current2.value && next.unit === current2.unit) {
1176
1272
  display();
1177
1273
  return;
@@ -1208,7 +1304,7 @@
1208
1304
  return {
1209
1305
  el: input,
1210
1306
  reset() {
1211
- current2 = norm2(fallback) || current2;
1307
+ current2 = norm3(fallback) || current2;
1212
1308
  display();
1213
1309
  },
1214
1310
  get() {
@@ -1247,7 +1343,7 @@
1247
1343
  "div",
1248
1344
  { class: "min-w-0 flex-1" },
1249
1345
  h("div", { class: "text-ui-sm font-medium text-foreground" }, name),
1250
- ...desc ? [h("div", { class: "mt-0.5 text-ui-xs/relaxed text-foreground-subtle" }, desc)] : []
1346
+ h("div", { class: "mt-0.5 text-ui-xs/relaxed text-foreground-subtle", "data-zcodepro-row-desc": "" }, desc ?? "")
1251
1347
  ),
1252
1348
  ...extraEl ? [extraEl] : [],
1253
1349
  h("button", {
@@ -1525,13 +1621,9 @@
1525
1621
  .zcodepro-imgmenu-item:hover {
1526
1622
  background-color: var(--color-accent, color-mix(in oklab, var(--color-foreground, #888) 10%, transparent));
1527
1623
  }
1528
- /* \u6298\u53E0\u9879\u76EE\u8FD0\u884C\u63D0\u793A\uFF08ws-running.js\uFF09\uFF1A\u9879\u76EE\u56FE\u6807\u65CB\u8F6C\u3002\u52A8\u753B\u7C7B\u6302\u5728\u56FE\u6807\u5916\u5C42\u7684
1529
- \u7A33\u5B9A span \u4E0A\uFF0C\u5C55\u5F00/\u6536\u8D77\u65F6\u5E94\u7528\u91CD\u5EFA svg \u4E5F\u4E0D\u53D7\u5F71\u54CD\uFF1B\u65F6\u957F\u4E0E\u5E94\u7528 loader \u4E00\u81F4 */
1530
- @keyframes zcodepro-ws-spin { to { transform: rotate(360deg); } }
1531
- span.zcodepro-ws-running > svg {
1532
- animation: zcodepro-ws-spin 1s linear infinite;
1533
- transform-origin: center;
1534
- }
1624
+ /* \u6298\u53E0\u9879\u76EE\u8FD0\u884C\u63D0\u793A\uFF1Afolder \u56FE\u6807\u8BA9\u4F4D\u7ED9 loader\uFF08loader \u7531\u811A\u672C\u63D2\u5165\uFF0C
1625
+ folder \u53EF\u80FD\u88AB React \u968F\u65F6\u91CD\u5EFA\uFF0C\u9760\u7C7B\u9009\u62E9\u5668\u7EDF\u4E00\u9690\u85CF\uFF0C\u540E\u4EE3\u5199\u6CD5\u517C\u5BB9\u5305\u88C5\u5C42\uFF09 */
1626
+ span.zcodepro-ws-running svg:not(.zcodepro-ws-loader) { display: none !important; }
1535
1627
  /* \u65E0\u611F\u63A2\u67E5\u671F\u95F4\u76D6\u5728\u9879\u76EE\u884C\u4E0A\u7684\u51BB\u7ED3\u514B\u9686\uFF1A\u56FA\u5B9A\u5B9A\u4F4D\u3001\u4E0D\u54CD\u5E94\u6307\u9488 */
1536
1628
  .zcodepro-ws-frozen {
1537
1629
  position: fixed;
@@ -1645,12 +1737,82 @@
1645
1737
  }
1646
1738
  .zcodepro-pin-head:hover .zcodepro-pin-chevron svg { opacity: 1; }
1647
1739
  .zcodepro-pin-collapsed .zcodepro-pin-chevron svg { transform: rotate(-90deg); }
1648
- .zcodepro-pin-collapsed > ul { display: none !important; }
1740
+ .zcodepro-pin-collapsed > :is(ul, div):has(li[data-task-item-key]) { display: none !important; }
1649
1741
  /* \u6298\u53E0\u540E\u53BB\u6389\u6807\u9898\u81EA\u5E26\u7684\u5E95\u90E8\u7559\u767D\uFF0C\u4E0E\u4E0B\u4E00\u5206\u533A\u7684\u95F4\u9694\u548C\u5176\u4ED6\u5206\u533A\u8282\u594F\u4E00\u81F4 */
1650
1742
  .zcodepro-pin-collapsed .zcodepro-pin-head { padding-bottom: 0; }
1651
1743
  `));
1652
1744
  }
1653
1745
 
1746
+ // src/inject/features/copy-path.js
1747
+ async function appendCopyPathItem(menu, anchorItem, project) {
1748
+ if (menu.querySelector('[data-zcodepro-item="copy-path"]')) return;
1749
+ const L = t();
1750
+ const item = anchorItem.cloneNode(true);
1751
+ item.removeAttribute("data-testid");
1752
+ item.removeAttribute("data-highlighted");
1753
+ item.setAttribute("data-zcodepro-item", "copy-path");
1754
+ for (const child of [...item.childNodes]) child.remove();
1755
+ const origIcon = anchorItem.querySelector("svg");
1756
+ const iconClass = origIcon ? origIcon.getAttribute("class") : "h-3.5 w-3.5";
1757
+ item.append(hCopyIcon(iconClass), document.createTextNode(L.copyPathItem));
1758
+ item.addEventListener("mouseenter", () => {
1759
+ for (const el of menu.querySelectorAll('[role="menuitem"]')) el.removeAttribute("data-highlighted");
1760
+ item.setAttribute("data-highlighted", "");
1761
+ });
1762
+ item.addEventListener("mouseleave", () => item.removeAttribute("data-highlighted"));
1763
+ item.addEventListener("click", () => {
1764
+ closeRadixMenu(menu);
1765
+ void copyText(project.path);
1766
+ });
1767
+ anchorItem.before(item);
1768
+ }
1769
+ async function copyText(text) {
1770
+ const L = t();
1771
+ if (await copyToClipboard(text)) showToast(L.pathCopied);
1772
+ else showToast(L.pathCopyFailed, "error");
1773
+ }
1774
+ async function copyToClipboard(text) {
1775
+ try {
1776
+ await navigator.clipboard.writeText(text);
1777
+ return true;
1778
+ } catch {
1779
+ return copyViaHiddenInput(text);
1780
+ }
1781
+ }
1782
+ function copyViaHiddenInput(text) {
1783
+ try {
1784
+ const input = h("input", { type: "text", style: "position:fixed;left:-9999px;top:0;opacity:0" });
1785
+ input.value = text;
1786
+ document.body.append(input);
1787
+ input.select();
1788
+ const ok = document.execCommand("copy");
1789
+ input.remove();
1790
+ return ok;
1791
+ } catch {
1792
+ return false;
1793
+ }
1794
+ }
1795
+ function hCopyIcon(cls) {
1796
+ const ns = "http://www.w3.org/2000/svg";
1797
+ const svg = document.createElementNS(ns, "svg");
1798
+ svg.setAttribute("viewBox", "0 0 24 24");
1799
+ svg.setAttribute("fill", "none");
1800
+ svg.setAttribute("stroke", "currentColor");
1801
+ svg.setAttribute("stroke-width", "2");
1802
+ svg.setAttribute("stroke-linecap", "round");
1803
+ svg.setAttribute("stroke-linejoin", "round");
1804
+ svg.setAttribute("class", cls);
1805
+ for (const d of [
1806
+ "M8 8h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2Z",
1807
+ "M4 16c-1.1 0-2-.9-2-2V4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2"
1808
+ ]) {
1809
+ const p = document.createElementNS(ns, "path");
1810
+ p.setAttribute("d", d);
1811
+ svg.append(p);
1812
+ }
1813
+ return svg;
1814
+ }
1815
+
1654
1816
  // src/inject/features/alias.js
1655
1817
  var norm = (p) => String(p || "").replace(/[\\/]+$/, "");
1656
1818
  var basenameOf = (p) => norm(p).split(/[\\/]/).pop() || "";
@@ -1679,6 +1841,7 @@
1679
1841
  return false;
1680
1842
  }
1681
1843
  async function startAliasWatcher() {
1844
+ if (isNewProjectSidebar()) return;
1682
1845
  await syncFromConfig();
1683
1846
  if (observer) return;
1684
1847
  observer = new MutationObserver((muts) => {
@@ -2053,76 +2216,6 @@
2053
2216
  return svg;
2054
2217
  }
2055
2218
 
2056
- // src/inject/features/copy-path.js
2057
- async function appendCopyPathItem(menu, anchorItem, project) {
2058
- if (menu.querySelector('[data-zcodepro-item="copy-path"]')) return;
2059
- const L = t();
2060
- const item = anchorItem.cloneNode(true);
2061
- item.removeAttribute("data-testid");
2062
- item.removeAttribute("data-highlighted");
2063
- item.setAttribute("data-zcodepro-item", "copy-path");
2064
- for (const child of [...item.childNodes]) child.remove();
2065
- const origIcon = anchorItem.querySelector("svg");
2066
- const iconClass = origIcon ? origIcon.getAttribute("class") : "h-3.5 w-3.5";
2067
- item.append(hCopyIcon(iconClass), document.createTextNode(L.copyPathItem));
2068
- item.addEventListener("mouseenter", () => {
2069
- for (const el of menu.querySelectorAll('[role="menuitem"]')) el.removeAttribute("data-highlighted");
2070
- item.setAttribute("data-highlighted", "");
2071
- });
2072
- item.addEventListener("mouseleave", () => item.removeAttribute("data-highlighted"));
2073
- item.addEventListener("click", () => {
2074
- closeRadixMenu(menu);
2075
- void copyText(project.path);
2076
- });
2077
- anchorItem.before(item);
2078
- }
2079
- async function copyText(text) {
2080
- const L = t();
2081
- if (await copyToClipboard(text)) showToast(L.pathCopied);
2082
- else showToast(L.pathCopyFailed, "error");
2083
- }
2084
- async function copyToClipboard(text) {
2085
- try {
2086
- await navigator.clipboard.writeText(text);
2087
- return true;
2088
- } catch {
2089
- return copyViaHiddenInput(text);
2090
- }
2091
- }
2092
- function copyViaHiddenInput(text) {
2093
- try {
2094
- const input = h("input", { type: "text", style: "position:fixed;left:-9999px;top:0;opacity:0" });
2095
- input.value = text;
2096
- document.body.append(input);
2097
- input.select();
2098
- const ok = document.execCommand("copy");
2099
- input.remove();
2100
- return ok;
2101
- } catch {
2102
- return false;
2103
- }
2104
- }
2105
- function hCopyIcon(cls) {
2106
- const ns = "http://www.w3.org/2000/svg";
2107
- const svg = document.createElementNS(ns, "svg");
2108
- svg.setAttribute("viewBox", "0 0 24 24");
2109
- svg.setAttribute("fill", "none");
2110
- svg.setAttribute("stroke", "currentColor");
2111
- svg.setAttribute("stroke-width", "2");
2112
- svg.setAttribute("stroke-linecap", "round");
2113
- svg.setAttribute("stroke-linejoin", "round");
2114
- svg.setAttribute("class", cls);
2115
- for (const d of [
2116
- "M8 8h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2Z",
2117
- "M4 16c-1.1 0-2-.9-2-2V4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2"
2118
- ]) {
2119
- const p = document.createElementNS(ns, "path");
2120
- p.setAttribute("d", d);
2121
- svg.append(p);
2122
- }
2123
- return svg;
2124
- }
2125
-
2126
2219
  // src/inject/features/project-menu.js
2127
2220
  var REMOVE_TEXTS = ["\u79FB\u9664", "Remove"];
2128
2221
  function extractPathFromTestId2(testid) {
@@ -2131,37 +2224,213 @@
2131
2224
  m = testid.match(/[-:=,|]([A-Za-z]:\\.*)$/);
2132
2225
  return m ? m[1] : null;
2133
2226
  }
2134
- function basenameOf2(p) {
2135
- return String(p || "").replace(/[\\/]+$/, "").split(/[\\/]/).pop() || "";
2227
+ function openMenuProjectRow() {
2228
+ const trigger = document.querySelector(
2229
+ '[data-testid="virtual-project-menu"][aria-expanded="true"], [data-testid="virtual-project-menu"][data-state="open"], [data-testid="virtual-project-row"][data-state="open"], [data-testid="virtual-project-row"][aria-expanded="true"]'
2230
+ );
2231
+ const row = trigger ? trigger.closest("section[data-project-id]") : null;
2232
+ if (!row) return null;
2233
+ const host = row.getAttribute("data-project-host");
2234
+ return host === null || host === "local" ? row : null;
2136
2235
  }
2137
2236
  async function resolveProjectPath(removeItem) {
2138
- const testid = removeItem.getAttribute("data-testid") || "";
2139
- const extracted = extractPathFromTestId2(testid);
2237
+ const extracted = extractPathFromTestId2(removeItem.getAttribute("data-testid") || "");
2140
2238
  if (!extracted) return null;
2141
2239
  const res = await rpc("/projects");
2142
2240
  if (res.ok && Array.isArray(res.projects)) {
2143
- const norm2 = (p) => String(p).replace(/[\\/]+$/, "");
2144
- const hit = res.projects.find((p) => norm2(p.path) === norm2(extracted));
2241
+ const norm3 = (p) => String(p).replace(/[\\/]+$/, "");
2242
+ const hit = res.projects.find((p) => norm3(p.path) === norm3(extracted));
2145
2243
  if (hit) return hit;
2146
2244
  }
2147
- return { path: extracted, name: basenameOf2(extracted) };
2245
+ return { path: extracted, name: String(extracted).replace(/[\\/]+$/, "").split(/[\\/]/).pop() || "" };
2246
+ }
2247
+ function cloneMenuItem(anchor, testid, label) {
2248
+ const item = anchor.cloneNode(true);
2249
+ item.removeAttribute("data-testid");
2250
+ item.removeAttribute("data-highlighted");
2251
+ item.removeAttribute("id");
2252
+ item.setAttribute("data-zcodepro-item", testid);
2253
+ for (const child of [...item.childNodes]) child.remove();
2254
+ const origIcon = anchor.querySelector("svg");
2255
+ const iconClass = origIcon ? origIcon.getAttribute("class") : "h-3.5 w-3.5";
2256
+ const ns = "http://www.w3.org/2000/svg";
2257
+ const svg = document.createElementNS(ns, "svg");
2258
+ svg.setAttribute("viewBox", "0 0 24 24");
2259
+ svg.setAttribute("fill", "none");
2260
+ svg.setAttribute("stroke", "currentColor");
2261
+ svg.setAttribute("stroke-width", "2");
2262
+ svg.setAttribute("stroke-linecap", "round");
2263
+ svg.setAttribute("stroke-linejoin", "round");
2264
+ svg.setAttribute("class", iconClass);
2265
+ const p = document.createElementNS(ns, "path");
2266
+ p.setAttribute("d", "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z");
2267
+ svg.append(p);
2268
+ item.append(svg, document.createTextNode(label));
2269
+ return item;
2270
+ }
2271
+ function wireHighlight(menu, item) {
2272
+ item.addEventListener("mouseenter", () => {
2273
+ for (const el of menu.querySelectorAll('[role="menuitem"]')) el.removeAttribute("data-highlighted");
2274
+ item.setAttribute("data-highlighted", "");
2275
+ });
2276
+ item.addEventListener("mouseleave", () => item.removeAttribute("data-highlighted"));
2277
+ }
2278
+ function attachFolderHover(menu, item, roots) {
2279
+ const L = t();
2280
+ let sub = null;
2281
+ let subHovered = false;
2282
+ let hideTimer = 0;
2283
+ let aliveTimer = 0;
2284
+ const removeSub = () => {
2285
+ clearTimeout(hideTimer);
2286
+ clearInterval(aliveTimer);
2287
+ sub?.remove();
2288
+ sub = null;
2289
+ subHovered = false;
2290
+ };
2291
+ const position = () => {
2292
+ const rect = item.getBoundingClientRect();
2293
+ sub.style.left = rect.right + "px";
2294
+ sub.style.top = rect.top + "px";
2295
+ const r = sub.getBoundingClientRect();
2296
+ if (r.right > window.innerWidth - 8) {
2297
+ sub.style.left = "";
2298
+ sub.style.right = window.innerWidth - rect.left + "px";
2299
+ }
2300
+ };
2301
+ const ensureSub = () => {
2302
+ if (sub) {
2303
+ position();
2304
+ return;
2305
+ }
2306
+ sub = document.createElement("div");
2307
+ sub.setAttribute("role", "menu");
2308
+ sub.setAttribute("data-zcodepro-item", "open-folder-sub");
2309
+ sub.className = "zcodepro-card flex flex-col gap-0.5 rounded-lg border border-border bg-menu p-1 text-ui-sm shadow-lg";
2310
+ sub.style.cssText = "position:fixed;z-index:60;min-width:14rem;";
2311
+ for (const root of roots) {
2312
+ const base = String(root.path).replace(/[\\/]+$/, "").split(/[\\/]/).pop() || root.path;
2313
+ const row = document.createElement("div");
2314
+ row.setAttribute("role", "menuitem");
2315
+ row.className = "flex cursor-pointer items-center gap-2 truncate rounded-md px-2 py-1.5 text-foreground transition-colors hover:bg-surface-hover";
2316
+ row.title = root.path;
2317
+ row.append(document.createTextNode(base + (root.primary ? ` \xB7 ${L.openFolderPrimary}` : "")));
2318
+ row.addEventListener("click", () => {
2319
+ try {
2320
+ menu.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", code: "Escape", bubbles: true, cancelable: true }));
2321
+ } catch {
2322
+ }
2323
+ removeSub();
2324
+ void rpc("/open-folder", { method: "POST", body: { path: root.path } });
2325
+ });
2326
+ sub.append(row);
2327
+ }
2328
+ sub.addEventListener("mouseenter", () => {
2329
+ subHovered = true;
2330
+ clearTimeout(hideTimer);
2331
+ });
2332
+ sub.addEventListener("mouseleave", () => {
2333
+ subHovered = false;
2334
+ scheduleHide();
2335
+ });
2336
+ document.body.append(sub);
2337
+ position();
2338
+ aliveTimer = setInterval(() => {
2339
+ if (!menu.isConnected) removeSub();
2340
+ }, 400);
2341
+ };
2342
+ const scheduleHide = () => {
2343
+ clearTimeout(hideTimer);
2344
+ hideTimer = setTimeout(() => {
2345
+ if (!subHovered) removeSub();
2346
+ }, 300);
2347
+ };
2348
+ item.addEventListener("mouseenter", () => {
2349
+ clearTimeout(hideTimer);
2350
+ ensureSub();
2351
+ });
2352
+ item.addEventListener("mouseleave", scheduleHide);
2353
+ item.addEventListener("click", () => {
2354
+ clearTimeout(hideTimer);
2355
+ ensureSub();
2356
+ });
2357
+ }
2358
+ async function injectNewMenuItems(content, menuRow) {
2359
+ const L = t();
2360
+ const projectId = menuRow.getAttribute("data-project-id");
2361
+ const editItem = content.querySelector('[data-testid="virtual-project-edit"]');
2362
+ if (!editItem || !projectId) return;
2363
+ if (content.querySelector("[data-zcodepro-item]")) return;
2364
+ const config = await getConfig();
2365
+ if (config.features && config.features.projectMenu === false) return;
2366
+ const res = await rpc("/projects-v2");
2367
+ if (!res.ok || !res.available) return;
2368
+ const proj = (res.projects || []).find((p) => p.id === projectId);
2369
+ if (!proj) return;
2370
+ const roots = (proj.roots || []).slice().sort((a, b) => (b.primary ? 1 : 0) - (a.primary ? 1 : 0));
2371
+ if (!roots.length) return;
2372
+ const primary = roots.find((r) => r.primary) || roots[0];
2373
+ const openItem = cloneMenuItem(editItem, "open-folder", L.openFolderItem);
2374
+ wireHighlight(content, openItem);
2375
+ if (roots.length === 1) {
2376
+ openItem.addEventListener("click", () => {
2377
+ try {
2378
+ content.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", code: "Escape", bubbles: true, cancelable: true }));
2379
+ } catch {
2380
+ }
2381
+ void rpc("/open-folder", { method: "POST", body: { path: primary.path } });
2382
+ });
2383
+ } else {
2384
+ const ns = "http://www.w3.org/2000/svg";
2385
+ const chev = document.createElementNS(ns, "svg");
2386
+ chev.setAttribute("viewBox", "0 0 24 24");
2387
+ chev.setAttribute("fill", "none");
2388
+ chev.setAttribute("stroke", "currentColor");
2389
+ chev.setAttribute("stroke-width", "2");
2390
+ chev.setAttribute("stroke-linecap", "round");
2391
+ chev.setAttribute("stroke-linejoin", "round");
2392
+ chev.setAttribute("class", "ml-auto size-3.5 shrink-0 text-foreground-subtle");
2393
+ const chevPath = document.createElementNS(ns, "path");
2394
+ chevPath.setAttribute("d", "m9 18 6-6-6-6");
2395
+ chev.append(chevPath);
2396
+ openItem.append(chev);
2397
+ attachFolderHover(content, openItem, roots);
2398
+ }
2399
+ editItem.after(openItem);
2400
+ const copyItem = cloneMenuItem(editItem, "copy-path", L.copyPathItem);
2401
+ wireHighlight(content, copyItem);
2402
+ copyItem.addEventListener("click", () => {
2403
+ try {
2404
+ content.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", code: "Escape", bubbles: true, cancelable: true }));
2405
+ } catch {
2406
+ }
2407
+ void copyToClipboard(primary.path).then((ok) => showToast(ok ? L.pathCopied : L.pathCopyFailed, ok ? void 0 : "error"));
2408
+ });
2409
+ openItem.after(copyItem);
2148
2410
  }
2149
2411
  function handleProjectMenu(content) {
2150
- if (content.querySelector('[data-zcodepro-item="alias"]')) return;
2412
+ if (content.querySelector("[data-zcodepro-item]")) return;
2151
2413
  const items = itemsOf(content);
2152
- const removeItem = items.find(
2414
+ const newUi = isNewProjectSidebar();
2415
+ const menuRow = newUi ? openMenuProjectRow() : null;
2416
+ const anchor = newUi ? items.find((el) => el.getAttribute("data-testid") === "virtual-project-edit") : items.find(
2153
2417
  (el) => el.hasAttribute("data-testid") && REMOVE_TEXTS.some((x) => itemText(el).startsWith(x))
2154
2418
  );
2155
- if (!removeItem) return;
2419
+ if (!anchor) return;
2420
+ if (newUi) {
2421
+ if (!menuRow) return;
2422
+ void injectNewMenuItems(content, menuRow);
2423
+ return;
2424
+ }
2156
2425
  void (async () => {
2157
2426
  const config = await getConfig();
2158
2427
  if (config.features && config.features.projectMenu === false) return;
2159
- const project = await resolveProjectPath(removeItem);
2428
+ const project = await resolveProjectPath(anchor);
2160
2429
  if (!project) return;
2161
- appendAliasItem(content, removeItem, project);
2162
- appendRelocateItem(content, removeItem, project);
2163
- appendOpenFolderItem(content, removeItem, project);
2164
- appendCopyPathItem(content, removeItem, project);
2430
+ appendAliasItem(content, anchor, project);
2431
+ appendRelocateItem(content, anchor, project);
2432
+ appendOpenFolderItem(content, anchor, project);
2433
+ appendCopyPathItem(content, anchor, project);
2165
2434
  })();
2166
2435
  }
2167
2436
 
@@ -2554,6 +2823,489 @@
2554
2823
  return v === "" || v !== "session" && !providers.some((p) => p.id === v);
2555
2824
  }
2556
2825
 
2826
+ // src/inject/features/ws-rows.js
2827
+ var norm2 = (p) => String(p || "").replace(/[\\/]+$/, "");
2828
+ var NEW_ROW_SEL = "section[data-project-id]";
2829
+ var OLD_ROW_SEL = '[data-testid^="workspace-item-"]';
2830
+ var pathByProjectId = /* @__PURE__ */ new Map();
2831
+ function projectRowSelector() {
2832
+ return isNewProjectSidebar() ? NEW_ROW_SEL : OLD_ROW_SEL;
2833
+ }
2834
+ function projectRows(root = document) {
2835
+ return [...root.querySelectorAll(projectRowSelector())];
2836
+ }
2837
+ function rowPath(row) {
2838
+ if (!row) return null;
2839
+ if (row.hasAttribute && row.hasAttribute("data-project-id")) {
2840
+ const host = row.getAttribute("data-project-host");
2841
+ if (host !== null && host !== "local") return null;
2842
+ const id = row.getAttribute("data-project-id");
2843
+ let found = null;
2844
+ for (const el of row.querySelectorAll("[data-task-item-key]")) {
2845
+ const key = el.getAttribute("data-task-item-key") || "";
2846
+ const cut = key.lastIndexOf(":");
2847
+ if (cut > 1) {
2848
+ found = key.slice(0, cut);
2849
+ break;
2850
+ }
2851
+ }
2852
+ if (found) pathByProjectId.set(id, found);
2853
+ return found || pathByProjectId.get(id) || null;
2854
+ }
2855
+ const testid = row.getAttribute && row.getAttribute("data-testid");
2856
+ if (!testid || !testid.startsWith("workspace-item-")) return null;
2857
+ return norm2(testid.slice("workspace-item-".length)) || null;
2858
+ }
2859
+ function findProjectRow(path) {
2860
+ const want = norm2(path);
2861
+ if (!want) return null;
2862
+ for (const row of projectRows()) {
2863
+ const p = rowPath(row);
2864
+ if (p && norm2(p) === want) return row;
2865
+ }
2866
+ return null;
2867
+ }
2868
+
2869
+ // src/inject/features/alias-migration.js
2870
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
2871
+ var basenameOf2 = (p) => String(p || "").replace(/[\\/]+$/, "").split(/[\\/]/).pop() || "";
2872
+ function waitFor(getter, timeoutMs, step) {
2873
+ const start = Date.now();
2874
+ return new Promise((resolve, reject) => {
2875
+ const tick2 = () => {
2876
+ let v = null;
2877
+ try {
2878
+ v = getter();
2879
+ } catch {
2880
+ }
2881
+ if (v) {
2882
+ resolve(v);
2883
+ return;
2884
+ }
2885
+ if (Date.now() - start >= timeoutMs) {
2886
+ reject(new Error(step));
2887
+ return;
2888
+ }
2889
+ setTimeout(tick2, 120);
2890
+ };
2891
+ tick2();
2892
+ });
2893
+ }
2894
+ function setReactInputValue(input, value) {
2895
+ const setter = Object.getOwnPropertyDescriptor(input.constructor.prototype, "value")?.set || Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
2896
+ if (!setter) throw new Error("input-setter");
2897
+ setter.call(input, value);
2898
+ input.dispatchEvent(new Event("input", { bubbles: true }));
2899
+ }
2900
+ function pressEscape() {
2901
+ try {
2902
+ document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", code: "Escape", bubbles: true, cancelable: true }));
2903
+ } catch {
2904
+ }
2905
+ }
2906
+ async function markDismissed() {
2907
+ await rpc("/config", { method: "POST", body: { migrations: { aliasRenameDismissed: true } } });
2908
+ clearConfigCache();
2909
+ }
2910
+ var MIGRATE_LOCK_KEY = "zcodepro:alias-migrate-lock";
2911
+ var MIGRATE_LOCK_MS = 5 * 6e4;
2912
+ function migrateLockFresh() {
2913
+ try {
2914
+ const at = Number(localStorage.getItem(MIGRATE_LOCK_KEY));
2915
+ return Number.isFinite(at) && Date.now() - at < MIGRATE_LOCK_MS;
2916
+ } catch {
2917
+ return false;
2918
+ }
2919
+ }
2920
+ function touchMigrateLock() {
2921
+ try {
2922
+ localStorage.setItem(MIGRATE_LOCK_KEY, String(Date.now()));
2923
+ } catch {
2924
+ }
2925
+ }
2926
+ async function migrateOne(path, alias) {
2927
+ if (document.querySelector('[data-testid="virtual-project-name"], [role="menu"]')) {
2928
+ pressEscape();
2929
+ await sleep(300);
2930
+ }
2931
+ let row = findProjectRow(path);
2932
+ if (!row) {
2933
+ const byName = [...document.querySelectorAll("section[data-project-id]")].filter((el) => {
2934
+ const host = el.getAttribute("data-project-host");
2935
+ return (host === null || host === "local") && el.getAttribute("data-project-name") === basenameOf2(path);
2936
+ });
2937
+ if (byName.length === 1) row = byName[0];
2938
+ }
2939
+ if (!row) throw new Error("project-row");
2940
+ const projectId = row.getAttribute("data-project-id");
2941
+ const rowById = () => document.querySelector(`section[data-project-id="${CSS.escape(projectId)}"]`);
2942
+ try {
2943
+ row.scrollIntoView({ block: "center" });
2944
+ } catch {
2945
+ }
2946
+ const trigger = await waitFor(
2947
+ () => rowById()?.querySelector('[data-testid="virtual-project-menu"]'),
2948
+ 4e3,
2949
+ "menu-trigger"
2950
+ );
2951
+ trigger.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true, pointerId: 1, isPrimary: true, button: 0 }));
2952
+ trigger.dispatchEvent(new PointerEvent("pointerup", { bubbles: true, cancelable: true, pointerId: 1, isPrimary: true, button: 0 }));
2953
+ trigger.click();
2954
+ const menu = await waitFor(() => {
2955
+ for (const m of document.querySelectorAll('[role="menu"]')) {
2956
+ if (m.querySelector('[data-testid="virtual-project-edit"]')) return m;
2957
+ }
2958
+ return null;
2959
+ }, 4e3, "menu-open");
2960
+ menu.querySelector('[data-testid="virtual-project-edit"]').click();
2961
+ const input = await waitFor(
2962
+ () => document.querySelector('[data-testid="virtual-project-name"]'),
2963
+ 5e3,
2964
+ "editor-open"
2965
+ );
2966
+ const wantName = alias.trim();
2967
+ setReactInputValue(input, wantName);
2968
+ const save = await waitFor(
2969
+ () => {
2970
+ const btn = document.querySelector('[data-testid="virtual-project-save"]');
2971
+ return btn && !btn.disabled ? btn : null;
2972
+ },
2973
+ 4e3,
2974
+ "save-ready"
2975
+ );
2976
+ save.click();
2977
+ await waitFor(() => {
2978
+ const r = rowById();
2979
+ return r && r.getAttribute("data-project-name") === wantName ? r : null;
2980
+ }, 8e3, "name-updated");
2981
+ await sleep(250);
2982
+ if (document.querySelector('[data-testid="virtual-project-name"]')) pressEscape();
2983
+ const res = await rpc("/project/alias", { method: "POST", body: { path, alias: "" } });
2984
+ if (!res.ok) throw new Error("alias-clear");
2985
+ }
2986
+ async function classifyEntry(path, alias, db) {
2987
+ const want = norm0(path);
2988
+ if (db) {
2989
+ let alsoDeleted = false;
2990
+ for (const proj of db.projects || []) {
2991
+ const hit = (proj.roots || []).find((r) => norm0(r.path) === want);
2992
+ if (!hit) continue;
2993
+ if (hit.primary) {
2994
+ if (proj.name === alias) return { state: "done", note: "" };
2995
+ return { state: "", note: "", overridden: !!proj.overridden };
2996
+ }
2997
+ alsoDeleted = (db.deletedRoots || []).some((p) => norm0(p) === want);
2998
+ return { state: "merged", note: proj.name, alsoDeleted };
2999
+ }
3000
+ if ((db.deletedRoots || []).some((p) => norm0(p) === want)) return { state: "deleted", note: "" };
3001
+ return { state: "missing", note: "" };
3002
+ }
3003
+ const localRows = [...document.querySelectorAll("section[data-project-id]")].filter((el) => {
3004
+ const host = el.getAttribute("data-project-host");
3005
+ return host === null || host === "local";
3006
+ });
3007
+ const byPath = localRows.find((el) => norm0(rowPath(el)) === want);
3008
+ if (byPath) {
3009
+ return (byPath.getAttribute("data-project-name") || "") === alias ? { state: "done", note: "" } : { state: "", note: "" };
3010
+ }
3011
+ const byName = localRows.filter((el) => el.getAttribute("data-project-name") === alias);
3012
+ if (byName.length === 1) return { state: "done", note: "" };
3013
+ for (const task of document.querySelectorAll("[data-task-item-key]")) {
3014
+ const key = task.getAttribute("data-task-item-key") || "";
3015
+ const cut = key.lastIndexOf(":");
3016
+ if (cut <= 1 || norm0(key.slice(0, cut)) !== want) continue;
3017
+ const owner = task.closest("section[data-project-id]");
3018
+ const ownerName = owner ? owner.getAttribute("data-project-name") || "" : "";
3019
+ if (ownerName) return { state: "merged", note: ownerName };
3020
+ }
3021
+ return { state: "missing", note: "" };
3022
+ }
3023
+ async function fetchProjectDb() {
3024
+ const res = await rpc("/projects-v2");
3025
+ return res.ok && res.available ? res : null;
3026
+ }
3027
+ var norm0 = (p) => String(p || "").replace(/[\\/]+$/, "");
3028
+ function openMigrationDialog() {
3029
+ ensureStyle();
3030
+ const L = t();
3031
+ let running = false;
3032
+ let decided = false;
3033
+ const decide = () => {
3034
+ if (decided) return;
3035
+ decided = true;
3036
+ void markDismissed();
3037
+ };
3038
+ touchMigrateLock();
3039
+ openDialog({
3040
+ title: L.aliasMigrateTitle,
3041
+ description: L.aliasMigrateDesc,
3042
+ width: "sm:max-w-md",
3043
+ // 迁移不可中途撤销且过程可见:点遮罩不关闭(防误触),右上角 ✕ 关闭
3044
+ dismissOnOutside: false,
3045
+ closable: true,
3046
+ onClose: () => {
3047
+ decide();
3048
+ window.dispatchEvent(new CustomEvent("zcodepro:aliases-changed"));
3049
+ },
3050
+ onMount: ({ body, close }) => {
3051
+ void (async () => {
3052
+ const config = await getConfig(true);
3053
+ const db = await fetchProjectDb();
3054
+ const entries = [];
3055
+ for (const [path, aliasRaw] of Object.entries(config.aliases || {})) {
3056
+ const alias = String(aliasRaw || "").trim();
3057
+ if (!alias) continue;
3058
+ const cls = await classifyEntry(path, alias, db);
3059
+ entries.push({
3060
+ path,
3061
+ alias,
3062
+ checked: cls.state === "" && !cls.overridden,
3063
+ state: cls.state,
3064
+ note: cls.note || "",
3065
+ overridden: !!cls.overridden,
3066
+ alsoDeleted: !!cls.alsoDeleted
3067
+ });
3068
+ }
3069
+ if (!entries.length) {
3070
+ close();
3071
+ return;
3072
+ }
3073
+ const badgesOf = (e) => {
3074
+ const out = [];
3075
+ if (e.state === "run") out.push({ text: L.aliasMigrateRunning, cls: "text-amber-500" });
3076
+ if (e.state === "ok") out.push({ text: L.aliasMigrateStateDone, cls: "text-emerald-600" });
3077
+ if (e.state === "fail") out.push({ text: L.aliasMigrateStateFailed, cls: "text-destructive" });
3078
+ if (e.state === "done") out.push({ text: L.aliasMigrateStateDone, cls: "text-emerald-600" });
3079
+ if (e.state === "merged") out.push({ text: L.aliasMigrateStateMerged.replace("{name}", e.note), cls: "text-amber-500" });
3080
+ if (e.state === "deleted" || e.state === "merged" && e.alsoDeleted) out.push({ text: L.aliasMigrateStateDeleted, cls: "text-foreground-subtle/70" });
3081
+ if (e.state === "missing") out.push({ text: L.aliasMigrateStateMissing, cls: "text-foreground-subtle/70" });
3082
+ if (e.state === "" && e.overridden) out.push({ text: L.aliasMigrateStateRenamed, cls: "text-foreground-subtle/70" });
3083
+ return out;
3084
+ };
3085
+ const progressEl = h("div", { class: "mb-1 text-ui-xs text-foreground-subtle", style: "display:none" });
3086
+ const listEl = h("div", { class: "max-h-[50vh] space-y-1.5 overflow-y-auto" });
3087
+ let deadOpen = false;
3088
+ const renderList = () => {
3089
+ const alive = entries.filter((e) => e.state !== "missing" && e.state !== "deleted");
3090
+ const dead = entries.filter((e) => e.state === "missing" || e.state === "deleted");
3091
+ const rowOf = (e, deadRow) => {
3092
+ const cb = h("input", { type: "checkbox" });
3093
+ cb.checked = e.checked;
3094
+ cb.disabled = running || e.state !== "" && e.state !== "fail" || e.overridden;
3095
+ cb.addEventListener("change", () => {
3096
+ e.checked = cb.checked;
3097
+ });
3098
+ const badges = badgesOf(e);
3099
+ const dim = deadRow || e.state !== "" && e.state !== "fail" && e.state !== "run" || e.overridden;
3100
+ return h(
3101
+ "label",
3102
+ { class: "flex cursor-pointer items-start gap-2 rounded-lg p-2 transition-colors hover:bg-surface-hover" + (dim ? " opacity-60" : "") },
3103
+ h("span", { class: "mt-0.5" }, cb),
3104
+ h(
3105
+ "span",
3106
+ { class: "min-w-0 flex-1" },
3107
+ h("span", { class: "block truncate text-ui-sm font-medium text-foreground" }, e.alias),
3108
+ h("span", { class: "block truncate font-mono text-ui-xs text-foreground-subtle" }, e.path)
3109
+ ),
3110
+ ...badges.map((b) => h("span", { class: "shrink-0 self-center text-ui-xs " + b.cls }, b.text))
3111
+ );
3112
+ };
3113
+ const parts = alive.map((e) => rowOf(e, false));
3114
+ if (dead.length) {
3115
+ const deadRows = h(
3116
+ "div",
3117
+ { class: "space-y-1", style: deadOpen ? "" : "display:none" },
3118
+ ...dead.map((e) => rowOf(e, true))
3119
+ );
3120
+ const toggle2 = h("button", {
3121
+ type: "button",
3122
+ class: "flex w-full items-center gap-1 rounded-lg p-2 text-left text-ui-xs text-foreground-subtle transition-colors hover:bg-surface-hover",
3123
+ onClick: () => {
3124
+ deadOpen = !deadOpen;
3125
+ renderList();
3126
+ }
3127
+ }, (deadOpen ? "\u25BE " : "\u25B8 ") + L.aliasMigrateDeadSummary.replace("{n}", String(dead.length)));
3128
+ parts.push(toggle2, deadRows);
3129
+ }
3130
+ listEl.replaceChildren(...parts);
3131
+ };
3132
+ renderList();
3133
+ const clearDead = async () => {
3134
+ if (running) return;
3135
+ const dead = entries.filter((e) => e.state === "missing" || e.state === "deleted");
3136
+ if (!dead.length) return;
3137
+ running = true;
3138
+ goBtn.setAttribute("disabled", "true");
3139
+ let ok = 0;
3140
+ for (const e of dead) {
3141
+ const r = await rpc("/project/alias", { method: "POST", body: { path: e.path, alias: "" } });
3142
+ if (r.ok) {
3143
+ ok++;
3144
+ entries.splice(entries.indexOf(e), 1);
3145
+ }
3146
+ }
3147
+ running = false;
3148
+ goBtn.removeAttribute("disabled");
3149
+ goBtn.textContent = L.aliasMigrateGo;
3150
+ clearConfigCache();
3151
+ renderList();
3152
+ window.dispatchEvent(new CustomEvent("zcodepro:aliases-changed"));
3153
+ if (ok === dead.length) showToast(L.aliasMigrateDeadCleared.replace("{n}", String(ok)));
3154
+ else showToast(L.aliasMigrateDeadClearFailed, "error");
3155
+ };
3156
+ const goBtn = btnPrimary(L.aliasMigrateGo, () => {
3157
+ void run();
3158
+ }, "min-w-24");
3159
+ const run = async () => {
3160
+ if (running) return;
3161
+ const todo = entries.filter((e) => e.checked);
3162
+ if (!todo.length) return;
3163
+ running = true;
3164
+ goBtn.setAttribute("disabled", "true");
3165
+ goBtn.textContent = L.aliasMigrateRunning;
3166
+ let ok = 0;
3167
+ const failed = [];
3168
+ for (let i = 0; i < todo.length; i++) {
3169
+ const e = todo[i];
3170
+ progressEl.style.display = "";
3171
+ progressEl.textContent = L.aliasMigrateProgress.replace("{i}", String(i + 1)).replace("{n}", String(todo.length)).replace("{name}", e.alias);
3172
+ e.state = "run";
3173
+ renderList();
3174
+ try {
3175
+ await migrateOne(e.path, e.alias);
3176
+ e.state = "ok";
3177
+ e.checked = false;
3178
+ ok++;
3179
+ } catch (err) {
3180
+ console.warn("[zcodepro] alias-migrate: " + e.path + " \u5931\u8D25\u4E8E " + (err && err.message));
3181
+ e.state = "fail";
3182
+ failed.push(e);
3183
+ }
3184
+ renderList();
3185
+ }
3186
+ running = false;
3187
+ progressEl.style.display = "none";
3188
+ goBtn.removeAttribute("disabled");
3189
+ goBtn.textContent = L.aliasMigrateGo;
3190
+ decide();
3191
+ close();
3192
+ if (!failed.length) {
3193
+ showToast(L.aliasMigrateDone.replace("{n}", String(ok)), "ok");
3194
+ } else if (ok) {
3195
+ showToast(L.aliasMigratePartial.replace("{n}", String(ok)).replace("{m}", String(failed.length)), "error");
3196
+ } else {
3197
+ showToast(L.aliasMigrateAllFailed, "error");
3198
+ }
3199
+ };
3200
+ body.append(
3201
+ progressEl,
3202
+ listEl,
3203
+ h("p", { class: "text-ui-xs/relaxed text-foreground-subtle" }, L.aliasMigrateItemHint),
3204
+ (() => {
3205
+ const footer = document.createElement("div");
3206
+ footer.className = "mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end";
3207
+ const hasDead = entries.some((e) => e.state === "missing" || e.state === "deleted");
3208
+ if (hasDead) {
3209
+ const clearBtn = btnSecondary(L.aliasMigrateClearDead, () => {
3210
+ void clearDead().then(() => {
3211
+ if (!entries.some((e) => e.state === "missing" || e.state === "deleted")) clearBtn.style.display = "none";
3212
+ });
3213
+ });
3214
+ footer.append(clearBtn);
3215
+ }
3216
+ footer.append(
3217
+ btnSecondary(L.aliasMigrateSkip, () => {
3218
+ if (running) return;
3219
+ decide();
3220
+ close();
3221
+ }),
3222
+ goBtn
3223
+ );
3224
+ return footer;
3225
+ })()
3226
+ );
3227
+ })();
3228
+ }
3229
+ });
3230
+ }
3231
+ function migrationCard() {
3232
+ const L = t();
3233
+ const card = h("div", {
3234
+ class: "flex items-center gap-2 rounded-lg p-2",
3235
+ "data-zcodepro-migration-card": ""
3236
+ });
3237
+ const render = (count) => {
3238
+ card.replaceChildren(
3239
+ h(
3240
+ "div",
3241
+ { class: "min-w-0 flex-1" },
3242
+ h("div", { class: "text-ui-sm font-medium text-foreground" }, L.aliasMigrateCardName),
3243
+ h(
3244
+ "div",
3245
+ { class: "mt-0.5 text-ui-xs/relaxed text-foreground-subtle" },
3246
+ count === null ? "\u2026" : L.aliasMigrateCardDesc.replace("{n}", String(count))
3247
+ )
3248
+ ),
3249
+ btnSmall(L.aliasMigrateRun, () => {
3250
+ openMigrationDialog();
3251
+ })
3252
+ );
3253
+ };
3254
+ render(null);
3255
+ const refresh = async () => {
3256
+ const config = await getConfig(true);
3257
+ const db = await fetchProjectDb();
3258
+ let count = 0;
3259
+ for (const [p, a] of Object.entries(config.aliases || {})) {
3260
+ if (!String(a || "").trim()) continue;
3261
+ const cls = await classifyEntry(p, String(a).trim(), db);
3262
+ if (cls.state === "" && !cls.overridden) count++;
3263
+ }
3264
+ if (!count) {
3265
+ card.remove();
3266
+ return;
3267
+ }
3268
+ render(count);
3269
+ };
3270
+ const onAliasesChanged = () => {
3271
+ if (!card.isConnected) {
3272
+ window.removeEventListener("zcodepro:aliases-changed", onAliasesChanged);
3273
+ return;
3274
+ }
3275
+ void refresh();
3276
+ };
3277
+ window.addEventListener("zcodepro:aliases-changed", onAliasesChanged);
3278
+ void refresh();
3279
+ return card;
3280
+ }
3281
+ function startAliasMigrationWatcher() {
3282
+ if (!officialRenameSupported() && !isNewProjectSidebar()) return;
3283
+ void (async () => {
3284
+ try {
3285
+ const config = await getConfig();
3286
+ const hasAliases = Object.values(config.aliases || {}).some((a) => String(a || "").trim());
3287
+ if (!hasAliases) return;
3288
+ if (config.migrations && config.migrations.aliasRenameDismissed) return;
3289
+ await waitFor(() => document.querySelector("section[data-project-id]"), 45e3, "sidebar");
3290
+ let focused = false;
3291
+ for (let i = 0; i < 600; i++) {
3292
+ if (document.visibilityState === "visible" && document.hasFocus()) {
3293
+ focused = true;
3294
+ break;
3295
+ }
3296
+ await sleep(500);
3297
+ }
3298
+ if (!focused) return;
3299
+ if (migrateLockFresh()) return;
3300
+ await waitFor(() => document.querySelector(".zcodepro-overlay") ? null : true, 12e4, "dialog-busy");
3301
+ const fresh = await getConfig(true);
3302
+ const still = Object.values(fresh.aliases || {}).some((a) => String(a || "").trim());
3303
+ if (still && !(fresh.migrations && fresh.migrations.aliasRenameDismissed)) openMigrationDialog();
3304
+ } catch {
3305
+ }
3306
+ })();
3307
+ }
3308
+
2557
3309
  // src/inject/features/styles.js
2558
3310
  var STYLE_DEFAULTS = {
2559
3311
  rowGap: 20,
@@ -2728,7 +3480,10 @@
2728
3480
  `${LIST} [data-testid^="workspace-item-"]{height:auto !important;min-height:${28 + 2 * pad}px !important;padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`,
2729
3481
  `${LIST} [data-testid^="workspace-item-"] > div:first-child{align-self:stretch !important;}`,
2730
3482
  `${SCROLL} [data-slot="collapsible-trigger"],${SCROLL} .flex.h-7{height:auto !important;}`,
2731
- `${SCROLL} [data-slot="collapsible-trigger"]{min-height:${28 + 2 * pad}px !important;padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`
3483
+ `${SCROLL} [data-slot="collapsible-trigger"]{min-height:${28 + 2 * pad}px !important;padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`,
3484
+ // 3.16.1 新结构:项目行(virtual-project-row,固定 h-8)按视觉总量放行内留白;
3485
+ // 分区间距由新侧栏容器自己的布局管理,不动
3486
+ `section[data-project-id] [data-testid="virtual-project-row"]{height:auto !important;min-height:${28 + 2 * pad}px !important;padding-block:${Math.round(pad)}px !important;}`
2732
3487
  );
2733
3488
  }
2734
3489
  const sts = styles.sidebarTaskSpacing;
@@ -2739,7 +3494,10 @@
2739
3494
  `ul.space-y-0\\.5:has(> li[data-task-item-key]) > :not(:last-child){margin-block-end:${m}px !important;margin-bottom:${m}px !important;}`,
2740
3495
  `ul.space-y-0\\.5:has(> li[data-task-item-key]) > li{padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`,
2741
3496
  `${SCROLL} .flex.flex-col.gap-2{gap:${m}px !important;row-gap:${m}px !important;}`,
2742
- `${SCROLL} div.cursor-pointer[class*="pl-8"]{padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`
3497
+ `${SCROLL} div.cursor-pointer[class*="pl-8"]{padding-block:${pad}px !important;padding-top:${pad}px !important;padding-bottom:${pad}px !important;}`,
3498
+ // 3.16.1 新结构:任务行(li[data-task-item-key])行内留白 + 相邻行间距
3499
+ `li[data-task-item-key]{padding-block:${Math.max(1, Math.round(pad))}px !important;}`,
3500
+ `li[data-task-item-key] + li[data-task-item-key]{margin-block-start:${m}px !important;}`
2743
3501
  );
2744
3502
  }
2745
3503
  return parts.join("");
@@ -2780,7 +3538,8 @@
2780
3538
  thinkingLineHeight: `[data-testid^="chat-assistant-history-content"]`,
2781
3539
  userLineHeight: `${CONV} [class*="user-row"] .whitespace-pre-wrap`,
2782
3540
  contentWidth: "[data-v4-timeline-content-column]",
2783
- sidebarProjectSpacing: '[data-testid^="workspace-item-"]',
3541
+ // 双结构:新侧栏项目行 / 旧 testid 行
3542
+ sidebarProjectSpacing: 'section[data-project-id] [data-testid="virtual-project-row"], [data-testid^="workspace-item-"]',
2784
3543
  sidebarTaskSpacing: "li[data-task-item-key]"
2785
3544
  };
2786
3545
  var HL_MARGIN = {
@@ -2824,6 +3583,7 @@
2824
3583
  } catch {
2825
3584
  }
2826
3585
  }
3586
+ var PLUGINS_REPO_URL = "https://github.com/duanluan/zcode-plugins";
2827
3587
  function makeUpgradeControls({ endpoint, metaRefresh, idleText }) {
2828
3588
  const L = t();
2829
3589
  const state = h("span", { class: "min-w-0 flex-1 truncate text-left text-ui-xs/relaxed text-foreground-subtle" });
@@ -3050,10 +3810,46 @@
3050
3810
  h("span", { class: "text-foreground-subtle/70" }, `${health.version} \xB7 ${HELPER_URL}`)
3051
3811
  );
3052
3812
  const rows = h("div", { class: "divide-y divide-border rounded-xl border border-border" });
3813
+ const pluginsStatusLine = h("span", { class: "max-w-40 truncate text-ui-xs/relaxed text-foreground-subtle" }, "\u2026");
3814
+ const pluginsBtn = btnSmall(L.pluginsCheckNow, () => {
3815
+ void runPluginsUpdate();
3816
+ });
3817
+ let pluginsUpdating = false;
3818
+ const runPluginsUpdate = async () => {
3819
+ if (pluginsUpdating) return;
3820
+ pluginsUpdating = true;
3821
+ pluginsBtn.disabled = true;
3822
+ pluginsStatusLine.textContent = L.pluginsUpdating;
3823
+ const res = await rpc("/plugins/update", { method: "POST", body: {} });
3824
+ pluginsUpdating = false;
3825
+ pluginsBtn.disabled = false;
3826
+ if (!res.ok) {
3827
+ pluginsStatusLine.textContent = "";
3828
+ showToast(L.pluginsUpdateFailed + ": " + errText(res), "error");
3829
+ return;
3830
+ }
3831
+ pluginsStatusLine.textContent = res.updated > 0 ? L.pluginsUpdatedDone.replaceAll("{n}", String(res.updated)) : L.pluginsUpToDate;
3832
+ showToast(pluginsStatusLine.textContent, "success");
3833
+ };
3834
+ void (async () => {
3835
+ const cfg = await getConfig(true).catch(() => null);
3836
+ const res = await rpc("/plugins/status");
3837
+ if (!res.ok) {
3838
+ pluginsStatusLine.textContent = "";
3839
+ return;
3840
+ }
3841
+ const n = (res.updates || []).length;
3842
+ if (cfg && (cfg.features || {}).autoUpdatePlugins === true && n > 0) {
3843
+ void runPluginsUpdate();
3844
+ return;
3845
+ }
3846
+ pluginsStatusLine.textContent = n > 0 ? L.pluginsUpdatesFound.replaceAll("{n}", String(n)) : L.pluginsUpToDate;
3847
+ })();
3053
3848
  const refreshRows = () => {
3054
3849
  const f = config.features || {};
3055
3850
  rows.replaceChildren(
3056
- settingRow(L.featureProjectMenu, L.featureProjectMenuDesc, f.projectMenu !== false, async () => {
3851
+ ...isNewProjectSidebar() ? [migrationCard()] : [],
3852
+ settingRow(L.featureProjectMenu, isNewProjectSidebar() ? L.featureProjectMenuDescNew : L.featureProjectMenuDesc, f.projectMenu !== false, async () => {
3057
3853
  const next = !(f.projectMenu !== false);
3058
3854
  if (await setFeature("projectMenu", next)) f.projectMenu = next;
3059
3855
  refreshRows();
@@ -3094,16 +3890,32 @@
3094
3890
  if (await setFeature("wsRunningSpin", next)) f.wsRunningSpin = next;
3095
3891
  refreshRows();
3096
3892
  }),
3097
- settingRow(L.featurePinnedExpand, L.featurePinnedExpandDesc, f.pinnedKeepCollapsed !== false, async () => {
3098
- const next = !(f.pinnedKeepCollapsed !== false);
3099
- if (await setFeature("pinnedKeepCollapsed", next)) f.pinnedKeepCollapsed = next;
3100
- refreshRows();
3101
- }),
3102
- settingRow(L.featureAutoUpdatePlugins, L.featureAutoUpdatePluginsDesc, f.autoUpdatePlugins === true, async () => {
3103
- const next = !(f.autoUpdatePlugins === true);
3104
- if (await setFeature("autoUpdatePlugins", next)) f.autoUpdatePlugins = next;
3105
- refreshRows();
3106
- })
3893
+ (() => {
3894
+ const repoLink = h("span", {
3895
+ class: "cursor-pointer underline-offset-4 hover:underline",
3896
+ title: PLUGINS_REPO_URL,
3897
+ onClick: (ev) => {
3898
+ ev.stopPropagation();
3899
+ openExternal(PLUGINS_REPO_URL);
3900
+ }
3901
+ }, L.featureAutoUpdatePluginsRepo);
3902
+ const row = settingRow("", "", f.autoUpdatePlugins === true, async () => {
3903
+ const next = !(f.autoUpdatePlugins === true);
3904
+ if (await setFeature("autoUpdatePlugins", next)) f.autoUpdatePlugins = next;
3905
+ refreshRows();
3906
+ }, h("div", { class: "flex items-center gap-2" }, pluginsBtn));
3907
+ const nameEl = row.querySelector(".text-ui-sm.font-medium");
3908
+ if (nameEl) {
3909
+ nameEl.replaceChildren(
3910
+ document.createTextNode(L.featureAutoUpdatePlugins + " "),
3911
+ repoLink,
3912
+ document.createTextNode(" \u63D2\u4EF6")
3913
+ );
3914
+ }
3915
+ const descEl = row.querySelector("[data-zcodepro-row-desc]");
3916
+ if (descEl) descEl.replaceChildren(pluginsStatusLine);
3917
+ return row;
3918
+ })()
3107
3919
  );
3108
3920
  };
3109
3921
  refreshRows();
@@ -3148,70 +3960,16 @@
3148
3960
  L.wechatGroupTitle,
3149
3961
  L.wechatGroupDesc.replaceAll("{id}", WECHAT_ID),
3150
3962
  () => hCopyIcon("size-4 shrink-0 text-foreground-subtle"),
3151
- async () => {
3152
- if (await copyToClipboard(WECHAT_ID)) showToast(L.wechatIdCopied);
3153
- }
3154
- )
3155
- );
3156
- let activeTab = "features";
3157
- const pluginsStatusLine = h("span", { class: "text-ui-xs/relaxed text-foreground-subtle" }, "\u2026");
3158
- const pluginsBtn = btnSmall(L.pluginsCheckNow, () => {
3159
- void runPluginsUpdate();
3160
- });
3161
- const runPluginsUpdate = async () => {
3162
- pluginsBtn.disabled = true;
3163
- pluginsStatusLine.textContent = L.pluginsUpdating;
3164
- const res = await rpc("/plugins/update", { method: "POST", body: {} });
3165
- pluginsBtn.disabled = false;
3166
- if (!res.ok) {
3167
- pluginsStatusLine.textContent = "";
3168
- showToast(L.pluginsUpdateFailed + ": " + errText(res), "error");
3169
- return;
3170
- }
3171
- pluginsStatusLine.textContent = res.updated > 0 ? L.pluginsUpdatedDone.replaceAll("{n}", String(res.updated)) : L.pluginsUpToDate;
3172
- showToast(pluginsStatusLine.textContent, "success");
3173
- };
3174
- void (async () => {
3175
- const res = await rpc("/plugins/status");
3176
- if (!res.ok) {
3177
- pluginsStatusLine.textContent = "";
3178
- return;
3179
- }
3180
- pluginsStatusLine.textContent = (res.updates || []).length > 0 ? L.pluginsUpdatesFound.replaceAll("{n}", String(res.updates.length)) : L.pluginsUpToDate;
3181
- })();
3182
- const PLUGINS_REPO_URL = "https://github.com/duanluan/zcode-plugins";
3183
- const repoName = "zcode-plugins";
3184
- const titleParts = L.pluginsUpdateTitle.split(repoName);
3185
- const pluginsTitle = h("div", { class: "truncate text-ui-sm font-medium text-foreground" });
3186
- if (titleParts.length === 2 && typeof window.zcode?.openExternal === "function") {
3187
- pluginsTitle.append(
3188
- titleParts[0],
3189
- h("span", {
3190
- class: "cursor-pointer underline-offset-4 hover:underline",
3191
- title: PLUGINS_REPO_URL,
3192
- onClick: () => openExternal(PLUGINS_REPO_URL)
3193
- }, repoName),
3194
- titleParts[1]
3195
- );
3196
- } else {
3197
- pluginsTitle.append(L.pluginsUpdateTitle);
3198
- }
3199
- const pluginsCard = h(
3200
- "div",
3201
- { class: "mt-3 flex items-center justify-between gap-2 rounded-xl border border-border p-2" },
3202
- h(
3203
- "div",
3204
- { class: "min-w-0" },
3205
- pluginsTitle,
3206
- h("div", { class: "mt-0.5 truncate text-ui-xs/relaxed text-foreground-subtle" }, pluginsStatusLine)
3207
- ),
3208
- pluginsBtn
3963
+ async () => {
3964
+ if (await copyToClipboard(WECHAT_ID)) showToast(L.wechatIdCopied);
3965
+ }
3966
+ )
3209
3967
  );
3968
+ let activeTab = "features";
3210
3969
  const paneFeatures = h(
3211
3970
  "div",
3212
3971
  { role: "tabpanel", class: "mt-4" },
3213
3972
  h("div", {}, rows),
3214
- pluginsCard,
3215
3973
  communityCards
3216
3974
  );
3217
3975
  const paneStyles = h("div", { role: "tabpanel", class: "mt-4", style: "display:none" });
@@ -3349,6 +4107,7 @@
3349
4107
  )
3350
4108
  };
3351
4109
  const cells = [
4110
+ // 侧栏间距双结构:3.15.x 旧容器/行 + 3.16.1 新项目行(virtual-project-row)与任务行
3352
4111
  styleCell(L.sidebarProjectSpacingName, L.sidebarProjectSpacingDesc, "sidebarProjectSpacing", { max: 24 }),
3353
4112
  styleCell(L.sidebarTaskSpacingName, L.sidebarTaskSpacingDesc, "sidebarTaskSpacing", { max: 24 }),
3354
4113
  widthCell,
@@ -4868,6 +5627,7 @@
4868
5627
  h("span", { class: "text-ui-sm text-foreground-subtle/70" }, "\u2026")
4869
5628
  );
4870
5629
  const hrFacts = h("div", { class: "mt-1.5 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3" });
5630
+ const hrInstList = h("div", { class: "mt-1.5 space-y-1", style: "display:none" });
4871
5631
  const hrHintLine = h("p", { class: "mt-1.5 text-ui-xs/relaxed text-amber-500", style: "display:none" });
4872
5632
  const hrRefresh = async () => {
4873
5633
  const res = await rpc("/headroom/status");
@@ -4876,6 +5636,8 @@
4876
5636
  h("span", { class: "text-ui-sm text-destructive" }, L.headroomStatusLoadFailed + ": " + errText(res))
4877
5637
  );
4878
5638
  hrFacts.replaceChildren();
5639
+ hrInstList.replaceChildren();
5640
+ hrInstList.style.display = "none";
4879
5641
  hrHintLine.style.display = "none";
4880
5642
  return;
4881
5643
  }
@@ -4895,9 +5657,23 @@
4895
5657
  fact(L.headroomCurrentBackend, hrDevLabel(s.backend)),
4896
5658
  fact(L.headroomDesiredBackend, hrDevLabel(s.desiredBackend)),
4897
5659
  fact(L.headroomPowerState, HR_PM[s.powerMode] || s.powerMode),
4898
- fact(L.headroomWatcher, s.watcherRunning ? L.headroomWatcherOn : L.headroomWatcherOff),
5660
+ fact(L.headroomWatcher, s.watcherRunning == null ? "\u2014" : s.watcherRunning ? L.headroomWatcherOn : L.headroomWatcherOff),
4899
5661
  fact(L.headroomSaverDetect, HR_DETECT[s.saverDetect] || s.saverDetect)
4900
5662
  );
5663
+ const insts = Array.isArray(s.instances) ? s.instances : [];
5664
+ hrInstList.replaceChildren(...insts.map((it) => h(
5665
+ "div",
5666
+ { class: "flex min-w-0 items-center gap-2" },
5667
+ h("span", { class: "shrink-0 font-mono text-ui-xs text-foreground-subtle" }, `:${it.port}`),
5668
+ h(
5669
+ "span",
5670
+ { class: "min-w-0 flex-1 truncate text-ui-xs text-foreground-subtle", title: `${it.upstream} | ${it.providers}` },
5671
+ `${it.format} \u2192 ${it.upstream}`
5672
+ ),
5673
+ h("span", { class: "max-w-[40%] shrink-0 truncate text-ui-xs text-foreground-subtle/70", title: it.providers }, it.providers),
5674
+ h("span", { class: "shrink-0 text-ui-xs " + (it.up ? "text-emerald-600" : "text-destructive") }, it.up ? L.hrInstRunning : L.hrInstStopped)
5675
+ )));
5676
+ hrInstList.style.display = insts.length ? "" : "none";
4901
5677
  hrHintLine.textContent = s.saverHint || "";
4902
5678
  hrHintLine.style.display = s.saverHint ? "" : "none";
4903
5679
  };
@@ -5085,6 +5861,7 @@
5085
5861
  ),
5086
5862
  hrStatusLine,
5087
5863
  hrFacts,
5864
+ hrInstList,
5088
5865
  hrHintLine
5089
5866
  ),
5090
5867
  h(
@@ -5462,7 +6239,7 @@
5462
6239
  let item = find();
5463
6240
  if (!item) {
5464
6241
  const ws = workspaceOf(key);
5465
- const header = document.querySelector(`[data-testid="workspace-item-${CSS.escape(ws)}"]`);
6242
+ const header = findProjectRow(ws);
5466
6243
  const expander = header && header.querySelector("[aria-expanded]");
5467
6244
  if (expander && expander.getAttribute("aria-expanded") === "false") {
5468
6245
  expander.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
@@ -5608,7 +6385,7 @@
5608
6385
  return;
5609
6386
  }
5610
6387
  if (!popupEl) await openPopup();
5611
- moveHighlight(k === "x" ? 1 : -1);
6388
+ moveHighlight(k === "x" ? -1 : 1);
5612
6389
  })();
5613
6390
  }, true);
5614
6391
  document.addEventListener("keyup", (e) => {
@@ -5626,6 +6403,7 @@
5626
6403
  var REVERIFY_MS = 3e3;
5627
6404
  var MAP_REFRESH_MS = 6e4;
5628
6405
  var installed2 = false;
6406
+ var seenRows = /* @__PURE__ */ new WeakSet();
5629
6407
  var enabled2 = true;
5630
6408
  var pinned = null;
5631
6409
  var resolved = false;
@@ -5682,7 +6460,17 @@
5682
6460
  if (first && !walker.nextNode()) first.nodeValue = text;
5683
6461
  else el.textContent = text;
5684
6462
  }
5685
- function scheduleEnforce(key) {
6463
+ function scheduleEnforce(key, { immediate = false } = {}) {
6464
+ if (immediate) {
6465
+ if (enabled2 && pinned) {
6466
+ const want = pinned.get(sessIdOf(key));
6467
+ if (want !== void 0) {
6468
+ for (const item of findRows(key)) {
6469
+ for (const el of titleElsOf(item)) writeTitle(el, want);
6470
+ }
6471
+ }
6472
+ }
6473
+ }
5686
6474
  if (pendingKeys.has(key)) return;
5687
6475
  pendingKeys.add(key);
5688
6476
  setTimeout(() => {
@@ -5718,7 +6506,13 @@
5718
6506
  if (!enabled2 || !pinned || pinned.size === 0) return;
5719
6507
  for (const item of document.querySelectorAll(TASK_SEL)) {
5720
6508
  const key = isMismatch(item);
5721
- if (key) scheduleEnforce(key);
6509
+ if (!key) {
6510
+ seenRows.add(item);
6511
+ continue;
6512
+ }
6513
+ const fresh = !seenRows.has(item);
6514
+ seenRows.add(item);
6515
+ scheduleEnforce(key, { immediate: fresh });
5722
6516
  }
5723
6517
  }
5724
6518
  var inTaskRow2 = (node) => !!(node instanceof Element && node.closest && node.closest(TASK_SEL));
@@ -5875,7 +6669,7 @@
5875
6669
  var installed3 = false;
5876
6670
  var knownKeys = /* @__PURE__ */ new Set();
5877
6671
  var attempted = /* @__PURE__ */ new Set();
5878
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
6672
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
5879
6673
  function sessIdOf2(key) {
5880
6674
  const i = key.indexOf(":sess_");
5881
6675
  return i > 0 ? key.slice(i + 1) : "";
@@ -5908,7 +6702,7 @@
5908
6702
  }
5909
6703
  async function onNewTaskRow(key) {
5910
6704
  const selDeadline = Date.now() + SELECT_WAIT_MS;
5911
- while (currentKey() !== key && Date.now() < selDeadline) await sleep(200);
6705
+ while (currentKey() !== key && Date.now() < selDeadline) await sleep2(200);
5912
6706
  if (currentKey() !== key) return;
5913
6707
  const cfg = await getConfig().catch(() => null);
5914
6708
  if (!cfg || !cfg.titleGen || cfg.titleGen.enabled !== true) return;
@@ -5920,7 +6714,7 @@
5920
6714
  while (Date.now() < msgDeadline) {
5921
6715
  texts = userTexts();
5922
6716
  if (texts.length) break;
5923
- await sleep(400);
6717
+ await sleep2(400);
5924
6718
  }
5925
6719
  if (!texts.length) return;
5926
6720
  let assistantSeen = false;
@@ -5943,7 +6737,7 @@
5943
6737
  let lastChange = Date.now();
5944
6738
  try {
5945
6739
  while (Date.now() - startAt < COLLECT_MAX_MS) {
5946
- await sleep(500);
6740
+ await sleep2(500);
5947
6741
  if (currentKey() !== key) {
5948
6742
  lastChange = Date.now();
5949
6743
  continue;
@@ -5963,7 +6757,7 @@
5963
6757
  if (linkDominant(texts.join("\n"))) {
5964
6758
  const deadline = Date.now() + 6e4;
5965
6759
  while (Date.now() < deadline) {
5966
- await sleep(2e3);
6760
+ await sleep2(2e3);
5967
6761
  if (currentKey() !== key) continue;
5968
6762
  const a = assistantText();
5969
6763
  if (a && a.length > 80) {
@@ -5976,7 +6770,7 @@
5976
6770
  let res = await callTitleGen();
5977
6771
  for (const delay of [5e3, 2e4]) {
5978
6772
  if (res && res.ok) break;
5979
- await sleep(delay);
6773
+ await sleep2(delay);
5980
6774
  res = await callTitleGen();
5981
6775
  }
5982
6776
  if (res && res.ok && res.written && res.title) {
@@ -6033,115 +6827,8 @@
6033
6827
  });
6034
6828
  }
6035
6829
 
6036
- // src/inject/features/pinned-expand.js
6037
- var installed4 = false;
6038
- var keepCollapsed = false;
6039
- var CONFIG_POLL_MIN_MS = 5e3;
6040
- var CONFIG_POLL_MAX_MS = 6e4;
6041
- var pollMs = CONFIG_POLL_MIN_MS;
6042
- async function refreshConfig() {
6043
- try {
6044
- const res = await rpc("/config");
6045
- if (res && res.ok && res.config && res.config.features) {
6046
- const next = res.config.features.pinnedKeepCollapsed !== false;
6047
- if (next !== keepCollapsed) {
6048
- keepCollapsed = next;
6049
- return true;
6050
- }
6051
- }
6052
- } catch {
6053
- }
6054
- return false;
6055
- }
6056
- function pollConfig() {
6057
- setTimeout(async () => {
6058
- if (document.hidden) pollMs = CONFIG_POLL_MAX_MS;
6059
- else pollMs = await refreshConfig() ? CONFIG_POLL_MIN_MS : Math.min(Math.round(pollMs * 1.5), CONFIG_POLL_MAX_MS);
6060
- pollConfig();
6061
- }, pollMs);
6062
- }
6063
- function startPinnedExpandSuppression() {
6064
- if (installed4 || typeof document === "undefined") return;
6065
- installed4 = true;
6066
- void refreshConfig();
6067
- pollConfig();
6068
- document.addEventListener("visibilitychange", () => {
6069
- if (!document.hidden) void refreshConfig();
6070
- });
6071
- document.addEventListener("click", (e) => {
6072
- if (!keepCollapsed) return;
6073
- const taskRow = e.target.closest && e.target.closest('[data-testid^="task-item-"]');
6074
- if (!taskRow) return;
6075
- const key = taskRow.getAttribute("data-task-item-key") || "";
6076
- const sep = key.lastIndexOf(":");
6077
- if (sep <= 0) return;
6078
- const wsKey = key.slice(0, sep);
6079
- const wsRow = document.querySelector(`[data-testid="workspace-item-${cssEscape(wsKey)}"]`);
6080
- if (!wsRow || wsRow.getAttribute("aria-expanded") !== "false") return;
6081
- const head = wsRow.matches("[aria-expanded]") ? wsRow : wsRow.querySelector("[aria-expanded]");
6082
- if (!head) return;
6083
- collapseAfterContentLoaded(wsRow);
6084
- }, true);
6085
- document.addEventListener("click", (e) => {
6086
- const row = e.target.closest && e.target.closest('[data-testid^="workspace-item-"]');
6087
- if (row) row.__zcodeproUserTouched = Date.now();
6088
- }, true);
6089
- }
6090
- function currentTaskRow() {
6091
- for (const el of document.querySelectorAll("[data-task-item-key]")) {
6092
- if ((el.className + "").includes("bg-selected")) return el;
6093
- }
6094
- return null;
6095
- }
6096
- function collapseNavSafe(head) {
6097
- const cur = currentTaskRow();
6098
- const backKey = cur ? cur.getAttribute("data-task-item-key") : "";
6099
- head.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
6100
- if (!backKey) return;
6101
- const back = cur && cur.isConnected ? cur : document.querySelector(`[data-task-item-key="${cssEscape(backKey)}"]`);
6102
- if (back) back.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
6103
- }
6104
- function collapseAfterContentLoaded(wsRow) {
6105
- const deadline = Date.now() + 25e3;
6106
- let lastLen = (document.querySelector("main") || document.body).innerText.length;
6107
- let grewAt = 0;
6108
- let settledAt = 0;
6109
- const headOf = () => {
6110
- const h2 = wsRow.matches("[aria-expanded]") ? wsRow : wsRow.querySelector("[aria-expanded]");
6111
- return h2 || null;
6112
- };
6113
- const userTouched2 = () => wsRow.__zcodeproUserTouched && Date.now() - wsRow.__zcodeproUserTouched < 800;
6114
- const tick2 = () => {
6115
- if (!keepCollapsed || Date.now() > deadline || !wsRow.isConnected) return done();
6116
- const len = (document.querySelector("main") || document.body).innerText.length;
6117
- if (len > lastLen) grewAt = Date.now();
6118
- if (grewAt && Date.now() - grewAt >= 1e3) settledAt = settledAt || Date.now();
6119
- lastLen = len;
6120
- const head = headOf();
6121
- if (head && head.getAttribute("aria-expanded") === "true" && !userTouched2()) {
6122
- collapseNavSafe(head);
6123
- }
6124
- if (settledAt && Date.now() - settledAt >= 1e3) {
6125
- const h2 = headOf();
6126
- if (h2 && h2.getAttribute("aria-expanded") === "true" && !userTouched2()) {
6127
- collapseNavSafe(h2);
6128
- }
6129
- return done();
6130
- }
6131
- setTimeout(tick2, 200);
6132
- };
6133
- const done = () => {
6134
- wsRow.__zcodeproSuppending = false;
6135
- };
6136
- wsRow.__zcodeproSuppending = true;
6137
- setTimeout(tick2, 400);
6138
- }
6139
- function cssEscape(s) {
6140
- return String(s).replace(/(["\\\]])/g, "\\$1");
6141
- }
6142
-
6143
6830
  // src/inject/features/ws-running.js
6144
- var installed5 = false;
6831
+ var installed4 = false;
6145
6832
  var enabled3 = true;
6146
6833
  var SCAN_DEBOUNCE_MS4 = 150;
6147
6834
  var SCAN_FALLBACK_MS4 = 5e3;
@@ -6150,34 +6837,148 @@
6150
6837
  var PEEK_SETTLE_MS = 160;
6151
6838
  var PEEK_MAX_MS = 1500;
6152
6839
  var PEEK_UNMOUNT_WAIT_MS = 800;
6153
- var CONFIG_POLL_MIN_MS2 = 5e3;
6154
- var CONFIG_POLL_MAX_MS2 = 6e4;
6840
+ var CONFIG_POLL_MIN_MS = 5e3;
6841
+ var CONFIG_POLL_MAX_MS = 6e4;
6155
6842
  var TASK_SEL3 = "[data-task-item-key]";
6156
- var WS_SEL = '[data-testid^="workspace-item-"]';
6843
+ var WS_SEL = () => projectRowSelector();
6844
+ function findWsRow(ws) {
6845
+ return findProjectRow(ws);
6846
+ }
6847
+ var LOADER_FALLBACK_PATHS = [
6848
+ "M12 2v4",
6849
+ "m16.2 7.8 2.9-2.9",
6850
+ "M18 12h4",
6851
+ "m19.8 16.2-2.9 2.9",
6852
+ "M12 18v4",
6853
+ "m7.8 19.8-2.9-2.9",
6854
+ "M6 12H2",
6855
+ "m4.2 7.8 2.9-2.9"
6856
+ ];
6857
+ function makeLoaderSvg(baseClass) {
6858
+ const ns = "http://www.w3.org/2000/svg";
6859
+ const proto = document.querySelector("svg.lucide-loader");
6860
+ if (proto) {
6861
+ const clone = proto.cloneNode(true);
6862
+ const origClass = proto.getAttribute("class") || "";
6863
+ const keep = origClass.split(/\s+/).filter((c) => /^(size-|text-)/.test(c)).join(" ");
6864
+ clone.setAttribute("class", ((keep || baseClass) + " animate-spin zcodepro-ws-loader").trim());
6865
+ return clone;
6866
+ }
6867
+ const svg = document.createElementNS(ns, "svg");
6868
+ svg.setAttribute("viewBox", "0 0 24 24");
6869
+ svg.setAttribute("fill", "none");
6870
+ svg.setAttribute("stroke", "currentColor");
6871
+ svg.setAttribute("stroke-width", "2");
6872
+ svg.setAttribute("stroke-linecap", "round");
6873
+ svg.setAttribute("stroke-linejoin", "round");
6874
+ svg.setAttribute("class", (baseClass + " animate-spin zcodepro-ws-loader").trim());
6875
+ for (const d of LOADER_FALLBACK_PATHS) {
6876
+ const path = document.createElementNS(ns, "path");
6877
+ path.setAttribute("d", d);
6878
+ svg.append(path);
6879
+ }
6880
+ return svg;
6881
+ }
6882
+ function setRunningIcon(holder, on) {
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());
6891
+ }
6892
+ }
6893
+ function iconHolderOf(row) {
6894
+ if (row.hasAttribute && row.hasAttribute("data-project-id")) {
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");
6899
+ }
6900
+ function isRunningRow(el) {
6901
+ const scope = el.firstElementChild;
6902
+ if (!scope) return false;
6903
+ const svg = scope.querySelector('svg[class*="lucide-loader"]');
6904
+ return !!svg;
6905
+ }
6157
6906
  var runningByWs = /* @__PURE__ */ new Map();
6158
6907
  var peekTimers = /* @__PURE__ */ new Map();
6159
6908
  var activePeeks = /* @__PURE__ */ new Set();
6160
6909
  var peekedWs = /* @__PURE__ */ new Set();
6161
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;
6945
+ }
6946
+ }
6947
+ async function authoritativeIdle(ws) {
6948
+ const services = findServices();
6949
+ const ts = services && services.zcodeTaskService;
6950
+ if (!ts || typeof ts.listActiveTaskIds !== "function") return null;
6951
+ try {
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
+ }
6970
+ }
6162
6971
  function workspaceOf2(key) {
6163
6972
  const i = key.indexOf(":sess_");
6164
6973
  return i > 0 ? key.slice(0, i) : key;
6165
6974
  }
6166
- function findWsRow(ws) {
6167
- return document.querySelector(`[data-testid="workspace-item-${CSS.escape(ws)}"]`);
6168
- }
6169
6975
  function wsHead(row) {
6170
6976
  return row.matches("[aria-expanded]") ? row : row.querySelector("[aria-expanded]");
6171
6977
  }
6172
- function isRunningRow(el) {
6173
- const holder = el.firstElementChild && el.firstElementChild.querySelector(":scope > span");
6174
- if (!holder) return false;
6175
- return [...holder.children].some((c) => c.tagName === "svg" && (c.getAttribute("class") || "").includes("lucide-loader"));
6176
- }
6177
6978
  function domRowsOf(ws) {
6178
6979
  return [...document.querySelectorAll(TASK_SEL3)].filter((e) => workspaceOf2(e.getAttribute("data-task-item-key") || "") === ws);
6179
6980
  }
6180
- function currentTaskRow2() {
6981
+ function currentTaskRow() {
6181
6982
  for (const el of document.querySelectorAll(TASK_SEL3)) {
6182
6983
  if ((el.className + "").includes("bg-selected")) return el;
6183
6984
  }
@@ -6190,7 +6991,7 @@
6190
6991
  }
6191
6992
  };
6192
6993
  function toggleNavSafe(head) {
6193
- const cur = currentTaskRow2();
6994
+ const cur = currentTaskRow();
6194
6995
  const backKey = cur ? cur.getAttribute("data-task-item-key") : "";
6195
6996
  synthClick(head);
6196
6997
  if (!backKey) return;
@@ -6258,17 +7059,169 @@
6258
7059
  }
6259
7060
  function apply() {
6260
7061
  const seen = /* @__PURE__ */ new Set();
6261
- for (const row of document.querySelectorAll(WS_SEL)) {
6262
- const path = row.getAttribute("data-testid").slice("workspace-item-".length);
7062
+ for (const row of document.querySelectorAll(WS_SEL())) {
7063
+ const path = rowPath(row);
7064
+ if (!path) continue;
6263
7065
  seen.add(path);
6264
7066
  const head = wsHead(row);
6265
7067
  const collapsed = !head || head.getAttribute("aria-expanded") === "false";
6266
- const running = !!(enabled3 && collapsed && runningByWs.get(path) && runningByWs.get(path).size);
6267
- const icon = row.firstElementChild && row.firstElementChild.querySelector(":scope > span");
6268
- if (icon) icon.classList.toggle("zcodepro-ws-running", running);
6269
- }
7068
+ const domRunning = !!(runningByWs.get(path) && runningByWs.get(path).size);
7069
+ const normP = (v) => String(v || "").replace(/[\\/]+$/, "");
7070
+ const running = enabled3 && collapsed && (activeProjectPaths.size ? [...activeProjectPaths].some((p2) => normP(p2) === normP(path)) : domRunning);
7071
+ const icon = iconHolderOf(row);
7072
+ icon?.classList.toggle("zcodepro-ws-running", running);
7073
+ setRunningIcon(icon, running);
7074
+ }
7075
+ applySectionSpin();
6270
7076
  for (const ws of [...runningByWs.keys()]) if (!seen.has(ws)) runningByWs.delete(ws);
6271
7077
  }
7078
+ var headInfoCache = /* @__PURE__ */ new WeakMap();
7079
+ var PROJECT_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u9879\u76EE", "projects"]);
7080
+ var TASK_HEAD_TEXTS = /* @__PURE__ */ new Set(["\u4EFB\u52A1", "tasks"]);
7081
+ function kindFromHeadText(head) {
7082
+ const text = (head.textContent || "").trim().toLowerCase();
7083
+ if (PROJECT_HEAD_TEXTS.has(text)) return "project";
7084
+ if (TASK_HEAD_TEXTS.has(text)) return "task";
7085
+ return null;
7086
+ }
7087
+ function sectionHeads() {
7088
+ const heads = [];
7089
+ for (const sv of document.querySelectorAll("svg[data-purpose-section-chevron]")) {
7090
+ const btn = sv.closest("button");
7091
+ if (btn) heads.push(btn);
7092
+ }
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
+ }
7106
+ var SEC_SPIN_CLASS = "zcodepro-ws-sec-spin";
7107
+ var anyActiveCache = { at: 0, value: null, busy: false };
7108
+ var sectionActive = { task: false, project: false };
7109
+ var activeProjectPaths = /* @__PURE__ */ new Set();
7110
+ setInterval(() => {
7111
+ if (!anyActiveCache.busy && Date.now() - anyActiveCache.at >= 1e4) globalAnyActive();
7112
+ }, 1e4);
7113
+ function globalAnyActive() {
7114
+ if (anyActiveCache.value !== null && Date.now() - anyActiveCache.at < 1e4) return anyActiveCache.value;
7115
+ if (anyActiveCache.busy) return anyActiveCache.value === true;
7116
+ anyActiveCache.busy = true;
7117
+ sectionActive.task = false;
7118
+ sectionActive.project = false;
7119
+ activeProjectPaths = /* @__PURE__ */ new Set();
7120
+ void (async () => {
7121
+ let hit = null;
7122
+ try {
7123
+ const res = await rpc("/projects-v2").catch(() => null);
7124
+ const services = findServices();
7125
+ const ts = services && services.zcodeTaskService;
7126
+ if (res && res.ok && res.available && ts && typeof ts.listActiveTaskIds === "function") {
7127
+ hit = false;
7128
+ const projPaths = /* @__PURE__ */ new Set();
7129
+ for (const proj of res.projects || []) {
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
+ }
7184
+ }
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
+ }
7190
+ } catch {
7191
+ }
7192
+ if (hit !== null) anyActiveCache = { at: Date.now(), value: hit, busy: false };
7193
+ else anyActiveCache.busy = false;
7194
+ apply();
7195
+ })();
7196
+ return anyActiveCache.value === true;
7197
+ }
7198
+ function applySectionSpin() {
7199
+ if (!enabled3) {
7200
+ document.querySelectorAll("." + SEC_SPIN_CLASS).forEach((el) => el.remove());
7201
+ return;
7202
+ }
7203
+ for (const { head, cont, kind } of sectionHeads()) {
7204
+ const running = !!(cont && cont.querySelector('li[data-task-item-key] svg[class*="lucide-loader"]'));
7205
+ let expanded = true;
7206
+ if (head.tagName === "BUTTON") expanded = head.getAttribute("aria-expanded") !== "false";
7207
+ else {
7208
+ const list = head.nextElementSibling;
7209
+ expanded = !list || list.offsetHeight > 0;
7210
+ }
7211
+ if (!kind) return;
7212
+ const scoped = kind === "project" ? sectionActive.project : sectionActive.task;
7213
+ const want = !expanded && scoped;
7214
+ const existing = head.querySelector(":scope > ." + SEC_SPIN_CLASS);
7215
+ if (want && !existing) {
7216
+ const span = document.createElement("span");
7217
+ span.className = "flex size-4 shrink-0 items-center justify-center " + SEC_SPIN_CLASS;
7218
+ span.append(makeLoaderSvg("size-4"));
7219
+ head.prepend(span);
7220
+ } else if (!want && existing) {
7221
+ existing.remove();
7222
+ }
7223
+ }
7224
+ }
6272
7225
  function schedulePeek(ws, delay) {
6273
7226
  clearTimeout(peekTimers.get(ws));
6274
7227
  peekTimers.set(ws, setTimeout(() => {
@@ -6300,6 +7253,24 @@
6300
7253
  }
6301
7254
  var peekChain = Promise.resolve();
6302
7255
  async function peek(ws, opts) {
7256
+ if (!opts?.manual) {
7257
+ const auth = await authoritativeIdle(ws);
7258
+ if (auth !== null) {
7259
+ if (auth) {
7260
+ runningByWs.delete(ws);
7261
+ } else {
7262
+ let set = runningByWs.get(ws);
7263
+ if (!set) {
7264
+ set = /* @__PURE__ */ new Set();
7265
+ runningByWs.set(ws, set);
7266
+ }
7267
+ set.add(ws + ":active");
7268
+ schedulePeek(ws, PEEK_REPEAT_MS);
7269
+ }
7270
+ apply();
7271
+ return true;
7272
+ }
7273
+ }
6303
7274
  const run = () => peekInner(ws, opts);
6304
7275
  const p = peekChain.then(run, run);
6305
7276
  peekChain = p.catch(() => {
@@ -6311,7 +7282,7 @@
6311
7282
  const row = findWsRow(ws);
6312
7283
  const head = row && wsHead(row);
6313
7284
  if (!row || !head || head.getAttribute("aria-expanded") !== "false") return false;
6314
- if (!currentTaskRow2()) {
7285
+ if (!currentTaskRow()) {
6315
7286
  schedulePeek(ws, PEEK_REPEAT_MS);
6316
7287
  return false;
6317
7288
  }
@@ -6327,9 +7298,10 @@
6327
7298
  document.body.append(frozen);
6328
7299
  row.style.visibility = "hidden";
6329
7300
  const hider = installPeekHider(ws);
7301
+ let readOk = false;
6330
7302
  try {
6331
7303
  toggleNavSafe(head);
6332
- await settleAndRead(ws);
7304
+ readOk = await settleAndRead(ws);
6333
7305
  const rowNow = findWsRow(ws) || row;
6334
7306
  const headNow = wsHead(rowNow);
6335
7307
  if (headNow && headNow.getAttribute("aria-expanded") === "true" && !userTouched(rowNow)) {
@@ -6345,10 +7317,10 @@
6345
7317
  apply();
6346
7318
  const set = runningByWs.get(ws);
6347
7319
  if (set && set.size && enabled3) schedulePeek(ws, PEEK_REPEAT_MS);
6348
- return true;
7320
+ return readOk;
6349
7321
  }
6350
7322
  function wsRunningSnapshot() {
6351
- const curKey = currentTaskRow2()?.getAttribute("data-task-item-key") || "";
7323
+ const curKey = currentTaskRow()?.getAttribute("data-task-item-key") || "";
6352
7324
  return {
6353
7325
  running: [...runningByWs.entries()].filter(([, set]) => set.size > 0).map(([ws]) => ws),
6354
7326
  current: curKey ? workspaceOf2(curKey) || null : null
@@ -6378,6 +7350,7 @@
6378
7350
  const t0 = Date.now();
6379
7351
  let lastCount = -1;
6380
7352
  let stableAt = 0;
7353
+ let zeroRows = false;
6381
7354
  const timer = setInterval(() => {
6382
7355
  const rows = domRowsOf(ws);
6383
7356
  const elapsed = Date.now() - t0;
@@ -6389,7 +7362,7 @@
6389
7362
  if (!settled && elapsed < PEEK_MAX_MS) return;
6390
7363
  clearInterval(timer);
6391
7364
  if (lastCount === 0) {
6392
- runningByWs.delete(ws);
7365
+ zeroRows = true;
6393
7366
  } else {
6394
7367
  let set = runningByWs.get(ws);
6395
7368
  if (!set) {
@@ -6402,7 +7375,7 @@
6402
7375
  else set.delete(key);
6403
7376
  }
6404
7377
  }
6405
- resolve();
7378
+ resolve(!zeroRows);
6406
7379
  }, 80);
6407
7380
  });
6408
7381
  }
@@ -6443,18 +7416,18 @@
6443
7416
  }
6444
7417
  function relevant(muts) {
6445
7418
  for (const m of muts) {
6446
- if (inSel(m.target, TASK_SEL3) || inSel(m.target, WS_SEL)) return true;
7419
+ if (inSel(m.target, TASK_SEL3) || inSel(m.target, WS_SEL())) return true;
6447
7420
  for (const n of m.addedNodes) {
6448
- if (n instanceof Element && (n.matches(TASK_SEL3) || n.matches(WS_SEL) || n.querySelector(TASK_SEL3) || n.querySelector(WS_SEL))) return true;
7421
+ if (n instanceof Element && (n.matches(TASK_SEL3) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL3) || n.querySelector(WS_SEL()))) return true;
6449
7422
  }
6450
7423
  for (const n of m.removedNodes) {
6451
- if (n instanceof Element && (n.matches(TASK_SEL3) || n.matches(WS_SEL) || n.querySelector(TASK_SEL3))) return true;
7424
+ if (n instanceof Element && (n.matches(TASK_SEL3) || n.matches(WS_SEL()) || n.querySelector(TASK_SEL3))) return true;
6452
7425
  }
6453
7426
  }
6454
7427
  return false;
6455
7428
  }
6456
- var pollMs2 = CONFIG_POLL_MIN_MS2;
6457
- async function refreshConfig2() {
7429
+ var pollMs = CONFIG_POLL_MIN_MS;
7430
+ async function refreshConfig() {
6458
7431
  try {
6459
7432
  const res = await rpc("/config");
6460
7433
  if (res && res.ok && res.config && res.config.features) {
@@ -6472,19 +7445,19 @@
6472
7445
  }
6473
7446
  return false;
6474
7447
  }
6475
- function pollConfig2() {
7448
+ function pollConfig() {
6476
7449
  setTimeout(async () => {
6477
- if (document.hidden) pollMs2 = CONFIG_POLL_MAX_MS2;
6478
- else pollMs2 = await refreshConfig2() ? CONFIG_POLL_MIN_MS2 : Math.min(Math.round(pollMs2 * 1.5), CONFIG_POLL_MAX_MS2);
6479
- pollConfig2();
6480
- }, pollMs2);
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);
6481
7454
  }
6482
7455
  var scanDebounce4 = 0;
6483
7456
  function startWsRunningSpin() {
6484
- if (installed5 || typeof document === "undefined") return;
6485
- installed5 = true;
6486
- void refreshConfig2();
6487
- pollConfig2();
7457
+ if (installed4 || typeof document === "undefined") return;
7458
+ installed4 = true;
7459
+ void refreshConfig();
7460
+ pollConfig();
6488
7461
  const observer2 = new MutationObserver((muts) => {
6489
7462
  if (!relevant(muts)) return;
6490
7463
  handleRemovals(muts);
@@ -6505,14 +7478,13 @@
6505
7478
  });
6506
7479
  document.addEventListener("click", (e) => {
6507
7480
  if (!e.isTrusted) return;
6508
- const row = e.target instanceof Element && e.target.closest(WS_SEL);
7481
+ const row = e.target instanceof Element && e.target.closest(WS_SEL());
6509
7482
  if (row) wsTouchAt.set(row, Date.now());
6510
7483
  }, true);
6511
7484
  }
6512
7485
 
6513
7486
  // src/inject/features/idle-reclaim.js
6514
7487
  var CHECK_MS = 3e4;
6515
- var WS_SEL2 = '[data-testid^="workspace-item-"]';
6516
7488
  var MIN_MINUTES = 1;
6517
7489
  var MAX_MINUTES = 1440;
6518
7490
  var idleSince = /* @__PURE__ */ new Map();
@@ -6520,46 +7492,16 @@
6520
7492
  var scanDisabledLogged = false;
6521
7493
  var bootAt = Date.now();
6522
7494
  var startupSweepDone = false;
6523
- var servicesRef = null;
6524
- function findServices() {
6525
- if (servicesRef) return servicesRef;
6526
- try {
6527
- const rootEl = document.getElementById("root");
6528
- const containerKey = rootEl && Object.keys(rootEl).find((k) => k.startsWith("__reactContainer$"));
6529
- if (!containerKey) return null;
6530
- const seen = /* @__PURE__ */ new Set();
6531
- let found = null;
6532
- const scanObj = (o) => {
6533
- if (!o || typeof o !== "object" || seen.has(o) || found) return;
6534
- seen.add(o);
6535
- const ts = o.zcodeTaskService;
6536
- if (ts && typeof ts === "object" && typeof ts.releaseWorkspacePreparation === "function") found = o;
6537
- };
6538
- let visited = 0;
6539
- const visit = (f) => {
6540
- if (!f || found || visited > 6e4) return;
6541
- visited++;
6542
- for (const holder of [f.memoizedProps, f.memoizedState]) {
6543
- if (!holder || typeof holder !== "object") continue;
6544
- scanObj(holder);
6545
- for (const v of Object.values(holder)) {
6546
- if (v && typeof v === "object") scanObj(v);
6547
- }
6548
- }
6549
- visit(f.child);
6550
- visit(f.sibling);
6551
- };
6552
- visit(rootEl[containerKey]);
6553
- if (found) servicesRef = found;
6554
- return found;
6555
- } catch {
6556
- return null;
6557
- }
6558
- }
6559
- function sidebarWorkspaces() {
7495
+ async function sidebarWorkspaces() {
6560
7496
  const out = /* @__PURE__ */ new Set();
6561
- for (const el of document.querySelectorAll(WS_SEL2)) {
6562
- out.add(el.getAttribute("data-testid").slice("workspace-item-".length));
7497
+ const res = await rpc("/projects-v2").catch(() => null);
7498
+ if (res && res.ok && res.available) {
7499
+ for (const proj of res.projects || []) {
7500
+ for (const r of proj.roots || []) {
7501
+ const p = String(r.path || "").replace(/[\/]+$/, "");
7502
+ if (p) out.add(p);
7503
+ }
7504
+ }
6563
7505
  }
6564
7506
  return out;
6565
7507
  }
@@ -6578,8 +7520,14 @@
6578
7520
  }
6579
7521
  }
6580
7522
  async function tryReclaim(ws, cooldownMs) {
6581
- const verifiedIdle = await verifyWorkspaceNotRunning(ws);
6582
- if (!verifiedIdle) {
7523
+ const auth = await authoritativeIdle(ws);
7524
+ if (auth === null) {
7525
+ const verifiedIdle = await verifyWorkspaceNotRunning(ws);
7526
+ if (!verifiedIdle) {
7527
+ blockUntil.set(ws, Date.now() + cooldownMs);
7528
+ return;
7529
+ }
7530
+ } else if (!auth) {
6583
7531
  blockUntil.set(ws, Date.now() + cooldownMs);
6584
7532
  return;
6585
7533
  }
@@ -6609,7 +7557,7 @@
6609
7557
  }
6610
7558
  const busy = new Set(snap.running);
6611
7559
  busy.add(snap.current);
6612
- const workspaces = sidebarWorkspaces();
7560
+ const workspaces = await sidebarWorkspaces();
6613
7561
  for (const ws of [...idleSince.keys(), ...blockUntil.keys()]) {
6614
7562
  if (!workspaces.has(ws)) {
6615
7563
  idleSince.delete(ws);
@@ -6665,24 +7613,34 @@
6665
7613
  var SYNC_DEBOUNCE_MS = 150;
6666
7614
  var SCAN_FALLBACK_MS5 = 5e3;
6667
7615
  var ROW_SEL = "[data-task-item-key]";
6668
- var MENU_SEL = '[data-testid="task-new-button"], [data-testid="automations-open"], [data-testid="plugin-store-sidebar-open"], [data-slot="command"], [data-testid="desktop-top-nav-back"]';
7616
+ var MENU_SEL = '[data-testid="task-new-button"], [data-testid="automations-open"], [data-testid="plugin-store-sidebar-open"], [data-testid="sidebar-search-open"], [data-slot="command"], [data-testid="desktop-top-nav-back"]';
6669
7617
  var enabled4 = true;
6670
7618
  var rowEl = null;
6671
7619
  var origs = null;
6672
7620
  var syncTimer = 0;
6673
7621
  var widthObserver = null;
6674
7622
  var widthObserved = null;
6675
- function findMenu() {
6676
- const nt = document.querySelector('[data-testid="task-new-button"]');
6677
- const menu = nt?.parentElement;
6678
- return menu && menu.querySelector('[data-testid="automations-open"]') ? menu : null;
6679
- }
6680
- function originalsOf(menu) {
6681
- const newTask = menu.querySelector('[data-testid="task-new-button"]');
6682
- const search = newTask && menu.querySelector('button [class*="lucide-search"]')?.closest("button");
6683
- const auto = menu.querySelector('[data-testid="automations-open"]');
6684
- const plugin = menu.querySelector('[data-testid="plugin-store-sidebar-open"]');
6685
- return newTask && search && auto && plugin ? { menu, newTask, search, auto, plugin } : null;
7623
+ function findParts() {
7624
+ const newTask = document.querySelector('[data-testid="task-new-button"]');
7625
+ if (!newTask) return null;
7626
+ if (!isNewProjectSidebar()) {
7627
+ const menu = newTask.parentElement;
7628
+ if (!menu || !menu.querySelector('[data-testid="automations-open"]')) return null;
7629
+ const search2 = menu.querySelector('button [class*="lucide-search"]')?.closest("button");
7630
+ const auto2 = menu.querySelector('[data-testid="automations-open"]');
7631
+ const plugin2 = menu.querySelector('[data-testid="plugin-store-sidebar-open"]');
7632
+ return search2 && auto2 && plugin2 ? { newTask, search: search2, auto: auto2, plugin: plugin2, hideEls: [menu] } : null;
7633
+ }
7634
+ const search = document.querySelector('[data-testid="sidebar-search-open"]');
7635
+ const auto = document.querySelector('[data-testid="automations-open"]');
7636
+ const plugin = document.querySelector('[data-testid="plugin-store-sidebar-open"]');
7637
+ if (!search || !auto || !plugin) return null;
7638
+ const hideEls = [.../* @__PURE__ */ new Set([
7639
+ newTask.closest('[data-testid="sidebar-primary-navigation"]'),
7640
+ auto.closest('[data-testid="sidebar-primary-navigation"]'),
7641
+ search.closest('[data-testid="sidebar-search-toolbar"]')
7642
+ ])].filter(Boolean);
7643
+ return hideEls.length ? { newTask, search, auto, plugin, hideEls } : null;
6686
7644
  }
6687
7645
  function nameOf(orig, nameSel, fallback) {
6688
7646
  let name = nameSel && (orig.querySelector(nameSel)?.textContent || "").trim();
@@ -6708,6 +7666,7 @@
6708
7666
  else btn.removeAttribute("data-active");
6709
7667
  if (kind === "auto" || kind === "plugin") btn.setAttribute("aria-pressed", on ? "true" : "false");
6710
7668
  }
7669
+ var lastSelectedKey = "";
6711
7670
  function syncActive() {
6712
7671
  if (!origs || !rowEl) return;
6713
7672
  const auto = origs.auto.getAttribute("aria-pressed") === "true";
@@ -6717,23 +7676,37 @@
6717
7676
  for (const el of document.querySelectorAll(ROW_SEL)) {
6718
7677
  if ((el.className + "").includes("bg-selected")) {
6719
7678
  selected = true;
7679
+ lastSelectedKey = el.getAttribute("data-task-item-key") || lastSelectedKey;
6720
7680
  break;
6721
7681
  }
6722
7682
  }
6723
- setActive("newTask", !selected && !auto && !plugin);
7683
+ let newTaskOn = false;
7684
+ if (!selected && lastSelectedKey) {
7685
+ const stillMounted = document.querySelector(`${ROW_SEL}[data-task-item-key="${CSS.escape(lastSelectedKey)}"]`);
7686
+ if (stillMounted) {
7687
+ newTaskOn = !auto && !plugin;
7688
+ lastSelectedKey = "";
7689
+ } else {
7690
+ const btn = rowEl?.querySelector('[data-kind="newTask"]');
7691
+ newTaskOn = btn ? btn.getAttribute("data-active") === "1" : false;
7692
+ }
7693
+ } else if (!selected) {
7694
+ newTaskOn = !auto && !plugin;
7695
+ }
7696
+ setActive("newTask", newTaskOn);
6724
7697
  setActive("search", palette);
6725
7698
  setActive("auto", auto);
6726
7699
  setActive("plugin", plugin);
6727
7700
  }
6728
7701
  function rebuild() {
6729
- const menu = findMenu();
6730
- if (!menu) return false;
6731
- const next = originalsOf(menu);
7702
+ const parts = findParts();
6732
7703
  const navRow = document.querySelector('[data-testid="desktop-top-nav-back"]')?.parentElement;
6733
- if (!next || !navRow) return false;
6734
- if (origs && origs.menu !== menu) origs.menu.classList.remove(HIDE_CLASS);
6735
- menu.classList.add(HIDE_CLASS);
6736
- origs = next;
7704
+ if (!parts || !navRow) return false;
7705
+ if (origs && origs.hideEls[0] !== parts.hideEls[0]) {
7706
+ for (const el of origs.hideEls) el.classList.remove(HIDE_CLASS);
7707
+ }
7708
+ for (const el of parts.hideEls) el.classList.add(HIDE_CLASS);
7709
+ origs = parts;
6737
7710
  rowEl?.remove();
6738
7711
  navRow.classList.add("zcodepro-tb-hidden-native");
6739
7712
  const L = t();
@@ -6748,17 +7721,17 @@
6748
7721
  setTimeout(syncActive, 150);
6749
7722
  }
6750
7723
  });
6751
- const newBtn = mk("newTask", next.newTask, "span.truncate", L.tbNewTask);
6752
- const icon = iconOf(next.newTask);
7724
+ const newBtn = mk("newTask", parts.newTask, "span.truncate", L.tbNewTask);
7725
+ const icon = iconOf(parts.newTask);
6753
7726
  if (icon) newBtn.append(icon);
6754
- const searchBtn = mk("search", next.search, "span.truncate", L.tbSearch);
6755
- const sIcon = iconOf(next.search);
7727
+ const searchBtn = mk("search", parts.search, "span.truncate", L.tbSearch);
7728
+ const sIcon = iconOf(parts.search);
6756
7729
  if (sIcon) searchBtn.append(sIcon);
6757
- const autoBtn = mk("auto", next.auto, null, L.tbAutomations);
6758
- const aIcon = iconOf(next.auto);
7730
+ const autoBtn = mk("auto", parts.auto, null, L.tbAutomations);
7731
+ const aIcon = iconOf(parts.auto);
6759
7732
  if (aIcon) autoBtn.append(aIcon);
6760
- const pluginBtn = mk("plugin", next.plugin, null, L.tbPluginStore);
6761
- const pIcon = iconOf(next.plugin);
7733
+ const pluginBtn = mk("plugin", parts.plugin, null, L.tbPluginStore);
7734
+ const pIcon = iconOf(parts.plugin);
6762
7735
  if (pIcon) pluginBtn.append(pIcon);
6763
7736
  rowEl = h("div", { class: "zcodepro-tb-row" }, newBtn, searchBtn, autoBtn, pluginBtn);
6764
7737
  const updBtn = [...navRow.querySelectorAll("button")].find((b) => /bg-(success|emerald)/.test(b.className || ""));
@@ -6773,7 +7746,7 @@
6773
7746
  }
6774
7747
  var NARROW_SIDEBAR_PX = 260;
6775
7748
  function sidebarTooNarrow() {
6776
- const scroll = document.querySelector(".flex.flex-1.min-h-0.flex-col.gap-3.overflow-y-auto");
7749
+ const scroll = document.querySelector(".flex.flex-1.min-h-0.flex-col.gap-3.overflow-y-auto") || document.querySelector("aside .min-h-0.flex-1.overflow-y-auto");
6777
7750
  if (!scroll) return false;
6778
7751
  if (!widthObserver) widthObserver = new ResizeObserver(() => scheduleSync());
6779
7752
  if (widthObserved !== scroll) {
@@ -6785,18 +7758,18 @@
6785
7758
  }
6786
7759
  function sync() {
6787
7760
  if (!enabled4) return;
6788
- const menu = findMenu();
6789
- if (!menu) {
7761
+ const parts = findParts();
7762
+ if (!parts) {
6790
7763
  if (rowEl) rowEl.style.display = "none";
6791
7764
  return;
6792
7765
  }
6793
7766
  if (sidebarCollapsed() || sidebarTooNarrow()) {
6794
7767
  if (rowEl) rowEl.style.display = "none";
6795
- menu.classList.remove(HIDE_CLASS);
7768
+ for (const el of parts.hideEls) el.classList.remove(HIDE_CLASS);
6796
7769
  document.querySelectorAll(".zcodepro-tb-hidden-native").forEach((el) => el.classList.remove("zcodepro-tb-hidden-native"));
6797
7770
  return;
6798
7771
  }
6799
- const alive = origs && origs.menu === menu && origs.newTask.isConnected && origs.search.isConnected && origs.auto.isConnected && origs.plugin.isConnected && rowEl && rowEl.isConnected;
7772
+ const alive = origs && origs.hideEls[0] === parts.hideEls[0] && origs.newTask.isConnected && origs.search.isConnected && origs.auto.isConnected && origs.plugin.isConnected && rowEl && rowEl.isConnected;
6800
7773
  if (!alive && !rebuild()) {
6801
7774
  if (rowEl) rowEl.style.display = "none";
6802
7775
  setTimeout(scheduleSync, 400);
@@ -6805,7 +7778,7 @@
6805
7778
  }
6806
7779
  const navRow = document.querySelector('[data-testid="desktop-top-nav-back"]')?.parentElement;
6807
7780
  if (navRow) navRow.classList.add("zcodepro-tb-hidden-native");
6808
- menu.classList.add(HIDE_CLASS);
7781
+ for (const el of parts.hideEls) el.classList.add(HIDE_CLASS);
6809
7782
  if (rowEl) rowEl.style.display = "";
6810
7783
  syncActive();
6811
7784
  }
@@ -6839,12 +7812,12 @@
6839
7812
  rowEl?.remove();
6840
7813
  rowEl = null;
6841
7814
  if (origs) {
6842
- origs.menu.classList.remove(HIDE_CLASS);
7815
+ for (const el of origs.hideEls) el.classList.remove(HIDE_CLASS);
6843
7816
  document.querySelectorAll(".zcodepro-tb-hidden-native").forEach((el) => el.classList.remove("zcodepro-tb-hidden-native"));
6844
7817
  origs = null;
6845
7818
  }
6846
7819
  }
6847
- async function refreshConfig3() {
7820
+ async function refreshConfig2() {
6848
7821
  const cfg = await getConfig(true).catch(() => null);
6849
7822
  enabled4 = !cfg || !cfg.features || cfg.features.toolbarIcons !== false;
6850
7823
  if (enabled4) sync();
@@ -6853,9 +7826,9 @@
6853
7826
  function startToolbarIcons() {
6854
7827
  ensureStyle();
6855
7828
  window.addEventListener("zcodepro:config-changed", () => {
6856
- void refreshConfig3();
7829
+ void refreshConfig2();
6857
7830
  });
6858
- void refreshConfig3();
7831
+ void refreshConfig2();
6859
7832
  new MutationObserver((muts) => {
6860
7833
  if (relevantMutations(muts)) scheduleSync();
6861
7834
  }).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class", "aria-pressed"] });
@@ -6877,8 +7850,8 @@
6877
7850
  var syncTimer2 = 0;
6878
7851
  function findPinnedHeader() {
6879
7852
  for (const h3 of document.querySelectorAll("h3")) {
6880
- const ul = h3.nextElementSibling;
6881
- if (ul && ul.tagName === "UL" && ul.querySelector("li[data-task-item-key]")) return h3;
7853
+ const list = h3.nextElementSibling;
7854
+ if (list && list.querySelector("li[data-task-item-key]")) return h3;
6882
7855
  }
6883
7856
  return null;
6884
7857
  }
@@ -6974,7 +7947,7 @@
6974
7947
  h3.parentElement?.classList.remove(COLLAPSED_CLASS);
6975
7948
  }
6976
7949
  }
6977
- async function refreshConfig4() {
7950
+ async function refreshConfig3() {
6978
7951
  const cfg = await getConfig(true).catch(() => null);
6979
7952
  enabled5 = !cfg || !cfg.features || cfg.features.pinnedCollapse !== false;
6980
7953
  if (enabled5) sync2();
@@ -6983,9 +7956,9 @@
6983
7956
  function startPinnedCollapse() {
6984
7957
  ensureStyle();
6985
7958
  window.addEventListener("zcodepro:config-changed", () => {
6986
- void refreshConfig4();
7959
+ void refreshConfig3();
6987
7960
  });
6988
- void refreshConfig4();
7961
+ void refreshConfig3();
6989
7962
  new MutationObserver((muts) => {
6990
7963
  if (relevantMutations2(muts)) scheduleSync2();
6991
7964
  }).observe(document.body, { childList: true, subtree: true });
@@ -7060,6 +8033,10 @@
7060
8033
  void startAliasWatcher();
7061
8034
  } catch {
7062
8035
  }
8036
+ try {
8037
+ startAliasMigrationWatcher();
8038
+ } catch {
8039
+ }
7063
8040
  try {
7064
8041
  startTaskOrderWatcher();
7065
8042
  } catch {
@@ -7080,10 +8057,6 @@
7080
8057
  startImageMenu();
7081
8058
  } catch {
7082
8059
  }
7083
- try {
7084
- startPinnedExpandSuppression();
7085
- } catch {
7086
- }
7087
8060
  try {
7088
8061
  startWsRunningSpin();
7089
8062
  } catch {