zcode-pro 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/inject.js
CHANGED
|
@@ -286,20 +286,19 @@
|
|
|
286
286
|
featureNewtabPanelsDesc: "\u5B98\u65B9\u201C\u65B0\u6807\u7B7E\u9875\u201D\u53EA\u5217\u5B98\u65B9\u9762\u677F\u4E0E\u63A8\u8350\u7684\u5B98\u65B9\u63D2\u4EF6\uFF0C\u6B64\u529F\u80FD\u628A\u7B2C\u4E09\u65B9\u5E02\u573A\u63D2\u4EF6\uFF08headroom\u3001rtk \u7B49\uFF09\u7684\u9762\u677F\u5361\u7247\u52A0\u8FDB\u53BB\uFF0C\u70B9\u51FB\u5728\u4FA7\u8FB9\u9762\u677F\u6253\u5F00\u3002",
|
|
287
287
|
ntpDescSuffix: "\u63D2\u4EF6\u9762\u677F",
|
|
288
288
|
ntpNeedSession: "\u5148\u6253\u5F00\u4E00\u4E2A\u4EFB\u52A1\u4F1A\u8BDD\uFF0C\u518D\u4ECE\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u63D2\u4EF6\u9762\u677F",
|
|
289
|
-
featureStatusBar: "\u72B6\u6001\u680F\u7EDF\u8BA1",
|
|
290
289
|
featureStatusBarDesc: "\u4E3B\u754C\u9762\u5E95\u90E8\u53F3\u4E0B\u89D2\u663E\u793A\u7EDF\u8BA1\u9879\uFF1A\u4E0A\u4E0B\u6587\u5360\u7528\u3001\u4F1A\u8BDD/\u4ECA\u65E5/\u7D2F\u8BA1 token\u3001\u4EFB\u52A1\u6570\u7B49\uFF1B\u5404\u9879\u7684\u987A\u5E8F\u4E0E\u663E\u9690\u5728\u201C\u6837\u5F0F \u2192 \u72B6\u6001\u680F\u201D\u91CC\u8C03\u6574\u3002",
|
|
291
290
|
tabStylesPane: "\u6837\u5F0F\u8C03\u6574",
|
|
292
291
|
tabStatusPane: "\u72B6\u6001\u680F",
|
|
293
292
|
sbItemCtx: "\u4E0A\u4E0B\u6587\u5360\u7528",
|
|
294
293
|
sbItemQuestions: "\u63D0\u95EE\u6B21\u6570",
|
|
294
|
+
sbMaster: "\u542F\u7528\u7EDF\u8BA1",
|
|
295
|
+
sbMasterDesc: "\u603B\u5F00\u5173\uFF1A\u5173\u95ED\u540E\u5E95\u90E8\u72B6\u6001\u680F\u4E0E\u6BCF\u8F6E\u56DE\u7B54\u7684\u7528\u91CF\u6807\u6CE8\u4E00\u8D77\u505C\u7528\u3002",
|
|
295
296
|
sbGroupSession: "\u4F1A\u8BDD\u7EDF\u8BA1\uFF08\u8DDF\u968F\u5F53\u524D\u4F1A\u8BDD\uFF09",
|
|
296
297
|
sbGroupGlobal: "\u603B\u7EDF\u8BA1",
|
|
297
298
|
sbGroupTurn: "\u6BCF\u8F6E\u7EDF\u8BA1\uFF08\u56DE\u7B54\u672B\u5C3E\uFF09",
|
|
298
299
|
sbLabelIn: "\u8F93\u5165",
|
|
299
300
|
sbLabelOut: "\u8F93\u51FA",
|
|
300
301
|
sbLabelCache: "\u7F13\u5B58",
|
|
301
|
-
featureTurnUsage: "\u6BCF\u8F6E\u56DE\u7B54 token \u7528\u91CF",
|
|
302
|
-
featureTurnUsageDesc: "\u5728\u6BCF\u6761\u56DE\u7B54\u672B\u5C3E\u64CD\u4F5C\u6309\u94AE\u7684\u65F6\u95F4\u540E\u9762\u663E\u793A\u8BE5\u8F6E\u7684\u8F93\u5165/\u8F93\u51FA token\uFF08\u672C\u5730\u8BB0\u5F55\u53EA\u4FDD\u7559\u6700\u8FD1\u82E5\u5E72\u8F6E\uFF0C\u5BF9\u4E0D\u4E0A\u65F6\u95F4\u7684\u65E7\u56DE\u7B54\u4E0D\u663E\u793A\uFF09\u3002",
|
|
303
302
|
turnUsageTitle: "\u672C\u8F6E token",
|
|
304
303
|
sbLabelQuestions: "\u63D0\u95EE",
|
|
305
304
|
sbItemTodayTokens: "\u4ECA\u65E5 token",
|
|
@@ -743,20 +742,19 @@
|
|
|
743
742
|
featureNewtabPanelsDesc: 'The built-in "new tab page" only lists built-in panels and recommended official plugins; this adds cards for third-party marketplace plugin panels (headroom, rtk, \u2026) that open in the side pane.',
|
|
744
743
|
ntpDescSuffix: "plugin panel",
|
|
745
744
|
ntpNeedSession: "Open a task session first, then open plugin panels from the new tab page",
|
|
746
|
-
featureStatusBar: "Status bar statistics",
|
|
747
745
|
featureStatusBarDesc: 'Shows statistics at the bottom-right of the main view: context usage, session/today/total tokens, task count, etc.; reorder or hide each item under "Styles \u2192 Status bar".',
|
|
748
746
|
tabStylesPane: "Styles",
|
|
749
747
|
tabStatusPane: "Status bar",
|
|
750
748
|
sbItemCtx: "Context usage",
|
|
751
749
|
sbItemQuestions: "Questions asked",
|
|
750
|
+
sbMaster: "Enable statistics",
|
|
751
|
+
sbMasterDesc: "Master switch: turning this off disables both the status bar and per-turn labels.",
|
|
752
752
|
sbGroupSession: "Session statistics (follows current session)",
|
|
753
753
|
sbGroupGlobal: "Global statistics",
|
|
754
754
|
sbGroupTurn: "Per-turn statistics (answer rows)",
|
|
755
755
|
sbLabelIn: "in",
|
|
756
756
|
sbLabelOut: "out",
|
|
757
757
|
sbLabelCache: "cache",
|
|
758
|
-
featureTurnUsage: "Per-turn token usage",
|
|
759
|
-
featureTurnUsageDesc: "Shows that turn's in/out tokens after the time in each answer's action row (local records keep only the most recent turns; older answers without a match stay unlabelled).",
|
|
760
758
|
turnUsageTitle: "Turn tokens",
|
|
761
759
|
sbLabelQuestions: "asks",
|
|
762
760
|
sbItemTodayTokens: "Today tokens",
|
|
@@ -4163,16 +4161,6 @@
|
|
|
4163
4161
|
if (await setFeature("newtabPanels", next)) f.newtabPanels = next;
|
|
4164
4162
|
refreshRows();
|
|
4165
4163
|
}),
|
|
4166
|
-
settingRow(L.featureStatusBar, L.featureStatusBarDesc, f.statusBar !== false, async () => {
|
|
4167
|
-
const next = !(f.statusBar !== false);
|
|
4168
|
-
if (await setFeature("statusBar", next)) f.statusBar = next;
|
|
4169
|
-
refreshRows();
|
|
4170
|
-
}),
|
|
4171
|
-
settingRow(L.featureTurnUsage, L.featureTurnUsageDesc, f.turnUsage !== false, async () => {
|
|
4172
|
-
const next = !(f.turnUsage !== false);
|
|
4173
|
-
if (await setFeature("turnUsage", next)) f.turnUsage = next;
|
|
4174
|
-
refreshRows();
|
|
4175
|
-
}),
|
|
4176
4164
|
(() => {
|
|
4177
4165
|
const repoLink = h("span", {
|
|
4178
4166
|
class: "cursor-pointer underline-offset-4 hover:underline",
|
|
@@ -4717,8 +4705,30 @@
|
|
|
4717
4705
|
renderGroup(sbGlobalList, STATUS_GLOBAL_IDS);
|
|
4718
4706
|
};
|
|
4719
4707
|
renderSbItems();
|
|
4708
|
+
const sbPaneRerender = () => {
|
|
4709
|
+
renderSbItems();
|
|
4710
|
+
};
|
|
4711
|
+
let masterRow = null;
|
|
4712
|
+
const renderMaster = () => {
|
|
4713
|
+
const next = masterRow ? !((config.features || {}).statusBar !== false) : (config.features || {}).statusBar !== false;
|
|
4714
|
+
const fresh = settingRow(L.sbMaster, L.sbMasterDesc, (config.features || {}).statusBar !== false, async () => {
|
|
4715
|
+
const to = !((config.features || {}).statusBar !== false);
|
|
4716
|
+
const res = await rpc("/config", { method: "POST", body: { features: { statusBar: to } } });
|
|
4717
|
+
clearConfigCache();
|
|
4718
|
+
if (res.ok) {
|
|
4719
|
+
config.features = { ...config.features || {}, statusBar: to };
|
|
4720
|
+
}
|
|
4721
|
+
window.dispatchEvent(new CustomEvent("zcodepro:config-changed"));
|
|
4722
|
+
renderMaster();
|
|
4723
|
+
});
|
|
4724
|
+
fresh.setAttribute("data-zcodepro-sb-master", "1");
|
|
4725
|
+
if (masterRow) masterRow.replaceWith(fresh);
|
|
4726
|
+
masterRow = fresh;
|
|
4727
|
+
};
|
|
4728
|
+
renderMaster();
|
|
4720
4729
|
paneStylesSub2.append(
|
|
4721
|
-
|
|
4730
|
+
masterRow,
|
|
4731
|
+
h("p", { class: "mt-2 text-ui-sm/relaxed text-foreground-subtle" }, L.featureStatusBarDesc),
|
|
4722
4732
|
h("div", { class: "mt-3 mb-1 text-ui-sm font-medium" }, L.sbGroupSession),
|
|
4723
4733
|
sbList,
|
|
4724
4734
|
h("div", { class: "mt-3 mb-1 text-ui-sm font-medium" }, L.sbGroupGlobal),
|
|
@@ -7014,7 +7024,7 @@
|
|
|
7014
7024
|
}
|
|
7015
7025
|
var SEC_SPIN_CLASS = "zcodepro-ws-sec-spin";
|
|
7016
7026
|
var anyActiveCache = { at: 0, value: null, busy: false };
|
|
7017
|
-
var sectionActive = { task: false, project: false };
|
|
7027
|
+
var sectionActive = { task: false, project: false, pinned: false };
|
|
7018
7028
|
var activeProjectPaths = /* @__PURE__ */ new Set();
|
|
7019
7029
|
setInterval(() => {
|
|
7020
7030
|
if (!anyActiveCache.busy && Date.now() - anyActiveCache.at >= 1e4) globalAnyActive();
|
|
@@ -7025,6 +7035,7 @@
|
|
|
7025
7035
|
anyActiveCache.busy = true;
|
|
7026
7036
|
sectionActive.task = false;
|
|
7027
7037
|
sectionActive.project = false;
|
|
7038
|
+
sectionActive.pinned = false;
|
|
7028
7039
|
activeProjectPaths = /* @__PURE__ */ new Set();
|
|
7029
7040
|
void (async () => {
|
|
7030
7041
|
let hit = null;
|
|
@@ -7092,8 +7103,29 @@
|
|
|
7092
7103
|
}
|
|
7093
7104
|
}
|
|
7094
7105
|
const taskDomRunning = !!document.querySelector('[data-task-item-key]:not(section[data-project-id] *) svg[class*="lucide-loader"]');
|
|
7095
|
-
|
|
7096
|
-
|
|
7106
|
+
const taskLive = [...byKind.task].some(live);
|
|
7107
|
+
const projLive = [...byKind.project].some(live);
|
|
7108
|
+
if (taskLive) sectionActive.task = true;
|
|
7109
|
+
if (projLive) sectionActive.project = true;
|
|
7110
|
+
if (!taskDomRunning && taskLive && document.querySelector("[data-task-item-key]:not(section[data-project-id] *)")) {
|
|
7111
|
+
sectionActive.task = false;
|
|
7112
|
+
}
|
|
7113
|
+
for (const h3 of document.querySelectorAll("h3")) {
|
|
7114
|
+
const list = h3.nextElementSibling;
|
|
7115
|
+
if (!list) continue;
|
|
7116
|
+
for (const el of list.querySelectorAll("[data-task-item-key]")) {
|
|
7117
|
+
if (el.closest("section[data-project-id]")) continue;
|
|
7118
|
+
const k = el.getAttribute("data-task-item-key") || "";
|
|
7119
|
+
const id = k.slice(k.indexOf(":sess_") + 1);
|
|
7120
|
+
const base = k.slice(0, k.lastIndexOf(":")).replace(/[\/]+$/, "");
|
|
7121
|
+
const ids = byKindByPath.get(base) || [];
|
|
7122
|
+
if (ids.map(String).includes(id) && ids.some(live)) {
|
|
7123
|
+
sectionActive.pinned = true;
|
|
7124
|
+
break;
|
|
7125
|
+
}
|
|
7126
|
+
}
|
|
7127
|
+
if (sectionActive.pinned) break;
|
|
7128
|
+
}
|
|
7097
7129
|
hit = sectionActive.task || sectionActive.project;
|
|
7098
7130
|
}
|
|
7099
7131
|
} catch {
|
|
@@ -7118,7 +7150,7 @@
|
|
|
7118
7150
|
expanded = !list || list.offsetHeight > 0;
|
|
7119
7151
|
}
|
|
7120
7152
|
if (!kind) return;
|
|
7121
|
-
const scoped = kind === "project" ? sectionActive.project : sectionActive.task;
|
|
7153
|
+
const scoped = head.tagName === "H3" ? sectionActive.pinned : kind === "project" ? sectionActive.project : sectionActive.task;
|
|
7122
7154
|
const want = !expanded && scoped;
|
|
7123
7155
|
const existing = head.querySelector(":scope > ." + SEC_SPIN_CLASS);
|
|
7124
7156
|
if (want && !existing) {
|
|
@@ -8323,13 +8355,13 @@
|
|
|
8323
8355
|
}
|
|
8324
8356
|
function startTurnUsage() {
|
|
8325
8357
|
void getConfig().then((cfg) => {
|
|
8326
|
-
enabled5 = cfg.features ? cfg.features.
|
|
8358
|
+
enabled5 = cfg.features ? cfg.features.statusBar !== false : true;
|
|
8327
8359
|
}).catch(() => {
|
|
8328
8360
|
});
|
|
8329
8361
|
refreshTurnItems();
|
|
8330
8362
|
window.addEventListener("zcodepro:config-changed", () => {
|
|
8331
8363
|
void getConfig().then((cfg) => {
|
|
8332
|
-
enabled5 = cfg.features ? cfg.features.
|
|
8364
|
+
enabled5 = cfg.features ? cfg.features.statusBar !== false : true;
|
|
8333
8365
|
}).catch(() => {
|
|
8334
8366
|
});
|
|
8335
8367
|
refreshTurnItems();
|
package/package.json
CHANGED
package/src/host/helper.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { reorderWorkspaceTasks, reorderGroupMembers } from './taskOrder.mjs';
|
|
|
17
17
|
import { webdavRequest, webdavPutWithMkcol, webdavHttpText, parseWebdavListing, findCurl } from './webdav.mjs';
|
|
18
18
|
import { resolveZcodeExecutable } from './paths.mjs';
|
|
19
19
|
|
|
20
|
-
const VERSION = '1.
|
|
20
|
+
const VERSION = '1.3.1';
|
|
21
21
|
|
|
22
22
|
// 全局提示词固定在用户主目录:官方加载器按 HOME/USERPROFILE 拼 .zcode/AGENTS.md,
|
|
23
23
|
// 不读 ZCODE_DATA_BASE_DIR(数据根迁走时全局指令仍在原位)。
|
|
@@ -1829,8 +1829,12 @@ export function mergeAliases(localRaw, remoteRaw) {
|
|
|
1829
1829
|
function applyFeaturesPartial(base, partial) {
|
|
1830
1830
|
const out = (base && typeof base === 'object') ? base : {};
|
|
1831
1831
|
if (!partial || typeof partial !== 'object') return out;
|
|
1832
|
-
|
|
1832
|
+
const known = new Set(Object.keys(defaultConfig().features));
|
|
1833
|
+
for (const key of Object.keys(partial)) {
|
|
1834
|
+
// 布尔特性一律可存(新特性未列入 defaultConfig 时不能被丢弃),
|
|
1835
|
+
// 非布尔值只在已知键内接受
|
|
1833
1836
|
if (typeof partial[key] === 'boolean') out[key] = partial[key];
|
|
1837
|
+
else if (known.has(key)) out[key] = partial[key];
|
|
1834
1838
|
}
|
|
1835
1839
|
return out;
|
|
1836
1840
|
}
|
package/src/inject/core.js
CHANGED
|
@@ -296,20 +296,19 @@ const zh = {
|
|
|
296
296
|
featureNewtabPanelsDesc: '官方“新标签页”只列官方面板与推荐的官方插件,此功能把第三方市场插件(headroom、rtk 等)的面板卡片加进去,点击在侧边面板打开。',
|
|
297
297
|
ntpDescSuffix: '插件面板',
|
|
298
298
|
ntpNeedSession: '先打开一个任务会话,再从新标签页打开插件面板',
|
|
299
|
-
featureStatusBar: '状态栏统计',
|
|
300
299
|
featureStatusBarDesc: '主界面底部右下角显示统计项:上下文占用、会话/今日/累计 token、任务数等;各项的顺序与显隐在“样式 → 状态栏”里调整。',
|
|
301
300
|
tabStylesPane: '样式调整',
|
|
302
301
|
tabStatusPane: '状态栏',
|
|
303
302
|
sbItemCtx: '上下文占用',
|
|
304
303
|
sbItemQuestions: '提问次数',
|
|
304
|
+
sbMaster: '启用统计',
|
|
305
|
+
sbMasterDesc: '总开关:关闭后底部状态栏与每轮回答的用量标注一起停用。',
|
|
305
306
|
sbGroupSession: '会话统计(跟随当前会话)',
|
|
306
307
|
sbGroupGlobal: '总统计',
|
|
307
308
|
sbGroupTurn: '每轮统计(回答末尾)',
|
|
308
309
|
sbLabelIn: '输入',
|
|
309
310
|
sbLabelOut: '输出',
|
|
310
311
|
sbLabelCache: '缓存',
|
|
311
|
-
featureTurnUsage: '每轮回答 token 用量',
|
|
312
|
-
featureTurnUsageDesc: '在每条回答末尾操作按钮的时间后面显示该轮的输入/输出 token(本地记录只保留最近若干轮,对不上时间的旧回答不显示)。',
|
|
313
312
|
turnUsageTitle: '本轮 token',
|
|
314
313
|
sbLabelQuestions: '提问',
|
|
315
314
|
sbItemTodayTokens: '今日 token',
|
|
@@ -754,20 +753,19 @@ const en = {
|
|
|
754
753
|
featureNewtabPanelsDesc: "The built-in \"new tab page\" only lists built-in panels and recommended official plugins; this adds cards for third-party marketplace plugin panels (headroom, rtk, …) that open in the side pane.",
|
|
755
754
|
ntpDescSuffix: 'plugin panel',
|
|
756
755
|
ntpNeedSession: 'Open a task session first, then open plugin panels from the new tab page',
|
|
757
|
-
featureStatusBar: 'Status bar statistics',
|
|
758
756
|
featureStatusBarDesc: 'Shows statistics at the bottom-right of the main view: context usage, session/today/total tokens, task count, etc.; reorder or hide each item under "Styles → Status bar".',
|
|
759
757
|
tabStylesPane: 'Styles',
|
|
760
758
|
tabStatusPane: 'Status bar',
|
|
761
759
|
sbItemCtx: 'Context usage',
|
|
762
760
|
sbItemQuestions: 'Questions asked',
|
|
761
|
+
sbMaster: 'Enable statistics',
|
|
762
|
+
sbMasterDesc: 'Master switch: turning this off disables both the status bar and per-turn labels.',
|
|
763
763
|
sbGroupSession: 'Session statistics (follows current session)',
|
|
764
764
|
sbGroupGlobal: 'Global statistics',
|
|
765
765
|
sbGroupTurn: 'Per-turn statistics (answer rows)',
|
|
766
766
|
sbLabelIn: 'in',
|
|
767
767
|
sbLabelOut: 'out',
|
|
768
768
|
sbLabelCache: 'cache',
|
|
769
|
-
featureTurnUsage: 'Per-turn token usage',
|
|
770
|
-
featureTurnUsageDesc: "Shows that turn's in/out tokens after the time in each answer's action row (local records keep only the most recent turns; older answers without a match stay unlabelled).",
|
|
771
769
|
turnUsageTitle: 'Turn tokens',
|
|
772
770
|
sbLabelQuestions: 'asks',
|
|
773
771
|
sbItemTodayTokens: 'Today tokens',
|
|
@@ -375,16 +375,6 @@ export function openSettingsDialog() {
|
|
|
375
375
|
if (await setFeature('newtabPanels', next)) f.newtabPanels = next;
|
|
376
376
|
refreshRows();
|
|
377
377
|
}),
|
|
378
|
-
settingRow(L.featureStatusBar, L.featureStatusBarDesc, f.statusBar !== false, async () => {
|
|
379
|
-
const next = !(f.statusBar !== false);
|
|
380
|
-
if (await setFeature('statusBar', next)) f.statusBar = next;
|
|
381
|
-
refreshRows();
|
|
382
|
-
}),
|
|
383
|
-
settingRow(L.featureTurnUsage, L.featureTurnUsageDesc, f.turnUsage !== false, async () => {
|
|
384
|
-
const next = !(f.turnUsage !== false);
|
|
385
|
-
if (await setFeature('turnUsage', next)) f.turnUsage = next;
|
|
386
|
-
refreshRows();
|
|
387
|
-
}),
|
|
388
378
|
(() => {
|
|
389
379
|
// 标题 = “自动更新 duanluan/zcode-plugins 插件”,仓库名可点击跳转仓库
|
|
390
380
|
const repoLink = h('span', {
|
|
@@ -840,8 +830,28 @@ export function openSettingsDialog() {
|
|
|
840
830
|
renderGroup(sbGlobalList, STATUS_GLOBAL_IDS);
|
|
841
831
|
};
|
|
842
832
|
renderSbItems();
|
|
833
|
+
const sbPaneRerender = () => { renderSbItems(); };
|
|
834
|
+
// 总开关:与其它设置行完全同款 settingRow(自带开关样式);保存成功后
|
|
835
|
+
// 重建该行让开关视觉立即跟随
|
|
836
|
+
let masterRow = null;
|
|
837
|
+
const renderMaster = () => {
|
|
838
|
+
const next = masterRow ? !((config.features || {}).statusBar !== false) : ((config.features || {}).statusBar !== false);
|
|
839
|
+
const fresh = settingRow(L.sbMaster, L.sbMasterDesc, (config.features || {}).statusBar !== false, async () => {
|
|
840
|
+
const to = !((config.features || {}).statusBar !== false);
|
|
841
|
+
const res = await rpc('/config', { method: 'POST', body: { features: { statusBar: to } } });
|
|
842
|
+
clearConfigCache();
|
|
843
|
+
if (res.ok) { config.features = { ...(config.features || {}), statusBar: to }; }
|
|
844
|
+
window.dispatchEvent(new CustomEvent('zcodepro:config-changed'));
|
|
845
|
+
renderMaster();
|
|
846
|
+
});
|
|
847
|
+
fresh.setAttribute('data-zcodepro-sb-master', '1');
|
|
848
|
+
if (masterRow) masterRow.replaceWith(fresh);
|
|
849
|
+
masterRow = fresh;
|
|
850
|
+
};
|
|
851
|
+
renderMaster();
|
|
843
852
|
paneStylesSub2.append(
|
|
844
|
-
|
|
853
|
+
masterRow,
|
|
854
|
+
h('p', { class: 'mt-2 text-ui-sm/relaxed text-foreground-subtle' }, L.featureStatusBarDesc),
|
|
845
855
|
h('div', { class: 'mt-3 mb-1 text-ui-sm font-medium' }, L.sbGroupSession),
|
|
846
856
|
sbList,
|
|
847
857
|
h('div', { class: 'mt-3 mb-1 text-ui-sm font-medium' }, L.sbGroupGlobal),
|
|
@@ -178,10 +178,10 @@ async function tick() {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
export function startTurnUsage() {
|
|
181
|
-
void getConfig().then((cfg) => { enabled = cfg.features ? cfg.features.
|
|
181
|
+
void getConfig().then((cfg) => { enabled = cfg.features ? cfg.features.statusBar !== false : true; }).catch(() => {});
|
|
182
182
|
refreshTurnItems();
|
|
183
183
|
window.addEventListener('zcodepro:config-changed', () => {
|
|
184
|
-
void getConfig().then((cfg) => { enabled = cfg.features ? cfg.features.
|
|
184
|
+
void getConfig().then((cfg) => { enabled = cfg.features ? cfg.features.statusBar !== false : true; }).catch(() => {});
|
|
185
185
|
refreshTurnItems();
|
|
186
186
|
});
|
|
187
187
|
// 回答行出现即注入(去抖);数据 5 秒刷新一次
|
|
@@ -374,8 +374,10 @@ const SEC_SPIN_CLASS = 'zcodepro-ws-sec-spin';
|
|
|
374
374
|
// 尾斜杠两种形式各查一次),任一非终态会话即“有任务在跑”。10 秒节流缓存;
|
|
375
375
|
// 接口不可用(≤3.15.x)时无缓存,分区头退回 DOM 检测
|
|
376
376
|
let anyActiveCache = { at: 0, value: null, busy: false };
|
|
377
|
-
// 活跃按分区归属:task = “任务”分区(非项目工作区),project =
|
|
378
|
-
|
|
377
|
+
// 活跃按分区归属:task = “任务”分区(非项目工作区),project = “项目”分区,
|
|
378
|
+
// pinned = “已置顶”标题(置顶区任务,需单独判定——不与 task/project 混用,
|
|
379
|
+
// 否则别的分区有活跃时已置顶头也会亮)
|
|
380
|
+
const sectionActive = { task: false, project: false, pinned: false };
|
|
379
381
|
// 权威扫描发现的有活跃任务的项目路径集合(全部 root);项目行折叠态判定用
|
|
380
382
|
let activeProjectPaths = new Set();
|
|
381
383
|
// 周期复查:缓存到期就无条件重扫(不看当前值)——只在 true 时扫会有两个缺口:
|
|
@@ -390,6 +392,7 @@ function globalAnyActive() {
|
|
|
390
392
|
anyActiveCache.busy = true;
|
|
391
393
|
sectionActive.task = false;
|
|
392
394
|
sectionActive.project = false;
|
|
395
|
+
sectionActive.pinned = false;
|
|
393
396
|
activeProjectPaths = new Set();
|
|
394
397
|
void (async () => {
|
|
395
398
|
let hit = null;
|
|
@@ -465,11 +468,42 @@ function globalAnyActive() {
|
|
|
465
468
|
if (projName) for (const p2 of projectPaths.get(projName) || []) activeProjectPaths.add(p2);
|
|
466
469
|
}
|
|
467
470
|
}
|
|
468
|
-
//
|
|
469
|
-
//
|
|
471
|
+
// 任务侧加一道 DOM 确认:非项目任务行上真有 loader 在转才亮——侧栏
|
|
472
|
+
// 显示的就是真相,syncer 报告的活跃(尤其历史残留工作区)不足为凭。
|
|
473
|
+
// 但“任务”分区折叠后行整体卸载(DOM 检测失效),此时退回只信权威扫描
|
|
474
|
+
//(否则分区折叠后头永远不亮——用户实测回归)
|
|
470
475
|
const taskDomRunning = !!document.querySelector('[data-task-item-key]:not(section[data-project-id] *) svg[class*="lucide-loader"]');
|
|
471
|
-
|
|
472
|
-
|
|
476
|
+
const taskLive = [...byKind.task].some(live);
|
|
477
|
+
const projLive = [...byKind.project].some(live);
|
|
478
|
+
// 分区头亮灯各管各的:任务头只看非项目工作区,项目头只看项目工作区。
|
|
479
|
+
// 折叠后行不在场(DOM 检测失效),只信权威扫描;DOM 确认仅在非项目
|
|
480
|
+
// 任务行在场(分区展开着)时用来否决 syncer 卡滞误报
|
|
481
|
+
if (taskLive) sectionActive.task = true;
|
|
482
|
+
if (projLive) sectionActive.project = true;
|
|
483
|
+
if (!taskDomRunning && taskLive
|
|
484
|
+
&& document.querySelector('[data-task-item-key]:not(section[data-project-id] *)')) {
|
|
485
|
+
// 非项目任务行在场但全没 loader(分区展开着)→ syncer 卡滞误报
|
|
486
|
+
sectionActive.task = false;
|
|
487
|
+
}
|
|
488
|
+
// 已置顶区单独判定:取“已置顶”标题(h3)旁边列表容器内的任务行
|
|
489
|
+
// (不在任何 data-project-id 分区里),它们的 id 有活跃才亮已置顶头
|
|
490
|
+
// ——跟 task/project 分区的活跃无关
|
|
491
|
+
for (const h3 of document.querySelectorAll('h3')) {
|
|
492
|
+
const list = h3.nextElementSibling;
|
|
493
|
+
if (!list) continue;
|
|
494
|
+
for (const el of list.querySelectorAll('[data-task-item-key]')) {
|
|
495
|
+
if (el.closest('section[data-project-id]')) continue;
|
|
496
|
+
const k = el.getAttribute('data-task-item-key') || '';
|
|
497
|
+
const id = k.slice(k.indexOf(':sess_') + 1);
|
|
498
|
+
const base = k.slice(0, k.lastIndexOf(':')).replace(/[\/]+$/, '');
|
|
499
|
+
const ids = byKindByPath.get(base) || [];
|
|
500
|
+
if (ids.map(String).includes(id) && ids.some(live)) {
|
|
501
|
+
sectionActive.pinned = true;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (sectionActive.pinned) break;
|
|
506
|
+
}
|
|
473
507
|
hit = sectionActive.task || sectionActive.project;
|
|
474
508
|
}
|
|
475
509
|
} catch { /* 查询失败保持旧值 */ }
|
|
@@ -500,7 +534,9 @@ function applySectionSpin() {
|
|
|
500
534
|
expanded = !list || list.offsetHeight > 0;
|
|
501
535
|
}
|
|
502
536
|
if (!kind) return; // 折叠后解析不到归属且无缓存:跳过(不动现有图标)
|
|
503
|
-
|
|
537
|
+
// 已置顶标题(h3)单独看 pinned scope,不复用 task 的
|
|
538
|
+
const scoped = head.tagName === 'H3' ? sectionActive.pinned
|
|
539
|
+
: kind === 'project' ? sectionActive.project : sectionActive.task;
|
|
504
540
|
// 折叠态一律只信权威扫描:DOM 检测在折叠后不可靠(容器卸载后解析会落到
|
|
505
541
|
// 别的分区,多目录项目的行匹配也套不上),且权威扫描周期覆盖刷新
|
|
506
542
|
const want = !expanded && scoped;
|