- package.json name、cordis.patch.yml id/name、lib/index.js 导出、client.js 插件 id/设置命名空间/显示名默认值,全部统一为单连字符 apes-sidebar - 双连字符写法在 npm 包名和 loader 解析中易与单连字符混淆,统一后更规范
823 lines
44 KiB
JavaScript
823 lines
44 KiB
JavaScript
/**
|
||
* apes-sidebar — WorkBuddy/Tutti 风格右侧边栏增强(配置化主插件 v0.4.0)
|
||
*
|
||
* 单个 client bundle 注册四个可配置 Tab:
|
||
* - 'wb:tasks' —— WorkBuddy 式任务导航:按工作区分组的会话列表、搜索、
|
||
* 运行中徽标;升级:含「运行中任务」区(子代理拓扑 +
|
||
* 实时计数角标),一键打开/新建会话、当前会话高亮。
|
||
* - 'wb:agents' —— Tutti 式 Agent 总览:子代理/后台 agent 列表、运行状态、
|
||
* 所属工作区、一键打开(不依赖 remote.commands)。
|
||
* - 'wb:apps' —— Tutti 式应用中心:已装应用网格(Design/PPT/Video 等),
|
||
* 点击在会话视图打开。
|
||
* - 'wb:profile' —— WorkBuddy 底部用户区:当前 provider/model、连接状态、
|
||
* 设置/帮助入口。
|
||
*
|
||
* 配置项(better-sidebar 设置页「侧边卡片」,持久化在
|
||
* prefs.pluginSettings['apes-sidebar']):
|
||
* - displayName (string, 默认 'apes-sidebar') 显示名;预设 'feyOS',
|
||
* 或用户任意自定义
|
||
* - enableTasks (bool, 默认 true) 显示 Tasks Tab
|
||
* - enableAgents (bool, 默认 true) 显示 Agents Tab
|
||
* - enableApps (bool, 默认 true) 显示 Apps Tab
|
||
* - enableProfile (bool, 默认 true) 显示 Profile Tab
|
||
* - tasks.showTime / tasks.showUngrouped Tasks 子设置
|
||
*
|
||
* 发布格式:DSH client 插件协议 —— window.__ModuleLoader__.load({ id, factory })。
|
||
* 纯 JS + React.createElement,无 JSX / TS / 构建步骤。
|
||
*/
|
||
window.__ModuleLoader__.load({
|
||
id: "apes-sidebar",
|
||
factory: (require) => {
|
||
var module = { exports: {} };
|
||
var exports = module.exports;
|
||
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
||
|
||
// ---- 依赖 ----------------------------------------------------------
|
||
var react = require("react");
|
||
var primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
||
|
||
// ---- 常量 ----------------------------------------------------------
|
||
/** 插件身份(client 侧注册名,与 host 同名同 id)。 */
|
||
var name = "apes-sidebar";
|
||
/** client 侧注入的服务名。 */
|
||
var inject = [
|
||
'betterSidebar',
|
||
'sessions',
|
||
'workspaces'
|
||
];
|
||
/** 显示名预设。 */
|
||
var DISPLAY_NAME_DEFAULT = 'apes-sidebar';
|
||
var DISPLAY_NAME_PRESET_FEYOS = 'feyOS';
|
||
/** 本插件设置命名空间(prefs.pluginSettings 下的键)。 */
|
||
var SETTINGS_NS = 'apes-sidebar';
|
||
var TASKS_TAB_ID = "wb:tasks";
|
||
var AGENTS_TAB_ID = "wb:agents";
|
||
var APPS_TAB_ID = "wb:apps";
|
||
var PROFILE_TAB_ID = "wb:profile";
|
||
var TASKS_STYLE_ID = "apes-sidebar-style";
|
||
var AGENTS_STYLE_ATTR = "data-apes-sidebar-agents-styles";
|
||
var PROFILE_STYLE_ID = "apes-sidebar-profile-style";
|
||
|
||
// ---- React 简写 ----------------------------------------------------
|
||
var e = react.createElement;
|
||
var useState = react.useState;
|
||
var useEffect = react.useEffect;
|
||
var useRef = react.useRef;
|
||
var useMemo = react.useMemo;
|
||
|
||
// ---- 本地文案(zh / en) -------------------------------------------
|
||
var zh = {
|
||
"tab.tasks.title": "任务",
|
||
"tab.agents.title": "Agents",
|
||
"tab.profile.title": "Profile",
|
||
"search.placeholder": "搜索会话…",
|
||
"search.remote": "搜索中…",
|
||
"search.empty": "没有匹配的会话",
|
||
"list.empty": "暂无会话。点击工作区右侧「+」新建。",
|
||
"group.ungrouped": "未分组",
|
||
"group.new": "新建会话",
|
||
"badge.running": "运行中",
|
||
"setting.enableTasks": "任务导航 Tab",
|
||
"setting.enableTasksDesc": "按工作区+时间分组的会话列表,含搜索与运行中徽标",
|
||
"setting.enableAgents": "Agent 总览 Tab",
|
||
"setting.enableAgentsDesc": "子代理/后台 agent 列表与运行状态",
|
||
"setting.enableProfile": "Profile Tab",
|
||
"setting.enableProfileDesc": "底部用户区:模型信息与设置/帮助入口",
|
||
"setting.enableApps": "应用中心 Tab",
|
||
"setting.enableAppsDesc": "已装应用网格(Design/PPT/Video),点击在会话视图打开",
|
||
"apps.title": "应用中心",
|
||
"apps.hint": "点击应用在会话视图打开;也可在会话顶栏视图切换",
|
||
"apps.open": "打开",
|
||
"apps.notFound": "未检测到该应用(可能未安装)",
|
||
"setting.showTime": "显示相对时间",
|
||
"setting.showTimeDesc": "会话行右侧显示最后活动时间",
|
||
"setting.showUngrouped": "显示未分组会话",
|
||
"setting.showUngroupedDesc": "未归入任何工作区的会话单独列出",
|
||
"agents.empty": "当前没有运行中的子代理/后台 agent",
|
||
"agents.hint": "子代理启动后出现在这里,点击可跳转",
|
||
"agents.childOf": "子代理",
|
||
"agents.done": "完成",
|
||
"agents.running": "运行中",
|
||
"agents.open": "打开",
|
||
"agents.roomsDisabled": "团队房间依赖 dsh-background-agents(当前与 DSH 基座存在兼容冲突,暂不可用)",
|
||
"profile.status": "状态",
|
||
"profile.connected": "已连接",
|
||
"profile.disconnected": "未连接",
|
||
"profile.provider": "Provider",
|
||
"profile.model": "模型",
|
||
"profile.settings": "设置",
|
||
"profile.help": "帮助",
|
||
"profile.footer": "apes-sidebar 0.4.0 · WorkBuddy/Tutti 风格增强"
|
||
};
|
||
var en = {
|
||
"tab.tasks.title": "Tasks",
|
||
"tab.agents.title": "Agents",
|
||
"tab.profile.title": "Profile",
|
||
"search.placeholder": "Search sessions…",
|
||
"search.remote": "Searching…",
|
||
"search.empty": "No matching sessions",
|
||
"list.empty": "No sessions. Click "+" next to a workspace to create one.",
|
||
"group.ungrouped": "Ungrouped",
|
||
"group.new": "New session",
|
||
"badge.running": "Running",
|
||
"setting.enableTasks": "Tasks tab",
|
||
"setting.enableTasksDesc": "Workspace-grouped session list with search and running badges",
|
||
"setting.enableAgents": "Agents tab",
|
||
"setting.enableAgentsDesc": "Subagent / background agent list and status",
|
||
"setting.enableProfile": "Profile tab",
|
||
"setting.enableProfileDesc": "Bottom user area: model info + settings/help",
|
||
"setting.enableApps": "Apps tab",
|
||
"setting.enableAppsDesc": "Installed app grid (Design/PPT/Video), click to open in conversation view",
|
||
"apps.title": "Apps",
|
||
"apps.hint": "Click an app to open it in the conversation view; also switchable in the view bar",
|
||
"apps.open": "Open",
|
||
"apps.notFound": "App not detected (maybe not installed)",
|
||
"setting.showTime": "Show relative time",
|
||
"setting.showTimeDesc": "Show last activity time on session rows",
|
||
"setting.showUngrouped": "Show ungrouped sessions",
|
||
"setting.showUngroupedDesc": "List sessions not in any workspace separately",
|
||
"agents.empty": "No running subagents / background agents",
|
||
"agents.hint": "Subagents appear here; click to jump",
|
||
"agents.childOf": "subagent",
|
||
"agents.done": "done",
|
||
"agents.running": "running",
|
||
"agents.open": "open",
|
||
"agents.roomsDisabled": "Team rooms require dsh-background-agents (currently incompatible with the DSH base; unavailable)",
|
||
"profile.status": "Status",
|
||
"profile.connected": "Connected",
|
||
"profile.disconnected": "Disconnected",
|
||
"profile.provider": "Provider",
|
||
"profile.model": "Model",
|
||
"profile.settings": "Settings",
|
||
"profile.help": "Help",
|
||
"profile.footer": "apes-sidebar 0.4.0 · WorkBuddy/Tutti style enhancement"
|
||
};
|
||
|
||
function isZh() {
|
||
try { return (typeof navigator !== 'undefined' && /zh/i.test(navigator.language || '')); } catch (err) { return true; }
|
||
}
|
||
function t(key, params) {
|
||
var dict = isZh() ? zh : en;
|
||
var text = dict[key] !== void 0 ? dict[key] : key;
|
||
if (params) {
|
||
for (var k in params) {
|
||
if (Object.prototype.hasOwnProperty.call(params, k)) {
|
||
text = text.split('{' + k + '}').join(String(params[k]));
|
||
}
|
||
}
|
||
}
|
||
return text;
|
||
}
|
||
|
||
// ---- 样式注入(DSH CSS 变量) --------------------------------------
|
||
function injectStyles(styleId, cssText) {
|
||
try {
|
||
if (document.head.querySelector('style[data-wb-style="' + styleId + '"]')) return;
|
||
var tag = document.createElement("style");
|
||
tag.setAttribute('data-wb-style', styleId);
|
||
tag.textContent = cssText;
|
||
document.head.appendChild(tag);
|
||
} catch (err) { /* ignore */ }
|
||
}
|
||
function disposeStyles(styleId) {
|
||
try {
|
||
var el = document.head.querySelector('style[data-wb-style="' + styleId + '"]');
|
||
if (el && typeof el.remove === 'function') el.remove();
|
||
} catch (err) { /* ignore */ }
|
||
}
|
||
|
||
// ====================================================================
|
||
// 配置读写(better-sidebar 设置)
|
||
// ====================================================================
|
||
/** 读取本插件的设置快照(防御性,读不到返回默认值)。 */
|
||
function readSettings(store) {
|
||
var defs = { displayName: DISPLAY_NAME_DEFAULT, enableTasks: true, enableAgents: true, enableApps: true, enableProfile: true };
|
||
try {
|
||
var raw = store && store.prefs && store.prefs.pluginSettings ? store.prefs.pluginSettings[SETTINGS_NS] : null;
|
||
if (raw && typeof raw === 'object') {
|
||
return {
|
||
displayName: typeof raw.displayName === 'string' && raw.displayName.trim() !== '' ? raw.displayName.trim() : DISPLAY_NAME_DEFAULT,
|
||
enableTasks: raw.enableTasks !== false,
|
||
enableAgents: raw.enableAgents !== false,
|
||
enableApps: raw.enableApps !== false,
|
||
enableProfile: raw.enableProfile !== false
|
||
};
|
||
}
|
||
} catch (err) { /* ignore */ }
|
||
return defs;
|
||
}
|
||
/** 当前显示名(设置里的 displayName,默认 apes-sidebar)。 */
|
||
function displayNameOf(ctx) {
|
||
try {
|
||
var bs = ctx.get ? ctx.get('betterSidebar') : null;
|
||
var settings = readSettings(bs && bs.store ? bs.store : null);
|
||
return settings.displayName;
|
||
} catch (err) { return DISPLAY_NAME_DEFAULT; }
|
||
}
|
||
|
||
// ====================================================================
|
||
// Tasks Tab(WorkBuddy 式任务导航)
|
||
// ====================================================================
|
||
var TASKS_CSS = [
|
||
'#' + TASKS_STYLE_ID + '-root{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,#1f2329);font-size:13px;line-height:1.5}',
|
||
'#' + TASKS_STYLE_ID + '-root *{box-sizing:border-box}',
|
||
'#' + TASKS_STYLE_ID + '-search{flex:0 0 auto;display:flex;align-items:center;gap:6px;margin:8px 10px 6px;padding:5px 8px;border:1px solid var(--dsw-alias-border-l2,transparent);border-radius:6px;background:var(--dsw-alias-bg-layer-1,transparent)}',
|
||
'#' + TASKS_STYLE_ID + '-search:focus-within{border-color:var(--dsw-alias-brand-primary,#3370ff)}',
|
||
'#' + TASKS_STYLE_ID + '-search input{flex:1;min-width:0;border:0;outline:0;background:transparent;color:var(--dsw-alias-label-primary,#1f2329);font-size:13px}',
|
||
'#' + TASKS_STYLE_ID + '-search input::placeholder{color:var(--dsw-alias-label-tertiary,#8f959e)}',
|
||
'#' + TASKS_STYLE_ID + '-search-icon{display:inline-flex;color:var(--dsw-alias-label-tertiary,#8f959e)}',
|
||
'#' + TASKS_STYLE_ID + '-clear{flex:0 0 auto;border:0;background:transparent;cursor:pointer;color:var(--dsw-alias-label-tertiary,#8f959e);padding:0 2px;line-height:1}',
|
||
'#' + TASKS_STYLE_ID + '-clear:hover{color:var(--dsw-alias-label-primary,#1f2329)}',
|
||
'#' + TASKS_STYLE_ID + '-list{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0 4px 12px}',
|
||
'#' + TASKS_STYLE_ID + '-hint{padding:20px 14px;color:var(--dsw-alias-label-tertiary,#8f959e);text-align:center;font-size:12px}',
|
||
'#' + TASKS_STYLE_ID + '-group{margin:6px 4px 2px}',
|
||
'#' + TASKS_STYLE_ID + '-group-head{display:flex;align-items:center;gap:6px;padding:6px 8px;border-radius:6px;cursor:pointer;user-select:none}',
|
||
'#' + TASKS_STYLE_ID + '-group-head:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'#' + TASKS_STYLE_ID + '-group-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary,#5c6069);font-weight:600;font-size:12px}',
|
||
'#' + TASKS_STYLE_ID + '-group-count{flex:0 0 auto;color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px}',
|
||
'#' + TASKS_STYLE_ID + '-group-add{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border:0;border-radius:4px;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#5c6069)}',
|
||
'#' + TASKS_STYLE_ID + '-group-add:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04));color:var(--dsw-alias-label-primary,#1f2329)}',
|
||
'#' + TASKS_STYLE_ID + '-row{box-sizing:border-box;width:100%;padding:6px 8px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:8px;color:var(--dsw-alias-label-primary,#1f2329);position:relative}',
|
||
'#' + TASKS_STYLE_ID + '-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'#' + TASKS_STYLE_ID + '-row.is-active{background:var(--dsw-alias-interactive-bg-active,rgba(51,112,255,.1))}',
|
||
'#' + TASKS_STYLE_ID + '-row.is-active::before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:3px;background:var(--dsw-alias-brand-primary,#3370ff)}',
|
||
'#' + TASKS_STYLE_ID + '-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-tertiary,#8f959e)}',
|
||
'#' + TASKS_STYLE_ID + '-dot.is-running{background:var(--dsw-alias-state-success-primary,#22c55e);animation:wb-pulse 1.6s ease-in-out infinite}',
|
||
'@keyframes wb-pulse{0%,100%{opacity:1}50%{opacity:.35}}',
|
||
'#' + TASKS_STYLE_ID + '-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}',
|
||
'#' + TASKS_STYLE_ID + '-time{flex:0 0 auto;color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px}',
|
||
'#' + TASKS_STYLE_ID + '-badge{flex:0 0 auto;padding:1px 6px;border-radius:999px;background:rgba(34,197,94,.12);color:var(--dsw-alias-state-success-primary,#16a34a);font-size:10px;font-weight:600}',
|
||
'#' + TASKS_STYLE_ID + '-tasks{flex:0 0 auto;margin:0 10px 2px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08));border-radius:8px;background:var(--dsw-alias-bg-layer-1,transparent)}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-head{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#5c6069);margin-bottom:6px}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-count{margin-left:auto;padding:1px 7px;border-radius:999px;background:rgba(34,197,94,.12);color:var(--dsw-alias-state-success-primary,#16a34a);font-size:10px}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-row{display:flex;align-items:center;gap:8px;padding:4px 2px;border-radius:6px;cursor:pointer;font-size:12px}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
|
||
'#' + TASKS_STYLE_ID + '-tasks-none{color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px;padding:2px 0}'
|
||
].join('\n');
|
||
|
||
function sessionsSnapshot(ctx) {
|
||
try { return ctx.sessions && ctx.sessions.list ? ctx.sessions.list.getSnapshot() : { current: null, byId: {} }; }
|
||
catch (err) { return { current: null, byId: {} }; }
|
||
}
|
||
function workspacesSnapshot(ctx) {
|
||
try { return ctx.workspaces && ctx.workspaces.list ? ctx.workspaces.list.getSnapshot() : { items: [] }; }
|
||
catch (err) { return { items: [] }; }
|
||
}
|
||
function sessionTitleOf(session) {
|
||
if (!session) return '';
|
||
return session.title || session.displayTitle || session.name || '';
|
||
}
|
||
function sessionUpdatedAt(session) {
|
||
if (!session) return 0;
|
||
var v = session.updatedAt !== void 0 ? session.updatedAt
|
||
: session.lastActive !== void 0 ? session.lastActive
|
||
: session.lastUpdatedAt !== void 0 ? session.lastUpdatedAt
|
||
: session.updated !== void 0 ? session.updated : 0;
|
||
return typeof v === 'number' ? v : Date.parse(String(v)) || 0;
|
||
}
|
||
|
||
/** useStoreSnapshot:手动 subscribe + 快照引用变化才 setState。 */
|
||
function useStoreSnapshot(ctx, storeName, getSnapshot) {
|
||
var snap = useState(function () { return getSnapshot(); })[0];
|
||
var setSnap = useState(function () { return function () {}; })[1];
|
||
// 用 update 方式:subscribe 回调里比较引用
|
||
var updater = useState(null)[1];
|
||
useEffect(function () {
|
||
var store = null;
|
||
try {
|
||
if (storeName === 'sessions') store = ctx.sessions && ctx.sessions.list;
|
||
else if (storeName === 'workspaces') store = ctx.workspaces && ctx.workspaces.list;
|
||
} catch (err) { store = null; }
|
||
if (!store || typeof store.subscribe !== 'function') return function () {};
|
||
var off = store.subscribe(function () {
|
||
var next = getSnapshot();
|
||
updater(function (prev) { return prev === next ? prev : next; });
|
||
});
|
||
return off;
|
||
}, [storeName]);
|
||
return snap;
|
||
}
|
||
|
||
/** Tasks 主视图。 */
|
||
function TasksView(props) {
|
||
var ctx = props.ctx;
|
||
var sessions = useStoreSnapshot(ctx, 'sessions', function () { return sessionsSnapshot(ctx); });
|
||
var workspaces = useStoreSnapshot(ctx, 'workspaces', function () { return workspacesSnapshot(ctx); });
|
||
var query = useState('')[0];
|
||
var setQuery = useState('')[1];
|
||
var expanded = useState({})[0];
|
||
var setExpanded = useState({})[1];
|
||
var currentId = (props.scope && props.scope.sessionId) || sessions.current || null;
|
||
var byId = sessions.byId || {};
|
||
var items = workspaces.items || [];
|
||
|
||
var groups = [];
|
||
var seen = {};
|
||
for (var i = 0; i < items.length; i++) {
|
||
var ws = items[i];
|
||
var wsId = ws.id || ws.workspaceId || 'ws-' + i;
|
||
var members = [];
|
||
var wsSessions = ws.sessionIds || ws.sessions || [];
|
||
for (var j = 0; j < wsSessions.length; j++) {
|
||
var sid = wsSessions[j];
|
||
if (byId[sid]) { members.push(byId[sid]); seen[sid] = true; }
|
||
}
|
||
members.sort(byRecency);
|
||
groups.push({ id: wsId, title: ws.title || ws.name || wsId, sessions: members, count: members.length });
|
||
}
|
||
var ungrouped = [];
|
||
var allIds = Object.keys(byId);
|
||
for (var k = 0; k < allIds.length; k++) {
|
||
if (!seen[allIds[k]]) ungrouped.push(byId[allIds[k]]);
|
||
}
|
||
ungrouped.sort(byRecency);
|
||
|
||
var q = (query || '').trim().toLowerCase();
|
||
var searchActive = q.length > 0;
|
||
var filterFn = function (s) {
|
||
if (!searchActive) return true;
|
||
var title = sessionTitleOf(s).toLowerCase();
|
||
var id = (s.id || '').toLowerCase();
|
||
var cwd = (s.cwd || '').toLowerCase();
|
||
return title.indexOf(q) !== -1 || id.indexOf(q) !== -1 || cwd.indexOf(q) !== -1;
|
||
};
|
||
|
||
var children = [];
|
||
if (searchActive) {
|
||
var hits = [];
|
||
for (var m = 0; m < groups.length; m++) {
|
||
for (var n = 0; n < groups[m].sessions.length; n++) {
|
||
var s = groups[m].sessions[n];
|
||
if (filterFn(s)) hits.push(s);
|
||
}
|
||
}
|
||
for (var p = 0; p < ungrouped.length; p++) { if (filterFn(ungrouped[p])) hits.push(ungrouped[p]); }
|
||
if (!hits.length) {
|
||
children.push(e('div', { key: 'empty', className: TASKS_STYLE_ID + '-hint' }, t('search.empty')));
|
||
} else {
|
||
children.push(e('div', { key: 'searchsec' },
|
||
hits.map(function (s) { return sessionRow(ctx, s, currentId); })));
|
||
}
|
||
} else {
|
||
var hasAny = groups.length > 0 || ungrouped.length > 0;
|
||
if (!hasAny) {
|
||
children.push(e('div', { key: 'empty', className: TASKS_STYLE_ID + '-hint' }, t('list.empty')));
|
||
}
|
||
for (var g = 0; g < groups.length; g++) {
|
||
var group = groups[g];
|
||
var isOpen = expanded[group.id] !== false;
|
||
children.push(e('div', { key: group.id, className: TASKS_STYLE_ID + '-group' },
|
||
e('div', { key: 'h', className: TASKS_STYLE_ID + '-group-head', onClick: function (ev) {
|
||
ev.stopPropagation();
|
||
var gid = group.id;
|
||
setExpanded(function (prev) {
|
||
var next = {};
|
||
for (var kk in prev) next[kk] = prev[kk];
|
||
next[gid] = prev[gid] === false;
|
||
return next;
|
||
});
|
||
} },
|
||
e('span', { className: TASKS_STYLE_ID + '-group-title' }, group.title),
|
||
e('span', { className: TASKS_STYLE_ID + '-group-count' }, String(group.count)),
|
||
e('button', { type: 'button', className: TASKS_STYLE_ID + '-group-add', title: t('group.new'),
|
||
onClick: function (ev) { ev.stopPropagation(); try { ctx.workspaces.startSession(group.id).catch(function () {}); } catch (err) {} } }, '+')),
|
||
isOpen ? group.sessions.map(function (s) { return sessionRow(ctx, s, currentId); }) : null));
|
||
}
|
||
var showUngrouped = true;
|
||
try {
|
||
var prefs = props.store && props.store.prefs ? props.store.prefs.pluginSettings : null;
|
||
if (prefs && prefs[TASKS_TAB_ID] && prefs[TASKS_TAB_ID].showUngrouped === false) showUngrouped = false;
|
||
} catch (err) { }
|
||
if (ungrouped.length && showUngrouped) {
|
||
children.push(e('div', { key: 'ungrouped', className: TASKS_STYLE_ID + '-group' },
|
||
e('div', { key: 'h', className: TASKS_STYLE_ID + '-group-head' },
|
||
e('span', { className: TASKS_STYLE_ID + '-group-title' }, t('group.ungrouped')),
|
||
e('span', { className: TASKS_STYLE_ID + '-group-count' }, String(ungrouped.length))),
|
||
ungrouped.map(function (s) { return sessionRow(ctx, s, currentId); })));
|
||
}
|
||
}
|
||
|
||
// 「运行中任务」区:当前会话的子代理拓扑(运行中优先),实时计数
|
||
var runningChildren = [];
|
||
var allIds = Object.keys(byId || {});
|
||
for (var ri = 0; ri < allIds.length; ri++) {
|
||
var rid = allIds[ri];
|
||
var rentry = byId[rid];
|
||
if (!rentry) continue;
|
||
if (rid === currentId) continue;
|
||
var rp = rentry.parentSessionId || rentry.parentId || rentry.parent;
|
||
var isChild = (rp && rp === currentId) || (currentId && (rid.indexOf(currentId + ':') === 0 || rid.indexOf(currentId + '/') === 0));
|
||
if (!isChild) continue;
|
||
runningChildren.push({
|
||
id: rid,
|
||
title: sessionTitleOf(rentry) || rid,
|
||
running: rentry.running === true
|
||
});
|
||
}
|
||
runningChildren.sort(function (a, b) { return (a.running === b.running) ? 0 : (a.running ? -1 : 1); });
|
||
|
||
return e('div', { id: TASKS_STYLE_ID + '-root' },
|
||
runningChildren.length > 0 ? e('div', { className: TASKS_STYLE_ID + '-tasks' },
|
||
e('div', { className: TASKS_STYLE_ID + '-tasks-head' },
|
||
'运行中任务',
|
||
e('span', { className: TASKS_STYLE_ID + '-tasks-count' }, String(runningChildren.length))),
|
||
runningChildren.map(function (rc) {
|
||
return e('div', { key: rc.id, className: TASKS_STYLE_ID + '-tasks-row', title: rc.id,
|
||
onClick: function () { try { ctx.sessions.open(rc.id); } catch (err) {} } },
|
||
e('span', { className: TASKS_STYLE_ID + '-dot' + (rc.running ? ' is-running' : '') }),
|
||
e('span', { className: TASKS_STYLE_ID + '-tasks-name' }, rc.title));
|
||
})) : null,
|
||
e('div', { className: TASKS_STYLE_ID + '-search' },
|
||
e('span', { className: TASKS_STYLE_ID + '-search-icon' }, '⌕'),
|
||
e('input', { placeholder: t('search.placeholder'), value: query,
|
||
onChange: function (ev) { setQuery(ev.target.value); } }),
|
||
query ? e('button', { type: 'button', className: TASKS_STYLE_ID + '-clear', onClick: function () { setQuery(''); } }, '✕') : null),
|
||
e('div', { className: TASKS_STYLE_ID + '-list' }, children));
|
||
}
|
||
|
||
function byRecency(a, b) {
|
||
var ta = sessionUpdatedAt(a);
|
||
var tb = sessionUpdatedAt(b);
|
||
if (ta !== tb) return tb - ta;
|
||
return String(a.id || '').localeCompare(String(b.id || ''));
|
||
}
|
||
|
||
function sessionRow(ctx, s, currentId) {
|
||
var sid = s.id || s.sessionId || '';
|
||
var running = s.running === true;
|
||
var isActive = sid === currentId;
|
||
return e('div', { key: sid, className: TASKS_STYLE_ID + '-row' + (isActive ? ' is-active' : ''),
|
||
onClick: function () { try { ctx.sessions.open(sid); } catch (err) {} } },
|
||
e('span', { className: TASKS_STYLE_ID + '-dot' + (running ? ' is-running' : '') }),
|
||
e('span', { className: TASKS_STYLE_ID + '-title', title: sid }, sessionTitleOf(s) || sid),
|
||
running ? e('span', { className: TASKS_STYLE_ID + '-badge' }, t('badge.running')) : null);
|
||
}
|
||
|
||
function tasksBadge(ctx, scope, state) {
|
||
try {
|
||
var snap = sessionsSnapshot(ctx);
|
||
var currentId = (scope && scope.sessionId) || snap.current || null;
|
||
var count = 0;
|
||
var byId = snap.byId || {};
|
||
for (var id in byId) {
|
||
if (Object.prototype.hasOwnProperty.call(byId, id) && byId[id] && byId[id].running === true) count += 1;
|
||
}
|
||
return count > 0 ? count : null;
|
||
} catch (err) { return null; }
|
||
}
|
||
|
||
function tasksTabDescriptor(ctx) {
|
||
return {
|
||
id: TASKS_TAB_ID,
|
||
title: function () { return t('tab.tasks.title'); },
|
||
icon: function (size) { return e(primitives.IconListPenOutline16, { size: size }); },
|
||
order: 100,
|
||
single: true,
|
||
badge: function (bctx, scope, state) { return tasksBadge(bctx, scope, state); },
|
||
settings: {
|
||
pluginToggles: [
|
||
{ key: "showTime", title: function () { return t('setting.showTime'); }, desc: function () { return t('setting.showTimeDesc'); } },
|
||
{ key: "showUngrouped", title: function () { return t('setting.showUngrouped'); }, desc: function () { return t('setting.showUngroupedDesc'); } }
|
||
]
|
||
},
|
||
component: function (props) { return e(TasksView, props); }
|
||
};
|
||
}
|
||
|
||
// ====================================================================
|
||
// Agents Tab(Tutti 式 Agent 总览)—— 不依赖 remote.commands
|
||
// ====================================================================
|
||
var AGENTS_CSS = [
|
||
'[data-wb-agents-styles]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,#1f2329);font-size:13px;line-height:1.5}',
|
||
'[data-wb-agents-styles] *{box-sizing:border-box}',
|
||
'.wb-agents-toolbar{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08))}',
|
||
'.wb-agents-title{flex:1;font-weight:600;font-size:13px}',
|
||
'.wb-agents-count{font-size:11px;color:var(--dsw-alias-label-tertiary,#8f959e);background:rgba(34,197,94,.12);padding:2px 8px;border-radius:999px}',
|
||
'.wb-agents-refresh{flex:0 0 auto;border:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08));background:transparent;color:var(--dsw-alias-label-secondary,#5c6069);border-radius:6px;padding:3px 10px;cursor:pointer;font-size:12px}',
|
||
'.wb-agents-refresh:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'.wb-agents-list{flex:1 1 auto;min-height:0;overflow-y:auto;padding:6px 8px}',
|
||
'.wb-agents-hint{padding:24px 14px;color:var(--dsw-alias-label-tertiary,#8f959e);text-align:center;font-size:12px}',
|
||
'.wb-agents-row{box-sizing:border-box;width:100%;padding:8px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:8px}',
|
||
'.wb-agents-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'.wb-agents-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-tertiary,#8f959e)}',
|
||
'.wb-agents-dot.is-running{background:var(--dsw-alias-state-success-primary,#22c55e);animation:wb-agents-pulse 1.6s ease-in-out infinite}',
|
||
'@keyframes wb-agents-pulse{0%,100%{opacity:1}50%{opacity:.35}}',
|
||
'.wb-agents-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}',
|
||
'.wb-agents-meta{color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px;flex:0 0 auto;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
|
||
'.wb-agents-tag{flex:0 0 auto;padding:1px 6px;border-radius:999px;font-size:10px;font-weight:600}',
|
||
'.wb-agents-tag.running{background:rgba(34,197,94,.12);color:var(--dsw-alias-state-success-primary,#16a34a)}',
|
||
'.wb-agents-tag.done{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04));color:var(--dsw-alias-label-tertiary,#8f959e)}',
|
||
'.wb-agents-rooms-note{margin:8px 10px;padding:8px 10px;border:1px dashed var(--dsw-alias-border-l2,rgba(31,35,41,.15));border-radius:8px;color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px;line-height:1.5}'
|
||
].join('\n');
|
||
|
||
/** 判定一个会话是否为子代理/后台 agent(防御性,多信号)。 */
|
||
function isSubagentLike(sessionId, entry, byId, currentId) {
|
||
if (!entry || !sessionId || sessionId === currentId) return false;
|
||
if (entry.kind === 'subagent' || entry.kind === 'continuable' || entry.agentId) return true;
|
||
var parent = entry.parentSessionId || entry.parentId || entry.parent || (entry.scope && entry.scope.parentSessionId);
|
||
if (parent && byId[parent]) return true;
|
||
if (entry.running === true) {
|
||
// running 的非顶层会话视作活跃子代理候选
|
||
if (sessionId.indexOf(currentId + ':') === 0 || sessionId.indexOf(currentId + '/') === 0) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/** 子代理行列表:当前会话的直接子代理优先,其次其他运行中的子代理。 */
|
||
function subagentRows(ctx, scope) {
|
||
var snap = sessionsSnapshot(ctx);
|
||
var byId = snap.byId || {};
|
||
var currentId = (scope && scope.sessionId) || snap.current || null;
|
||
var rows = [];
|
||
for (var id in byId) {
|
||
if (!Object.prototype.hasOwnProperty.call(byId, id)) continue;
|
||
var entry = byId[id];
|
||
if (!isSubagentLike(id, entry, byId, currentId)) continue;
|
||
var title = entry.title || entry.displayTitle || entry.name || '';
|
||
if (!title) title = String(id).slice(0, 24);
|
||
rows.push({
|
||
id: id,
|
||
title: title,
|
||
running: entry.running === true,
|
||
cwd: entry.cwd || '',
|
||
workspace: entry.cwd ? String(entry.cwd).split('/').filter(Boolean).slice(-1)[0] || '' : '',
|
||
parentId: entry.parentSessionId || entry.parentId || entry.parent || '',
|
||
relatedToCurrent: currentId ? (id.indexOf(currentId + ':') === 0 || id.indexOf(currentId + '/') === 0 || entry.parentSessionId === currentId || entry.parentId === currentId) : false
|
||
});
|
||
}
|
||
rows.sort(function (a, b) {
|
||
if (a.relatedToCurrent !== b.relatedToCurrent) return a.relatedToCurrent ? -1 : 1;
|
||
if (a.running !== b.running) return a.running ? -1 : 1;
|
||
return String(a.id).localeCompare(String(b.id));
|
||
});
|
||
return rows;
|
||
}
|
||
|
||
function agentsBadge(ctx, scope, state) {
|
||
try {
|
||
var rows = subagentRows(ctx, scope);
|
||
var running = 0;
|
||
for (var i = 0; i < rows.length; i++) if (rows[i].running) running += 1;
|
||
return running > 0 ? running : null;
|
||
} catch (err) { return null; }
|
||
}
|
||
|
||
function AgentsView(props) {
|
||
var ctx = props.ctx;
|
||
var scope = props.scope;
|
||
var refreshTick = useState(0)[0];
|
||
var setRefreshTick = useState(0)[1];
|
||
var sessions = useStoreSnapshot(ctx, 'sessions', function () { return sessionsSnapshot(ctx); });
|
||
var rows = subagentRows(ctx, scope);
|
||
var running = 0;
|
||
for (var i = 0; i < rows.length; i++) if (rows[i].running) running += 1;
|
||
|
||
return e('div', { 'data-wb-agents-styles': '' },
|
||
e('div', { className: 'wb-agents-toolbar' },
|
||
e('span', { className: 'wb-agents-title' }, t('tab.agents.title')),
|
||
running > 0 ? e('span', { className: 'wb-agents-count' }, String(running) + ' running') : null,
|
||
e('button', { type: 'button', className: 'wb-agents-refresh', onClick: function () { setRefreshTick(function (x) { return x + 1; }); } }, '↻')),
|
||
e('div', { className: 'wb-agents-list' },
|
||
!rows.length
|
||
? e('div', { className: 'wb-agents-hint' }, t('agents.empty'))
|
||
: rows.map(function (row) {
|
||
return e('div', { key: row.id, className: 'wb-agents-row', title: row.id,
|
||
onClick: function () { try { ctx.sessions.open(row.id); } catch (err) {} } },
|
||
e('span', { className: 'wb-agents-dot' + (row.running ? ' is-running' : '') }),
|
||
e('span', { className: 'wb-agents-name' }, row.title),
|
||
row.workspace ? e('span', { className: 'wb-agents-meta' }, row.workspace) : null,
|
||
e('span', { className: 'wb-agents-tag ' + (row.running ? 'running' : 'done') }, row.running ? t('agents.running') : t('agents.done')));
|
||
})),
|
||
e('div', { className: 'wb-agents-rooms-note' }, t('agents.roomsDisabled')));
|
||
}
|
||
|
||
function agentsTabDescriptor(ctx) {
|
||
return {
|
||
id: AGENTS_TAB_ID,
|
||
title: function () { return t('tab.agents.title'); },
|
||
icon: function (size) { return e(primitives.IconBranchOutline16, { size: size }); },
|
||
order: 80,
|
||
single: true,
|
||
badge: function (bctx, scope, state) { return agentsBadge(bctx, scope, state); },
|
||
component: function (props) { return e(AgentsView, props); }
|
||
};
|
||
}
|
||
|
||
|
||
// ====================================================================
|
||
// Apps Tab(Tutti 式应用中心)
|
||
// ====================================================================
|
||
/** 默认应用清单:deepseek 三件套(视图 id 与 slots 注册一致)。 */
|
||
var DEFAULT_APPS = [
|
||
{ id: 'ipollowork-design-studio', name: 'Design', desc: 'DeepSeek iDesign · 设计稿/UI', viewId: 'ipollowork-design-studio' },
|
||
{ id: 'ipollowork-ppt-studio', name: 'PPT', desc: 'DeepSeek iPPT · 演示文稿', viewId: 'ipollowork-ppt-studio' },
|
||
{ id: 'ipollowork-video-studio', name: 'Video', desc: 'DeepSeek iVideo · 视频创作', viewId: 'ipollowork-video-studio' }
|
||
];
|
||
var APPS_STYLE_ID = 'apes-sidebar-apps-style';
|
||
var APPS_CSS = [
|
||
'#' + APPS_STYLE_ID + '-root{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,#1f2329);font-size:13px;line-height:1.5}',
|
||
'#' + APPS_STYLE_ID + '-root *{box-sizing:border-box}',
|
||
'#' + APPS_STYLE_ID + '-head{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08))}',
|
||
'#' + APPS_STYLE_ID + '-title{flex:1;font-weight:600;font-size:13px}',
|
||
'#' + APPS_STYLE_ID + '-grid{flex:1 1 auto;min-height:0;overflow-y:auto;padding:10px;display:grid;grid-template-columns:repeat(2,1fr);gap:10px;align-content:start}',
|
||
'#' + APPS_STYLE_ID + '-card{border:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08));border-radius:10px;padding:12px;cursor:pointer;background:var(--dsw-alias-bg-layer-1,transparent);display:flex;flex-direction:column;gap:6px;transition:border-color .15s,background .15s}',
|
||
'#' + APPS_STYLE_ID + '-card:hover{border-color:var(--dsw-alias-brand-primary,#3370ff);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'#' + APPS_STYLE_ID + '-card-icon{width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;color:#fff;background:linear-gradient(135deg,#3370ff,#7c3aed)}',
|
||
'#' + APPS_STYLE_ID + '-card-name{font-weight:600;font-size:13px}',
|
||
'#' + APPS_STYLE_ID + '-card-desc{color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px;line-height:1.4}',
|
||
'#' + APPS_STYLE_ID + '-card-open{margin-top:2px;font-size:11px;color:var(--dsw-alias-brand-primary,#3370ff)}',
|
||
'#' + APPS_STYLE_ID + '-hint{padding:14px;color:var(--dsw-alias-label-tertiary,#8f959e);font-size:12px;line-height:1.6}'
|
||
].join('\n');
|
||
|
||
/** 应用清单:配置里的 apps.list 覆盖默认(防御性合并)。 */
|
||
function appsList(store) {
|
||
try {
|
||
var raw = store && store.prefs && store.prefs.pluginSettings && store.prefs.pluginSettings[SETTINGS_NS] ? store.prefs.pluginSettings[SETTINGS_NS] : null;
|
||
var custom = raw && Array.isArray(raw.appsList) ? raw.appsList : null;
|
||
if (custom && custom.length > 0) return custom;
|
||
} catch (err) { /* ignore */ }
|
||
return DEFAULT_APPS;
|
||
}
|
||
|
||
/** 尝试在会话视图打开应用(viewId = conversation.view slot 的 id)。 */
|
||
function openAppView(ctx, app) {
|
||
var viewId = app.viewId || app.id;
|
||
try {
|
||
// 方式1:uiConversation 视图激活(若公开)
|
||
var uc = ctx.get ? ctx.get('uiConversation') : null;
|
||
if (uc && typeof uc.activateView === 'function') { uc.activateView(viewId); return true; }
|
||
if (uc && uc.views && typeof uc.views.activate === 'function') { uc.views.activate(viewId); return true; }
|
||
} catch (err) { /* ignore */ }
|
||
try {
|
||
// 方式2:slots 激活 conversation.view
|
||
var slots = ctx.get ? ctx.get('slots') : null;
|
||
if (slots && typeof slots.set === 'function') { slots.set('conversation.view', viewId); return true; }
|
||
} catch (err) { /* ignore */ }
|
||
// 降级:提示在会话视图顶栏手动切换
|
||
return false;
|
||
}
|
||
|
||
function AppsView(props) {
|
||
var ctx = props.ctx;
|
||
var apps = appsList(props.store);
|
||
return e('div', { id: APPS_STYLE_ID + '-root' },
|
||
e('div', { id: APPS_STYLE_ID + '-head' },
|
||
e('span', { id: APPS_STYLE_ID + '-title' }, t('apps.title'))),
|
||
e('div', { id: APPS_STYLE_ID + '-grid' },
|
||
apps.map(function (app) {
|
||
return e('div', { key: app.id || app.name, id: APPS_STYLE_ID + '-card',
|
||
title: app.desc || app.name,
|
||
onClick: function () { openAppView(ctx, app); } },
|
||
e('div', { id: APPS_STYLE_ID + '-card-icon' }, String(app.name || 'A').charAt(0).toUpperCase()),
|
||
e('div', { id: APPS_STYLE_ID + '-card-name' }, app.name || app.id),
|
||
app.desc ? e('div', { id: APPS_STYLE_ID + '-card-desc' }, app.desc) : null,
|
||
e('div', { id: APPS_STYLE_ID + '-card-open' }, t('apps.open')));
|
||
})),
|
||
e('div', { id: APPS_STYLE_ID + '-hint' }, t('apps.hint')));
|
||
}
|
||
|
||
function appsTabDescriptor(ctx) {
|
||
return {
|
||
id: APPS_TAB_ID,
|
||
title: function () { return t('apps.title'); },
|
||
icon: function (size) { return e(primitives.IconGridOutline16 || primitives.IconAppsOutline16, { size: size }); },
|
||
order: 90,
|
||
single: true,
|
||
component: function (props) { return e(AppsView, props); }
|
||
};
|
||
}
|
||
|
||
// ====================================================================
|
||
// Profile Tab(WorkBuddy 底部用户区)
|
||
// ====================================================================
|
||
var PROFILE_CSS = [
|
||
'#' + PROFILE_STYLE_ID + '-root{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,#1f2329);font-size:13px;line-height:1.5}',
|
||
'#' + PROFILE_STYLE_ID + '-root *{box-sizing:border-box}',
|
||
'#' + PROFILE_STYLE_ID + '-card{margin:10px;padding:12px;border:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08));border-radius:10px;background:var(--dsw-alias-bg-layer-1,transparent)}',
|
||
'#' + PROFILE_STYLE_ID + '-avatar{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#fff;background:linear-gradient(135deg,#3370ff,#7c3aed);margin-bottom:10px}',
|
||
'#' + PROFILE_STYLE_ID + '-name{font-weight:600;font-size:14px}',
|
||
'#' + PROFILE_STYLE_ID + '-sub{color:var(--dsw-alias-label-tertiary,#8f959e);font-size:12px;margin-top:2px}',
|
||
'#' + PROFILE_STYLE_ID + '-row{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(31,35,41,.05))}',
|
||
'#' + PROFILE_STYLE_ID + '-row:last-child{border-bottom:0}',
|
||
'#' + PROFILE_STYLE_ID + '-row-label{color:var(--dsw-alias-label-secondary,#5c6069);font-size:12px}',
|
||
'#' + PROFILE_STYLE_ID + '-row-value{font-size:12px;word-break:break-all;text-align:right;max-width:60%}',
|
||
'#' + PROFILE_STYLE_ID + '-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px;background:var(--dsw-alias-state-success-primary,#22c55e)}',
|
||
'#' + PROFILE_STYLE_ID + '-actions{display:flex;gap:8px;margin:10px}',
|
||
'#' + PROFILE_STYLE_ID + '-btn{flex:1;padding:7px 0;border:1px solid var(--dsw-alias-border-l2,rgba(31,35,41,.08));border-radius:6px;background:var(--dsw-alias-bg-layer-1,transparent);color:var(--dsw-alias-label-primary,#1f2329);font-size:12px;cursor:pointer;text-align:center}',
|
||
'#' + PROFILE_STYLE_ID + '-btn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}',
|
||
'#' + PROFILE_STYLE_ID + '-footer{margin-top:auto;padding:8px 10px;color:var(--dsw-alias-label-tertiary,#8f959e);font-size:11px;border-top:1px solid var(--dsw-alias-border-l1,rgba(31,35,41,.05))}'
|
||
].join('\n');
|
||
|
||
function currentModelInfo(profileCtx) {
|
||
var info = { provider: '', model: '', connected: true };
|
||
try {
|
||
var snap = sessionsSnapshot(profileCtx);
|
||
var sid = snap.current || null;
|
||
var entry = sid && snap.byId ? snap.byId[sid] : null;
|
||
if (entry) {
|
||
if (entry.provider) info.provider = entry.provider;
|
||
if (entry.model) info.model = entry.model;
|
||
}
|
||
} catch (err) { /* ignore */ }
|
||
return info;
|
||
}
|
||
|
||
function ProfileView(props) {
|
||
var ctx = props.ctx;
|
||
var info = currentModelInfo(ctx);
|
||
var displayName = displayNameOf(ctx);
|
||
var avatarLetter = String(displayName).charAt(0).toUpperCase() || 'A';
|
||
return e('div', { id: PROFILE_STYLE_ID + '-root' },
|
||
e('div', { id: PROFILE_STYLE_ID + '-card' },
|
||
e('div', { id: PROFILE_STYLE_ID + '-avatar' }, avatarLetter),
|
||
e('div', { id: PROFILE_STYLE_ID + '-name' }, displayName),
|
||
e('div', { id: PROFILE_STYLE_ID + '-sub' }, '本地 Agent 工作台'),
|
||
e('div', { id: PROFILE_STYLE_ID + '-row' },
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-label' }, t('profile.status')),
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-value' },
|
||
e('span', { id: PROFILE_STYLE_ID + '-dot' }),
|
||
info.connected ? t('profile.connected') : t('profile.disconnected'))),
|
||
e('div', { id: PROFILE_STYLE_ID + '-row' },
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-label' }, t('profile.provider')),
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-value' }, info.provider || '—')),
|
||
e('div', { id: PROFILE_STYLE_ID + '-row' },
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-label' }, t('profile.model')),
|
||
e('span', { id: PROFILE_STYLE_ID + '-row-value' }, info.model || '—'))),
|
||
e('div', { id: PROFILE_STYLE_ID + '-actions' },
|
||
e('button', { id: PROFILE_STYLE_ID + '-btn', type: 'button', onClick: function () { try { if (ctx.commands) ctx.commands.execute('settings'); } catch (err) {} } }, t('profile.settings')),
|
||
e('button', { id: PROFILE_STYLE_ID + '-btn', type: 'button', onClick: function () { try { if (ctx.commands) ctx.commands.execute('help'); else window.open('https://github.com/deepseek-ai/deepseek-harness', '_blank'); } catch (err) {} } }, t('profile.help'))),
|
||
e('div', { id: PROFILE_STYLE_ID + '-footer' }, t('profile.footer')));
|
||
}
|
||
|
||
function profileTabDescriptor(ctx) {
|
||
return {
|
||
id: PROFILE_TAB_ID,
|
||
title: function () { return displayNameOf(ctx); },
|
||
icon: function (size) { return e(primitives.IconUserOutline16 || primitives.IconContactOutline16, { size: size }); },
|
||
order: 110,
|
||
single: true,
|
||
// 显示名 + 功能开关设置(better-sidebar 设置页「侧边卡片」)
|
||
settings: {
|
||
pluginToggles: [
|
||
{
|
||
key: "displayName",
|
||
title: function () { return '显示名'; },
|
||
desc: function () { return "默认 apes-sidebar;预设 feyOS,或输入任意名字"; },
|
||
type: "select",
|
||
options: [
|
||
{ value: DISPLAY_NAME_DEFAULT, title: function () { return 'apes-sidebar(默认)'; } },
|
||
{ value: DISPLAY_NAME_PRESET_FEYOS, title: function () { return 'feyOS'; } }
|
||
]
|
||
}
|
||
]
|
||
},
|
||
component: function (props) { return e(ProfileView, props); }
|
||
};
|
||
}
|
||
|
||
// ====================================================================
|
||
// apply:按配置注册三个 Tab
|
||
// ====================================================================
|
||
function apply(ctx) {
|
||
injectStyles(TASKS_STYLE_ID, TASKS_CSS);
|
||
injectStyles(AGENTS_STYLE_ATTR, AGENTS_CSS);
|
||
injectStyles(APPS_STYLE_ID, APPS_CSS);
|
||
injectStyles(PROFILE_STYLE_ID, PROFILE_CSS);
|
||
|
||
ctx.effect(function () {
|
||
var disposers = [];
|
||
try {
|
||
// 从 store 读取配置(better-sidebar 设置页开关)
|
||
var settings = readSettings(ctx.get('betterSidebar') && ctx.get('betterSidebar').store ? ctx.get('betterSidebar').store : null);
|
||
if (settings.enableTasks) disposers.push(ctx.betterSidebar.registerTab(tasksTabDescriptor(ctx)));
|
||
if (settings.enableAgents) disposers.push(ctx.betterSidebar.registerTab(agentsTabDescriptor(ctx)));
|
||
if (settings.enableApps) disposers.push(ctx.betterSidebar.registerTab(appsTabDescriptor(ctx)));
|
||
if (settings.enableProfile) disposers.push(ctx.betterSidebar.registerTab(profileTabDescriptor(ctx)));
|
||
} catch (err) {
|
||
// 配置读取失败时注册全部(保守默认)
|
||
disposers.push(ctx.betterSidebar.registerTab(tasksTabDescriptor(ctx)));
|
||
disposers.push(ctx.betterSidebar.registerTab(agentsTabDescriptor(ctx)));
|
||
disposers.push(ctx.betterSidebar.registerTab(appsTabDescriptor(ctx)));
|
||
disposers.push(ctx.betterSidebar.registerTab(profileTabDescriptor(ctx)));
|
||
}
|
||
return function () {
|
||
for (var i = 0; i < disposers.length; i++) { try { disposers[i](); } catch (err) { } }
|
||
};
|
||
}, "apes-sidebar: register tabs");
|
||
|
||
ctx.effect(function () {
|
||
return function () {
|
||
disposeStyles(TASKS_STYLE_ID);
|
||
disposeStyles(AGENTS_STYLE_ATTR);
|
||
disposeStyles(APPS_STYLE_ID);
|
||
disposeStyles(PROFILE_STYLE_ID);
|
||
};
|
||
}, "apes-sidebar: dispose styles");
|
||
}
|
||
|
||
module.exports = { name: name, inject: inject, apply: apply };
|
||
return module.exports;
|
||
}
|
||
});
|