dsh-plugin-t-expert 0.2.15 → 0.3.6

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/lib/client.js CHANGED
@@ -19719,6 +19719,108 @@ function date4(params) {
19719
19719
  // inlined team-engine client bundle
19720
19720
  var client_bundle_default = 'window.__ModuleLoader__.load({\n id: "dsh-plugin-t-expert",\n factory: (require) => {\n var module = { exports: {} };\n var exports = module.exports;\n Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });\n let react_jsx_runtime = require("react/jsx-runtime");\n let react = require("react");\n let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");\n /** Compact `provider/model` route, or just the model when the provider is absent. */\n function memberRouteLabel(member) {\n if (member === void 0) return "";\n const provider = member.provider?.trim() ?? "";\n const model = member.model?.trim() ?? "";\n if (provider !== "" && model !== "") return `${provider}/${model}`;\n return model;\n }\n /**\n * Compact route shown on a running task. Prefer the task\'s own snapshot\n * field; fall back to the assignee member when older hosts omit it.\n */\n function taskModelLabel(task, members) {\n const direct = task.model?.trim() ?? "";\n if (direct !== "") return direct;\n return memberRouteLabel(members.find((candidate) => candidate.name === task.assignee));\n }\n /** Short model id for tight DAG/chip surfaces (`openai/gpt-5.6-sol` \u2192 `gpt-5.6-sol`). */\n function compactModelLabel(route) {\n const trimmed = route.trim();\n if (trimmed === "") return "";\n const slash = trimmed.lastIndexOf("/");\n return slash === -1 ? trimmed : trimmed.slice(slash + 1);\n }\n /** Whether the captain chat should keep showing the in-progress banner. */\n function teamIsActive(team) {\n if (team.halted === true || team.phase === "staged") return false;\n if (team.members.some((member) => member.activity === "working" || member.status === "working")) return true;\n if (team.tasks.some((task) => task.status === "pending" || task.status === "claimed" || task.status === "in_progress")) return true;\n return team.members.length > 0 && team.tasks.length === 0;\n }\n /** Use a fill-width grid when the task graph has no real dependency edges. */\n function usesParallelTaskGrid(tasks) {\n if (tasks.length === 0) return false;\n const taskIds = new Set(tasks.map((task) => task.id));\n return tasks.every((task) => task.dependencies.every((dependency) => !taskIds.has(dependency)));\n }\n /**\n * Whether an expanded activity panel still belongs to the current session.\n *\n * The panel is mounted in the root-scoped shell overlay, so React does not\n * remount it when the conversation route changes. Ownership keeps an expanded\n * panel from leaking onto the new-session screen (or another conversation)\n * while its local open state is being reset.\n */\n function activityPanelExpandedForSession(open, owner, current) {\n return open && owner !== void 0 && owner === current;\n }\n /**\n * Auto-expand only for live teams that appear after the current session\'s\n * initial restore pass. Replayed cards, archived teams, and live teams restored\n * while reopening a conversation must remain behind the collapsed badge.\n */\n function activityPanelShouldAutoExpand({ alreadyAutoOpened, pageSettled, restoreComplete, previousLiveTeamIds, currentLiveTeamIds }) {\n return !alreadyAutoOpened && pageSettled && restoreComplete && currentLiveTeamIds.some((teamId) => !previousLiveTeamIds.has(teamId));\n }\n /**\n * Resolve the task whose dependency chain should be highlighted.\n *\n * A pinned task is an explicit user choice. Keyboard focus takes precedence\n * over delayed pointer intent so an older hover timer cannot steal the active\n * chain from someone navigating the task map with the keyboard.\n */\n function dependencyFocusTaskId(pinnedTaskId, keyboardTaskId, hoverTaskId) {\n return pinnedTaskId ?? keyboardTaskId ?? hoverTaskId;\n }\n /** Group tasks by their precomputed dependency depth. */\n function taskStages(tasks) {\n const byDepth = /* @__PURE__ */ new Map();\n for (const task of tasks) {\n const depth = Number.isFinite(task.depth) ? Math.max(0, Math.floor(task.depth)) : 0;\n const stage = byDepth.get(depth) ?? [];\n stage.push(task);\n byDepth.set(depth, stage);\n }\n return [...byDepth.entries()].sort(([left], [right]) => left - right).map(([depth, stageTasks]) => ({\n depth,\n tasks: stageTasks.slice().sort((left, right) => left.id.localeCompare(right.id, "en", { numeric: true }))\n }));\n }\n /**\n * Lay tasks out as the reference panel\'s compact left-to-right DAG.\n *\n * Columns are dependency-depth stages. Rows are stable task-id order within\n * each stage. Edges use cubic curves so fan-in remains readable without\n * turning every task into a large card.\n */\n function compactDagLayout(tasks) {\n const stages = taskStages(tasks);\n const positions = /* @__PURE__ */ new Map();\n const nodes = [];\n for (const [column, stage] of stages.entries()) for (const [row, task] of stage.tasks.entries()) {\n const x = column * 118;\n const y = row * 38;\n positions.set(task.id, {\n x,\n y\n });\n nodes.push({\n task,\n x,\n y\n });\n }\n const edges = [];\n for (const task of tasks) {\n const target = positions.get(task.id);\n if (target === void 0) continue;\n for (const dependency of task.dependencies) {\n const source = positions.get(dependency);\n if (source === void 0) continue;\n const x1 = source.x + 92;\n const y1 = source.y + 30 / 2;\n const x2 = target.x;\n const y2 = target.y + 30 / 2;\n edges.push({\n from: dependency,\n to: task.id,\n path: `M${x1} ${y1}C${x1 + 14} ${y1},${x2 - 14} ${y2},${x2} ${y2}`\n });\n }\n }\n const rows = Math.max(1, ...stages.map((stage) => stage.tasks.length));\n return {\n width: stages.length === 0 ? 0 : stages.length * 92 + (stages.length - 1) * 26,\n height: stages.length === 0 ? 0 : rows * 30 + (rows - 1) * 8,\n nodes,\n edges\n };\n }\n /**\n * Return the complete upstream/downstream chain around one task.\n *\n * Traversal uses both dependency directions and remains cycle-safe, so the UI\n * can highlight every handoff related to the focused task even if malformed\n * durable data contains a cycle.\n */\n function relatedTaskIds(taskId, tasks) {\n const byId = new Map(tasks.map((task) => [task.id, task]));\n if (!byId.has(taskId)) return /* @__PURE__ */ new Set();\n const dependents = /* @__PURE__ */ new Map();\n for (const task of tasks) for (const dependency of task.dependencies) {\n const targets = dependents.get(dependency) ?? [];\n targets.push(task.id);\n dependents.set(dependency, targets);\n }\n const related = /* @__PURE__ */ new Set();\n const upstreamSeen = /* @__PURE__ */ new Set();\n const downstreamSeen = /* @__PURE__ */ new Set();\n const visitUpstream = (id) => {\n if (upstreamSeen.has(id)) return;\n upstreamSeen.add(id);\n related.add(id);\n for (const dependency of byId.get(id)?.dependencies ?? []) visitUpstream(dependency);\n };\n const visitDownstream = (id) => {\n if (downstreamSeen.has(id)) return;\n downstreamSeen.add(id);\n related.add(id);\n for (const dependent of dependents.get(id) ?? []) visitDownstream(dependent);\n };\n visitUpstream(taskId);\n visitDownstream(taskId);\n return related;\n }\n\n\n /** Shared, demand-driven state for the T Team browser monitor. */\n const targets = /* @__PURE__ */ new Map();\n const targetListeners = /* @__PURE__ */ new Set();\n const snapshotListeners = /* @__PURE__ */ new Set();\n let targetSnapshot = [];\n let activitySnapshots = {\n teams: [],\n archivedTeams: []\n };\n function targetKey(sessionId, teamId) {\n return `${sessionId}\\u0000${teamId}`;\n }\n function publishTargets() {\n targetSnapshot = [...targets.values()].filter((target) => target.active).map(({ key, sessionId, teamId }) => ({\n key,\n sessionId,\n teamId\n }));\n for (const listener of targetListeners) listener();\n }\n /** Subscribe to the active monitor-target list (React external-store shape). */\n function subscribeActivityMonitorTargets(listener) {\n targetListeners.add(listener);\n return () => {\n targetListeners.delete(listener);\n };\n }\n /** Read the stable active-target snapshot. */\n function getActivityMonitorTargetsSnapshot() {\n return targetSnapshot;\n }\n /**\n * Register one successful T Team card as a monitoring demand.\n *\n * The returned cleanup is reference-counted so multiple cards and React\n * StrictMode remounts cannot stop another card\'s monitor.\n */\n function monitorAgentTeam(sessionId, teamId) {\n const owner = sessionId.trim();\n const id = teamId.trim();\n if (owner === "" || id === "") return () => {};\n const key = targetKey(owner, id);\n const existing = targets.get(key);\n if (existing === void 0) {\n targets.set(key, {\n key,\n sessionId: owner,\n teamId: id,\n refs: 1,\n active: true\n });\n publishTargets();\n } else {\n existing.refs += 1;\n if (!existing.active) {\n existing.active = true;\n publishTargets();\n }\n }\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = targets.get(key);\n if (current === void 0) return;\n current.refs -= 1;\n if (current.refs <= 0) {\n targets.delete(key);\n if (current.active) publishTargets();\n }\n };\n }\n /** Stop polling targets whose final archived snapshot has been captured. */\n function settleActivityMonitorTargets(keys) {\n let changed = false;\n for (const key of keys) {\n const target = targets.get(key);\n if (target?.active !== true) continue;\n target.active = false;\n changed = true;\n }\n if (changed) publishTargets();\n }\n /** Subscribe to the shared live/archive snapshot. */\n function subscribeActivitySnapshots(listener) {\n snapshotListeners.add(listener);\n return () => {\n snapshotListeners.delete(listener);\n };\n }\n /** Read the stable shared live/archive snapshot. */\n function getActivitySnapshotsSnapshot() {\n return activitySnapshots;\n }\n /** Publish one or both successful state-route responses. */\n function updateActivitySnapshots(update) {\n const next = {\n teams: update.teams ?? activitySnapshots.teams,\n archivedTeams: update.archivedTeams ?? activitySnapshots.archivedTeams\n };\n if (next.teams === activitySnapshots.teams && next.archivedTeams === activitySnapshots.archivedTeams) return;\n activitySnapshots = next;\n for (const listener of snapshotListeners) listener();\n }\n /** Poll cadence for the live host snapshot route. */\n const ACTIVITY_POLL_MS = 1e3;\n /**\n * Low-frequency probe cadence while a cardless discovery session still owns\n * no team. The probe keeps the panel able to pick up a team created later in\n * that session (e.g. a run_code-wrapped t_team_create) without turning\n * every ordinary session into a one-second filesystem scan.\n */\n const ACTIVITY_PROBE_MS = 5e3;\n /** Host route serving live and archived team snapshots. */\n const ACTIVITY_STATE_URL = "/plugins/t-team/state";\n const ACTIVITY_HALT_URL = "/plugins/t-team/halt";\n /**\n * Start the single polling loop for the current session\'s requested targets.\n *\n * With neither targets nor a discovery session this is deliberately inert.\n * Explicit card targets poll at the live cadence from the start. A discovery\n * session performs an immediate live+archive restore pass, then \u2014 while it\n * still owns no team \u2014 probes on a low-frequency cadence, so a team created\n * later in that session (e.g. a run_code-wrapped t_team_create) is\n * discovered without a manual reload, without turning every ordinary session\n * into a one-second filesystem scan. The moment a team for the discovery\n * session appears, the controller upgrades to the live one-second cadence for\n * the rest of its lifetime. The caller \u2014 the session view, which stops the\n * controller when the session is no longer current \u2014 bounds the lifetime, and\n * archive state is refreshed when a target or a previously discovered live\n * team disappears.\n */\n function startActivityPolling(monitorTargets, runtime = {}) {\n const discoverySessionId = runtime.discoverySessionId?.trim();\n if (monitorTargets.length === 0 && (discoverySessionId === void 0 || discoverySessionId === "")) return {\n firstTick: Promise.resolve(),\n stop: () => {}\n };\n const fetchState = runtime.fetchState ?? ((url, init) => fetch(url, init));\n const schedule = runtime.schedule ?? ((callback, intervalMs) => setInterval(callback, intervalMs));\n const cancel = runtime.cancel ?? ((timer) => {\n clearInterval(timer);\n });\n const publishSnapshots = runtime.publishSnapshots ?? updateActivitySnapshots;\n const settleTargets = runtime.settleTargets ?? settleActivityMonitorTargets;\n let cancelled = false;\n let inFlight = false;\n let hot = monitorTargets.length > 0;\n let discoveryComplete = false;\n let discoveredLiveKeys = /* @__PURE__ */ new Set();\n let controller;\n let timer;\n const intervalMs = () => hot ? ACTIVITY_POLL_MS : ACTIVITY_PROBE_MS;\n const reschedule = () => {\n cancel(timer);\n timer = schedule(() => {\n tick();\n }, intervalMs());\n };\n const tick = async () => {\n if (inFlight || cancelled) return;\n inFlight = true;\n controller = new AbortController();\n try {\n const liveResponse = await fetchState(ACTIVITY_STATE_URL, {\n cache: "no-store",\n signal: controller.signal\n });\n if (!liveResponse.ok) return;\n const body = await liveResponse.json();\n if (cancelled || !Array.isArray(body.teams)) return;\n const liveTeams = body.teams;\n publishSnapshots({ teams: liveTeams });\n const previousDiscoveredKeys = discoveredLiveKeys;\n discoveredLiveKeys = new Set(discoverySessionId === void 0 || discoverySessionId === "" ? [] : liveTeams.filter((team) => team.captainSessionId === discoverySessionId).map((team) => team.teamId));\n if (!hot && discoveredLiveKeys.size > 0) {\n hot = true;\n reschedule();\n }\n const discoveredTeamArchived = [...previousDiscoveredKeys].some((teamId) => !discoveredLiveKeys.has(teamId));\n const missing = monitorTargets.filter((target) => !liveTeams.some((team) => team.captainSessionId === target.sessionId && team.teamId === target.teamId));\n const needsDiscoveryArchive = discoverySessionId !== void 0 && discoverySessionId !== "" && !discoveryComplete;\n if (missing.length === 0 && !needsDiscoveryArchive && !discoveredTeamArchived) return;\n const archivedResponse = await fetchState(`${ACTIVITY_STATE_URL}?archived=1`, {\n cache: "no-store",\n signal: controller.signal\n });\n if (!archivedResponse.ok) return;\n const archivedBody = await archivedResponse.json();\n if (cancelled || !Array.isArray(archivedBody.teams)) return;\n publishSnapshots({ archivedTeams: archivedBody.teams });\n discoveryComplete = true;\n settleTargets(new Set(missing.map((target) => target.key)));\n } catch (error) {\n if (error?.name === "AbortError") return;\n } finally {\n inFlight = false;\n }\n };\n const firstTick = tick();\n if (timer === void 0) timer = schedule(() => {\n tick();\n }, intervalMs());\n return {\n firstTick,\n stop: () => {\n if (cancelled) return;\n cancelled = true;\n controller?.abort();\n cancel(timer);\n }\n };\n }\n\n\n /**\n * Shared whale artwork lookup for the activity panel and the conversation\n * card: role keywords map to the packaged role images; the captain always\n * uses the lead whale.\n * @module t-team/client/artwork\n */\n /** Artwork route prefix served by the plugin host half. */\n const ART_BASE = "/plugins/t-team/assets/";\n /** V2 whale role artwork per role keyword. */\n const ROLE_ART = [\n [/data|analys|metric|performance|\u6570\u636E|\u5206\u6790|\u6307\u6807|\u6027\u80FD/, "member-data-v2.png"],\n [/resear|investig|explor|study|\u7814\u7A76|\u8C03\u67E5|\u63A2\u7D22|\u8C03\u7814/, "member-researcher-v2.png"],\n [/\\bqa\\b|test|verif|quality|\u6D4B\u8BD5|\u8D28\u91CF|\u9A8C\u8BC1/, "member-qa-v2.png"],\n [/engineer|dev\\b|server|backend|\\bapi\\b|runtime|watcher|contract|\u5DE5\u7A0B|\u540E\u7AEF|\u670D\u52A1|\u63A5\u53E3|\u5F00\u53D1|\u4EE3\u7801|\u7F16\u7A0B/, "member-engineer-v2.png"],\n [/design|\\bui\\b|\\bux\\b|front|theme|accessib|\u8BBE\u8BA1|\u524D\u7AEF|\u4E3B\u9898|\u65E0\u969C\u788D/, "member-designer-v2.png"],\n [/secur|audit|risk|threat|review|\u5B89\u5168|\u5BA1\u8BA1|\u5BA1\u67E5|\u98CE\u9669/, "member-security-v2.png"],\n [/docs|writer|product|spec|\u64B0\u5199|\u6587\u6848|\u5199\u4F5C|\u6587\u6863|\u89C4\u8303/, "member-docs-v2.png"],\n [/release|\\bbuild\\b|deploy|\\bops\\b|\\bci\\b|ship|coordin|\u53D1\u5E03|\u6784\u5EFA|\u90E8\u7F72|\u8FD0\u7EF4|\u534F\u8C03/, "member-operator-v2.png"]\n ];\n /** Captain artwork (always the lead whale). */\n const LEAD_ART = `${ART_BASE}team-lead-v2.png`;\n /** Status action artwork per member activity. */\n const ACTION_ART = {\n working: `${ART_BASE}action-working-v2.png`,\n idle: `${ART_BASE}action-sleeping-v2.png`,\n unknown: `${ART_BASE}action-thinking-v2.png`\n };\n /**\n * Member artwork URL, or null when no role matches (initial-letter fallback).\n * @param name - the member\'s display name.\n * @param role - the member\'s role text.\n * @returns the artwork URL, or null when unmatched.\n */\n function memberArtUrl(name, role) {\n const identity = `${name} ${role}`.toLowerCase();\n for (const [pattern, art] of ROLE_ART) if (pattern.test(identity)) return `${ART_BASE}${art}`;\n return null;\n }\n\n\n const css$1 = ".kPAopq_root{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module-platform);border-radius:10px;flex-direction:column;gap:8px;width:100%;min-width:0;padding:10px 12px;display:flex}.kPAopq_head{align-items:center;gap:8px;min-width:0;display:flex}.kPAopq_leadAvatar{object-fit:contain;filter:drop-shadow(0 1px 1px #122d4833);background:0 0;border:0;border-radius:0;flex:none;width:30px;height:30px}.kPAopq_teamName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.kPAopq_memberCount{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;margin-left:auto;font-size:11px;line-height:16px}.kPAopq_panelButton{border:1px solid var(--dsw-alias-line-strong);background:var(--dsw-alias-bg-module);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;flex:none;padding:2px 8px;font-size:10.5px;font-weight:600;line-height:16px;transition:border-color .12s,color .12s}.kPAopq_panelButton:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.kPAopq_panelButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.kPAopq_members{flex-wrap:wrap;gap:6px;min-width:0;display:flex}.kPAopq_member{border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module);max-width:160px;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;align-items:center;gap:5px;padding:3px 8px 3px 3px;font-size:11px;font-weight:500;line-height:16px;transition:border-color .12s,background-color .12s;display:inline-flex}.kPAopq_member:hover{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-fill-neutral)}.kPAopq_member:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.kPAopq_memberArt{object-fit:contain;filter:drop-shadow(0 1px 1px #122d482e);background:0 0;border:0;border-radius:0;width:24px;height:24px}.kPAopq_memberInitial{background:var(--dsw-alias-bg-fill-business);width:20px;height:20px;color:var(--dsw-alias-label-on-fill);border-radius:50%;justify-content:center;align-items:center;font-size:10px;font-weight:600;line-height:20px;display:inline-flex}.kPAopq_memberName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}";\n const tagId$1 = "dsh-plugin-t-expert/TTeamCard.module.css";\n if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {\n const tag = document.createElement("style");\n tag.dataset.plugin = "dsh-plugin-t-expert";\n tag.dataset.pluginCss = tagId$1;\n tag.textContent = css$1;\n document.head.appendChild(tag);\n }\n var TTeamCard_module_css_default = {\n "head": "kPAopq_head",\n "leadAvatar": "kPAopq_leadAvatar",\n "member": "kPAopq_member",\n "memberArt": "kPAopq_memberArt",\n "memberCount": "kPAopq_memberCount",\n "memberInitial": "kPAopq_memberInitial",\n "memberName": "kPAopq_memberName",\n "members": "kPAopq_members",\n "panelButton": "kPAopq_panelButton",\n "root": "kPAopq_root",\n "teamName": "kPAopq_teamName"\n };\n\n\n /**\n * T Team conversation card: the lightweight in-conversation summary for\n * one team \u2014 the captain\'s whale avatar and name, the member roster as\n * clickable whale avatars (opening the member\'s subagent transcript), and\n * an "activity panel" button that re-activates the top-right floater.\n *\n * The floater and this card share the `t-team:open-panel` window event\n * so the card can summon the panel even after it was closed (or when an old\n * session is re-opened for review).\n * @module t-team/client/card\n */\n /** Window event name the floater listens for to open itself. */\n const OPEN_PANEL_EVENT = "t-team:open-panel";\n /** Re-activate the top-right activity panel, carrying this team\'s summary\n * so the panel can show it even when the team no longer exists on disk\n * (historical session review). */\n function openActivityPanel(data) {\n window.dispatchEvent(new CustomEvent(OPEN_PANEL_EVENT, { detail: {\n teamId: data.teamId,\n captainSessionId: data.captainSessionId,\n teamName: data.teamName,\n members: data.members\n } }));\n }\n /** Render one durable team as a compact conversation card. */\n function TTeamCard({ node, openMember, sessionId, t }) {\n const data = node.data;\n const owner = data.captainSessionId || sessionId;\n const { teams, archivedTeams } = (0, react.useSyncExternalStore)(subscribeActivitySnapshots, getActivitySnapshotsSnapshot);\n (0, react.useEffect)(() => {\n return monitorAgentTeam(owner, data.teamId);\n }, [data.teamId, owner]);\n const snapshot = teams.find((team) => team.teamId === data.teamId && (owner === "" || team.captainSessionId === owner)) ?? archivedTeams.find((team) => team.teamId === data.teamId && (owner === "" || team.captainSessionId === owner));\n const resolved = (0, react.useMemo)(() => ({\n ...data,\n captainSessionId: snapshot?.captainSessionId ?? owner,\n teamName: snapshot?.name ?? data.teamName,\n members: snapshot?.members.map((member) => ({\n id: member.id,\n name: member.name,\n role: member.role\n })) ?? data.members\n }), [\n data,\n owner,\n snapshot\n ]);\n return (0, react_jsx_runtime.jsxs)("section", {\n className: TTeamCard_module_css_default.root,\n "data-t-team-card": true,\n "data-team-id": resolved.teamId,\n children: [(0, react_jsx_runtime.jsxs)("header", {\n className: TTeamCard_module_css_default.head,\n children: [\n (0, react_jsx_runtime.jsx)("img", {\n className: TTeamCard_module_css_default.leadAvatar,\n src: LEAD_ART,\n alt: "",\n "aria-hidden": true\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: TTeamCard_module_css_default.teamName,\n title: resolved.teamName,\n children: resolved.teamName\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: TTeamCard_module_css_default.memberCount,\n children: t("card.memberCount", { count: resolved.members.length })\n }),\n (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n className: TTeamCard_module_css_default.panelButton,\n onClick: () => {\n openActivityPanel(resolved);\n },\n "aria-label": t("action.openActivityPanel"),\n title: t("action.openActivityPanel"),\n children: t("activity.panelButton")\n })\n ]\n }), resolved.members.length > 0 && (0, react_jsx_runtime.jsx)("div", {\n className: TTeamCard_module_css_default.members,\n children: resolved.members.map((member) => (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: TTeamCard_module_css_default.member,\n onClick: () => {\n if (member.id !== "") openMember(owner, member.id);\n },\n title: member.role === "" ? member.name : `${member.name} \xB7 ${member.role}`,\n children: [memberArtUrl(member.name, member.role) !== null ? (0, react_jsx_runtime.jsx)("img", {\n className: TTeamCard_module_css_default.memberArt,\n src: memberArtUrl(member.name, member.role) ?? "",\n alt: "",\n "aria-hidden": true\n }) : (0, react_jsx_runtime.jsx)("span", {\n className: TTeamCard_module_css_default.memberInitial,\n children: member.name.trim().slice(0, 1).toUpperCase() || "?"\n }), (0, react_jsx_runtime.jsx)("span", {\n className: TTeamCard_module_css_default.memberName,\n children: member.name\n })]\n }, member.id))\n })]\n });\n }\n\n\n const css = "html{--t-team-panel-shift:420px}html[data-t-team-panel-open] [data-phase=active]{box-sizing:border-box;padding-right:var(--t-team-panel-shift)}.aYQbCq_badge,.aYQbCq_panel{--dsw-alias-line-normal:var(--dsw-static-neutral-bluish-150,#e7e9ee);--dsw-alias-line-strong:color-mix(in srgb, var(--dsw-static-neutral-bluish-200,#e1e5ee) 50%, var(--dsw-static-neutral-bluish-300,#cfd3d6));--dsw-alias-bg-module:var(--dsw-alias-bg-layer-1,#fff);--dsw-alias-bg-fill-neutral:var(--dsw-static-neutral-bluish-100,#eef0f4);--dsw-alias-bg-fill-business:var(--dsw-alias-state-business-primary,#4d6bfe);--dsw-alias-bg-fill-success:var(--dsw-alias-state-success-primary,#12a150);--dsw-alias-bg-fill-warning:var(--dsw-alias-state-warn-primary,#e08700);--dsw-alias-bg-fill-danger:var(--dsw-alias-state-error-primary,#e5484d);--dsw-alias-state-success:var(--dsw-alias-state-success-primary,#12a150);--dsw-alias-state-warning:var(--dsw-alias-state-warn-primary,#e08700);--dsw-alias-state-danger:var(--dsw-alias-state-error-primary,#e5484d);--dsw-alias-label-on-fill:var(--dsw-alias-label-primary-inverted,#fff)}.aYQbCq_badge{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 92%, transparent);backdrop-filter:blur(16px);height:34px;box-shadow:0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border-radius:999px;align-items:center;gap:7px;padding:0 12px;font-size:12px;font-weight:600;line-height:20px;transition:border-color .15s,transform .12s;display:inline-flex;position:absolute;top:64px;right:18px}.aYQbCq_badge:hover{border-color:var(--dsw-alias-line-strong);transform:translateY(-1px)}.aYQbCq_badge:active{transform:translateY(0)scale(.98)}.aYQbCq_badge:focus-visible,.aYQbCq_iconButton:focus-visible,.aYQbCq_memberRow:focus-visible,.aYQbCq_membersToggle:focus-visible,.aYQbCq_sectionToggleTitle:focus-visible,.aYQbCq_dagNode:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.aYQbCq_badgeDot,.aYQbCq_panelDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;width:7px;height:7px}.aYQbCq_badgeDot[data-busy=true],.aYQbCq_panelDot[data-busy=true]{background:var(--dsw-alias-state-business-primary);animation:1.25s ease-in-out infinite aYQbCq_tTeamPulse}.aYQbCq_badgeCount,.aYQbCq_memberCount,.aYQbCq_teamStats,.aYQbCq_stageLabel,.aYQbCq_taskId{font-variant-numeric:tabular-nums}.aYQbCq_panel{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--dsw-alias-line-strong) 58%, transparent);background:color-mix(in srgb, var(--dsw-alias-bg-module) 95%, transparent);backdrop-filter:blur(20px)saturate(1.08);box-shadow:0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent), 0 32px 72px color-mix(in srgb, var(--dsw-alias-label-primary) 16%, transparent);will-change:transform;border-radius:16px;flex-direction:column;animation:.16s ease-out aYQbCq_tTeamPanelIn;display:flex;position:absolute;top:0;left:0;overflow:hidden}.aYQbCq_panel[data-dragging],.aYQbCq_panel[data-resizing]{user-select:none;box-shadow:0 16px 38px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent), 0 36px 78px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent)}@keyframes aYQbCq_tTeamPanelIn{0%{opacity:0}to{opacity:1}}@keyframes aYQbCq_tTeamPulse{0%,to{opacity:.42}50%{opacity:1}}.aYQbCq_panelHead{border-bottom:1px solid var(--dsw-alias-line-normal);cursor:grab;touch-action:none;flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:0 14px 0 16px;display:flex}.aYQbCq_panelHead:active,.aYQbCq_panel[data-dragging] .aYQbCq_panelHead{cursor:grabbing}.aYQbCq_panel[data-compact] .aYQbCq_panelHead{cursor:default;touch-action:auto}.aYQbCq_panelTitle{color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:14px;font-weight:600;line-height:20px;display:inline-flex}.aYQbCq_panelControls{flex:none;align-items:center;gap:2px;display:inline-flex}.aYQbCq_iconButton{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:7px;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,transform .12s;display:inline-flex}.aYQbCq_iconButton:hover{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-primary)}.aYQbCq_iconButton:active{transform:scale(.94)}.aYQbCq_iconButton[data-control=dock][data-mode=docked] svg{transform:scaleX(-1)}.aYQbCq_resizeHandle{z-index:5;touch-action:none;pointer-events:auto;position:absolute}.aYQbCq_resizeHandle[data-resize-edge=left]{cursor:ew-resize;width:14px;top:44px;bottom:14px;left:0}.aYQbCq_resizeHandle[data-resize-edge=left]:after{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 42%, transparent);content:\\"\\";opacity:.45;border-radius:999px;width:3px;height:48px;transition:background-color .12s,opacity .12s;position:absolute;top:50%;left:4px;transform:translateY(-50%)}.aYQbCq_resizeHandle[data-resize-edge=bottom]{cursor:ns-resize;height:14px;bottom:0;left:20px;right:20px}.aYQbCq_resizeHandle[data-resize-edge=bottom]:after{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 42%, transparent);content:\\"\\";opacity:.45;border-radius:999px;width:48px;height:3px;transition:background-color .12s,opacity .12s;position:absolute;bottom:4px;left:50%;transform:translate(-50%)}.aYQbCq_resizeHandle[data-resize-edge=corner]{cursor:nwse-resize;width:28px;height:28px;bottom:0;right:0}.aYQbCq_resizeHandle[data-resize-edge=corner]:after{border-right:2px solid var(--dsw-alias-label-tertiary);border-bottom:2px solid var(--dsw-alias-label-tertiary);content:\\"\\";opacity:.58;width:10px;height:10px;transition:border-color .12s,opacity .12s;position:absolute;bottom:6px;right:6px}.aYQbCq_resizeHandle:hover:after,.aYQbCq_panel[data-resizing] .aYQbCq_resizeHandle:after{background-color:var(--dsw-alias-bg-fill-business);border-color:var(--dsw-alias-bg-fill-business);opacity:.95}.aYQbCq_teams{overscroll-behavior:contain;scrollbar-color:color-mix(in srgb, var(--dsw-alias-label-tertiary) 28%, transparent) transparent;scrollbar-width:thin;flex-direction:column;min-height:0;display:flex;overflow-y:auto}.aYQbCq_teams::-webkit-scrollbar{width:6px}.aYQbCq_teams::-webkit-scrollbar-track{background:0 0}.aYQbCq_teams::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 28%, transparent);background-clip:padding-box;border:2px solid #0000;border-radius:999px}.aYQbCq_teams:hover::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 44%, transparent);background-clip:padding-box}.aYQbCq_team{border-bottom:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:12px;padding:12px 14px 16px;display:flex;container:aYQbCq_agent-team/inline-size}.aYQbCq_team:last-child{border-bottom:0}.aYQbCq_teamHead{align-items:center;gap:10px;min-width:0;display:flex}.aYQbCq_teamName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;font-weight:600;line-height:18px;overflow:hidden}.aYQbCq_teamStats{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;gap:8px;font-size:10.5px;line-height:16px;display:inline-flex}.aYQbCq_teamStopButton{border:1px solid var(--dsw-alias-line-normal);width:26px;height:26px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border-radius:7px;flex:none;place-items:center;padding:0;transition:border-color .15s,background .15s,color .15s;display:grid}.aYQbCq_teamStopButton:hover{border-color:color-mix(in srgb, var(--dsw-alias-state-danger) 42%, var(--dsw-alias-line-normal));background:color-mix(in srgb, var(--dsw-alias-state-danger) 7%, transparent);color:var(--dsw-alias-state-danger)}.aYQbCq_teamStopButton:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.aYQbCq_stopModalActions{justify-content:flex-end;gap:8px;display:flex}.aYQbCq_stopModalActions button{border:1px solid var(--dsw-alias-line-normal,#e7e9ee);background:var(--dsw-alias-bg-fill-neutral,#eef0f4);min-height:34px;color:var(--dsw-alias-label-primary,#1c1c1e);cursor:pointer;font:inherit;border-radius:8px;justify-content:center;align-items:center;gap:6px;padding:6px 13px;font-size:12px;font-weight:600;display:inline-flex}.aYQbCq_stopModalActions button[data-danger]{border-color:var(--dsw-alias-state-danger,#e5484d);background:var(--dsw-alias-state-danger,#e5484d);color:var(--dsw-alias-label-on-fill,#fff)}.aYQbCq_stopModalActions button:disabled{cursor:wait;opacity:.58}.aYQbCq_stopModalError{background:color-mix(in srgb, var(--dsw-alias-state-danger,#e5484d) 8%, transparent);color:var(--dsw-alias-state-danger,#e5484d);border-radius:8px;align-items:flex-start;gap:7px;margin:0;padding:9px 10px;font-size:12px;line-height:18px;display:flex}.aYQbCq_stopModalError svg{flex:none;margin-top:1px}.aYQbCq_sectionHead{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.aYQbCq_sectionTitle{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.aYQbCq_sectionHint{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.aYQbCq_delegationSection{min-width:0}.aYQbCq_captainNode{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 32%, var(--dsw-alias-line-normal));background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 7%, var(--dsw-alias-bg-module));border-radius:10px;grid-template-columns:48px minmax(0,1fr) auto;align-items:center;gap:9px;min-height:56px;padding:6px 10px;display:grid}.aYQbCq_captainAvatar,.aYQbCq_memberAvatar{flex:none;justify-content:center;align-items:center;display:inline-flex;position:relative}.aYQbCq_captainAvatar{width:46px;height:46px}.aYQbCq_leadAvatar,.aYQbCq_memberArt{object-fit:contain;filter:drop-shadow(0 1px 1px #122d4833);background:0 0;border:0;border-radius:0}.aYQbCq_leadAvatar{width:44px;height:44px}.aYQbCq_memberArt{width:40px;height:40px}.aYQbCq_captainInfo,.aYQbCq_memberInfo{flex-direction:column;min-width:0;display:flex}.aYQbCq_captainInfo{gap:2px}.aYQbCq_captainLine,.aYQbCq_memberLine{align-items:center;gap:6px;min-width:0;display:flex}.aYQbCq_captainName,.aYQbCq_memberName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;font-weight:600;line-height:18px;overflow:hidden}.aYQbCq_captainRole,.aYQbCq_memberRole{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.aYQbCq_captainSummary,.aYQbCq_memberStatusLine{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:10.5px;line-height:15px;overflow:hidden}.aYQbCq_taskDetailModel{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9.5px;line-height:14px;overflow:hidden}.aYQbCq_memberModel{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-fill-neutral);min-width:0;max-width:132px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;flex:0 auto;align-items:center;padding:0 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;font-weight:600;line-height:15px;display:inline-flex;overflow:hidden}.aYQbCq_captainState,.aYQbCq_memberState{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;align-items:center;gap:5px;font-size:10px;font-weight:500;line-height:15px;display:inline-flex}.aYQbCq_captainState[data-busy=true],.aYQbCq_memberState[data-activity=working]{color:var(--dsw-alias-bg-fill-business)}.aYQbCq_workGlyph rect{opacity:.5}.aYQbCq_workGlyph[data-active=true] rect{animation:1.1s ease-in-out infinite aYQbCq_tTeamDot}@keyframes aYQbCq_tTeamDot{0%,to{opacity:.25}50%{opacity:1}}.aYQbCq_progressOverview{flex-direction:column;gap:7px;display:flex}.aYQbCq_progressTitle{color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:600;line-height:16px}.aYQbCq_progressSegments{gap:3px;display:flex}.aYQbCq_progressSegments>span,.aYQbCq_progressEmpty{background:var(--dsw-alias-line-strong);border-radius:2px;flex:1;height:5px}.aYQbCq_progressEmpty{width:100%;display:block}.aYQbCq_progressSegments>span[data-state=running]{background:var(--dsw-alias-state-business-primary)}.aYQbCq_progressSegments>span[data-state=blocked]{background:var(--dsw-alias-state-warning)}.aYQbCq_progressSegments>span[data-state=completed]{background:var(--dsw-alias-state-success)}.aYQbCq_progressSegments>span[data-state=failed]{background:var(--dsw-alias-state-danger)}.aYQbCq_progressSegments>span[data-state=cancelled]{opacity:.55}.aYQbCq_progressLegend{color:var(--dsw-alias-label-tertiary);gap:10px;font-size:9.5px;line-height:14px;display:flex}.aYQbCq_progressLegend>span[data-state=running]{color:var(--dsw-alias-state-business-primary)}.aYQbCq_progressLegend>span[data-state=blocked]{color:var(--dsw-alias-state-warning)}.aYQbCq_progressLegend>span[data-state=completed]{color:var(--dsw-alias-state-success)}.aYQbCq_progressSummary{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 7%, var(--dsw-alias-bg-module));min-width:0;color:var(--dsw-alias-label-secondary);border-radius:8px;align-items:center;gap:6px;padding:5px 8px;font-size:10px;font-weight:600;line-height:15px;display:flex}.aYQbCq_progressSummary[data-state=warning]{background:color-mix(in srgb, var(--dsw-alias-state-warning) 8%, var(--dsw-alias-bg-module))}.aYQbCq_progressSummary[data-state=completed]{background:color-mix(in srgb, var(--dsw-alias-state-success) 8%, var(--dsw-alias-bg-module))}.aYQbCq_progressSummary[data-state=discarded]{background:var(--dsw-alias-bg-fill-neutral)}.aYQbCq_progressSummary>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.aYQbCq_progressSummaryDot{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:5px;height:5px}.aYQbCq_progressSummary[data-state=warning] .aYQbCq_progressSummaryDot{background:var(--dsw-alias-state-warning)}.aYQbCq_progressSummary[data-state=completed] .aYQbCq_progressSummaryDot{background:var(--dsw-alias-state-success)}.aYQbCq_progressSummary[data-state=discarded] .aYQbCq_progressSummaryDot{background:var(--dsw-alias-label-tertiary)}.aYQbCq_membersToggle{background:var(--dsw-alias-bg-module-platform);width:100%;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border:0;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-size:10.5px;font-weight:600;line-height:15px;display:flex}.aYQbCq_membersToggle:hover{background:var(--dsw-alias-bg-fill-neutral)}.aYQbCq_membersToggle>span{align-items:center;gap:5px;display:inline-flex}.aYQbCq_membersToggle>span:last-child{color:var(--dsw-alias-state-business-primary)}.aYQbCq_chevron{flex:none;transition:transform .14s}.aYQbCq_chevron[data-open=true]{transform:rotate(90deg)}.aYQbCq_delegationTree{flex-direction:column;gap:2px;margin-left:18px;padding:9px 0 0 20px;display:flex;position:relative}.aYQbCq_delegationTree:before{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 48%, var(--dsw-alias-line-normal));content:\\"\\";width:1px;position:absolute;top:0;bottom:22px;left:0}.aYQbCq_memberBlock{flex-direction:column;min-width:0;padding:3px 0 7px;display:flex;position:relative}.aYQbCq_memberBranch{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 48%, var(--dsw-alias-line-normal));width:20px;height:1px;display:block;position:absolute;top:27px;right:100%}.aYQbCq_memberBranch:before{background:var(--dsw-alias-state-business-primary);content:\\"\\";border-radius:50%;width:5px;height:5px;position:absolute;top:-2px;right:-1px}.aYQbCq_memberRow{box-sizing:border-box;width:100%;min-width:0;min-height:48px;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;grid-template-columns:46px minmax(0,1fr) auto;align-items:center;gap:8px;padding:4px 6px;transition:background-color .12s,transform .12s;display:grid}.aYQbCq_memberRow:hover,.aYQbCq_memberRow[data-activity=working]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 6%, var(--dsw-alias-bg-module))}.aYQbCq_memberRow:active{transform:scale(.995)}.aYQbCq_memberAvatar{width:42px;height:42px}.aYQbCq_memberAvatar[data-unread=true]:after{box-sizing:border-box;border:1px solid var(--dsw-alias-bg-module);background:var(--dsw-alias-state-business-primary);content:\\"\\";border-radius:50%;width:6px;height:6px;animation:1.8s ease-in-out infinite aYQbCq_tTeamUnreadPulse;position:absolute;top:0;right:-1px}@keyframes aYQbCq_tTeamUnreadPulse{0%,to{opacity:.78;transform:scale(.92)}50%{opacity:1;transform:scale(1.16)}}.aYQbCq_memberInitial{background:var(--dsw-alias-bg-fill-business);width:34px;height:34px;color:var(--dsw-alias-label-on-fill);border-radius:50%;justify-content:center;align-items:center;font-size:14px;font-weight:600;line-height:20px;display:inline-flex}.aYQbCq_stateArt{box-sizing:border-box;object-fit:contain;width:22px;height:22px;filter:drop-shadow(0 0 1px var(--dsw-alias-bg-module)) drop-shadow(0 1px 1px #122d483d);background:0 0;border:0;border-radius:0;position:absolute;bottom:-3px;right:-5px}.aYQbCq_stateArt[data-activity=working]{animation:2.4s ease-in-out infinite aYQbCq_tTeamFloat}.aYQbCq_stateArt[data-activity=idle]{animation:4.2s ease-in-out infinite aYQbCq_tTeamBreathe}.aYQbCq_stateArt[data-activity=unknown]{animation:2.8s ease-in-out infinite aYQbCq_tTeamThink}@keyframes aYQbCq_tTeamFloat{0%,to{transform:translateY(0)rotate(-4deg)}50%{transform:translateY(-2px)rotate(4deg)}}@keyframes aYQbCq_tTeamBreathe{0%,to{opacity:.82;transform:scale(1)}50%{opacity:1;transform:scale(1.06)}}@keyframes aYQbCq_tTeamThink{0%,to{transform:rotate(-7deg)}50%{transform:rotate(7deg)}}.aYQbCq_memberState{margin-left:auto}.aYQbCq_memberCount{color:var(--dsw-alias-label-tertiary);font-size:10.5px;line-height:16px}.aYQbCq_assignmentLine{align-items:center;gap:7px;min-width:0;padding:0 6px 0 60px;display:flex}.aYQbCq_assignmentLabel{color:var(--dsw-alias-label-tertiary);flex:none;font-size:9.5px;line-height:14px}.aYQbCq_assignmentTasks{flex-wrap:wrap;flex:1;gap:4px;min-width:0;display:flex}.aYQbCq_assignmentChip{background:var(--dsw-alias-bg-fill-neutral);max-width:100%;min-height:16px;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;align-items:center;padding:0 5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;font-weight:600;line-height:14px;display:inline-flex;overflow:hidden}.aYQbCq_assignmentChip[data-state=running]{background:var(--dsw-alias-bg-fill-business);color:var(--dsw-alias-label-on-fill)}.aYQbCq_assignmentChip[data-state=completed]{background:var(--dsw-alias-bg-fill-success);color:var(--dsw-alias-label-on-fill)}.aYQbCq_assignmentChip[data-state=blocked]{background:var(--dsw-alias-bg-fill-warning);color:var(--dsw-alias-label-on-fill)}.aYQbCq_assignmentChip[data-state=failed]{background:var(--dsw-alias-bg-fill-danger);color:var(--dsw-alias-label-on-fill)}.aYQbCq_assignmentChip[data-state=cancelled]{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}.aYQbCq_unreadPill{color:var(--dsw-alias-state-business-primary);white-space:nowrap;flex:none;font-size:9.5px;font-weight:600;line-height:14px}.aYQbCq_taskEmpty{color:var(--dsw-alias-label-tertiary);font-size:9.5px;line-height:14px}.aYQbCq_dependencySection{border-top:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:7px;min-width:0;padding-top:10px;display:flex}.aYQbCq_sectionToggleTitle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.aYQbCq_dagViewport{scrollbar-width:thin;min-width:0;padding:2px 0 4px;overflow-x:auto}.aYQbCq_dagCanvas{min-width:100%;position:relative}.aYQbCq_dagCanvas[data-layout=parallel]{flex-wrap:wrap;gap:8px;display:flex}.aYQbCq_dagCanvas[data-layout=parallel] .aYQbCq_dagNode{flex:92px;min-width:92px;position:relative}.aYQbCq_dagEdges{pointer-events:none;position:absolute;inset:0;overflow:visible}.aYQbCq_dagEdges path{fill:none;stroke:var(--dsw-alias-line-strong);stroke-width:1px;transition:opacity .14s,stroke .14s,stroke-width .14s}.aYQbCq_dagEdges path[data-active=true]{stroke:var(--dsw-alias-state-business-primary);stroke-width:1.6px}.aYQbCq_dagEdges path[data-dimmed=true]{opacity:.24}.aYQbCq_dagNode{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;border-radius:6px;flex-direction:column;justify-content:center;gap:1px;padding:0 6px;transition:border-color .14s,background-color .14s,opacity .14s;display:flex;position:absolute}.aYQbCq_dagNode:hover,.aYQbCq_dagNode[data-focused=true]{border-color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 6%, var(--dsw-alias-bg-module))}.aYQbCq_dagNode[data-dimmed=true]{opacity:.3}.aYQbCq_dagNode[data-state=running][data-dimmed=true]{opacity:.58}.aYQbCq_dagNode[data-state=completed]{border-color:color-mix(in srgb, var(--dsw-alias-state-success) 48%, var(--dsw-alias-line-normal))}.aYQbCq_dagNode[data-state=blocked]{border-color:color-mix(in srgb, var(--dsw-alias-state-warning) 52%, var(--dsw-alias-line-normal))}.aYQbCq_dagNode[data-state=failed]{border-color:color-mix(in srgb, var(--dsw-alias-state-danger) 56%, var(--dsw-alias-line-normal))}.aYQbCq_dagNodeHead{color:var(--dsw-alias-label-primary);align-items:center;gap:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9.5px;font-weight:700;display:flex}.aYQbCq_dagNodeDot{background:var(--dsw-alias-line-strong);border-radius:1.5px;flex:none;width:5px;height:5px}.aYQbCq_dagNode[data-state=running] .aYQbCq_dagNodeDot{background:var(--dsw-alias-state-business-primary)}.aYQbCq_dagNode[data-state=running] .aYQbCq_dagNodeHead{padding-right:12px}.aYQbCq_dagRunningState{width:9px;height:9px;color:var(--dsw-alias-state-business-primary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex;position:absolute;top:4px;right:5px}.aYQbCq_dagRunningState .aYQbCq_workGlyph{width:9px;height:9px}.aYQbCq_dagNode[data-state=blocked] .aYQbCq_dagNodeDot{background:var(--dsw-alias-state-warning)}.aYQbCq_dagNode[data-state=completed] .aYQbCq_dagNodeDot{background:var(--dsw-alias-state-success)}.aYQbCq_dagNode[data-state=failed] .aYQbCq_dagNodeDot{background:var(--dsw-alias-state-danger)}.aYQbCq_dagNodeLabel{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:8.5px;line-height:11px;overflow:hidden}.aYQbCq_taskDetail{border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module-platform);border-radius:9px;flex-direction:column;gap:3px;min-width:0;padding:7px 9px;display:flex}.aYQbCq_taskDetailHead{align-items:center;gap:6px;min-width:0;display:flex}.aYQbCq_taskDetailId{color:var(--dsw-alias-state-business-primary);flex:none;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;font-weight:700}.aYQbCq_taskDetailSubject{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:600;line-height:16px;overflow:hidden}.aYQbCq_taskDetailBadge{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 5px;font-size:8.5px;font-weight:600;line-height:14px}.aYQbCq_taskDetailBadge[data-state=running]{background:var(--dsw-alias-bg-fill-business);color:var(--dsw-alias-label-on-fill)}.aYQbCq_taskDetailBadge[data-state=blocked]{background:var(--dsw-alias-bg-fill-warning);color:var(--dsw-alias-label-on-fill)}.aYQbCq_taskDetailBadge[data-state=completed]{background:var(--dsw-alias-bg-fill-success);color:var(--dsw-alias-label-on-fill)}.aYQbCq_taskDetailBadge[data-state=failed]{background:var(--dsw-alias-bg-fill-danger);color:var(--dsw-alias-label-on-fill)}.aYQbCq_taskDetailLine,.aYQbCq_taskDetailMeta{color:var(--dsw-alias-label-secondary);font-size:9.5px;line-height:14px}.aYQbCq_taskDetailMeta{color:var(--dsw-alias-label-tertiary)}.aYQbCq_emptyHint{color:var(--dsw-alias-label-tertiary);padding:10px 12px;font-size:11px;line-height:16px}.aYQbCq_planEditor{border:1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 30%, var(--dsw-alias-line-normal));background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 94%, var(--dsw-alias-state-business-primary));box-shadow:inset 0 1px 0 color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent);border-radius:10px;flex-direction:column;gap:12px;margin:0 10px 12px;padding:12px;display:flex}.aYQbCq_planHeader>span{justify-content:space-between;align-items:center;gap:8px;display:flex}.aYQbCq_planHeader>span>span{flex-direction:column;gap:2px;min-width:0;display:flex}.aYQbCq_planHeader strong{color:var(--dsw-alias-label-primary);font-size:12px}.aYQbCq_planHeader small{color:var(--dsw-alias-label-secondary);font-size:9px;font-weight:500;line-height:13px}.aYQbCq_planHeader em{background:var(--dsw-alias-bg-fill-business);color:var(--dsw-alias-label-on-fill);border-radius:999px;flex:none;padding:1px 7px;font-size:9px;font-style:normal;line-height:16px}.aYQbCq_planHeader p{color:var(--dsw-alias-label-secondary);margin:5px 0 0;font-size:10px;line-height:15px}.aYQbCq_planFlow{grid-template-columns:repeat(3,minmax(0,1fr));margin:0;padding:0;list-style:none;display:grid}.aYQbCq_planFlow li{min-width:0;color:var(--dsw-alias-label-tertiary);align-items:center;gap:5px;font-size:9px;font-weight:600;line-height:14px;display:flex;position:relative}.aYQbCq_planFlow li:not(:last-child):after{background:var(--dsw-alias-line-normal);content:\\"\\";flex:1;min-width:8px;height:1px;margin-right:5px}.aYQbCq_planFlow li>span{border:1px solid var(--dsw-alias-line-normal);border-radius:50%;flex:none;place-items:center;width:18px;height:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;display:grid}.aYQbCq_planFlow li[data-active]{color:var(--dsw-alias-state-business-primary)}.aYQbCq_planFlow li[data-active]>span{border-color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent)}.aYQbCq_planSection{border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-module-platform);border-radius:8px;overflow:hidden}.aYQbCq_planSectionToggle,.aYQbCq_planCardHeader{box-sizing:border-box;width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:0}.aYQbCq_planSectionToggle{justify-content:space-between;align-items:center;gap:8px;min-height:42px;padding:7px 9px;display:flex}.aYQbCq_planSectionToggle:hover,.aYQbCq_planCardHeader:hover{background:color-mix(in srgb, var(--dsw-alias-bg-fill-neutral) 46%, transparent)}.aYQbCq_planSectionToggle>span{align-items:baseline;gap:7px;min-width:0;display:flex}.aYQbCq_planSectionToggle strong{font-size:10.5px}.aYQbCq_planSectionToggle small{color:var(--dsw-alias-label-tertiary);font-size:9px}.aYQbCq_planList{border-top:1px solid var(--dsw-alias-line-normal);flex-direction:column;gap:0;display:flex}.aYQbCq_planEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;padding:12px;font-size:10px}.aYQbCq_planCard{background:0 0;border:0;border-radius:0;min-width:0;margin:0;padding:0;display:block;position:relative}.aYQbCq_planCard+.aYQbCq_planCard{border-top:1px solid var(--dsw-alias-line-normal)}.aYQbCq_planCard[data-open=true]{background:color-mix(in srgb, var(--dsw-alias-bg-base) 62%, transparent)}.aYQbCq_planCardHeader{grid-template-columns:minmax(80px,.9fr) minmax(72px,1.15fr) auto 12px;align-items:center;gap:7px;min-height:40px;padding:6px 9px;display:grid}.aYQbCq_planCardIdentity{flex-direction:column;gap:1px;min-width:0;display:flex}.aYQbCq_planCardIdentity strong,.aYQbCq_planTaskSummary{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;font-weight:650;line-height:14px;overflow:hidden}.aYQbCq_planCardIdentity>span,.aYQbCq_planCardMeta{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:8.5px;line-height:12px;overflow:hidden}.aYQbCq_planTaskId{background:var(--dsw-alias-bg-fill-neutral);width:max-content;color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:8.5px;font-weight:700;line-height:14px}.aYQbCq_planDirty{background:color-mix(in srgb, var(--dsw-alias-state-warning) 13%, transparent);color:var(--dsw-alias-state-warning);border-radius:999px;justify-self:end;padding:1px 5px;font-size:8px;font-style:normal;font-weight:650;line-height:14px}.aYQbCq_planChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .18s cubic-bezier(.2,.7,.2,1)}.aYQbCq_planChevron[data-open=true]{transform:rotate(90deg)}.aYQbCq_planCardBody{flex-direction:column;gap:8px;padding:0 9px 9px;display:flex}.aYQbCq_planCardBody fieldset{border:0;flex-direction:column;gap:7px;min-width:0;margin:0;padding:0;display:flex}.aYQbCq_planCardBody label,.aYQbCq_planNewTask label{min-width:0;color:var(--dsw-alias-label-tertiary);flex-direction:column;flex:1;gap:4px;font-size:9px;display:flex}.aYQbCq_planCardBody label small{color:var(--dsw-alias-label-tertiary);font-size:8px;line-height:11px}.aYQbCq_planCard input,.aYQbCq_planCard textarea,.aYQbCq_planCard select,.aYQbCq_planNewTask input{box-sizing:border-box;border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-base);width:100%;min-width:0;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;outline:none;font-size:10.5px;line-height:16px;transition:border-color .16s,box-shadow .16s}.aYQbCq_planCard input,.aYQbCq_planCard select,.aYQbCq_planNewTask input{min-height:32px;padding:6px 8px}.aYQbCq_planCard textarea{resize:vertical;min-height:58px;padding:7px 8px}.aYQbCq_planCard input:focus-visible,.aYQbCq_planCard textarea:focus-visible,.aYQbCq_planCard select:focus-visible,.aYQbCq_planNewTask input:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 16%, transparent)}.aYQbCq_planGrid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:6px;display:grid}.aYQbCq_planModelPicker{grid-template-columns:minmax(0,1fr);gap:5px;display:grid}.aYQbCq_planModelMenu{width:100%;display:flex}.aYQbCq_planModelTrigger{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:100%;min-height:38px;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;border-radius:7px;justify-content:space-between;align-items:center;gap:8px;padding:7px 9px;transition:border-color .16s,background-color .16s,transform .12s;display:flex}.aYQbCq_planModelTrigger:hover:not(:disabled){border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-interactive-bg-hover)}.aYQbCq_planModelTrigger:active:not(:disabled){transform:translateY(1px)}.aYQbCq_planModelTrigger:focus-visible{border-color:var(--dsw-alias-state-business-primary);outline:2px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 16%, transparent);outline-offset:1px}.aYQbCq_planModelTrigger:disabled{cursor:wait;opacity:.64}.aYQbCq_planModelTriggerCopy{align-items:baseline;gap:6px;min-width:0;display:flex}.aYQbCq_planModelTriggerCopy strong,.aYQbCq_planModelTriggerCopy span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.aYQbCq_planModelTriggerCopy strong{color:var(--dsw-alias-label-primary);font-size:10px;font-weight:650;line-height:15px}.aYQbCq_planModelTriggerCopy span{color:var(--dsw-alias-label-tertiary);font-size:9px;line-height:14px}.aYQbCq_planModelMenuRow{grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;width:100%;min-width:0;display:grid}.aYQbCq_planModelMenuRow>span:first-child{color:var(--dsw-alias-label-primary)}.aYQbCq_planModelMenuRow strong{color:var(--dsw-alias-label-tertiary);text-align:right;text-overflow:ellipsis;white-space:nowrap;font-weight:450;overflow:hidden}.aYQbCq_planModelMenuBack{align-items:center;gap:7px;display:inline-flex}.aYQbCq_planModelMenuBack svg{transform:rotate(180deg)}.aYQbCq_planModelEffortRow{flex-direction:column;align-items:flex-start;min-width:0;display:flex}.aYQbCq_planModelEffortRow small{width:100%;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:10px;line-height:14px;overflow:hidden}.aYQbCq_planModelHint{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:8.5px;line-height:12px;overflow:hidden}.aYQbCq_planModelNotice{background:color-mix(in srgb, var(--dsw-alias-state-warning) 9%, transparent);color:var(--dsw-alias-label-secondary);border-radius:6px;grid-column:1/-1;justify-content:space-between;align-items:center;gap:8px;padding:6px 7px;font-size:8.5px;line-height:12px;display:flex}.aYQbCq_planModelNotice button{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;background:0 0;border:0;flex:none;padding:2px 6px;font-weight:650}.aYQbCq_planActions,.aYQbCq_planApproveRow,.aYQbCq_planNewTask,.aYQbCq_planConfirm,.aYQbCq_planApproveActions,.aYQbCq_planSecondaryActions{align-items:center;gap:7px;display:flex}.aYQbCq_planReviewActions{grid-template-columns:minmax(0,1fr);gap:6px;width:100%;display:grid}.aYQbCq_planSecondaryActions{grid-template-columns:minmax(0,1fr) auto;display:grid}.aYQbCq_planActions{justify-content:flex-end}.aYQbCq_planActions button,.aYQbCq_planNewTask button,.aYQbCq_planApproveRow button,.aYQbCq_planConfirm button{border:1px solid var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-fill-neutral);min-height:30px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:5px 10px;font-size:9.5px;font-weight:600;transition:background .16s,border-color .16s,transform .16s}.aYQbCq_planActions button:hover:not(:disabled),.aYQbCq_planNewTask button:hover:not(:disabled),.aYQbCq_planApproveRow button:hover:not(:disabled),.aYQbCq_planConfirm button:hover:not(:disabled){border-color:var(--dsw-alias-label-tertiary)}.aYQbCq_planActions button:active:not(:disabled),.aYQbCq_planNewTask button:active:not(:disabled),.aYQbCq_planApproveRow button:active:not(:disabled),.aYQbCq_planConfirm button:active:not(:disabled){transform:scale(.98)}.aYQbCq_planActions button[data-danger],.aYQbCq_planConfirm button[data-danger]{color:var(--dsw-alias-state-danger)}.aYQbCq_planFeedback{min-width:0;color:var(--dsw-alias-label-secondary);flex:1;align-items:center;gap:5px;font-size:9px;line-height:13px;animation:.18s ease-out aYQbCq_plan-feedback-in;display:inline-flex}.aYQbCq_planFeedback[data-tone=success]{color:var(--dsw-alias-state-success)}.aYQbCq_planFeedback[data-tone=error]{color:var(--dsw-alias-state-danger)}.aYQbCq_planFeedback>span{border:1px solid;border-radius:50%;flex:none;place-items:center;width:15px;height:15px;display:grid}.aYQbCq_planFeedback svg{width:11px;height:11px}@keyframes aYQbCq_plan-feedback-in{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}.aYQbCq_planConfirm{border:1px solid color-mix(in srgb, var(--dsw-alias-state-danger) 30%, var(--dsw-alias-line-normal));background:color-mix(in srgb, var(--dsw-alias-state-danger) 7%, transparent);border-radius:7px;flex-wrap:wrap;justify-content:flex-end;padding:7px}.aYQbCq_planConfirm>span{min-width:140px;color:var(--dsw-alias-label-secondary);flex:1;font-size:9px;line-height:13px}.aYQbCq_planNewTask{align-items:flex-end}.aYQbCq_planNewTask label{gap:4px}.aYQbCq_planNewTask label>span{line-height:13px}.aYQbCq_planApproveRow{z-index:1;border:1px solid var(--dsw-alias-line-normal);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 94%, transparent);min-height:50px;box-shadow:0 -5px 16px color-mix(in srgb, var(--dsw-alias-bg-base) 35%, transparent);backdrop-filter:blur(8px);border-radius:8px;flex-direction:column;justify-content:flex-end;align-items:stretch;margin:0 -4px -4px;padding:8px;position:sticky;bottom:0}.aYQbCq_planApproveRow[data-armed=true]{border-color:color-mix(in srgb, var(--dsw-alias-state-business-primary) 45%, var(--dsw-alias-line-normal))}.aYQbCq_planApproveRow[data-discard=true]{border-color:color-mix(in srgb, var(--dsw-alias-state-danger) 45%, var(--dsw-alias-line-normal))}.aYQbCq_planApproveCopy{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.aYQbCq_planApproveCopy strong{color:var(--dsw-alias-label-primary);font-size:9.5px;line-height:13px}.aYQbCq_planApproveCopy small{color:var(--dsw-alias-label-tertiary);font-size:8.5px;line-height:12px}.aYQbCq_planApproveRow button{background:var(--dsw-alias-state-business-primary);min-height:32px;color:var(--dsw-alias-label-on-fill);padding-inline:13px}.aYQbCq_planReviewActions>button[data-plan-approve]{width:100%}.aYQbCq_planApproveActions>button:first-child{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-primary)}.aYQbCq_planSecondaryActions>button,.aYQbCq_planApproveActions>button[data-danger]{border-color:var(--dsw-alias-line-normal);background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-primary)}.aYQbCq_planSecondaryActions>button[data-danger],.aYQbCq_planApproveActions>button[data-danger]{color:var(--dsw-alias-state-danger)}.aYQbCq_planSectionToggle:focus-visible,.aYQbCq_planCardHeader:focus-visible,.aYQbCq_planActions button:focus-visible,.aYQbCq_planNewTask button:focus-visible,.aYQbCq_planApproveRow button:focus-visible,.aYQbCq_planConfirm button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.aYQbCq_planActions button:disabled,.aYQbCq_planNewTask button:disabled,.aYQbCq_planApproveRow button:disabled{cursor:default;opacity:.55}.aYQbCq_historicPill{background:var(--dsw-alias-bg-fill-neutral);color:var(--dsw-alias-label-tertiary);border-radius:4px;flex:none;margin-left:auto;padding:1px 7px;font-size:9.5px;font-weight:600;line-height:15px}.aYQbCq_members{flex-direction:column;gap:3px;display:flex}.aYQbCq_archiveLabel{color:var(--dsw-alias-label-tertiary);padding:5px 14px 0;font-size:9.5px;font-weight:600;line-height:14px;display:block}@media (prefers-reduced-motion:reduce){.aYQbCq_panel,.aYQbCq_badge,.aYQbCq_badgeDot,.aYQbCq_panelDot,.aYQbCq_workGlyph rect,.aYQbCq_stateArt,.aYQbCq_memberAvatar[data-unread=true]:after,.aYQbCq_planChevron,.aYQbCq_planFeedback,.aYQbCq_planActions button,.aYQbCq_planNewTask button,.aYQbCq_planApproveRow button,.aYQbCq_planConfirm button,.aYQbCq_planCard input,.aYQbCq_planCard textarea,.aYQbCq_planCard select,.aYQbCq_planNewTask input{transition:none;animation:none}}@media (width<=960px){html[data-t-team-panel-open] [data-phase=active]{padding-right:0}}@media (width<=640px){.aYQbCq_badge{top:56px;right:10px}.aYQbCq_teamStats span[data-stat=messages]{display:none}.aYQbCq_captainNode{grid-template-columns:48px minmax(0,1fr)}.aYQbCq_captainState{display:none}.aYQbCq_delegationTree{margin-left:12px;padding-left:15px}.aYQbCq_memberBranch{width:15px}.aYQbCq_assignmentLine{padding-left:53px}.aYQbCq_planFlow li{gap:4px;font-size:8px}.aYQbCq_planFlow li:not(:last-child):after{margin-right:3px}.aYQbCq_planCardHeader{grid-template-columns:auto minmax(0,1fr) auto}.aYQbCq_planCardHeader .aYQbCq_planCardMeta{display:none}.aYQbCq_planGrid,.aYQbCq_planModelPicker{grid-template-columns:minmax(0,1fr)}.aYQbCq_planNewTask,.aYQbCq_planApproveRow{flex-direction:column;align-items:stretch}.aYQbCq_planNewTask button,.aYQbCq_planApproveRow>button,.aYQbCq_planApproveActions,.aYQbCq_planReviewActions{width:100%}.aYQbCq_planApproveActions button,.aYQbCq_planReviewActions button,.aYQbCq_planSecondaryActions button{flex:1}}@container aYQbCq_agent-team (width<=360px){.aYQbCq_planEditor{margin-inline:0;padding-inline:10px}.aYQbCq_planHeader>span{align-items:flex-start}.aYQbCq_planFlow li{gap:3px;font-size:7.5px}.aYQbCq_planFlow li:not(:last-child):after{min-width:4px;margin-right:2px}.aYQbCq_planSecondaryActions,.aYQbCq_planApproveActions{grid-template-columns:minmax(0,1fr);width:100%;display:grid}.aYQbCq_planSecondaryActions button,.aYQbCq_planApproveActions button{width:100%}}";\n const tagId = "dsh-plugin-t-expert/ActivityPanel.module.css";\n if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {\n const tag = document.createElement("style");\n tag.dataset.plugin = "dsh-plugin-t-expert";\n tag.dataset.pluginCss = tagId;\n tag.textContent = css;\n document.head.appendChild(tag);\n }\n var ActivityPanel_module_css_default = {\n "agent-team": "aYQbCq_agent-team",\n "tTeamBreathe": "aYQbCq_tTeamBreathe",\n "tTeamDot": "aYQbCq_tTeamDot",\n "tTeamFloat": "aYQbCq_tTeamFloat",\n "tTeamPanelIn": "aYQbCq_tTeamPanelIn",\n "tTeamPulse": "aYQbCq_tTeamPulse",\n "tTeamThink": "aYQbCq_tTeamThink",\n "tTeamUnreadPulse": "aYQbCq_tTeamUnreadPulse",\n "archiveLabel": "aYQbCq_archiveLabel",\n "assignmentChip": "aYQbCq_assignmentChip",\n "assignmentLabel": "aYQbCq_assignmentLabel",\n "assignmentLine": "aYQbCq_assignmentLine",\n "assignmentTasks": "aYQbCq_assignmentTasks",\n "badge": "aYQbCq_badge",\n "badgeCount": "aYQbCq_badgeCount",\n "badgeDot": "aYQbCq_badgeDot",\n "captainAvatar": "aYQbCq_captainAvatar",\n "captainInfo": "aYQbCq_captainInfo",\n "captainLine": "aYQbCq_captainLine",\n "captainName": "aYQbCq_captainName",\n "captainNode": "aYQbCq_captainNode",\n "captainRole": "aYQbCq_captainRole",\n "captainState": "aYQbCq_captainState",\n "captainSummary": "aYQbCq_captainSummary",\n "chevron": "aYQbCq_chevron",\n "dagCanvas": "aYQbCq_dagCanvas",\n "dagEdges": "aYQbCq_dagEdges",\n "dagNode": "aYQbCq_dagNode",\n "dagNodeDot": "aYQbCq_dagNodeDot",\n "dagNodeHead": "aYQbCq_dagNodeHead",\n "dagNodeLabel": "aYQbCq_dagNodeLabel",\n "dagRunningState": "aYQbCq_dagRunningState",\n "dagViewport": "aYQbCq_dagViewport",\n "delegationSection": "aYQbCq_delegationSection",\n "delegationTree": "aYQbCq_delegationTree",\n "dependencySection": "aYQbCq_dependencySection",\n "emptyHint": "aYQbCq_emptyHint",\n "historicPill": "aYQbCq_historicPill",\n "iconButton": "aYQbCq_iconButton",\n "leadAvatar": "aYQbCq_leadAvatar",\n "memberArt": "aYQbCq_memberArt",\n "memberAvatar": "aYQbCq_memberAvatar",\n "memberBlock": "aYQbCq_memberBlock",\n "memberBranch": "aYQbCq_memberBranch",\n "memberCount": "aYQbCq_memberCount",\n "memberInfo": "aYQbCq_memberInfo",\n "memberInitial": "aYQbCq_memberInitial",\n "memberLine": "aYQbCq_memberLine",\n "memberModel": "aYQbCq_memberModel",\n "memberName": "aYQbCq_memberName",\n "memberRole": "aYQbCq_memberRole",\n "memberRow": "aYQbCq_memberRow",\n "memberState": "aYQbCq_memberState",\n "memberStatusLine": "aYQbCq_memberStatusLine",\n "members": "aYQbCq_members",\n "membersToggle": "aYQbCq_membersToggle",\n "panel": "aYQbCq_panel",\n "panelControls": "aYQbCq_panelControls",\n "panelDot": "aYQbCq_panelDot",\n "panelHead": "aYQbCq_panelHead",\n "panelTitle": "aYQbCq_panelTitle",\n "plan-feedback-in": "aYQbCq_plan-feedback-in",\n "planActions": "aYQbCq_planActions",\n "planApproveActions": "aYQbCq_planApproveActions",\n "planApproveCopy": "aYQbCq_planApproveCopy",\n "planApproveRow": "aYQbCq_planApproveRow",\n "planCard": "aYQbCq_planCard",\n "planCardBody": "aYQbCq_planCardBody",\n "planCardHeader": "aYQbCq_planCardHeader",\n "planCardIdentity": "aYQbCq_planCardIdentity",\n "planCardMeta": "aYQbCq_planCardMeta",\n "planChevron": "aYQbCq_planChevron",\n "planConfirm": "aYQbCq_planConfirm",\n "planDirty": "aYQbCq_planDirty",\n "planEditor": "aYQbCq_planEditor",\n "planEmpty": "aYQbCq_planEmpty",\n "planFeedback": "aYQbCq_planFeedback",\n "planFlow": "aYQbCq_planFlow",\n "planGrid": "aYQbCq_planGrid",\n "planHeader": "aYQbCq_planHeader",\n "planList": "aYQbCq_planList",\n "planModelEffortRow": "aYQbCq_planModelEffortRow",\n "planModelHint": "aYQbCq_planModelHint",\n "planModelMenu": "aYQbCq_planModelMenu",\n "planModelMenuBack": "aYQbCq_planModelMenuBack",\n "planModelMenuRow": "aYQbCq_planModelMenuRow",\n "planModelNotice": "aYQbCq_planModelNotice",\n "planModelPicker": "aYQbCq_planModelPicker",\n "planModelTrigger": "aYQbCq_planModelTrigger",\n "planModelTriggerCopy": "aYQbCq_planModelTriggerCopy",\n "planNewTask": "aYQbCq_planNewTask",\n "planReviewActions": "aYQbCq_planReviewActions",\n "planSecondaryActions": "aYQbCq_planSecondaryActions",\n "planSection": "aYQbCq_planSection",\n "planSectionToggle": "aYQbCq_planSectionToggle",\n "planTaskId": "aYQbCq_planTaskId",\n "planTaskSummary": "aYQbCq_planTaskSummary",\n "progressEmpty": "aYQbCq_progressEmpty",\n "progressLegend": "aYQbCq_progressLegend",\n "progressOverview": "aYQbCq_progressOverview",\n "progressSegments": "aYQbCq_progressSegments",\n "progressSummary": "aYQbCq_progressSummary",\n "progressSummaryDot": "aYQbCq_progressSummaryDot",\n "progressTitle": "aYQbCq_progressTitle",\n "resizeHandle": "aYQbCq_resizeHandle",\n "sectionHead": "aYQbCq_sectionHead",\n "sectionHint": "aYQbCq_sectionHint",\n "sectionTitle": "aYQbCq_sectionTitle",\n "sectionToggleTitle": "aYQbCq_sectionToggleTitle",\n "stageLabel": "aYQbCq_stageLabel",\n "stateArt": "aYQbCq_stateArt",\n "stopModalActions": "aYQbCq_stopModalActions",\n "stopModalError": "aYQbCq_stopModalError",\n "taskDetail": "aYQbCq_taskDetail",\n "taskDetailBadge": "aYQbCq_taskDetailBadge",\n "taskDetailHead": "aYQbCq_taskDetailHead",\n "taskDetailId": "aYQbCq_taskDetailId",\n "taskDetailLine": "aYQbCq_taskDetailLine",\n "taskDetailMeta": "aYQbCq_taskDetailMeta",\n "taskDetailModel": "aYQbCq_taskDetailModel",\n "taskDetailSubject": "aYQbCq_taskDetailSubject",\n "taskEmpty": "aYQbCq_taskEmpty",\n "taskId": "aYQbCq_taskId",\n "team": "aYQbCq_team",\n "teamHead": "aYQbCq_teamHead",\n "teamName": "aYQbCq_teamName",\n "teamStats": "aYQbCq_teamStats",\n "teamStopButton": "aYQbCq_teamStopButton",\n "teams": "aYQbCq_teams",\n "unreadPill": "aYQbCq_unreadPill",\n "workGlyph": "aYQbCq_workGlyph"\n };\n\n\n /**\n * Editable pre-run roster and DAG review for staged T Team plans.\n *\n * This leaf owns only transient form/disclosure state. Durable truth remains\n * on the host and returns through the ordinary activity polling snapshot.\n * @module t-team/client/staging-plan\n */\n const PLAN_URL = "/plugins/t-team/plan";\n function useDismissSuccess(feedback, setFeedback) {\n (0, react.useEffect)(() => {\n if (feedback?.tone !== "success") return;\n const timeout = window.setTimeout(() => {\n setFeedback(void 0);\n }, 3500);\n return () => {\n window.clearTimeout(timeout);\n };\n }, [feedback, setFeedback]);\n }\n async function mutatePlan(payload) {\n const response = await fetch(PLAN_URL, {\n method: "POST",\n cache: "no-store",\n headers: { "content-type": "application/json" },\n body: JSON.stringify(payload)\n });\n if (response.ok) return;\n let message = `HTTP ${response.status}`;\n try {\n const body = await response.json();\n if (typeof body.error === "string" && body.error.trim() !== "") message = body.error;\n } catch {}\n throw new Error(message);\n }\n function errorMessage(error) {\n return error instanceof Error ? error.message : String(error);\n }\n function DisclosureChevron({ open }) {\n return (0, react_jsx_runtime.jsx)("svg", {\n className: ActivityPanel_module_css_default.planChevron,\n "data-open": open,\n width: "12",\n height: "12",\n viewBox: "0 0 12 12",\n fill: "none",\n stroke: "currentColor",\n strokeWidth: "1.5",\n strokeLinecap: "round",\n "aria-hidden": true,\n children: (0, react_jsx_runtime.jsx)("path", { d: "M4 2.5 7.5 6 4 9.5" })\n });\n }\n function Feedback({ value }) {\n if (value === void 0) return null;\n return (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planFeedback,\n "data-tone": value.tone,\n role: value.tone === "error" ? "alert" : "status",\n "aria-live": value.tone === "error" ? "assertive" : "polite",\n children: [(0, react_jsx_runtime.jsx)("span", {\n "aria-hidden": true,\n children: value.tone === "success" ? (0, react_jsx_runtime.jsx)("svg", {\n viewBox: "0 0 12 12",\n fill: "none",\n stroke: "currentColor",\n strokeWidth: "1.8",\n children: (0, react_jsx_runtime.jsx)("path", { d: "m2.5 6.2 2.2 2.2 4.8-5" })\n }) : (0, react_jsx_runtime.jsx)("svg", {\n viewBox: "0 0 12 12",\n fill: "none",\n stroke: "currentColor",\n strokeWidth: "1.8",\n children: (0, react_jsx_runtime.jsx)("path", { d: "M6 2.3v4.1M6 8.8v.1" })\n })\n }), value.message]\n });\n }\n function routeKey(provider, model) {\n return JSON.stringify([provider, model]);\n }\n const MODEL_MENU_OPEN_MODELS = "open:models";\n const MODEL_MENU_OPEN_EFFORT = "open:effort";\n const MODEL_MENU_BACK = "navigate:back";\n const MODEL_MENU_RETRY = "action:retry";\n const MODEL_MENU_DEFAULT_EFFORT = "effort:default";\n function modelMenuId(provider, model) {\n return `model:${routeKey(provider, model)}`;\n }\n function effortMenuId(effort) {\n return `effort:${effort}`;\n }\n /**\n * Thin staged-plan adapter over the official model directory. It deliberately\n * reads only catalog metadata: choosing a member route must not change the\n * captain session\'s composer model.\n */\n function StagedModelPicker({ directory, provider, model, reasoningEffort, busy, onChange, t }) {\n const state = (0, react.useSyncExternalStore)(directory.store.subscribe, directory.store.getSnapshot);\n const [open, setOpen] = (0, react.useState)(false);\n const [pane, setPane] = (0, react.useState)("root");\n const catalogRoutes = state.groups.flatMap((group) => group.models.map((candidate) => ({\n key: routeKey(group.id, candidate.id),\n provider: group.id,\n providerName: group.name,\n model: candidate\n })));\n const selectedKey = routeKey(provider, model);\n const selected = catalogRoutes.find((candidate) => candidate.key === selectedKey);\n const efforts = selected?.model.reasoning?.efforts ?? [];\n const currentMissing = provider !== "" && model !== "" && selected === void 0;\n const defaultEffort = selected?.model.reasoning?.defaultEffort;\n const effectiveEffort = reasoningEffort === "" || reasoningEffort === "default" ? defaultEffort : reasoningEffort;\n const selectedEffort = efforts.find((effort) => effort.id === effectiveEffort);\n const modelLabel = selected?.model.name ?? (model === "" ? t("plan.model.choose") : model);\n const effortLabel = selectedEffort?.name ?? (effectiveEffort === void 0 ? t("plan.model.providerDefault") : effectiveEffort);\n const unavailable = state.status === "error" || state.failures.length > 0;\n const close = () => {\n setOpen(false);\n setPane("root");\n };\n const rootItems = [{\n id: MODEL_MENU_OPEN_MODELS,\n label: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelMenuRow,\n children: [\n (0, react_jsx_runtime.jsx)("span", { children: t("plan.member.model") }),\n (0, react_jsx_runtime.jsx)("strong", { children: modelLabel }),\n (0, react_jsx_runtime.jsx)(DisclosureChevron, { open: false })\n ]\n }),\n disabled: state.status === "loading" && catalogRoutes.length === 0\n }, {\n id: MODEL_MENU_OPEN_EFFORT,\n label: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelMenuRow,\n children: [\n (0, react_jsx_runtime.jsx)("span", { children: t("plan.member.reasoning") }),\n (0, react_jsx_runtime.jsx)("strong", { children: effortLabel }),\n (0, react_jsx_runtime.jsx)(DisclosureChevron, { open: false })\n ]\n }),\n disabled: selected?.model.reasoning === void 0\n }];\n const modelItems = [{\n id: MODEL_MENU_BACK,\n label: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelMenuBack,\n children: [(0, react_jsx_runtime.jsx)(DisclosureChevron, { open: false }), t("plan.model.back")]\n })\n }, {\n type: "separator",\n id: "models:separator"\n }];\n if (catalogRoutes.length === 0) modelItems.push({\n id: "models:empty",\n label: state.status === "loading" ? t("plan.model.loading") : t("plan.model.empty"),\n disabled: true\n });\n else for (const group of state.groups) {\n modelItems.push({\n type: "label",\n id: `provider:${group.id}`,\n text: group.name\n });\n for (const candidate of group.models) modelItems.push({\n id: modelMenuId(group.id, candidate.id),\n label: candidate.name\n });\n }\n const effortItems = [\n {\n id: MODEL_MENU_BACK,\n label: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelMenuBack,\n children: [(0, react_jsx_runtime.jsx)(DisclosureChevron, { open: false }), t("plan.model.back")]\n })\n },\n {\n type: "separator",\n id: "effort:separator"\n },\n {\n id: MODEL_MENU_DEFAULT_EFFORT,\n label: defaultEffort === void 0 ? t("plan.model.providerDefault") : t("plan.model.modelDefault", { effort: efforts.find((effort) => effort.id === defaultEffort)?.name ?? defaultEffort })\n },\n ...efforts.map((effort) => ({\n id: effortMenuId(effort.id),\n label: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelEffortRow,\n children: [(0, react_jsx_runtime.jsx)("span", { children: effort.name }), effort.description !== void 0 && (0, react_jsx_runtime.jsx)("small", { children: effort.description })]\n })\n }))\n ];\n const items = pane === "models" ? modelItems : pane === "effort" ? effortItems : rootItems;\n const selectedId = pane === "models" ? modelMenuId(provider, model) : pane === "effort" ? reasoningEffort === "" || reasoningEffort === "default" ? MODEL_MENU_DEFAULT_EFFORT : effortMenuId(reasoningEffort) : void 0;\n const choose = (id) => {\n if (id === MODEL_MENU_OPEN_MODELS) {\n setPane("models");\n return;\n }\n if (id === MODEL_MENU_OPEN_EFFORT) {\n setPane("effort");\n return;\n }\n if (id === MODEL_MENU_BACK) {\n setPane("root");\n return;\n }\n if (id === MODEL_MENU_RETRY) {\n directory.load().catch(() => void 0);\n return;\n }\n const nextModel = catalogRoutes.find((candidate) => modelMenuId(candidate.provider, candidate.model.id) === id);\n if (nextModel !== void 0) {\n close();\n if (nextModel.provider === provider && nextModel.model.id === model) return;\n onChange({\n provider: nextModel.provider,\n model: nextModel.model.id,\n reasoningEffort: "default"\n });\n return;\n }\n if (id === MODEL_MENU_DEFAULT_EFFORT) {\n close();\n if (effectiveEffort === defaultEffort) return;\n onChange({\n provider,\n model,\n reasoningEffort: "default"\n });\n return;\n }\n const nextEffort = efforts.find((effort) => effortMenuId(effort.id) === id);\n if (nextEffort === void 0) return;\n close();\n if (nextEffort.id === reasoningEffort) return;\n onChange({\n provider,\n model,\n reasoningEffort: nextEffort.id\n });\n };\n return (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.planModelPicker,\n "data-model-directory-status": state.status,\n children: [\n (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {\n open,\n portal: true,\n align: "end",\n compact: true,\n className: ActivityPanel_module_css_default.planModelMenu,\n items,\n footer: unavailable ? [{\n id: MODEL_MENU_RETRY,\n label: t("plan.model.retry")\n }] : void 0,\n selectedId,\n onSelect: choose,\n onClose: close,\n anchor: (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.planModelTrigger,\n "data-plan-model-trigger": true,\n "aria-label": t("plan.model.triggerAria", {\n model: modelLabel,\n effort: effortLabel\n }),\n "aria-haspopup": "menu",\n "aria-expanded": open,\n disabled: busy,\n onClick: () => {\n if (open) close();\n else {\n setPane("root");\n setOpen(true);\n directory.load().catch(() => void 0);\n }\n },\n children: [(0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelTriggerCopy,\n children: [(0, react_jsx_runtime.jsx)("strong", { children: state.status === "loading" && catalogRoutes.length === 0 ? t("plan.model.loading") : modelLabel }), (0, react_jsx_runtime.jsx)("span", { children: effortLabel })]\n }), (0, react_jsx_runtime.jsx)(DisclosureChevron, { open })]\n })\n }),\n (0, react_jsx_runtime.jsx)("small", {\n className: ActivityPanel_module_css_default.planModelHint,\n children: currentMissing ? t("plan.model.currentUnavailable", {\n provider,\n model\n }) : selected?.model.description ?? t("plan.model.route", {\n provider,\n model\n })\n }),\n unavailable && (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planModelNotice,\n role: state.status === "error" ? "alert" : "status",\n children: [(0, react_jsx_runtime.jsx)("span", { children: state.error ?? t("plan.model.partialFailure", { count: state.failures.length }) }), (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n disabled: busy || state.status === "loading",\n onClick: () => {\n directory.load().catch(() => void 0);\n },\n children: t("plan.model.retry")\n })]\n })\n ]\n });\n }\n function StagedMemberEditor({ team, member, modelDirectory, onPendingChange, t }) {\n const bodyId = (0, react.useId)();\n const [open, setOpen] = (0, react.useState)(false);\n const [role, setRole] = (0, react.useState)(member.role);\n const [provider, setProvider] = (0, react.useState)(member.provider ?? "");\n const [model, setModel] = (0, react.useState)(member.model ?? "");\n const [reasoningEffort, setReasoningEffort] = (0, react.useState)(member.reasoningEffort ?? "");\n const [executionPrompt, setExecutionPrompt] = (0, react.useState)(member.executionPrompt ?? "");\n const remoteSignature = JSON.stringify([\n member.role,\n member.provider ?? "",\n member.model ?? "",\n member.reasoningEffort ?? "",\n member.executionPrompt ?? ""\n ]);\n const [savedSignature, setSavedSignature] = (0, react.useState)(remoteSignature);\n const [busy, setBusy] = (0, react.useState)(false);\n const [feedback, setFeedback] = (0, react.useState)();\n useDismissSuccess(feedback, setFeedback);\n const dirty = JSON.stringify([\n role,\n provider,\n model,\n reasoningEffort,\n executionPrompt\n ]) !== savedSignature;\n (0, react.useEffect)(() => {\n onPendingChange(`member:${member.name}`, dirty || busy);\n return () => {\n onPendingChange(`member:${member.name}`, false);\n };\n }, [\n busy,\n dirty,\n member.name,\n onPendingChange\n ]);\n (0, react.useEffect)(() => {\n setRole(member.role);\n setProvider(member.provider ?? "");\n setModel(member.model ?? "");\n setReasoningEffort(member.reasoningEffort ?? "");\n setExecutionPrompt(member.executionPrompt ?? "");\n setSavedSignature(remoteSignature);\n }, [\n member.role,\n member.provider,\n member.model,\n member.reasoningEffort,\n member.executionPrompt,\n remoteSignature\n ]);\n const markEdited = () => {\n setFeedback(void 0);\n };\n const persist = async (selection = {\n provider,\n model,\n reasoningEffort\n }) => {\n const nextSignature = JSON.stringify([\n role,\n selection.provider,\n selection.model,\n selection.reasoningEffort,\n executionPrompt\n ]);\n setProvider(selection.provider);\n setModel(selection.model);\n setReasoningEffort(selection.reasoningEffort);\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "update_member",\n memberName: member.name,\n role,\n provider: selection.provider,\n model: selection.model,\n reasoningEffort: selection.reasoningEffort,\n executionPrompt\n });\n setSavedSignature(nextSignature);\n setFeedback({\n tone: "success",\n message: t("plan.saved")\n });\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n } finally {\n setBusy(false);\n }\n };\n const save = async (event) => {\n event.preventDefault();\n await persist();\n };\n const route = `${provider}/${model}`.replace(/^\\//u, "");\n return (0, react_jsx_runtime.jsxs)("article", {\n className: ActivityPanel_module_css_default.planCard,\n "data-plan-member": member.name,\n "data-open": open,\n children: [(0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.planCardHeader,\n "aria-expanded": open,\n "aria-controls": bodyId,\n onClick: () => {\n setOpen((current) => !current);\n },\n children: [\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planCardIdentity,\n children: [(0, react_jsx_runtime.jsx)("strong", { children: member.name }), (0, react_jsx_runtime.jsx)("span", { children: role || t("plan.member.roleFallback") })]\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.planCardMeta,\n title: route,\n children: route\n }),\n dirty && (0, react_jsx_runtime.jsx)("em", {\n className: ActivityPanel_module_css_default.planDirty,\n children: t("plan.unsaved")\n }),\n (0, react_jsx_runtime.jsx)(DisclosureChevron, { open })\n ]\n }), open && (0, react_jsx_runtime.jsxs)("form", {\n id: bodyId,\n className: ActivityPanel_module_css_default.planCardBody,\n onSubmit: (event) => {\n save(event);\n },\n children: [(0, react_jsx_runtime.jsxs)("fieldset", {\n disabled: busy,\n children: [\n (0, react_jsx_runtime.jsxs)("label", { children: [t("plan.member.role"), (0, react_jsx_runtime.jsx)("input", {\n name: "role",\n value: role,\n onChange: (event) => {\n setRole(event.currentTarget.value);\n markEdited();\n }\n })] }),\n (0, react_jsx_runtime.jsx)(StagedModelPicker, {\n directory: modelDirectory,\n provider,\n model,\n reasoningEffort,\n busy,\n onChange: (selection) => {\n persist(selection);\n },\n t\n }),\n (0, react_jsx_runtime.jsxs)("label", { children: [t("plan.member.prompt"), (0, react_jsx_runtime.jsx)("textarea", {\n name: "executionPrompt",\n value: executionPrompt,\n onChange: (event) => {\n setExecutionPrompt(event.currentTarget.value);\n markEdited();\n },\n rows: 3\n })] })\n ]\n }), (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planActions,\n children: [(0, react_jsx_runtime.jsx)(Feedback, { value: feedback }), (0, react_jsx_runtime.jsx)("button", {\n type: "submit",\n disabled: busy || !dirty || provider.trim() === "" || model.trim() === "",\n children: busy ? t("plan.saving") : t("plan.save")\n })]\n })]\n })]\n });\n }\n function StagedTaskEditor({ team, task, onPendingChange, t }) {\n const bodyId = (0, react.useId)();\n const taskDependencies = task.dependencies.join(", ");\n const [open, setOpen] = (0, react.useState)(false);\n const [subject, setSubject] = (0, react.useState)(task.subject);\n const [description, setDescription] = (0, react.useState)(task.description ?? "");\n const [assignee, setAssignee] = (0, react.useState)(task.assignee);\n const [dependencies, setDependencies] = (0, react.useState)(taskDependencies);\n const remoteSignature = JSON.stringify([\n task.subject,\n task.description ?? "",\n task.assignee,\n taskDependencies\n ]);\n const [savedSignature, setSavedSignature] = (0, react.useState)(remoteSignature);\n const [busy, setBusy] = (0, react.useState)(false);\n const [confirmingRemove, setConfirmingRemove] = (0, react.useState)(false);\n const [feedback, setFeedback] = (0, react.useState)();\n useDismissSuccess(feedback, setFeedback);\n const signature = JSON.stringify([\n subject,\n description,\n assignee,\n dependencies\n ]);\n const dirty = signature !== savedSignature;\n (0, react.useEffect)(() => {\n onPendingChange(`task:${task.id}`, dirty || busy);\n return () => {\n onPendingChange(`task:${task.id}`, false);\n };\n }, [\n busy,\n dirty,\n onPendingChange,\n task.id\n ]);\n (0, react.useEffect)(() => {\n setSubject(task.subject);\n setDescription(task.description ?? "");\n setAssignee(task.assignee);\n setDependencies(taskDependencies);\n setSavedSignature(remoteSignature);\n }, [\n task.subject,\n task.description,\n task.assignee,\n taskDependencies,\n remoteSignature\n ]);\n const markEdited = () => {\n setFeedback(void 0);\n setConfirmingRemove(false);\n };\n const save = async (event) => {\n event.preventDefault();\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "update_task",\n taskId: task.id,\n subject,\n description,\n assignee,\n dependencies: dependencies.split(",").map((item) => item.trim()).filter(Boolean)\n });\n setSavedSignature(signature);\n setFeedback({\n tone: "success",\n message: t("plan.saved")\n });\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n } finally {\n setBusy(false);\n }\n };\n const remove = async () => {\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "remove_task",\n taskId: task.id\n });\n setFeedback({\n tone: "success",\n message: t("plan.removed")\n });\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n setBusy(false);\n }\n };\n const dependencySummary = task.dependencies.length === 0 ? t("plan.dependencies.none") : t("plan.dependencies.count", { count: task.dependencies.length });\n return (0, react_jsx_runtime.jsxs)("article", {\n className: ActivityPanel_module_css_default.planCard,\n "data-plan-task": task.id,\n "data-open": open,\n children: [(0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.planCardHeader,\n "aria-expanded": open,\n "aria-controls": bodyId,\n onClick: () => {\n setOpen((current) => !current);\n },\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.planTaskId,\n children: task.id\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.planTaskSummary,\n title: subject,\n children: subject\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planCardMeta,\n children: [\n assignee || t("plan.task.unassigned"),\n " \xB7 ",\n dependencySummary\n ]\n }),\n dirty && (0, react_jsx_runtime.jsx)("em", {\n className: ActivityPanel_module_css_default.planDirty,\n children: t("plan.unsaved")\n }),\n (0, react_jsx_runtime.jsx)(DisclosureChevron, { open })\n ]\n }), open && (0, react_jsx_runtime.jsxs)("form", {\n id: bodyId,\n className: ActivityPanel_module_css_default.planCardBody,\n onSubmit: (event) => {\n save(event);\n },\n children: [\n (0, react_jsx_runtime.jsxs)("fieldset", {\n disabled: busy,\n children: [\n (0, react_jsx_runtime.jsxs)("label", { children: [t("plan.task.subject"), (0, react_jsx_runtime.jsx)("input", {\n name: "subject",\n required: true,\n value: subject,\n onChange: (event) => {\n setSubject(event.currentTarget.value);\n markEdited();\n }\n })] }),\n (0, react_jsx_runtime.jsxs)("label", { children: [t("plan.task.description"), (0, react_jsx_runtime.jsx)("textarea", {\n name: "description",\n value: description,\n onChange: (event) => {\n setDescription(event.currentTarget.value);\n markEdited();\n },\n rows: 3\n })] }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planGrid,\n children: [(0, react_jsx_runtime.jsxs)("label", { children: [t("plan.task.assignee"), (0, react_jsx_runtime.jsxs)("select", {\n name: "assignee",\n value: assignee,\n onChange: (event) => {\n setAssignee(event.currentTarget.value);\n markEdited();\n },\n children: [(0, react_jsx_runtime.jsx)("option", {\n value: "",\n children: t("plan.task.unassigned")\n }), team.members.map((member) => (0, react_jsx_runtime.jsx)("option", {\n value: member.name,\n children: member.name\n }, member.name))]\n })] }), (0, react_jsx_runtime.jsxs)("label", { children: [\n t("plan.task.dependencies"),\n (0, react_jsx_runtime.jsx)("input", {\n name: "dependencies",\n value: dependencies,\n onChange: (event) => {\n setDependencies(event.currentTarget.value);\n markEdited();\n }\n }),\n (0, react_jsx_runtime.jsx)("small", { children: t("plan.task.dependenciesHint") })\n ] })]\n })\n ]\n }),\n confirmingRemove && (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planConfirm,\n role: "alert",\n children: [\n (0, react_jsx_runtime.jsx)("span", { children: t("plan.removeWarning", { task: task.id }) }),\n (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n onClick: () => {\n setConfirmingRemove(false);\n },\n children: t("plan.cancel")\n }),\n (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-danger": true,\n "data-confirming": true,\n onClick: () => {\n remove();\n },\n children: t("plan.removeConfirm")\n })\n ]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planActions,\n children: [\n (0, react_jsx_runtime.jsx)(Feedback, { value: feedback }),\n (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-danger": true,\n onClick: () => {\n setConfirmingRemove(true);\n setFeedback(void 0);\n },\n disabled: busy || confirmingRemove,\n children: t("plan.remove")\n }),\n (0, react_jsx_runtime.jsx)("button", {\n type: "submit",\n disabled: busy || !dirty || subject.trim() === "",\n children: busy ? t("plan.saving") : t("plan.save")\n })\n ]\n })\n ]\n })]\n });\n }\n function StagingPlanEditor({ team, modelDirectory, onContinuePlanning, onDiscarded, t }) {\n const membersId = (0, react.useId)();\n const tasksId = (0, react.useId)();\n const [membersOpen, setMembersOpen] = (0, react.useState)(true);\n const [tasksOpen, setTasksOpen] = (0, react.useState)(true);\n const [newTask, setNewTask] = (0, react.useState)("");\n const [busy, setBusy] = (0, react.useState)(false);\n const [discardArmed, setDiscardArmed] = (0, react.useState)(false);\n const [pendingEditors, setPendingEditors] = (0, react.useState)(/* @__PURE__ */ new Set());\n const [feedback, setFeedback] = (0, react.useState)();\n useDismissSuccess(feedback, setFeedback);\n const dependencyLinks = team.tasks.reduce((total, task) => total + task.dependencies.length, 0);\n const runnable = team.members.length > 0 && team.tasks.length > 0;\n const hasPendingEdits = pendingEditors.size > 0 || newTask.trim() !== "";\n const waitingForFeedback = team.planReviewState === "awaiting_feedback";\n (0, react.useEffect)(() => {\n modelDirectory.load().catch(() => void 0);\n }, [modelDirectory]);\n const onPendingChange = (0, react.useCallback)((key, pending) => {\n setPendingEditors((current) => {\n if (pending === current.has(key)) return current;\n const next = new Set(current);\n if (pending) next.add(key);\n else next.delete(key);\n return next;\n });\n }, []);\n const addTask = async (event) => {\n event.preventDefault();\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "add_task",\n subject: newTask,\n dependencies: []\n });\n setNewTask("");\n setFeedback({\n tone: "success",\n message: t("plan.taskAdded")\n });\n setTasksOpen(true);\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n } finally {\n setBusy(false);\n }\n };\n const approve = async () => {\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "approve"\n });\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n setBusy(false);\n }\n };\n const continueInChat = async () => {\n if (waitingForFeedback) {\n onContinuePlanning();\n return;\n }\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "continue"\n });\n onContinuePlanning();\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n setBusy(false);\n }\n };\n const discard = async () => {\n setBusy(true);\n setFeedback(void 0);\n try {\n await mutatePlan({\n sessionId: team.captainSessionId,\n teamId: team.teamId,\n action: "discard"\n });\n onDiscarded();\n } catch (error) {\n setFeedback({\n tone: "error",\n message: t("plan.failed", { message: errorMessage(error) })\n });\n setBusy(false);\n setDiscardArmed(false);\n }\n };\n return (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.planEditor,\n "data-staging-editor": true,\n children: [\n (0, react_jsx_runtime.jsxs)("header", {\n className: ActivityPanel_module_css_default.planHeader,\n children: [(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("strong", { children: t("plan.title") }), (0, react_jsx_runtime.jsx)("small", { children: t("plan.readySummary", {\n members: team.members.length,\n tasks: team.tasks.length,\n links: dependencyLinks\n }) })] }), (0, react_jsx_runtime.jsx)("em", { children: t("plan.badge") })] }), (0, react_jsx_runtime.jsx)("p", { children: t("plan.description") })]\n }),\n (0, react_jsx_runtime.jsxs)("ol", {\n className: ActivityPanel_module_css_default.planFlow,\n "aria-label": t("plan.flow.aria"),\n children: [\n (0, react_jsx_runtime.jsxs)("li", {\n "data-active": true,\n children: [(0, react_jsx_runtime.jsx)("span", { children: "1" }), t("plan.flow.review")]\n }),\n (0, react_jsx_runtime.jsxs)("li", { children: [(0, react_jsx_runtime.jsx)("span", { children: "2" }), t("plan.flow.spawn")] }),\n (0, react_jsx_runtime.jsxs)("li", { children: [(0, react_jsx_runtime.jsx)("span", { children: "3" }), t("plan.flow.run")] })\n ]\n }),\n (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.planSection,\n children: [(0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.planSectionToggle,\n "aria-expanded": membersOpen,\n "aria-controls": membersId,\n onClick: () => {\n setMembersOpen((current) => !current);\n },\n children: [(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("strong", { children: t("plan.members.title") }), (0, react_jsx_runtime.jsx)("small", { children: t("plan.members.count", { count: team.members.length }) })] }), (0, react_jsx_runtime.jsx)(DisclosureChevron, { open: membersOpen })]\n }), membersOpen && (0, react_jsx_runtime.jsx)("div", {\n id: membersId,\n className: ActivityPanel_module_css_default.planList,\n children: team.members.length === 0 ? (0, react_jsx_runtime.jsx)("p", {\n className: ActivityPanel_module_css_default.planEmpty,\n children: t("plan.members.empty")\n }) : team.members.map((member) => (0, react_jsx_runtime.jsx)(StagedMemberEditor, {\n team,\n member,\n modelDirectory,\n onPendingChange,\n t\n }, member.name))\n })]\n }),\n (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.planSection,\n children: [(0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.planSectionToggle,\n "aria-expanded": tasksOpen,\n "aria-controls": tasksId,\n onClick: () => {\n setTasksOpen((current) => !current);\n },\n children: [(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("strong", { children: t("plan.tasks.title") }), (0, react_jsx_runtime.jsx)("small", { children: t("plan.tasks.count", {\n count: team.tasks.length,\n links: dependencyLinks\n }) })] }), (0, react_jsx_runtime.jsx)(DisclosureChevron, { open: tasksOpen })]\n }), tasksOpen && (0, react_jsx_runtime.jsx)("div", {\n id: tasksId,\n className: ActivityPanel_module_css_default.planList,\n children: team.tasks.length === 0 ? (0, react_jsx_runtime.jsx)("p", {\n className: ActivityPanel_module_css_default.planEmpty,\n children: t("plan.tasks.empty")\n }) : team.tasks.map((task) => (0, react_jsx_runtime.jsx)(StagedTaskEditor, {\n team,\n task,\n onPendingChange,\n t\n }, task.id))\n })]\n }),\n (0, react_jsx_runtime.jsxs)("form", {\n className: ActivityPanel_module_css_default.planNewTask,\n onSubmit: (event) => {\n addTask(event);\n },\n children: [(0, react_jsx_runtime.jsxs)("label", { children: [(0, react_jsx_runtime.jsx)("span", { children: t("plan.newTaskLabel") }), (0, react_jsx_runtime.jsx)("input", {\n name: "newTask",\n value: newTask,\n onChange: (event) => {\n setNewTask(event.currentTarget.value);\n setFeedback(void 0);\n },\n placeholder: t("plan.newTask"),\n disabled: busy\n })] }), (0, react_jsx_runtime.jsx)("button", {\n type: "submit",\n disabled: busy || newTask.trim() === "",\n children: busy ? t("plan.adding") : t("plan.addTask")\n })]\n }),\n (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.planApproveRow,\n "data-armed": discardArmed || void 0,\n "data-discard": discardArmed || void 0,\n "data-review-state": waitingForFeedback ? "awaiting-feedback" : "awaiting-review",\n children: [\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planApproveCopy,\n children: [(0, react_jsx_runtime.jsx)("strong", { children: discardArmed ? t("plan.discardConfirmTitle") : waitingForFeedback ? t("plan.feedbackTitle") : t("plan.approveTitle") }), (0, react_jsx_runtime.jsx)("small", { children: discardArmed ? t("plan.discardWarning") : waitingForFeedback ? t("plan.feedbackHint") : hasPendingEdits ? t("plan.pendingEdits") : t("plan.approveHint", {\n members: team.members.length,\n tasks: team.tasks.length\n }) })]\n }),\n (0, react_jsx_runtime.jsx)(Feedback, { value: feedback }),\n discardArmed ? (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planApproveActions,\n children: [(0, react_jsx_runtime.jsx)("button", {\n type: "button",\n disabled: busy,\n onClick: () => {\n setDiscardArmed(false);\n },\n children: t("plan.cancel")\n }), (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-plan-discard": true,\n "data-danger": true,\n "data-confirming": true,\n disabled: busy,\n onClick: () => {\n discard();\n },\n children: busy ? t("plan.discarding") : t("plan.discardConfirm")\n })]\n }) : (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planReviewActions,\n children: [(0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-plan-approve": true,\n disabled: busy || !runnable || hasPendingEdits,\n onClick: () => {\n approve();\n },\n children: t("plan.approve")\n }), (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.planSecondaryActions,\n children: [(0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-plan-continue": true,\n disabled: busy,\n onClick: () => {\n continueInChat();\n },\n children: t(waitingForFeedback ? "plan.returnToChat" : "plan.continue")\n }), (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n "data-plan-discard": true,\n "data-danger": true,\n disabled: busy,\n onClick: () => {\n setDiscardArmed(true);\n setFeedback(void 0);\n },\n children: t("plan.discard")\n })]\n })]\n })\n ]\n })\n ]\n });\n }\n\n\n /** Pure persisted geometry rules for the T Team shell-overlay panel. */\n const PANEL_LAYOUT_STORAGE_KEY = "t-team:activity-panel:v1";\n const DEFAULT_PANEL_LAYOUT = Object.freeze({\n mode: "docked",\n x: 0,\n y: 64,\n width: 388,\n height: 640,\n heightMode: "auto"\n });\n function clamp(value, minimum, maximum) {\n return Math.min(Math.max(value, minimum), maximum);\n }\n function finite(value) {\n return typeof value === "number" && Number.isFinite(value);\n }\n /** Decode one versioned localStorage value, rejecting partial/corrupt state. */\n function parsePanelLayout(value) {\n if (value === null) return DEFAULT_PANEL_LAYOUT;\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed !== "object" || parsed === null) return DEFAULT_PANEL_LAYOUT;\n const record = parsed;\n if (record.mode !== "docked" && record.mode !== "floating" || !finite(record.x) || !finite(record.y) || !finite(record.width) || !finite(record.height)) return DEFAULT_PANEL_LAYOUT;\n return {\n mode: record.mode,\n x: record.x,\n y: record.y,\n width: record.width,\n height: record.height,\n heightMode: record.mode === "floating" && record.heightMode === "manual" ? "manual" : "auto"\n };\n } catch {\n return DEFAULT_PANEL_LAYOUT;\n }\n }\n /** Whether the panel should become a simple inset overlay with no gestures. */\n function compactPanelForBounds(bounds) {\n return bounds.width <= 960;\n }\n /** Docked and compact panels always fit content; floating panels may be user-sized. */\n function panelUsesAutoHeight(layout, bounds) {\n return compactPanelForBounds(bounds) || layout.mode === "docked" || layout.heightMode === "auto";\n }\n /** CSS max-height ceiling that keeps an auto-height panel inside its shell. */\n function panelMaximumHeight(layout, bounds) {\n const bottomInset = compactPanelForBounds(bounds) || layout.mode === "floating" ? 12 : 48;\n return Math.max(1, bounds.height - layout.y - bottomInset);\n }\n /** Resolve persisted state into a visible rectangle inside the current shell. */\n function resolvePanelGeometry(layout, bounds) {\n const boundsWidth = Math.max(1, bounds.width);\n const boundsHeight = Math.max(1, bounds.height);\n if (compactPanelForBounds(bounds)) return {\n ...layout,\n x: 12,\n y: 12,\n width: Math.max(1, boundsWidth - 24),\n height: Math.max(1, boundsHeight - 24)\n };\n const maximumWidth = Math.max(1, Math.min(640, boundsWidth - 24));\n const minimumWidth = Math.min(320, maximumWidth);\n const width = clamp(layout.width, minimumWidth, maximumWidth);\n const maximumHeight = Math.max(1, boundsHeight - 24);\n const minimumHeight = Math.min(360, maximumHeight);\n if (layout.mode === "docked") {\n const y = clamp(64, 12, Math.max(12, boundsHeight - minimumHeight - 12));\n const availableHeight = Math.max(1, boundsHeight - y - 48);\n const height = clamp(availableHeight, Math.min(minimumHeight, availableHeight), maximumHeight);\n const anchorRight = clamp(bounds.anchorRight, 0, boundsWidth);\n const maximumX = Math.max(12, boundsWidth - width - 12);\n return {\n mode: "docked",\n x: clamp(anchorRight - 18 - width, 12, maximumX),\n y,\n width,\n height,\n heightMode: layout.heightMode\n };\n }\n const height = clamp(layout.height, minimumHeight, maximumHeight);\n return {\n mode: "floating",\n x: clamp(layout.x, 12, Math.max(12, boundsWidth - width - 12)),\n y: clamp(layout.y, 12, Math.max(12, boundsHeight - height - 12)),\n width,\n height,\n heightMode: layout.heightMode\n };\n }\n /** Undock without a visual jump by adopting the panel\'s resolved rectangle. */\n function floatPanelLayout(geometry, bounds) {\n return resolvePanelGeometry({\n ...geometry,\n mode: "floating"\n }, bounds);\n }\n /** Return to the right dock, preserving width and restoring content-fit height. */\n function dockPanelLayout(layout, bounds) {\n return resolvePanelGeometry({\n ...layout,\n mode: "docked",\n heightMode: "auto"\n }, bounds);\n }\n /** Translate a floating panel and clamp it back into the visible shell. */\n function movePanelLayout(start, dx, dy, bounds) {\n return resolvePanelGeometry({\n ...start,\n mode: "floating",\n x: start.x + dx,\n y: start.y + dy\n }, bounds);\n }\n /** Resize while keeping the edge opposite the active handle stationary. */\n function resizePanelLayout(start, edge, dx, dy, bounds) {\n if (start.mode === "docked") {\n if (edge !== "left") return resolvePanelGeometry(start, bounds);\n return resolvePanelGeometry({\n ...start,\n width: start.width - dx\n }, bounds);\n }\n const resolved = resolvePanelGeometry(start, bounds);\n const minimumWidth = Math.min(320, resolved.x + resolved.width - 12);\n const minimumHeight = Math.min(360, bounds.height - resolved.y - 12);\n if (edge === "left") {\n const right = resolved.x + resolved.width;\n const maximumWidth = Math.max(1, Math.min(640, right - 12));\n const width = clamp(resolved.width - dx, Math.min(minimumWidth, maximumWidth), maximumWidth);\n return {\n ...resolved,\n x: right - width,\n width\n };\n }\n const maximumHeight = Math.max(1, bounds.height - resolved.y - 12);\n const height = clamp(resolved.height + dy, Math.min(minimumHeight, maximumHeight), maximumHeight);\n if (edge === "bottom") return {\n ...resolved,\n height,\n heightMode: "manual"\n };\n const maximumWidth = Math.max(1, Math.min(640, bounds.width - resolved.x - 12));\n const width = clamp(resolved.width + dx, Math.min(minimumWidth, maximumWidth), maximumWidth);\n return {\n ...resolved,\n width,\n height,\n heightMode: "manual"\n };\n }\n\n\n /**\n * T Team activity panel: the top-right floater monitoring every team.\n *\n * Modeled on the Claude Code desktop SessionActivityPanel: a shell-overlay\n * panel that docks at the conversation\'s top-right edge by default, can be\n * dragged into a floating window, resized, and folded into an activity badge.\n * On wide viewports the docked panel makes the conversation column yield\n * space; narrow viewports keep a simple inset overlay. It\n * polls the host `/plugins/t-team/state` route for\n * server-side snapshots (durable files + live subagent activity), with a\n * collapsed badge that auto-expands once when activity appears. Archived\n * teams stay available for the owning conversation after live work ends.\n *\n * The floater mounts in ui-layout\'s additive `shell.overlay`; it is not a\n * conversation node \u2014 the in-conversation panel was removed in favor of this\n * always-available monitor.\n * @module t-team/client/activity\n */\n /** Grace before the panel collapses once no team remains. */\n const AUTOCLOSE_GRACE_MS = 2e3;\n /**\n * Page-settle window after mount: activity restored on page load only shows\n * the collapsed badge, so the panel never yanks the conversation column\n * right after load. New activity after this window auto-expands as usual.\n */\n const AUTO_OPEN_SETTLE_MS = 4e3;\n /** Root marker shared with the panel CSS while the shell overlay is expanded. */\n const PANEL_OPEN_ATTRIBUTE = "data-t-team-panel-open";\n /** Shared width concession consumed by the conversation root CSS. */\n const PANEL_SHIFT_PROPERTY = "--t-team-panel-shift";\n const PANEL_CONVERSATION_GAP = 14;\n const MOVE_THRESHOLD = 4;\n const CAPTAIN_ASSIGNEE = "captain";\n function initialPanelLayout() {\n if (typeof window === "undefined") return DEFAULT_PANEL_LAYOUT;\n return parsePanelLayout(window.localStorage.getItem(PANEL_LAYOUT_STORAGE_KEY));\n }\n function initialPanelBounds() {\n if (typeof window === "undefined") return {\n width: 1440,\n height: 900,\n anchorRight: 1440\n };\n return {\n width: window.innerWidth,\n height: window.innerHeight,\n anchorRight: window.innerWidth\n };\n }\n /** Initial-letter fallback for unmatched roles. */\n function memberInitial(name) {\n return name.trim().slice(0, 1).toUpperCase() || "?";\n }\n function stableHash(value) {\n let hash = 0;\n for (let index = 0; index < value.length; index += 1) hash = (hash << 5) - hash + value.charCodeAt(index) | 0;\n return Math.abs(hash);\n }\n const ACCENTS = [\n "var(--dsw-alias-state-business-primary)",\n "var(--dsw-alias-state-success)",\n "var(--dsw-alias-state-danger)",\n "var(--dsw-alias-state-warning)",\n "var(--dsw-alias-label-tertiary)"\n ];\n function accentOf(id) {\n return ACCENTS[stableHash(id) % ACCENTS.length] ?? ACCENTS[0];\n }\n /** Badge text follows the raw task status (finer than the 4 visual states):\n * claimed/pending/failed/cancelled keep their own labels and colors. */\n const TASK_STATUS_LABEL = {\n pending: "task.status.pending",\n claimed: "task.status.claimed",\n in_progress: "task.status.inProgress",\n completed: "task.status.completed",\n failed: "task.status.failed",\n cancelled: "task.status.cancelled"\n };\n function taskStatusLabel(status, t) {\n const key = TASK_STATUS_LABEL[status];\n return key === void 0 ? status : t(key);\n }\n function formatTaskIds(ids, t) {\n return ids.join(t("format.listSeparator"));\n }\n function taskTitle(task, model) {\n const extras = [\n task.kind,\n task.round === void 0 ? void 0 : `r${task.round}`,\n task.verdict,\n model === "" ? void 0 : model\n ].filter((item) => item !== void 0);\n return extras.length === 0 ? `${task.id} \xB7 ${task.subject}` : `${task.id} \xB7 ${task.subject} \xB7 ${extras.join(" \xB7 ")}`;\n }\n /** Badge/bar coloring key: visual state, widened for terminal statuses. */\n function taskTone(state, status) {\n if (status === "failed") return "failed";\n if (status === "cancelled") return "cancelled";\n return state;\n }\n function Chevron({ open }) {\n return (0, react_jsx_runtime.jsx)("svg", {\n className: ActivityPanel_module_css_default.chevron,\n "data-open": open,\n width: "9",\n height: "9",\n viewBox: "0 0 10 10",\n fill: "none",\n stroke: "currentColor",\n strokeWidth: "1.5",\n strokeLinecap: "round",\n "aria-hidden": true,\n children: (0, react_jsx_runtime.jsx)("path", { d: "M3.5 2l3 3-3 3" })\n });\n }\n function WorkGlyph({ active }) {\n return (0, react_jsx_runtime.jsx)("svg", {\n className: ActivityPanel_module_css_default.workGlyph,\n "data-active": active,\n width: "11",\n height: "11",\n viewBox: "0 0 11 11",\n fill: "currentColor",\n "aria-hidden": true,\n children: [\n [0, 0],\n [4.2, 0],\n [8.4, 0],\n [0, 4.2],\n [4.2, 4.2],\n [8.4, 4.2]\n ].map(([x, y], index) => (0, react_jsx_runtime.jsx)("rect", {\n x,\n y,\n width: "2.6",\n height: "2.6",\n rx: ".6",\n style: { animationDelay: `${index * .15}s` }\n }, `${x}:${y}`))\n });\n }\n /** Collapsed badge: an always-visible corner pill while any team exists. */\n function CollapsedBadge({ count, busy, onClick, t }) {\n return (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.badge,\n "data-t-team-collapsed": true,\n "data-busy": busy,\n onClick,\n "aria-label": t("activity.badgeAria", { count }),\n children: [(0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.badgeDot,\n "data-busy": busy,\n "aria-hidden": true\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.badgeCount,\n children: count\n })]\n });\n }\n function memberStateLabel(member, tasks, historic, t) {\n const owned = tasks.filter((task) => task.assignee === member.name);\n if (member.activity === "working") return t("member.state.working");\n if (owned.some((task) => task.status === "failed")) return t("member.state.failed");\n if (owned.some((task) => task.state === "blocked")) return t("member.state.waiting");\n if (owned.length > 0 && owned.every((task) => task.status === "completed")) return t("member.state.delivered");\n if (member.status === "removed") return t(historic ? "member.state.left" : "member.state.removed");\n if (owned.length > 0) return t("member.state.pending");\n return t("member.state.unassigned");\n }\n function memberStatusText(member, tasks, t) {\n const owned = tasks.filter((task) => task.assignee === member.name);\n const current = owned.find((task) => task.id === member.currentTask);\n const blocked = owned.find((task) => task.state === "blocked");\n if (member.activity === "working" && current !== void 0) {\n const model = taskModelLabel(current, [member]);\n return model === "" ? t("member.status.executing", { taskId: current.id }) : t("member.status.executingModel", {\n taskId: current.id,\n model\n });\n }\n if (member.activity === "working") return t("member.status.working");\n if (blocked !== void 0) {\n const dependency = tasks.find((task) => blocked.dependencies.includes(task.id) && task.state !== "completed");\n if (dependency !== void 0) return t("member.status.waitingOn", {\n taskId: dependency.id,\n assignee: dependency.assignee || t("task.assignee.unclaimed")\n });\n return t("member.status.waitingPrerequisite");\n }\n if (member.total === 0) return t("member.status.waitingAssignment");\n if (member.done === member.total) return t("member.status.delivered");\n return t(member.activity === "idle" ? "member.status.idle" : "member.status.unknown");\n }\n function compactTaskLabel(subject) {\n const withoutVerb = subject.replace(/^\u5F00\u53D1\\s*/u, "").replace(/^\\d+[-_.\u3001\\s]*/u, "");\n const head = withoutVerb.split(/[\uFF08(\xB7\uFF1A:]/u)[0]?.trim() ?? withoutVerb;\n return head.length > 18 ? `${head.slice(0, 17)}\u2026` : head;\n }\n function taskSummary(team, t, discarded = false) {\n const completed = team.tasks.filter((task) => task.status === "completed");\n const cancelled = team.tasks.filter((task) => task.status === "cancelled");\n const running = team.tasks.filter((task) => task.state === "running");\n const blocked = team.tasks.filter((task) => task.state === "blocked");\n const ready = team.tasks.filter((task) => task.state === "open" && task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled");\n const failed = team.tasks.filter((task) => task.status === "failed");\n if (discarded) return t("task.summary.discarded", { count: team.tasks.length });\n if (team.tasks.length === 0) return t("task.summary.waitingBreakdown");\n if (team.phase === "staged") return t("task.summary.staged", { count: team.tasks.length });\n if (completed.length === team.tasks.length) return t("task.summary.allDelivered", { count: completed.length });\n if (completed.length + cancelled.length + failed.length === team.tasks.length) return t("task.summary.ended", {\n completed: completed.length,\n cancelled: cancelled.length,\n failed: failed.length\n });\n if (failed.length > 0 && running.length === 0 && ready.length === 0 && blocked.length === 0) return t("task.summary.failedSettled", { count: failed.length });\n if (blocked.length > 0 && running.length > 0) return t("task.summary.blockedAndRunning", {\n tasks: formatTaskIds(blocked.slice(0, 3).map((task) => task.id), t),\n more: blocked.length > 3 ? t("task.summary.more", { count: blocked.length - 3 }) : ""\n });\n if (running.length > 0) return t("task.summary.running", { tasks: formatTaskIds(running.map((task) => task.id), t) });\n if (ready.length > 0) return t("task.summary.ready", { tasks: formatTaskIds(ready.map((task) => task.id), t) });\n if (blocked.length > 0) return t("task.summary.blocked", { tasks: formatTaskIds(blocked.map((task) => task.id), t) });\n return t("task.summary.waitingSchedule");\n }\n function ProgressOverview({ team, t, discarded = false }) {\n const running = discarded ? 0 : team.tasks.filter((task) => task.state === "running").length;\n const blocked = discarded ? 0 : team.tasks.filter((task) => task.state === "blocked").length;\n const completed = discarded ? 0 : team.tasks.filter((task) => task.status === "completed").length;\n const settled = !discarded && team.tasks.length > 0 && team.tasks.every((task) => task.status === "completed" || task.status === "failed" || task.status === "cancelled");\n const summaryTone = discarded ? "discarded" : blocked > 0 ? "warning" : settled ? "completed" : "running";\n return (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.progressOverview,\n "aria-label": t("progress.aria"),\n "data-progress-summary": true,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.progressTitle,\n children: t("progress.title")\n }),\n team.tasks.length > 0 ? (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.progressSegments,\n "aria-hidden": true,\n children: team.tasks.map((task) => (0, react_jsx_runtime.jsx)("span", { "data-state": discarded ? "cancelled" : taskTone(task.state, task.status) }, task.id))\n }) : (0, react_jsx_runtime.jsx)("span", { className: ActivityPanel_module_css_default.progressEmpty }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.progressLegend,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n "data-state": "running",\n children: t("progress.running", { count: running })\n }),\n (0, react_jsx_runtime.jsx)("span", {\n "data-state": "blocked",\n children: t("progress.blocked", { count: blocked })\n }),\n (0, react_jsx_runtime.jsx)("span", {\n "data-state": "completed",\n children: t("progress.delivered", { count: completed })\n })\n ]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.progressSummary,\n "data-state": summaryTone,\n children: [(0, react_jsx_runtime.jsx)("span", { className: ActivityPanel_module_css_default.progressSummaryDot }), (0, react_jsx_runtime.jsx)("span", { children: taskSummary(team, t, discarded) })]\n })\n ]\n });\n }\n function DependencyMap({ tasks, members, t, discarded = false }) {\n const [open, setOpen] = (0, react.useState)(true);\n const [hoverTaskId, setHoverTaskId] = (0, react.useState)(null);\n const [keyboardTaskId, setKeyboardTaskId] = (0, react.useState)(null);\n const [pinnedTaskId, setPinnedTaskId] = (0, react.useState)(null);\n const hoverTimer = (0, react.useRef)(null);\n const focusedTaskId = dependencyFocusTaskId(pinnedTaskId, keyboardTaskId, hoverTaskId);\n const layout = (0, react.useMemo)(() => compactDagLayout(tasks), [tasks]);\n const parallel = (0, react.useMemo)(() => usesParallelTaskGrid(tasks), [tasks]);\n const related = (0, react.useMemo)(() => focusedTaskId === null ? null : relatedTaskIds(focusedTaskId, tasks), [focusedTaskId, tasks]);\n const scheduleHover = (id) => {\n if (hoverTimer.current !== null) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = null;\n }\n if (id === null) {\n setHoverTaskId(null);\n return;\n }\n hoverTimer.current = setTimeout(() => {\n hoverTimer.current = null;\n setHoverTaskId(id);\n }, 180);\n };\n (0, react.useEffect)(() => () => {\n if (hoverTimer.current !== null) clearTimeout(hoverTimer.current);\n }, []);\n (0, react.useEffect)(() => {\n const onKeyDown = (event) => {\n if (event.key === "Escape") setPinnedTaskId(null);\n };\n window.addEventListener("keydown", onKeyDown);\n return () => {\n window.removeEventListener("keydown", onKeyDown);\n };\n }, []);\n if (tasks.length === 0) return null;\n const fallbackTask = tasks.find((task) => task.state === "blocked") ?? tasks.find((task) => task.state === "running") ?? tasks[0];\n const detailTask = tasks.find((task) => task.id === focusedTaskId) ?? fallbackTask;\n const detailModel = taskModelLabel(detailTask, members);\n const waitingOn = detailTask.dependencies.filter((dependency) => tasks.find((task) => task.id === dependency)?.status !== "completed");\n const dependents = tasks.filter((task) => task.dependencies.includes(detailTask.id));\n return (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.dependencySection,\n "aria-label": t("dependency.aria"),\n "data-dependency-map": true,\n children: [(0, react_jsx_runtime.jsxs)("header", {\n className: ActivityPanel_module_css_default.sectionHead,\n children: [(0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.sectionToggleTitle,\n onClick: () => {\n setOpen((current) => !current);\n },\n "aria-expanded": open,\n children: [\n (0, react_jsx_runtime.jsx)(Chevron, { open }),\n (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),\n " ",\n t(parallel ? "dependency.parallel" : "dependency.title")\n ]\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.sectionHint,\n children: pinnedTaskId === null ? t(parallel ? "dependency.hint.parallel" : "dependency.hint.chain") : t("dependency.hint.pinned", { taskId: pinnedTaskId })\n })]\n }), open && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {\n className: ActivityPanel_module_css_default.dagViewport,\n children: (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.dagCanvas,\n "data-layout": parallel ? "parallel" : "dependency",\n style: parallel ? void 0 : {\n width: layout.width,\n height: layout.height\n },\n children: [!parallel && (0, react_jsx_runtime.jsx)("svg", {\n className: ActivityPanel_module_css_default.dagEdges,\n width: layout.width,\n height: layout.height,\n "aria-hidden": true,\n children: layout.edges.map((edge) => {\n const active = related !== null && related.has(edge.from) && related.has(edge.to);\n return (0, react_jsx_runtime.jsx)("path", {\n d: edge.path,\n "data-active": active,\n "data-dimmed": related !== null && !active\n }, `${edge.from}:${edge.to}`);\n })\n }), layout.nodes.map(({ task, x, y }) => {\n const model = taskModelLabel(task, members);\n const shortModel = compactModelLabel(model);\n return (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.dagNode,\n style: parallel ? { height: 30 } : {\n left: x,\n top: y,\n width: 92,\n height: 30\n },\n "data-task-id": task.id,\n "data-state": discarded ? "cancelled" : taskTone(task.state, task.status),\n "data-task-model": model || void 0,\n "data-focused": related?.has(task.id) ?? false,\n "data-dimmed": related !== null && !related.has(task.id),\n "aria-pressed": pinnedTaskId === task.id,\n title: taskTitle(task, model),\n onClick: () => {\n setPinnedTaskId((current) => current === task.id ? null : task.id);\n },\n onMouseEnter: () => {\n scheduleHover(task.id);\n },\n onMouseLeave: () => {\n scheduleHover(null);\n },\n onFocus: () => {\n setKeyboardTaskId(task.id);\n },\n onBlur: () => {\n setKeyboardTaskId(null);\n },\n children: [\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.dagNodeHead,\n children: [(0, react_jsx_runtime.jsx)("span", { className: ActivityPanel_module_css_default.dagNodeDot }), task.id]\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.dagNodeLabel,\n children: task.state === "running" && shortModel !== "" ? shortModel : compactTaskLabel(task.subject)\n }),\n task.state === "running" && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.dagRunningState,\n "aria-label": t("task.runningAria"),\n children: (0, react_jsx_runtime.jsx)(WorkGlyph, { active: true })\n })\n ]\n }, task.id);\n })]\n })\n }), (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.taskDetail,\n "data-task-detail": detailTask.id,\n children: [\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.taskDetailHead,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskDetailId,\n children: detailTask.id\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskDetailSubject,\n title: detailTask.subject,\n children: detailTask.subject.replace(/^\u5F00\u53D1\\s*/u, "")\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskDetailBadge,\n "data-state": discarded ? "cancelled" : taskTone(detailTask.state, detailTask.status),\n children: discarded ? t("task.status.notRun") : taskStatusLabel(detailTask.status, t)\n })\n ]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.taskDetailLine,\n children: [\n detailTask.assignee || t("task.assignee.unclaimed"),\n " \xB7 ",\n discarded ? t("task.detail.notRun") : detailTask.status === "completed" ? t("task.detail.completed") : detailTask.dependencies.length === 0 ? t("task.detail.noPrerequisite") : waitingOn.length === 0 ? t("task.detail.ready") : t("task.detail.waitingOn", { tasks: formatTaskIds(waitingOn, t) })\n ]\n }),\n detailModel !== "" && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskDetailModel,\n "data-task-model": detailModel,\n children: t("task.model", { model: detailModel })\n }),\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskDetailMeta,\n children: dependents.length === 0 ? t("task.detail.noDownstream") : t("task.detail.unlocks", { tasks: formatTaskIds(dependents.map((task) => task.id), t) })\n })\n ]\n })] })]\n });\n }\n function TeamSection({ team, modelDirectory, onContinuePlanning, onDiscarded, onNavigate, t, historic = false }) {\n const [membersOpen, setMembersOpen] = (0, react.useState)(true);\n const [stopOpen, setStopOpen] = (0, react.useState)(false);\n const [stopping, setStopping] = (0, react.useState)(false);\n const [stopError, setStopError] = (0, react.useState)("");\n const discarded = historic && team.phase === "staged";\n const stopped = !historic && team.halted === true;\n const busyCount = team.members.filter((member) => member.activity === "working").length;\n const assignedCount = team.tasks.filter((task) => task.assignee !== "" && task.assignee !== CAPTAIN_ASSIGNEE).length;\n const captainOwned = team.tasks.filter((task) => task.assignee === CAPTAIN_ASSIGNEE && task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled");\n const captainBusy = captainOwned.length > 0;\n const captainTaskIds = formatTaskIds(captainOwned.map((task) => task.id), t);\n const completedCount = team.tasks.filter((task) => task.status === "completed").length;\n const allCompleted = team.tasks.length > 0 && completedCount === team.tasks.length;\n const allSettled = team.tasks.length > 0 && team.tasks.every((task) => task.status === "completed" || task.status === "failed" || task.status === "cancelled");\n const unfinishedCount = team.tasks.filter((task) => task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled").length;\n const canStop = !historic && team.phase === "running" && team.halted !== true && teamIsActive(team);\n const stopTeam = async () => {\n if (stopping) return;\n setStopping(true);\n setStopError("");\n try {\n const response = await fetch(ACTIVITY_HALT_URL, {\n method: "POST",\n cache: "no-store",\n headers: { "content-type": "application/json" },\n body: JSON.stringify({\n sessionId: team.captainSessionId,\n teamId: team.teamId\n })\n });\n if (!response.ok) {\n let message = t("team.stopRequestFailed");\n try {\n const body = await response.json();\n if (typeof body.error === "string" && body.error.trim() !== "") message = body.error;\n } catch {}\n throw new Error(message);\n }\n setStopOpen(false);\n } catch (error) {\n setStopError(t("team.stopFailed", { message: error instanceof Error ? error.message : String(error) }));\n } finally {\n setStopping(false);\n }\n };\n return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.team,\n "data-team-id": team.teamId,\n children: [\n (0, react_jsx_runtime.jsxs)("header", {\n className: ActivityPanel_module_css_default.teamHead,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.teamName,\n title: team.name,\n children: team.name\n }),\n historic && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.historicPill,\n children: t(discarded ? "team.discarded" : "team.ended")\n }),\n stopped && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.historicPill,\n children: t("team.stopped")\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.teamStats,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n "data-stat": "members",\n children: t("team.stats.members", { count: team.members.length })\n }),\n (0, react_jsx_runtime.jsx)("span", {\n "data-stat": "tasks",\n children: t("team.stats.completed", {\n completed: completedCount,\n total: team.tasks.length\n })\n }),\n (0, react_jsx_runtime.jsx)("span", {\n "data-stat": "messages",\n children: t("team.stats.messages", { count: team.messageCount })\n })\n ]\n }),\n canStop && (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.teamStopButton,\n "aria-label": t("team.stop"),\n title: t("team.stop"),\n onClick: () => {\n setStopError("");\n setStopOpen(true);\n },\n children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconStopFill16, {})\n })\n ]\n }),\n team.phase === "staged" && !historic && modelDirectory !== void 0 && onContinuePlanning !== void 0 && onDiscarded !== void 0 && (0, react_jsx_runtime.jsx)(StagingPlanEditor, {\n team,\n modelDirectory,\n onContinuePlanning,\n onDiscarded,\n t\n }),\n (0, react_jsx_runtime.jsxs)("section", {\n className: ActivityPanel_module_css_default.delegationSection,\n "aria-label": t("delegation.aria"),\n "data-delegation-map": true,\n children: [\n (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.captainNode,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.captainAvatar,\n children: (0, react_jsx_runtime.jsx)("img", {\n className: ActivityPanel_module_css_default.leadAvatar,\n src: LEAD_ART,\n alt: "",\n "aria-hidden": true\n })\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.captainInfo,\n children: [(0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.captainLine,\n children: [(0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.captainName,\n children: t("captain.name")\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.captainRole,\n children: t("captain.role")\n })]\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.captainSummary,\n children: discarded ? t("captain.summary.discarded", {\n tasks: team.tasks.length,\n members: team.members.length\n }) : captainBusy ? t("captain.summary.withTakeover", {\n tasks: assignedCount,\n captainTasks: captainTaskIds\n }) : team.phase === "staged" ? t(team.planReviewState === "awaiting_feedback" ? "captain.summary.awaitingFeedback" : "captain.summary.staged", {\n tasks: team.tasks.length,\n members: team.members.length\n }) : t("captain.summary", {\n tasks: assignedCount,\n members: team.members.length\n })\n })]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.captainState,\n "data-busy": captainBusy || busyCount > 0,\n children: [(0, react_jsx_runtime.jsx)(WorkGlyph, { active: captainBusy || busyCount > 0 }), discarded ? t("captain.state.discarded") : captainBusy ? t("captain.state.takeover", { tasks: captainTaskIds }) : team.phase === "staged" ? t(team.planReviewState === "awaiting_feedback" ? "captain.state.awaitingFeedback" : "captain.state.staged") : busyCount > 0 ? t("captain.state.working", { count: busyCount }) : t(allCompleted ? "captain.state.collected" : allSettled ? "captain.state.settled" : "captain.state.waiting")]\n })\n ]\n }),\n (0, react_jsx_runtime.jsx)(ProgressOverview, {\n team,\n t,\n discarded\n }),\n (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.membersToggle,\n onClick: () => {\n setMembersOpen((current) => !current);\n },\n "aria-expanded": membersOpen,\n "data-members-toggle": true,\n children: [(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)(Chevron, { open: membersOpen }), t("members.toggle", { count: team.members.length })] }), (0, react_jsx_runtime.jsx)("span", { children: t(membersOpen ? "members.collapse" : "members.expand") })]\n }),\n membersOpen && (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.delegationTree,\n children: [team.members.length === 0 && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.emptyHint,\n children: t("members.empty")\n }), team.members.map((member) => {\n const owned = team.tasks.filter((task) => task.assignee === member.name);\n const memberModel = memberRouteLabel(member);\n return (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.memberBlock,\n "data-activity": member.activity,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberBranch,\n "aria-hidden": true,\n children: (0, react_jsx_runtime.jsx)("span", {})\n }),\n (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.memberRow,\n "data-activity": member.activity,\n onClick: () => {\n if (member.id !== "") onNavigate(team.captainSessionId, member.id);\n },\n children: [\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.memberAvatar,\n "data-unread": member.unread > 0,\n children: [memberArtUrl(member.name, member.role) !== null ? (0, react_jsx_runtime.jsx)("img", {\n className: ActivityPanel_module_css_default.memberArt,\n src: memberArtUrl(member.name, member.role) ?? "",\n alt: "",\n "aria-hidden": true\n }) : (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberInitial,\n style: { background: accentOf(member.id) },\n children: memberInitial(member.name)\n }), (0, react_jsx_runtime.jsx)("img", {\n className: ActivityPanel_module_css_default.stateArt,\n "data-activity": member.activity,\n src: ACTION_ART[member.activity],\n alt: "",\n "aria-hidden": true\n })]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.memberInfo,\n children: [(0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.memberLine,\n children: [\n (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberName,\n children: member.name\n }),\n member.role !== "" && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberRole,\n children: member.role\n }),\n memberModel !== "" && (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberModel,\n role: "img",\n "data-member-model": memberModel,\n title: memberModel,\n "aria-label": memberModel,\n children: compactModelLabel(memberModel)\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.memberState,\n "data-activity": member.activity,\n children: [(0, react_jsx_runtime.jsx)(WorkGlyph, { active: member.activity === "working" }), discarded ? t("member.state.notCreated") : stopped ? t("member.state.stopped") : team.phase === "staged" ? t("member.state.staged") : memberStateLabel(member, team.tasks, historic, t)]\n })\n ]\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.memberStatusLine,\n children: discarded ? t("member.status.discarded") : stopped ? t("member.status.stopped") : team.phase === "staged" ? t("member.status.staged") : historic && owned.length > 0 && owned.every((task) => task.status === "completed" || task.status === "failed" || task.status === "cancelled") ? t("member.status.settled") : memberStatusText(member, team.tasks, t)\n })]\n }),\n (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.memberCount,\n children: [\n member.done,\n "/",\n member.total\n ]\n })\n ]\n }),\n (0, react_jsx_runtime.jsxs)("div", {\n className: ActivityPanel_module_css_default.assignmentLine,\n children: [(0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.assignmentLabel,\n children: t(discarded ? "assignment.discarded" : team.phase === "staged" ? "assignment.staged" : "assignment.label")\n }), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.assignmentTasks,\n children: owned.length === 0 ? (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.taskEmpty,\n children: t("assignment.empty")\n }) : owned.map((task) => {\n const model = taskModelLabel(task, team.members);\n const shortModel = compactModelLabel(model);\n return (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.assignmentChip,\n "data-state": discarded ? "cancelled" : taskTone(task.state, task.status),\n "data-task-model": model || void 0,\n title: taskTitle(task, model),\n children: task.state === "running" && shortModel !== "" ? `${task.id} \xB7 ${shortModel}` : task.id\n }, task.id);\n })\n })]\n })\n ]\n }, member.id || member.name);\n })]\n })\n ]\n }),\n (0, react_jsx_runtime.jsx)(DependencyMap, {\n tasks: team.tasks,\n members: team.members,\n t,\n discarded\n })\n ]\n }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {\n open: stopOpen,\n onClose: () => {\n if (!stopping) setStopOpen(false);\n },\n title: t("team.stopTitle", { team: team.name }),\n closeLabel: t("plan.cancel"),\n description: t("team.stopDescription", {\n tasks: unfinishedCount,\n members: busyCount\n }),\n footer: (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.stopModalActions,\n children: [(0, react_jsx_runtime.jsx)("button", {\n type: "button",\n disabled: stopping,\n onClick: () => {\n setStopOpen(false);\n },\n children: t("team.stopCancel")\n }), (0, react_jsx_runtime.jsxs)("button", {\n type: "button",\n "data-danger": true,\n disabled: stopping,\n onClick: () => {\n stopTeam();\n },\n children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconStopFill16, {}), stopping ? t("team.stopping") : t("team.stopConfirm")]\n })]\n }),\n children: stopError !== "" && (0, react_jsx_runtime.jsxs)("p", {\n className: ActivityPanel_module_css_default.stopModalError,\n role: "alert",\n children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {}), stopError]\n })\n })] });\n }\n /** Legacy conversation cards may outlive their host archive. Project their\n * durable roster through the same rebuilt panel instead of a second UI. */\n function historicCardTeam(data, owner) {\n return {\n workspace: "",\n teamId: data.teamId,\n name: data.teamName,\n captainSessionId: data.captainSessionId || owner,\n phase: "running",\n members: data.members.map((member) => ({\n ...member,\n status: "removed",\n activity: "idle",\n progress: 0,\n done: 0,\n total: 0,\n currentTask: "",\n unread: 0\n })),\n tasks: [],\n messageCount: 0,\n captainInbox: []\n };\n }\n function ActivityPanel({ sessionsList, modelDirectories, openMember, t, conversationVisible = true }) {\n const navigateToSession = (parentId, childId) => {\n setOpen(false);\n setWasActive(false);\n openMember(parentId, childId);\n };\n const [open, setOpen] = (0, react.useState)(false);\n const [openOwner, setOpenOwner] = (0, react.useState)();\n const [autoOpened, setAutoOpened] = (0, react.useState)(false);\n const [wasActive, setWasActive] = (0, react.useState)(false);\n const [historic, setHistoric] = (0, react.useState)(/* @__PURE__ */ new Map());\n const [layout, setLayout] = (0, react.useState)(initialPanelLayout);\n const [bounds, setBounds] = (0, react.useState)(initialPanelBounds);\n const [interaction, setInteraction] = (0, react.useState)(null);\n const panelRef = (0, react.useRef)(null);\n const boundsRef = (0, react.useRef)(bounds);\n const gestureRef = (0, react.useRef)(null);\n const frameRef = (0, react.useRef)(null);\n const pendingLayoutRef = (0, react.useRef)(null);\n const current = (0, react.useSyncExternalStore)(sessionsList.subscribe, sessionsList.getSnapshot).current;\n const autoOpenTrackerRef = (0, react.useRef)({\n sessionId: current,\n restoreComplete: false,\n liveTeamIds: /* @__PURE__ */ new Set()\n });\n const monitorTargets = (0, react.useSyncExternalStore)(subscribeActivityMonitorTargets, getActivityMonitorTargetsSnapshot);\n const returnToComposer = () => {\n setOpen(false);\n setOpenOwner(void 0);\n window.requestAnimationFrame(() => {\n document.querySelector("[data-composer-card] [contenteditable=\\"true\\"][role=\\"textbox\\"], [data-composer-card] textarea")?.focus();\n });\n };\n const { teams, archivedTeams } = (0, react.useSyncExternalStore)(subscribeActivitySnapshots, getActivitySnapshotsSnapshot);\n const currentTargets = (0, react.useMemo)(() => current === void 0 ? [] : monitorTargets.filter((target) => target.sessionId === current), [current, monitorTargets]);\n const currentRef = (0, react.useRef)(current);\n (0, react.useEffect)(() => {\n currentRef.current = current;\n }, [current]);\n const mountedAtRef = (0, react.useRef)(performance.now());\n const expanded = conversationVisible && activityPanelExpandedForSession(open, openOwner, current);\n const geometry = (0, react.useMemo)(() => resolvePanelGeometry(layout, bounds), [layout, bounds]);\n const compact = compactPanelForBounds(bounds);\n const commitLayout = (0, react.useCallback)((next) => {\n setLayout(next);\n }, []);\n (0, react.useEffect)(() => {\n window.localStorage.setItem(PANEL_LAYOUT_STORAGE_KEY, JSON.stringify(layout));\n }, [layout]);\n (0, react.useLayoutEffect)(() => {\n const overlay = document.querySelector("[data-shell-overlay]");\n if (overlay === null) return;\n const conversation = document.querySelector("[data-phase=\'active\']");\n let frame = null;\n const measure = () => {\n frame = null;\n const overlayRect = overlay.getBoundingClientRect();\n const conversationRect = conversation?.getBoundingClientRect();\n const next = {\n width: overlayRect.width,\n height: overlayRect.height,\n anchorRight: conversationRect === void 0 ? overlayRect.width : Math.min(Math.max(conversationRect.right - overlayRect.left, 0), overlayRect.width)\n };\n const previous = boundsRef.current;\n if (previous.width === next.width && previous.height === next.height && previous.anchorRight === next.anchorRight) return;\n boundsRef.current = next;\n setBounds(next);\n };\n const scheduleMeasure = () => {\n frame ??= requestAnimationFrame(measure);\n };\n measure();\n const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(scheduleMeasure);\n observer?.observe(overlay);\n if (conversation !== null) observer?.observe(conversation);\n window.addEventListener("resize", scheduleMeasure);\n return () => {\n if (frame !== null) cancelAnimationFrame(frame);\n observer?.disconnect();\n window.removeEventListener("resize", scheduleMeasure);\n };\n }, [current]);\n (0, react.useLayoutEffect)(() => {\n const tracker = autoOpenTrackerRef.current;\n if (tracker.sessionId !== current) {\n tracker.sessionId = current;\n tracker.restoreComplete = false;\n tracker.liveTeamIds = /* @__PURE__ */ new Set();\n setWasActive(false);\n setAutoOpened(false);\n }\n if (openOwner === void 0 || openOwner === current) return;\n setOpen(false);\n setOpenOwner(void 0);\n }, [current, openOwner]);\n (0, react.useLayoutEffect)(() => {\n const root = document.documentElement;\n if (expanded && geometry.mode === "docked" && !compact) {\n root.setAttribute(PANEL_OPEN_ATTRIBUTE, "");\n root.style.setProperty(PANEL_SHIFT_PROPERTY, `${geometry.width + PANEL_CONVERSATION_GAP + 18}px`);\n } else {\n root.removeAttribute(PANEL_OPEN_ATTRIBUTE);\n root.style.removeProperty(PANEL_SHIFT_PROPERTY);\n }\n return () => {\n root.removeAttribute(PANEL_OPEN_ATTRIBUTE);\n root.style.removeProperty(PANEL_SHIFT_PROPERTY);\n };\n }, [\n compact,\n expanded,\n geometry.mode,\n geometry.width\n ]);\n (0, react.useEffect)(() => {\n if (current === void 0) return;\n const controller = startActivityPolling(currentTargets, { discoverySessionId: current });\n let active = true;\n const tracker = autoOpenTrackerRef.current;\n if (tracker.sessionId === current && !tracker.restoreComplete) controller.firstTick.then(() => {\n const latest = autoOpenTrackerRef.current;\n if (!active || latest.sessionId !== current || latest.restoreComplete) return;\n latest.liveTeamIds = new Set(getActivitySnapshotsSnapshot().teams.filter((team) => team.captainSessionId === current).map((team) => team.teamId));\n latest.restoreComplete = true;\n });\n return () => {\n active = false;\n controller.stop();\n };\n }, [current, currentTargets]);\n (0, react.useEffect)(() => {\n const onOpenPanel = (event) => {\n const activeSession = currentRef.current;\n if (activeSession === void 0) return;\n setOpenOwner(activeSession);\n setOpen(true);\n const detail = event.detail;\n if (detail?.teamId !== void 0) {\n const owner = detail.captainSessionId !== "" ? detail.captainSessionId : currentRef.current ?? "";\n const teamKey = `${owner}:${detail.teamId}`;\n setHistoric((previous) => {\n const next = new Map(previous);\n next.set(teamKey, {\n data: detail,\n owner\n });\n return next;\n });\n }\n };\n window.addEventListener(OPEN_PANEL_EVENT, onOpenPanel);\n return () => {\n window.removeEventListener(OPEN_PANEL_EVENT, onOpenPanel);\n };\n }, []);\n const visibleTeams = (0, react.useMemo)(() => current === void 0 ? [] : teams.filter((team) => team.captainSessionId === current), [teams, current]);\n const visibleHistoric = (0, react.useMemo)(() => current === void 0 ? [] : [...historic.values()].filter(({ data, owner }) => owner === current && !teams.some((live) => live.captainSessionId === current && live.teamId === data.teamId) && !archivedTeams.some((archived) => archived.captainSessionId === current && archived.teamId === data.teamId)), [\n historic,\n current,\n teams,\n archivedTeams\n ]);\n const visibleArchived = (0, react.useMemo)(() => current === void 0 ? [] : archivedTeams.filter((team) => team.captainSessionId === current && !teams.some((live) => live.captainSessionId === current && live.teamId === team.teamId)), [\n archivedTeams,\n current,\n teams\n ]);\n const visibleCount = visibleTeams.length + visibleArchived.length + visibleHistoric.length;\n const visibleLiveTeamIds = (0, react.useMemo)(() => visibleTeams.map((team) => team.teamId).sort(), [visibleTeams]);\n (0, react.useEffect)(() => {\n const tracker = autoOpenTrackerRef.current;\n const settled = performance.now() - mountedAtRef.current >= AUTO_OPEN_SETTLE_MS;\n const shouldAutoExpand = tracker.sessionId === current && activityPanelShouldAutoExpand({\n alreadyAutoOpened: autoOpened,\n pageSettled: settled,\n restoreComplete: tracker.restoreComplete,\n previousLiveTeamIds: tracker.liveTeamIds,\n currentLiveTeamIds: visibleLiveTeamIds\n });\n if (tracker.sessionId === current && tracker.restoreComplete) tracker.liveTeamIds = new Set(visibleLiveTeamIds);\n if (visibleCount > 0) {\n setWasActive(true);\n if (shouldAutoExpand) {\n setOpenOwner(current);\n setOpen(true);\n setAutoOpened(true);\n }\n return;\n }\n if (!wasActive) return;\n const timer = setTimeout(() => {\n setOpen(false);\n setOpenOwner(void 0);\n setWasActive(false);\n setAutoOpened(false);\n }, AUTOCLOSE_GRACE_MS);\n return () => {\n clearTimeout(timer);\n };\n }, [\n visibleCount,\n visibleLiveTeamIds.join("\\0"),\n autoOpened,\n wasActive,\n current\n ]);\n const busy = (0, react.useMemo)(() => visibleTeams.some((team) => team.members.some((member) => member.activity === "working")), [visibleTeams]);\n const hasTeams = visibleCount > 0;\n const panelGeometryForGesture = (0, react.useCallback)(() => {\n const measuredHeight = panelRef.current?.getBoundingClientRect().height;\n if (measuredHeight === void 0 || measuredHeight <= 0) return geometry;\n return {\n ...geometry,\n height: measuredHeight\n };\n }, [geometry]);\n const flushScheduledLayout = (0, react.useCallback)(() => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n const pending = pendingLayoutRef.current;\n pendingLayoutRef.current = null;\n if (pending !== null) commitLayout(pending);\n }, [commitLayout]);\n const scheduleLayout = (0, react.useCallback)((next) => {\n pendingLayoutRef.current = next;\n frameRef.current ??= requestAnimationFrame(() => {\n frameRef.current = null;\n const pending = pendingLayoutRef.current;\n pendingLayoutRef.current = null;\n if (pending !== null) commitLayout(pending);\n });\n }, [commitLayout]);\n (0, react.useEffect)(() => () => {\n if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);\n }, []);\n const beginMove = (0, react.useCallback)((event) => {\n if (compact || event.button !== 0 || event.target.closest("button") !== null) return;\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n gestureRef.current = {\n kind: "move",\n pointerId: event.pointerId,\n originX: event.clientX,\n originY: event.clientY,\n start: panelGeometryForGesture(),\n activated: false\n };\n }, [compact, panelGeometryForGesture]);\n const beginResize = (0, react.useCallback)((edge, event) => {\n if (compact || event.button !== 0 || geometry.mode === "docked" && edge !== "left") return;\n event.preventDefault();\n event.stopPropagation();\n event.currentTarget.setPointerCapture(event.pointerId);\n gestureRef.current = {\n kind: "resize",\n edge,\n pointerId: event.pointerId,\n originX: event.clientX,\n originY: event.clientY,\n start: panelGeometryForGesture(),\n activated: true\n };\n setInteraction("resizing");\n }, [\n compact,\n geometry.mode,\n panelGeometryForGesture\n ]);\n const updateGesture = (0, react.useCallback)((event) => {\n const gesture = gestureRef.current;\n if (gesture === null || gesture.pointerId !== event.pointerId || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n const dx = event.clientX - gesture.originX;\n const dy = event.clientY - gesture.originY;\n const activeBounds = boundsRef.current;\n if (gesture.kind === "move") {\n if (!gesture.activated && Math.hypot(dx, dy) < MOVE_THRESHOLD) return;\n if (!gesture.activated) {\n gesture.activated = true;\n setInteraction("dragging");\n }\n scheduleLayout(movePanelLayout(floatPanelLayout(gesture.start, activeBounds), dx, dy, activeBounds));\n return;\n }\n scheduleLayout(resizePanelLayout(gesture.start, gesture.edge ?? "left", dx, dy, activeBounds));\n }, [scheduleLayout]);\n const endGesture = (0, react.useCallback)((event) => {\n const gesture = gestureRef.current;\n if (gesture === null || gesture.pointerId !== event.pointerId) return;\n updateGesture(event);\n flushScheduledLayout();\n if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);\n gestureRef.current = null;\n setInteraction(null);\n }, [flushScheduledLayout, updateGesture]);\n const cancelGesture = (0, react.useCallback)((event) => {\n const gesture = gestureRef.current;\n if (gesture === null || gesture.pointerId !== event.pointerId) return;\n flushScheduledLayout();\n gestureRef.current = null;\n setInteraction(null);\n }, [flushScheduledLayout]);\n const toggleDock = (0, react.useCallback)(() => {\n const liveGeometry = panelGeometryForGesture();\n commitLayout(liveGeometry.mode === "docked" ? floatPanelLayout(liveGeometry, boundsRef.current) : dockPanelLayout(liveGeometry, boundsRef.current));\n }, [commitLayout, panelGeometryForGesture]);\n const autoHeight = panelUsesAutoHeight(geometry, bounds);\n const panelStyle = {\n width: geometry.width,\n height: autoHeight ? "auto" : geometry.height,\n maxHeight: panelMaximumHeight(geometry, bounds),\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`\n };\n if (!conversationVisible || !hasTeams && !expanded) return null;\n return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!expanded && (0, react_jsx_runtime.jsx)(CollapsedBadge, {\n count: visibleCount,\n busy,\n t,\n onClick: () => {\n if (current === void 0) return;\n setOpenOwner(current);\n setOpen(true);\n }\n }), expanded && (0, react_jsx_runtime.jsxs)("aside", {\n ref: panelRef,\n className: ActivityPanel_module_css_default.panel,\n style: panelStyle,\n "data-t-team-activity": true,\n "data-panel-mode": geometry.mode,\n "data-height-mode": autoHeight ? "auto" : "manual",\n "data-compact": compact || void 0,\n "data-dragging": interaction === "dragging" || void 0,\n "data-resizing": interaction === "resizing" || void 0,\n "aria-label": t("activity.panelAria"),\n children: [\n (0, react_jsx_runtime.jsxs)("header", {\n className: ActivityPanel_module_css_default.panelHead,\n onPointerDown: beginMove,\n onPointerMove: updateGesture,\n onPointerUp: endGesture,\n onPointerCancel: cancelGesture,\n "data-drag-handle": !compact || void 0,\n children: [(0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.panelTitle,\n children: [t("activity.title"), (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.panelDot,\n "data-busy": busy,\n "aria-hidden": true\n })]\n }), (0, react_jsx_runtime.jsxs)("span", {\n className: ActivityPanel_module_css_default.panelControls,\n children: [!compact && (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.iconButton,\n "data-control": "dock",\n "data-mode": geometry.mode,\n onClick: toggleDock,\n "aria-label": t(geometry.mode === "docked" ? "activity.float" : "activity.dockRight"),\n title: t(geometry.mode === "docked" ? "activity.float" : "activity.dockRight"),\n children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPanelLeftOutline16, {})\n }), (0, react_jsx_runtime.jsx)("button", {\n type: "button",\n className: ActivityPanel_module_css_default.iconButton,\n "data-control": "collapse",\n onClick: () => {\n setOpen(false);\n setOpenOwner(void 0);\n },\n "aria-label": t("activity.collapse"),\n title: t("activity.collapse"),\n children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})\n })]\n })]\n }),\n (0, react_jsx_runtime.jsx)("div", {\n className: ActivityPanel_module_css_default.teams,\n children: visibleCount === 0 ? (0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.emptyHint,\n children: t("activity.empty")\n }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [\n visibleTeams.map((team) => (0, react_jsx_runtime.jsx)(TeamSection, {\n team,\n modelDirectory: team.phase === "staged" ? modelDirectories.directoryFor(team.captainSessionId) : void 0,\n onContinuePlanning: returnToComposer,\n onDiscarded: returnToComposer,\n onNavigate: navigateToSession,\n t\n }, team.teamId)),\n visibleArchived.map((team) => (0, react_jsx_runtime.jsxs)("div", {\n "data-team-id": team.teamId,\n "data-historic": true,\n className: ActivityPanel_module_css_default.archivedWrap,\n children: [(0, react_jsx_runtime.jsx)("span", {\n className: ActivityPanel_module_css_default.archiveLabel,\n children: t(team.phase === "staged" ? "archive.discardedLabel" : "archive.label")\n }), (0, react_jsx_runtime.jsx)(TeamSection, {\n team,\n onNavigate: navigateToSession,\n t,\n historic: true\n })]\n }, `${team.captainSessionId}:${team.teamId}`)),\n visibleHistoric.map(({ data: team, owner }) => {\n const teamKey = `${owner}:${team.teamId}`;\n return (0, react_jsx_runtime.jsx)(TeamSection, {\n team: historicCardTeam(team, owner),\n onNavigate: navigateToSession,\n t,\n historic: true\n }, teamKey);\n })\n ] })\n }),\n !compact && (0, react_jsx_runtime.jsx)("div", {\n className: ActivityPanel_module_css_default.resizeHandle,\n "data-resize-edge": "left",\n onPointerDown: (event) => {\n beginResize("left", event);\n },\n onPointerMove: updateGesture,\n onPointerUp: endGesture,\n onPointerCancel: cancelGesture,\n "aria-hidden": true\n }),\n !compact && geometry.mode === "floating" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {\n className: ActivityPanel_module_css_default.resizeHandle,\n "data-resize-edge": "bottom",\n onPointerDown: (event) => {\n beginResize("bottom", event);\n },\n onPointerMove: updateGesture,\n onPointerUp: endGesture,\n onPointerCancel: cancelGesture,\n "aria-hidden": true\n }), (0, react_jsx_runtime.jsx)("div", {\n className: ActivityPanel_module_css_default.resizeHandle,\n "data-resize-edge": "corner",\n onPointerDown: (event) => {\n beginResize("corner", event);\n },\n onPointerMove: updateGesture,\n onPointerUp: endGesture,\n onPointerCancel: cancelGesture,\n "aria-hidden": true\n })] })\n ]\n })] });\n }\n\n\n /**\n * T Team conversation card: a lightweight in-conversation summary shown\n * when a team is created \u2014 the captain\'s name, the member roster with whale\n * avatars, and an entry point that re-activates the top-right activity\n * panel (useful after the floater was closed, or when re-opening an old\n * session for review).\n *\n * The fold anchors to the Harness\'s durable `tool/call` + `tool/result`\n * records for `t_team_create`. Those are first-party session events, so\n * the card survives restarts without writing an out-of-repo event type.\n * @module t-team/client/card\n */\n /** Parse the only create-call fields the historic card owns. */\n function parseTTeamCreateArgs(value) {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed !== "object" || parsed === null || !("name" in parsed) || typeof parsed.name !== "string") return;\n const name = parsed.name.trim();\n if (name === "") return void 0;\n const cleaned = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");\n return {\n teamId: cleaned === "" ? "team" : cleaned,\n name\n };\n } catch {\n return;\n }\n }\n /** Durable first-party tool events folded into one keyed Chat node. */\n const tTeamCardDefinition = {\n kind: "t-team",\n target: "chat",\n match: (event) => {\n if (event.type === "tool/call" && event.data.name === "t_team_create") return parseTTeamCreateArgs(event.data.arguments) === void 0 ? null : {\n id: String(event.data.callId),\n role: "start"\n };\n if (event.type === "tool/result" && event.data.message.source.kind === "tool") return {\n id: String(event.data.message.source.callId),\n role: "update"\n };\n return null;\n },\n start: (_context, match) => {\n if (match.event.type !== "tool/call") throw new Error("t-team card start requires t_team_create tool/call");\n const parsed = parseTTeamCreateArgs(match.event.data.arguments);\n if (parsed === void 0) throw new Error("t-team card start requires valid create arguments");\n return {\n ...parsed,\n accepted: false\n };\n },\n update: (context, match) => {\n if (match.event.type !== "tool/result") return context.state;\n if (match.event.data.error !== void 0 || match.event.data.message.content.some((block) => block.type === "tool-result" && block.isError === true)) return context.state;\n return {\n ...context.state,\n accepted: true\n };\n },\n buildViewNode: (context) => {\n if (context.start === void 0) return null;\n const state = context.state;\n if (!state.accepted) return null;\n return {\n key: context.key,\n kind: "t-team",\n id: context.id,\n target: "chat",\n anchorSeq: context.start.event.seq,\n location: context.start.location,\n visibility: "visible",\n data: {\n teamId: state.teamId,\n captainSessionId: "",\n teamName: state.name,\n members: []\n }\n };\n }\n };\n\n\n /** `tTeam` namespace dictionaries for every plugin-owned Web surface. */\n /** Dictionary namespace owned by the T Team client plugin. */\n const T_TEAM_LOCALE_NAMESPACE = "tTeam";\n /** Simplified Chinese dictionary (the key-set source of truth). */\n const zh = {\n "card.memberCount": "{count} \u540D\u6210\u5458",\n "action.openActivityPanel": "\u6253\u5F00\u6D3B\u52A8\u9762\u677F",\n "activity.panelButton": "\u6D3B\u52A8\u9762\u677F",\n "activity.badgeAria": "T\u4E13\u5BB6 \u56E2\u961F\u6D3B\u52A8\u4E0E\u5386\u53F2\uFF0C{count} \u6761\u56E2\u961F\u8BB0\u5F55",\n "activity.panelAria": "T\u4E13\u5BB6 \u56E2\u961F\u6D3B\u52A8\u9762\u677F",\n "activity.title": "T\u4E13\u5BB6 \u56E2\u961F\u6D3B\u52A8",\n "activity.float": "\u5207\u6362\u4E3A\u6D6E\u52A8\u9762\u677F",\n "activity.dockRight": "\u505C\u9760\u5230\u53F3\u4FA7",\n "activity.collapse": "\u6536\u8D77\u6D3B\u52A8\u9762\u677F",\n "activity.empty": "\u6682\u65E0\u56E2\u961F\u6D3B\u52A8",\n "team.stop": "\u505C\u6B62\u56E2\u961F",\n "team.stopped": "\u5DF2\u505C\u6B62",\n "team.stopTitle": "\u786E\u8BA4\u505C\u6B62\u201C{team}\u201D\uFF1F",\n "team.stopDescription": "\u5C06\u53D6\u6D88 {tasks} \u9879\u672A\u5B8C\u6210\u4EFB\u52A1\uFF0C\u5E76\u505C\u6B62 {members} \u540D\u6B63\u5728\u5DE5\u4F5C\u7684\u6210\u5458\u3002\u5DF2\u5B8C\u6210\u7684\u7ED3\u679C\u4F1A\u4FDD\u7559\u3002",\n "team.stopCancel": "\u7EE7\u7EED\u8FD0\u884C",\n "team.stopConfirm": "\u786E\u8BA4\u505C\u6B62",\n "team.stopping": "\u6B63\u5728\u505C\u6B62\u2026",\n "team.stopFailed": "\u505C\u6B62\u5931\u8D25\uFF1A{message}",\n "team.stopRequestFailed": "\u670D\u52A1\u5668\u672A\u80FD\u505C\u6B62\u56E2\u961F\uFF0C\u8BF7\u91CD\u8BD5",\n "team.discarded": "\u5DF2\u653E\u5F03",\n "format.listSeparator": "\u3001",\n "task.status.pending": "\u5F85\u9886\u53D6",\n "task.status.claimed": "\u5DF2\u8BA4\u9886",\n "task.status.inProgress": "\u8FDB\u884C\u4E2D",\n "task.status.completed": "\u5DF2\u5B8C\u6210",\n "task.status.failed": "\u5931\u8D25",\n "task.status.cancelled": "\u5DF2\u53D6\u6D88",\n "task.status.notRun": "\u672A\u6267\u884C",\n "member.state.working": "\u5DE5\u4F5C\u4E2D",\n "member.state.failed": "\u6709\u5931\u8D25",\n "member.state.waiting": "\u7B49\u5F85",\n "member.state.delivered": "\u5DF2\u4EA4\u4ED8",\n "member.state.left": "\u5DF2\u79BB\u961F",\n "member.state.removed": "\u5DF2\u79FB\u9664",\n "member.state.pending": "\u5F85\u6267\u884C",\n "member.state.unassigned": "\u5F85\u6D3E\u5DE5",\n "member.state.staged": "\u5F85\u521B\u5EFA",\n "member.state.notCreated": "\u672A\u521B\u5EFA",\n "member.state.stopped": "\u5DF2\u505C\u6B62",\n "member.status.executing": "\u6B63\u5728\u6267\u884C {taskId}",\n "member.status.executingModel": "\u6B63\u5728\u6267\u884C {taskId} \xB7 {model}",\n "member.status.working": "\u6B63\u5728\u5904\u7406\u5DF2\u6D3E\u4EFB\u52A1",\n "member.status.waitingOn": "\u7B49\u5F85 {taskId} \xB7 {assignee}",\n "member.status.waitingPrerequisite": "\u7B49\u5F85\u524D\u7F6E\u4EFB\u52A1",\n "member.status.waitingAssignment": "\u7B49\u5F85\u961F\u957F\u6D3E\u5DE5",\n "member.status.delivered": "\u4EFB\u52A1\u5DF2\u4EA4\u4ED8",\n "member.status.idle": "\u5F85\u7EE7\u7EED\u6267\u884C",\n "member.status.unknown": "\u72B6\u6001\u672A\u77E5",\n "member.status.staged": "\u786E\u8BA4\u540E\u521B\u5EFA\u5E76\u542F\u52A8",\n "member.status.settled": "\u4EFB\u52A1\u5747\u5DF2\u7EC8\u7ED3",\n "member.status.discarded": "\u8BA1\u5212\u5DF2\u653E\u5F03\uFF0C\u672A\u521B\u5EFA",\n "member.status.stopped": "\u56E2\u961F\u5DF2\u505C\u6B62\uFF0C\u9700\u663E\u5F0F\u6062\u590D",\n "task.assignee.unclaimed": "\u5F85\u8BA4\u9886",\n "task.summary.waitingBreakdown": "\u7B49\u5F85\u961F\u957F\u62C6\u89E3\u4EFB\u52A1",\n "task.summary.staged": "{count} \u9879\u8BA1\u5212\u7B49\u5F85\u786E\u8BA4",\n "task.summary.discarded": "{count} \u9879\u8BA1\u5212\u5DF2\u653E\u5F03\uFF0C\u5747\u672A\u6267\u884C",\n "task.summary.allDelivered": "\u5168\u90E8 {count} \u9879\u4EFB\u52A1\u5DF2\u4EA4\u4ED8",\n "task.summary.ended": "\u7EC8\u6001\uFF1A{completed} \u5DF2\u4EA4\u4ED8 \xB7 {cancelled} \u5DF2\u53D6\u6D88 \xB7 {failed} \u5931\u8D25",\n "task.summary.blockedAndRunning": "{tasks}{more} \u7B49\u5F85\u524D\u7F6E\uFF0C\u5176\u4F59\u5DF2\u5F00\u5DE5",\n "task.summary.more": " \u7B49 {count} \u9879",\n "task.summary.running": "{tasks} \u6B63\u5728\u6267\u884C",\n "task.summary.ready": "{tasks} \u5DF2\u5C31\u7EEA\u5F85\u5F00\u5DE5",\n "task.summary.blocked": "{tasks} \u7B49\u5F85\u524D\u7F6E",\n "task.summary.failedSettled": "{count} \u9879\u5DF2\u5931\u8D25\uFF0C\u81EA\u52A8\u5FAA\u73AF\u5DF2\u505C\u6B62",\n "task.summary.waitingSchedule": "\u7B49\u5F85\u4E0B\u4E00\u8F6E\u8C03\u5EA6",\n "progress.aria": "\u56E2\u961F\u603B\u8FDB\u5EA6",\n "progress.title": "\u603B\u8FDB\u5EA6",\n "progress.running": "\u25A0 \u8FDB\u884C\u4E2D {count}",\n "progress.blocked": "\u25A0 \u7B49\u5F85\u4F9D\u8D56 {count}",\n "progress.delivered": "\u25A0 \u5DF2\u4EA4\u4ED8 {count}",\n "dependency.aria": "\u4EFB\u52A1\u4F9D\u8D56\u94FE",\n "dependency.parallel": "\u5E76\u884C\u4EFB\u52A1",\n "dependency.title": "\u4EFB\u52A1\u4F9D\u8D56",\n "dependency.hint.parallel": "\u65E0\u524D\u540E\u4F9D\u8D56 \xB7 \u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",\n "dependency.hint.chain": "\u60AC\u505C\u9AD8\u4EAE\u4F9D\u8D56\u94FE \xB7 \u70B9\u51FB\u56FA\u5B9A",\n "dependency.hint.pinned": "{taskId} \u5DF2\u56FA\u5B9A \xB7 Esc \u53D6\u6D88",\n "task.runningAria": "\u8FD0\u884C\u4E2D",\n "task.model": "{model}",\n "task.detail.completed": "\u5DF2\u5B8C\u6210\u5E76\u4EA4\u4ED8",\n "task.detail.noPrerequisite": "\u65E0\u524D\u7F6E\uFF0C\u53EF\u7ACB\u5373\u5F00\u5DE5",\n "task.detail.ready": "\u524D\u7F6E\u5DF2\u5C31\u7EEA\uFF0C\u53EF\u5F00\u5DE5",\n "task.detail.waitingOn": "\u7B49\u5F85 {tasks}",\n "task.detail.notRun": "\u8BA1\u5212\u5DF2\u653E\u5F03\uFF0C\u4EFB\u52A1\u672A\u6267\u884C",\n "task.detail.noDownstream": "\u65E0\u4E0B\u6E38\u4EFB\u52A1",\n "task.detail.unlocks": "\u5B8C\u6210\u540E\u89E3\u9501 {tasks}",\n "team.ended": "\u5DF2\u7ED3\u675F",\n "plan.badge": "\u5F85\u786E\u8BA4",\n "plan.title": "\u6267\u884C\u524D\u8BA1\u5212\u5BA1\u67E5",\n "plan.description": "\u6210\u5458\u5C1A\u672A\u521B\u5EFA\u3001\u4EFB\u52A1\u5C1A\u672A\u8C03\u5EA6\u3002\u53EF\u76F4\u63A5\u8C03\u6574\u8BA1\u5212\uFF0C\u4E5F\u53EF\u8FD4\u56DE\u5BF9\u8BDD\u544A\u8BC9\u961F\u957F\u54EA\u91CC\u9700\u8981\u4FEE\u6539\u3002",\n "plan.member.role": "\u89D2\u8272",\n "plan.member.provider": "Provider",\n "plan.member.model": "\u6A21\u578B",\n "plan.member.reasoning": "\u63A8\u7406\u7B49\u7EA7",\n "plan.member.reasoningHint": "\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u503C\uFF1B\u53EF\u7528 low\u3001medium\u3001high\u3001xhigh \u7B49",\n "plan.model.choose": "\u9009\u62E9\u6A21\u578B",\n "plan.model.currentUnavailable": "{provider}/{model}\uFF08\u5F53\u524D\u76EE\u5F55\u4E0D\u53EF\u7528\uFF09",\n "plan.model.route": "\u8DEF\u7531\uFF1A{provider}/{model}",\n "plan.model.defaultReasoning": "\u9ED8\u8BA4\u63A8\u7406\u7B49\u7EA7",\n "plan.model.providerDefault": "Provider \u9ED8\u8BA4\u503C",\n "plan.model.modelDefault": "\u6A21\u578B\u9ED8\u8BA4\u503C\uFF08{effort}\uFF09",\n "plan.model.triggerAria": "\u9009\u62E9\u6210\u5458\u6A21\u578B\uFF0C\u5F53\u524D {model}\uFF0C\u63A8\u7406\u7B49\u7EA7 {effort}",\n "plan.model.back": "\u8FD4\u56DE",\n "plan.model.loading": "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u2026",\n "plan.model.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u578B",\n "plan.model.partialFailure": "{count} \u4E2A Provider \u7684\u6A21\u578B\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25",\n "plan.model.retry": "\u91CD\u8BD5",\n "plan.member.prompt": "\u89D2\u8272\u63D0\u793A\u8BCD",\n "plan.member.roleFallback": "\u672A\u8BBE\u7F6E\u89D2\u8272",\n "plan.task.subject": "\u4EFB\u52A1\u540D\u79F0",\n "plan.task.description": "\u4EFB\u52A1\u8BF4\u660E",\n "plan.task.assignee": "\u8D1F\u8D23\u4EBA",\n "plan.task.dependencies": "\u4F9D\u8D56\u4EFB\u52A1 ID\uFF08\u9017\u53F7\u5206\u9694\uFF09",\n "plan.task.dependenciesHint": "\u4F8B\u5982 task-1, task-2\uFF1B\u4E0D\u5F97\u5F62\u6210\u5FAA\u73AF\u4F9D\u8D56",\n "plan.task.unassigned": "\u5171\u4EAB\u4EFB\u52A1\u6C60",\n "plan.unsaved": "\u672A\u4FDD\u5B58",\n "plan.save": "\u4FDD\u5B58",\n "plan.saving": "\u4FDD\u5B58\u4E2D\u2026",\n "plan.remove": "\u5220\u9664",\n "plan.removed": "\u4EFB\u52A1\u5DF2\u5220\u9664",\n "plan.removeConfirm": "\u786E\u8BA4\u5220\u9664",\n "plan.removeWarning": "\u5220\u9664 {task} \u540E\u5C06\u91CD\u65B0\u8BA1\u7B97\u4F9D\u8D56\u5173\u7CFB\u3002",\n "plan.cancel": "\u53D6\u6D88",\n "plan.addTask": "\u6DFB\u52A0\u4EFB\u52A1",\n "plan.adding": "\u6DFB\u52A0\u4E2D\u2026",\n "plan.taskAdded": "\u4EFB\u52A1\u5DF2\u6DFB\u52A0",\n "plan.newTask": "\u65B0\u4EFB\u52A1\u540D\u79F0",\n "plan.newTaskLabel": "\u65B0\u589E\u8BA1\u5212\u4EFB\u52A1",\n "plan.readySummary": "{members} \u540D\u6210\u5458 \xB7 {tasks} \u9879\u4EFB\u52A1 \xB7 {links} \u6761\u4F9D\u8D56",\n "plan.flow.aria": "\u56E2\u961F\u542F\u52A8\u6D41\u7A0B",\n "plan.flow.review": "\u5BA1\u67E5\u8BA1\u5212",\n "plan.flow.spawn": "\u521B\u5EFA\u6210\u5458",\n "plan.flow.run": "\u5F00\u59CB\u6267\u884C",\n "plan.members.title": "\u6210\u5458\u4E0E\u6A21\u578B\u8DEF\u7531",\n "plan.members.count": "{count} \u540D\u6210\u5458",\n "plan.members.empty": "\u5C1A\u672A\u89C4\u5212\u6210\u5458",\n "plan.tasks.title": "\u4EFB\u52A1\u4E0E\u4F9D\u8D56",\n "plan.tasks.count": "{count} \u9879\u4EFB\u52A1 \xB7 {links} \u6761\u4F9D\u8D56",\n "plan.tasks.empty": "\u5C1A\u672A\u89C4\u5212\u4EFB\u52A1",\n "plan.dependencies.none": "\u65E0\u4F9D\u8D56",\n "plan.dependencies.count": "{count} \u6761\u4F9D\u8D56",\n "plan.approve": "\u786E\u8BA4\u5E76\u542F\u52A8\u56E2\u961F",\n "plan.approving": "\u6B63\u5728\u521B\u5EFA\u6210\u5458\u2026",\n "plan.approveTitle": "\u8BA1\u5212\u68C0\u67E5\u5B8C\u6BD5\uFF1F",\n "plan.approveHint": "\u786E\u8BA4\u540E\u5C06\u521B\u5EFA {members} \u540D\u6210\u5458\u5E76\u8C03\u5EA6 {tasks} \u9879\u4EFB\u52A1\u3002",\n "plan.approveConfirmTitle": "\u786E\u8BA4\u542F\u52A8\u6B64\u56E2\u961F",\n "plan.approveWarning": "\u542F\u52A8\u540E\u4E0D\u80FD\u518D\u5728\u6B64\u5904\u7F16\u8F91\u6210\u5458\u548C\u4F9D\u8D56\u3002",\n "plan.approveConfirm": "\u786E\u8BA4\u542F\u52A8",\n "plan.continue": "\u8FD4\u56DE\u5BF9\u8BDD\u4FEE\u6539",\n "plan.returnToChat": "\u56DE\u5230\u5BF9\u8BDD",\n "plan.feedbackTitle": "\u6B63\u5728\u7B49\u4F60\u8BF4\u660E\u4FEE\u6539\u65B9\u5411",\n "plan.feedbackHint": "\u961F\u957F\u4F1A\u5728\u5BF9\u8BDD\u4E2D\u8FFD\u95EE\uFF1B\u6536\u5230\u4F60\u7684\u56DE\u590D\u540E\uFF0C\u53EA\u4FEE\u6539\u8FD9\u4EFD\u8349\u6848\u5E76\u518D\u6B21\u7B49\u5F85\u786E\u8BA4\u3002",\n "plan.discard": "\u653E\u5F03\u672C\u6B21\u8BA1\u5212",\n "plan.discardConfirmTitle": "\u653E\u5F03\u672C\u6B21\u8BA1\u5212\uFF1F",\n "plan.discardWarning": "\u8BE5\u8BA1\u5212\u4F1A\u7ED3\u675F\u5E76\u5F52\u6863\uFF1B\u5C1A\u672A\u521B\u5EFA\u4EFB\u4F55\u6210\u5458\uFF0C\u4E5F\u4E0D\u4F1A\u6267\u884C\u4EFB\u52A1\u3002",\n "plan.discardConfirm": "\u786E\u8BA4\u653E\u5F03",\n "plan.discarding": "\u6B63\u5728\u653E\u5F03\u2026",\n "plan.pendingEdits": "\u8BF7\u5148\u4FDD\u5B58\u5F53\u524D\u4FEE\u6539\uFF0C\u518D\u542F\u52A8\u56E2\u961F\u3002",\n "plan.saved": "\u8BA1\u5212\u5DF2\u4FDD\u5B58",\n "plan.failed": "\u64CD\u4F5C\u5931\u8D25\uFF1A{message}",\n "team.stats.members": "{count} \u540D\u6210\u5458",\n "team.stats.completed": "{completed}/{total} \u5B8C\u6210",\n "team.stats.messages": "{count} \u6761\u6D88\u606F",\n "delegation.aria": "\u961F\u957F\u6D3E\u5DE5\u5173\u7CFB",\n "captain.name": "\u961F\u957F",\n "captain.role": "\u62C6\u89E3 \xB7 \u6D3E\u53D1 \xB7 \u6C47\u603B",\n "captain.summary": "\u5DF2\u6D3E\u53D1 {tasks} \u9879\u4EFB\u52A1\u7ED9 {members} \u540D\u6210\u5458",\n "captain.summary.staged": "\u5DF2\u89C4\u5212 {tasks} \u9879\u4EFB\u52A1\u4E0E {members} \u540D\u6210\u5458\uFF0C\u7B49\u5F85\u786E\u8BA4",\n "captain.summary.awaitingFeedback": "\u8349\u6848\u5DF2\u4FDD\u7559\uFF0C\u7B49\u5F85\u4F60\u5728\u5BF9\u8BDD\u4E2D\u8BF4\u660E\u4FEE\u6539\u65B9\u5411",\n "captain.summary.discarded": "\u8BA1\u5212\u5DF2\u653E\u5F03\uFF1A{members} \u540D\u6210\u5458\u672A\u521B\u5EFA\uFF0C{tasks} \u9879\u4EFB\u52A1\u672A\u6267\u884C",\n "captain.summary.withTakeover": "\u5DF2\u6D3E\u53D1 {tasks} \u9879\u7ED9\u6210\u5458 \xB7 \u961F\u957F\u63A5\u7BA1 {captainTasks}",\n "captain.state.working": "{count} \u4EBA\u6267\u884C\u4E2D",\n "captain.state.takeover": "\u6B63\u5728\u6267\u884C {tasks}",\n "captain.state.collected": "\u5DF2\u6536\u9F50",\n "captain.state.waiting": "\u7B49\u5F85\u56DE\u62A5",\n "captain.state.staged": "\u5F85\u786E\u8BA4",\n "captain.state.awaitingFeedback": "\u5F85\u53CD\u9988",\n "captain.state.discarded": "\u5DF2\u653E\u5F03",\n "captain.state.settled": "\u5DF2\u7EC8\u7ED3",\n "members.toggle": "{count} \u540D\u6210\u5458",\n "members.collapse": "\u6536\u8D77",\n "members.expand": "\u5C55\u5F00",\n "members.empty": "\u6682\u65E0\u6210\u5458\uFF0C\u7B49\u5F85\u961F\u957F\u7EC4\u5EFA\u56E2\u961F",\n "assignment.label": "\u961F\u957F\u6D3E\u53D1",\n "assignment.staged": "\u8BA1\u5212\u4EFB\u52A1",\n "assignment.discarded": "\u672A\u6267\u884C\u7684\u8BA1\u5212",\n "assignment.empty": "\u6682\u65E0\u4EFB\u52A1",\n "archive.label": "\u5DF2\u7ED3\u675F \xB7 \u5386\u53F2\u5F52\u6863",\n "archive.discardedLabel": "\u8BA1\u5212\u5DF2\u653E\u5F03 \xB7 \u5386\u53F2\u5F52\u6863"\n };\n /** English dictionary, checked complete against the Chinese source key set. */\n const en = {\n "card.memberCount": "{count} members",\n "action.openActivityPanel": "Open activity panel",\n "activity.panelButton": "Activity panel",\n "activity.badgeAria": "T Team activity and history, {count} team records",\n "activity.panelAria": "T Team activity panel",\n "activity.title": "T Team activity",\n "activity.float": "Switch to floating panel",\n "activity.dockRight": "Dock to the right",\n "activity.collapse": "Collapse activity panel",\n "activity.empty": "No team activity",\n "team.stop": "Stop team",\n "team.stopped": "Stopped",\n "team.stopTitle": "Stop \u201C{team}\u201D?",\n "team.stopDescription": "This cancels {tasks} unfinished tasks and stops {members} working members. Completed results are kept.",\n "team.stopCancel": "Keep running",\n "team.stopConfirm": "Stop team",\n "team.stopping": "Stopping\u2026",\n "team.stopFailed": "Could not stop team: {message}",\n "team.stopRequestFailed": "The server could not stop this team. Try again.",\n "team.discarded": "Discarded",\n "format.listSeparator": ", ",\n "task.status.pending": "Unclaimed",\n "task.status.claimed": "Claimed",\n "task.status.inProgress": "In progress",\n "task.status.completed": "Completed",\n "task.status.failed": "Failed",\n "task.status.cancelled": "Cancelled",\n "task.status.notRun": "Not run",\n "member.state.working": "Working",\n "member.state.failed": "Has failures",\n "member.state.waiting": "Waiting",\n "member.state.delivered": "Delivered",\n "member.state.left": "Left team",\n "member.state.removed": "Removed",\n "member.state.pending": "Pending",\n "member.state.unassigned": "Awaiting assignment",\n "member.state.staged": "Not spawned",\n "member.state.notCreated": "Not created",\n "member.state.stopped": "Stopped",\n "member.status.executing": "Working on {taskId}",\n "member.status.executingModel": "Working on {taskId} \xB7 {model}",\n "member.status.working": "Working on assigned tasks",\n "member.status.waitingOn": "Waiting for {taskId} \xB7 {assignee}",\n "member.status.waitingPrerequisite": "Waiting for prerequisites",\n "member.status.waitingAssignment": "Waiting for the captain to assign work",\n "member.status.delivered": "Tasks delivered",\n "member.status.idle": "Ready to continue",\n "member.status.unknown": "Status unknown",\n "member.status.staged": "Will be spawned after approval",\n "member.status.settled": "All assigned work is settled",\n "member.status.discarded": "Plan discarded; member was not created",\n "member.status.stopped": "Team stopped; explicit resume required",\n "task.assignee.unclaimed": "Unclaimed",\n "task.summary.waitingBreakdown": "Waiting for the captain to break down the work",\n "task.summary.staged": "{count} planned tasks awaiting approval",\n "task.summary.discarded": "{count} planned tasks discarded; none ran",\n "task.summary.allDelivered": "All {count} tasks delivered",\n "task.summary.ended": "Final: {completed} delivered \xB7 {cancelled} cancelled \xB7 {failed} failed",\n "task.summary.blockedAndRunning": "{tasks}{more} waiting on prerequisites; other work has started",\n "task.summary.more": " and {count} more",\n "task.summary.running": "{tasks} in progress",\n "task.summary.ready": "{tasks} ready to start",\n "task.summary.blocked": "{tasks} waiting on prerequisites",\n "task.summary.failedSettled": "{count} failed; the automatic loop has stopped",\n "task.summary.waitingSchedule": "Waiting for the next scheduling round",\n "progress.aria": "Overall team progress",\n "progress.title": "Overall progress",\n "progress.running": "\u25A0 In progress {count}",\n "progress.blocked": "\u25A0 Waiting {count}",\n "progress.delivered": "\u25A0 Delivered {count}",\n "dependency.aria": "Task dependency chain",\n "dependency.parallel": "Parallel tasks",\n "dependency.title": "Task dependencies",\n "dependency.hint.parallel": "No dependencies \xB7 Click for details",\n "dependency.hint.chain": "Hover to highlight dependencies \xB7 Click to pin",\n "dependency.hint.pinned": "{taskId} pinned \xB7 Esc to clear",\n "task.runningAria": "Running",\n "task.model": "{model}",\n "task.detail.completed": "Completed and delivered",\n "task.detail.noPrerequisite": "No prerequisites; ready to start",\n "task.detail.ready": "Prerequisites ready; can start",\n "task.detail.waitingOn": "Waiting for {tasks}",\n "task.detail.notRun": "Plan discarded; task was not run",\n "task.detail.noDownstream": "No downstream tasks",\n "task.detail.unlocks": "Unlocks {tasks} when complete",\n "team.ended": "Ended",\n "plan.badge": "Awaiting approval",\n "plan.title": "Pre-run plan review",\n "plan.description": "Members have not been spawned and tasks have not been scheduled. Edit the draft here, or return to chat and tell the Captain what should change.",\n "plan.member.role": "Role",\n "plan.member.provider": "Provider",\n "plan.member.model": "Model",\n "plan.member.reasoning": "Reasoning effort",\n "plan.member.reasoningHint": "Leave blank for default; accepts low, medium, high, xhigh, and more",\n "plan.model.choose": "Choose a model",\n "plan.model.currentUnavailable": "{provider}/{model} (not in the current catalog)",\n "plan.model.route": "Route: {provider}/{model}",\n "plan.model.defaultReasoning": "Default reasoning effort",\n "plan.model.providerDefault": "Provider default",\n "plan.model.modelDefault": "Model default ({effort})",\n "plan.model.triggerAria": "Choose member model, currently {model}, reasoning effort {effort}",\n "plan.model.back": "Back",\n "plan.model.loading": "Loading models\u2026",\n "plan.model.empty": "No models available",\n "plan.model.partialFailure": "{count} provider catalogs could not be loaded",\n "plan.model.retry": "Retry",\n "plan.member.prompt": "Role prompt",\n "plan.member.roleFallback": "Role not set",\n "plan.task.subject": "Task subject",\n "plan.task.description": "Task description",\n "plan.task.assignee": "Assignee",\n "plan.task.dependencies": "Dependency task IDs (comma-separated)",\n "plan.task.dependenciesHint": "For example task-1, task-2; cycles are rejected",\n "plan.task.unassigned": "Shared task pool",\n "plan.unsaved": "Unsaved",\n "plan.save": "Save",\n "plan.saving": "Saving\u2026",\n "plan.remove": "Remove",\n "plan.removed": "Task removed",\n "plan.removeConfirm": "Confirm remove",\n "plan.removeWarning": "Removing {task} will recalculate downstream dependencies.",\n "plan.cancel": "Cancel",\n "plan.addTask": "Add task",\n "plan.adding": "Adding\u2026",\n "plan.taskAdded": "Task added",\n "plan.newTask": "New task subject",\n "plan.newTaskLabel": "Add a planned task",\n "plan.readySummary": "{members} members \xB7 {tasks} tasks \xB7 {links} dependencies",\n "plan.flow.aria": "Team launch flow",\n "plan.flow.review": "Review plan",\n "plan.flow.spawn": "Create members",\n "plan.flow.run": "Start work",\n "plan.members.title": "Members & model routes",\n "plan.members.count": "{count} members",\n "plan.members.empty": "No members planned yet",\n "plan.tasks.title": "Tasks & dependencies",\n "plan.tasks.count": "{count} tasks \xB7 {links} dependencies",\n "plan.tasks.empty": "No tasks planned yet",\n "plan.dependencies.none": "No dependencies",\n "plan.dependencies.count": "{count} dependencies",\n "plan.approve": "Approve & Run",\n "plan.approving": "Creating members\u2026",\n "plan.approveTitle": "Plan ready?",\n "plan.approveHint": "Approval creates {members} members and schedules {tasks} tasks.",\n "plan.approveConfirmTitle": "Confirm team launch",\n "plan.approveWarning": "Member routes and dependencies cannot be edited here after launch.",\n "plan.approveConfirm": "Confirm launch",\n "plan.continue": "Return to chat & revise",\n "plan.returnToChat": "Return to chat",\n "plan.feedbackTitle": "Waiting for your revision direction",\n "plan.feedbackHint": "The Captain will ask in chat. After your reply, it will revise this draft and wait for approval again.",\n "plan.discard": "Discard this plan",\n "plan.discardConfirmTitle": "Discard this plan?",\n "plan.discardWarning": "The plan will end and be archived. No members have been spawned and no tasks will run.",\n "plan.discardConfirm": "Discard plan",\n "plan.discarding": "Discarding\u2026",\n "plan.pendingEdits": "Save the current edits before launching the team.",\n "plan.saved": "Plan saved",\n "plan.failed": "Operation failed: {message}",\n "team.stats.members": "{count} members",\n "team.stats.completed": "{completed}/{total} completed",\n "team.stats.messages": "{count} messages",\n "delegation.aria": "Captain delegation map",\n "captain.name": "Captain",\n "captain.role": "Break down \xB7 Delegate \xB7 Synthesize",\n "captain.summary": "Assigned {tasks} tasks to {members} members",\n "captain.summary.staged": "Planned {tasks} tasks and {members} members; awaiting approval",\n "captain.summary.awaitingFeedback": "Draft preserved; waiting for your revision direction in chat",\n "captain.summary.discarded": "Plan discarded: {members} members were not created and {tasks} tasks did not run",\n "captain.summary.withTakeover": "Assigned {tasks} to members \xB7 Captain owns {captainTasks}",\n "captain.state.working": "{count} active",\n "captain.state.takeover": "Working on {tasks}",\n "captain.state.collected": "All reports received",\n "captain.state.waiting": "Waiting for reports",\n "captain.state.staged": "Awaiting approval",\n "captain.state.awaitingFeedback": "Awaiting feedback",\n "captain.state.discarded": "Discarded",\n "captain.state.settled": "Settled",\n "members.toggle": "Members {count}",\n "members.collapse": "Collapse",\n "members.expand": "Expand",\n "members.empty": "No members yet; waiting for the captain to assemble the team",\n "assignment.label": "Captain assigned",\n "assignment.staged": "Planned task",\n "assignment.discarded": "Plan not run",\n "assignment.empty": "No tasks",\n "archive.label": "Ended \xB7 Archived history",\n "archive.discardedLabel": "Plan discarded \xB7 Archived history"\n };\n\n\n /** Version-tolerant navigation into durable T Team member transcripts. */\n /**\n * Open one member\'s persisted transcript.\n *\n * Harness rc.8 intentionally removed cold subagents from the ordinary session\n * list. They must first be rediscovered in their parent\'s catalog, then opened\n * with the exact parent/child/mode address. Older runtimes have only `open()`;\n * the fallback preserves ordinary-session navigation. New layouts also select\n * the Conversation panel and cancel catalog refreshes superseded by navigation.\n */\n async function openAgentTeamMember(sessions, parentSessionId, childSessionId, layout) {\n const navigation = layout?.beginNavigation?.();\n if (sessions.openSubagent === void 0 || sessions.refreshSubagents === void 0) {\n sessions.open(childSessionId);\n layout?.selectPanel?.(null);\n return "session";\n }\n await sessions.refreshSubagents(parentSessionId);\n if (navigation?.aborted) return "cancelled";\n const retained = sessions.subagentAddress?.(childSessionId);\n sessions.openSubagent(retained?.parentSessionId === parentSessionId ? retained : {\n parentSessionId,\n childSessionId,\n mode: "continuable"\n });\n layout?.selectPanel?.(null);\n return "subagent";\n }\n\n\n /** Required services: conversation nodes, slots, sessions navigation, and locale. */\n const inject = [\n "uiConversation",\n "slots",\n "sessions",\n "locale",\n "modelDirectories",\n "layout"\n ];\n const useLegacyPanelInfo = (select) => select({ activePanelId: null });\n /** The replayed user message is the canonical transcript entry. */\n function HiddenTTeamCommand() {\n return null;\n }\n /**\n * Register the activity monitor in the shell\'s additive overlay and the\n * in-conversation team card. The card\'s activity button re-opens a folded\n * monitor via a window event \u2014 the recovery path for an old session.\n */\n function apply(ctx) {\n ctx.effect(() => ctx.locale.register(T_TEAM_LOCALE_NAMESPACE, {\n zh,\n en\n }), "t-team: dictionaries");\n const openMember = (parentId, childId) => {\n openAgentTeamMember(ctx.sessions, parentId, childId, ctx.layout).catch((error) => {\n console.warn(`t-team: failed to open member transcript ${childId}: ${String(error)}`);\n });\n };\n const Panel = ({ t, usePanelInfo }) => {\n return (0, react_jsx_runtime.jsx)(ActivityPanel, {\n conversationVisible: (usePanelInfo ?? useLegacyPanelInfo)((panel) => panel.activePanelId === null),\n sessionsList: ctx.sessions.list,\n modelDirectories: ctx.modelDirectories,\n openMember,\n t\n });\n };\n ctx.slots.inject("shell.overlay", () => ctx.slots.register({\n name: "shell.overlay",\n id: "t-team-activity",\n order: 80,\n label: () => ctx.locale.bind(T_TEAM_LOCALE_NAMESPACE)("activity.title"),\n locale: T_TEAM_LOCALE_NAMESPACE\n }, Panel));\n ctx.slots.inject("conversation.chat.commandview", () => ctx.slots.register({\n name: "conversation.chat.commandview",\n key: "t-team-hidden"\n }, HiddenTTeamCommand));\n ctx.uiConversation.events.register(tTeamCardDefinition);\n ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({\n name: "conversation.chat.node",\n key: "t-team",\n locale: T_TEAM_LOCALE_NAMESPACE,\n inject: () => ({ openMember })\n }, TTeamCard));\n }\n\n exports.apply = apply;\n exports.inject = inject;\n return module.exports;\n }\n});\n\n';
19721
19721
 
19722
+ // src/schedule-cron.js
19723
+ var WEEKDAY_KEYS = [1, 2, 3, 4, 5, 6, 0];
19724
+ var CRON_PRESETS = [
19725
+ { id: "hourly", cron: "0 * * * *" },
19726
+ { id: "min30", cron: "*/30 * * * *" },
19727
+ { id: "daily9", cron: "0 9 * * *" },
19728
+ { id: "weekday830", cron: "30 8 * * 1-5" },
19729
+ { id: "mon10", cron: "0 10 * * 1" }
19730
+ ];
19731
+ var HOURLY_STEPS = [60, 30, 15, 10, 5];
19732
+ function int2(value, min, max) {
19733
+ if (!/^\d+$/.test(value)) return null;
19734
+ const n = Number(value);
19735
+ return n >= min && n <= max ? n : null;
19736
+ }
19737
+ function parseDow(field) {
19738
+ if (field === "*") return null;
19739
+ const days = /* @__PURE__ */ new Set();
19740
+ for (const token of field.split(",")) {
19741
+ const range = token.match(/^(\d+)-(\d+)$/);
19742
+ let lo;
19743
+ let hi;
19744
+ if (range) {
19745
+ lo = Number(range[1]);
19746
+ hi = Number(range[2]);
19747
+ if (lo > hi) return null;
19748
+ } else {
19749
+ lo = hi = Number(token);
19750
+ }
19751
+ for (let atom = lo; atom <= hi; atom++) {
19752
+ if (!Number.isInteger(atom)) return null;
19753
+ if (atom < 0 || atom > 7) return null;
19754
+ days.add(atom === 7 ? 0 : atom);
19755
+ }
19756
+ }
19757
+ if (days.size === 0) return null;
19758
+ return WEEKDAY_KEYS.filter((key) => days.has(key));
19759
+ }
19760
+ function parseCron(str) {
19761
+ const raw = typeof str === "string" ? str.trim() : "";
19762
+ const custom2 = { mode: "custom", raw };
19763
+ const fields = raw.split(/\s+/);
19764
+ if (fields.length !== 5) return raw === "" ? { mode: "daily", minute: 0, hour: 9 } : custom2;
19765
+ const [mf, hf, domf, monf, dowf] = fields;
19766
+ if (domf !== "*" || monf !== "*") return custom2;
19767
+ if (hf === "*" && dowf === "*") {
19768
+ const step = mf.match(/^\*\/(\d+)$/);
19769
+ if (step) {
19770
+ const n = Number(step[1]);
19771
+ return HOURLY_STEPS.includes(n) ? { mode: "hourly", step: n } : custom2;
19772
+ }
19773
+ const minute2 = int2(mf, 0, 59);
19774
+ return minute2 === null ? custom2 : { mode: "hourly", step: 60, minute: minute2 };
19775
+ }
19776
+ const hour = int2(hf, 0, 23);
19777
+ const minute = int2(mf, 0, 59);
19778
+ if (hour === null || minute === null) return custom2;
19779
+ const days = parseDow(dowf);
19780
+ if (days === null) return dowf === "*" ? { mode: "daily", hour, minute } : custom2;
19781
+ return { mode: "weekly", hour, minute, days };
19782
+ }
19783
+ function formatDow(days) {
19784
+ const week = days.filter((d) => d >= 1 && d <= 6).sort((a, b) => a - b);
19785
+ const tokens = [];
19786
+ let start = null;
19787
+ let prev = null;
19788
+ const flush = () => {
19789
+ if (start === null) return;
19790
+ tokens.push(start === prev ? String(start) : `${start}-${prev}`);
19791
+ start = null;
19792
+ };
19793
+ for (const d of week) {
19794
+ if (start === null) {
19795
+ start = d;
19796
+ prev = d;
19797
+ } else if (d === prev + 1) {
19798
+ prev = d;
19799
+ } else {
19800
+ flush();
19801
+ start = d;
19802
+ prev = d;
19803
+ }
19804
+ }
19805
+ flush();
19806
+ if (days.includes(0)) tokens.push("0");
19807
+ return tokens.join(",");
19808
+ }
19809
+ function buildCron(model) {
19810
+ if (!model || model.mode === "custom") return (model?.raw || "").trim();
19811
+ const minute = model.minute ?? 0;
19812
+ if (model.mode === "hourly") {
19813
+ return model.step && model.step < 60 ? `*/${model.step} * * * *` : `${minute} * * * *`;
19814
+ }
19815
+ const hour = model.hour ?? 9;
19816
+ if (model.mode === "daily") return `${minute} ${hour} * * *`;
19817
+ if (model.mode === "weekly") {
19818
+ const days = model.days && model.days.length ? model.days : [1];
19819
+ return `${minute} ${hour} * * ${formatDow(days)}`;
19820
+ }
19821
+ return "";
19822
+ }
19823
+
19722
19824
  // lib/remote-schemas.js
19723
19825
  var expertSchema = external_exports.object({
19724
19826
  slug: external_exports.string(),
@@ -19770,6 +19872,14 @@ var enabledStateSchema = external_exports.object({
19770
19872
  enabled: external_exports.array(external_exports.string()),
19771
19873
  revision: external_exports.number().int().min(0)
19772
19874
  });
19875
+ var uiPrefsSchema = external_exports.object({
19876
+ showTaskBadge: external_exports.boolean(),
19877
+ showScheduleButton: external_exports.boolean()
19878
+ });
19879
+ var uiPrefsPatchSchema = external_exports.object({
19880
+ showTaskBadge: external_exports.boolean().optional(),
19881
+ showScheduleButton: external_exports.boolean().optional()
19882
+ });
19773
19883
  var promptSchema = external_exports.object({ prompt: external_exports.string() });
19774
19884
  var squadMemberSchema = external_exports.object({
19775
19885
  slug: external_exports.string(),
@@ -19840,14 +19950,95 @@ var squadInputSchema = external_exports.object({
19840
19950
  enabled: external_exports.boolean(),
19841
19951
  members: external_exports.array(external_exports.string())
19842
19952
  });
19953
+ var scheduleRunSchema = external_exports.object({
19954
+ at: external_exports.string(),
19955
+ ok: external_exports.boolean(),
19956
+ sessionId: external_exports.string().optional(),
19957
+ error: external_exports.string().optional()
19958
+ });
19959
+ var scheduleItemSchema = external_exports.object({
19960
+ id: external_exports.string(),
19961
+ title: external_exports.string(),
19962
+ prompt: external_exports.string(),
19963
+ cron: external_exports.string(),
19964
+ enabled: external_exports.boolean(),
19965
+ workspaceId: external_exports.string().optional(),
19966
+ createdAt: external_exports.string(),
19967
+ updatedAt: external_exports.string(),
19968
+ lastRunAt: external_exports.string().optional(),
19969
+ lastRunError: external_exports.string().optional(),
19970
+ runs: external_exports.array(scheduleRunSchema)
19971
+ });
19972
+ var scheduleSnapshotSchema = external_exports.object({
19973
+ items: external_exports.array(scheduleItemSchema),
19974
+ /** 定时事项功能是否启用(= 设置页那个开关的当前值)。 */
19975
+ armed: external_exports.boolean(),
19976
+ /** 数据文件绝对路径(面板把它显示在说明里,便于用户备份)。 */
19977
+ file: external_exports.string(),
19978
+ /** 正在执行中的事项 id(面板据此显示「执行中…」)。 */
19979
+ running: external_exports.array(external_exports.string()),
19980
+ capabilities: external_exports.object({ agents: external_exports.boolean(), presets: external_exports.boolean() }),
19981
+ workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string() }))
19982
+ });
19983
+ var scheduleInputSchema = external_exports.object({
19984
+ title: external_exports.string().min(1).max(200),
19985
+ prompt: external_exports.string().min(1).max(2e4),
19986
+ cron: external_exports.string().min(1).max(120),
19987
+ enabled: external_exports.boolean(),
19988
+ /** 空串 = 不绑定工作区(显式解绑也走这个值)。 */
19989
+ workspaceId: external_exports.string().max(200).optional()
19990
+ });
19991
+ var schedulePatchSchema = scheduleInputSchema.partial();
19992
+ var schedulePreviewSchema = external_exports.object({ fires: external_exports.array(external_exports.string()) });
19993
+ var scheduleArmedSchema = external_exports.object({ armed: external_exports.boolean() });
19843
19994
 
19844
19995
  // src/client.jsx
19845
19996
  var NS = "t-team";
19997
+ var CLIENT_BUILD_VERSION = "0.3.6";
19998
+ var uiPrefs = { showTaskBadge: true, showScheduleButton: true };
19999
+ var uiPrefsListeners = /* @__PURE__ */ new Set();
20000
+ function setUiPrefs(next) {
20001
+ let changed = false;
20002
+ for (const key of Object.keys(uiPrefs)) {
20003
+ const value = next?.[key];
20004
+ if (typeof value !== "boolean" || value === uiPrefs[key]) continue;
20005
+ uiPrefs[key] = value;
20006
+ changed = true;
20007
+ }
20008
+ if (!changed) return;
20009
+ for (const listener of uiPrefsListeners) listener();
20010
+ }
20011
+ function subscribeUiPrefs(listener) {
20012
+ uiPrefsListeners.add(listener);
20013
+ return () => uiPrefsListeners.delete(listener);
20014
+ }
20015
+ function scheduleEntryVisible() {
20016
+ return uiPrefs.showScheduleButton !== false;
20017
+ }
20018
+ function useUiPref(key, fallback = true) {
20019
+ return import_react.default.useSyncExternalStore(
20020
+ (onChange) => {
20021
+ uiPrefsListeners.add(onChange);
20022
+ return () => uiPrefsListeners.delete(onChange);
20023
+ },
20024
+ () => uiPrefs[key],
20025
+ () => fallback
20026
+ );
20027
+ }
20028
+ function useShowTaskBadge() {
20029
+ return useUiPref("showTaskBadge", true);
20030
+ }
20031
+ function useShowScheduleButton() {
20032
+ return useUiPref("showScheduleButton", true);
20033
+ }
19846
20034
  var PLUGIN_ID = "dsh-plugin-t-expert";
19847
20035
  var DIVISION_FALLBACK = "specialized";
19848
20036
  var NEW_DIVISION = "__new";
19849
20037
  var zh = {
19850
20038
  "settings.title": "T\u4E13\u5BB6",
20039
+ "settings.showTaskBadge": "\u663E\u793A\u4EFB\u52A1\u5FBD\u7AE0",
20040
+ "settings.showTaskBadgeHint": "\u5173\u95ED\u540E\u4E0D\u518D\u81EA\u52A8\u51FA\u73B0\u53F3\u4E0A\u89D2\u7684\u4EFB\u52A1\u5FBD\u7AE0\uFF08\u8F93\u5165\u533A\u6D6E\u5C42\u91CC\u7684\u300C\u4EFB\u52A1\u300D\u9875\u4ECD\u7136\u53EF\u7528\uFF09",
20041
+ "settings.showTaskBadgeUnreadable": "\u8BFB\u53D6\u8BE5\u8BBE\u7F6E\u5931\u8D25",
19851
20042
  "settings.loading": "\u6B63\u5728\u8BFB\u53D6\u540D\u518C\u2026",
19852
20043
  "settings.retry": "\u91CD\u8BD5",
19853
20044
  "settings.search": "\u641C\u7D22\u4E13\u5BB6\u540D\u6216\u7B80\u4ECB",
@@ -19888,6 +20079,31 @@ var zh = {
19888
20079
  "tab.squads": "\u5C0F\u961F",
19889
20080
  "tab.teams": "\u56E2\u961F",
19890
20081
  "tab.roster": "\u961F\u4F0D",
20082
+ "tab.tasks": "\u4EFB\u52A1",
20083
+ "tasks.hint": "\u5F53\u524D\u4F1A\u8BDD\u53CA\u5176\u5B50\u4EE3\u7406\u7684\u540E\u53F0\u4EFB\u52A1\uFF1A\u7531\u5BBF\u4E3B\u7684 session/jobs \u63A8\u9001\u5B9E\u65F6\u5237\u65B0\uFF0C\u53EA\u8BFB\uFF0C\u4E0D\u542B\u8F93\u51FA\u4E0E\u7EC8\u6B62\u3002",
20084
+ "tasks.empty": "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u540E\u53F0\u4EFB\u52A1\u3002",
20085
+ "tasks.count": "{total} \u9879",
20086
+ "tasks.countRunning": "{running} \u9879\u8FD0\u884C\u4E2D \xB7 {total} \u9879",
20087
+ "tasks.owner": "\u5F52\u5C5E\uFF1A{name}",
20088
+ "tasks.status.running": "\u8FD0\u884C\u4E2D",
20089
+ "tasks.status.stopping": "\u505C\u6B62\u4E2D",
20090
+ "tasks.status.completed": "\u5DF2\u5B8C\u6210",
20091
+ "tasks.status.killed": "\u5DF2\u7EC8\u6B62",
20092
+ "tasks.status.failed": "\u5931\u8D25",
20093
+ "tasks.duration.seconds": "{seconds} \u79D2",
20094
+ "tasks.duration.minutes": "{minutes} \u5206 {seconds} \u79D2",
20095
+ "tasks.badgeTitle": "\u540E\u53F0\u4EFB\u52A1\uFF1A\u70B9\u5F00\u770B\u5217\u8868\uFF08\u53EF\u62D6\u52A8\u9762\u677F\uFF09",
20096
+ "tasks.subagents": "\u5B50\u4EE3\u7406",
20097
+ "tasks.subagentRunningCount": "{running} \u4E2A\u5B50\u4EE3\u7406\u8FD0\u884C\u4E2D",
20098
+ "tasks.subagentCount": "{total} \u4E2A\u5B50\u4EE3\u7406",
20099
+ "tasks.jobRunningCount": "{running} \u9879\u4EFB\u52A1\u8FD0\u884C\u4E2D",
20100
+ "tasks.jobCount": "{total} \u9879\u4EFB\u52A1",
20101
+ "tasks.noSubagents": "\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u5B50\u4EE3\u7406\u3002",
20102
+ "tasks.stateRunning": "\u8FD0\u884C\u4E2D",
20103
+ "tasks.modeOneShot": "\u4E00\u6B21\u6027",
20104
+ "tasks.modeContinuable": "\u53EF\u7EE7\u7EED",
20105
+ "tasks.stateInactive": "\u5DF2\u7ED3\u675F",
20106
+ "tasks.subagentOpen": "\u70B9\u51FB\u6253\u5F00\u8BE5\u5B50\u4EE3\u7406\u4F1A\u8BDD",
19891
20107
  "roster.squads": "\u5C0F\u961F\u6A21\u677F\uFF08\u53EF\u590D\u7528\uFF09",
19892
20108
  "roster.squadsHint": "\u9884\u5148\u6311\u597D\u7684\u73ED\u5E95\uFF1A\u6210\u5458\u3001\u522B\u540D\u3001\u542F\u505C\u3002\u7528\u5B83\u5C31\u8BF4 /t <\u5C0F\u961F> <\u76EE\u6807>\uFF0C\u6216\u5728\u8F93\u5165\u6846\u5F39\u7A97\u91CC\u70B9\u300C\u586B\u5165\u300D\uFF1B\u6539\u5B8C\u4FDD\u5B58\u540E\u7ACB\u5373\u751F\u6548\u3001\u65E0\u9700\u91CD\u542F\uFF08/t \u5217\u8868\u4F1A\u7ACB\u5373\u5237\u65B0\uFF0C\u5F15\u64CE\u4F1A\u5C31\u5730\u70ED\u91CD\u8F7D\uFF09\uFF1B\u4FDD\u5B58\u5931\u8D25\u4F1A\u56DE\u6EDA\uFF0C\u76D8\u4E0A\u4ECD\u662F\u65E7\u914D\u7F6E\u3002",
19893
20109
  "roster.teams": "\u8FD0\u884C\u4E2D\u7684\u56E2\u961F",
@@ -19989,10 +20205,96 @@ var zh = {
19989
20205
  "pop.emptySquads": "\u8FD8\u6CA1\u6709\u5C0F\u961F\uFF0C\u53BB \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u2192 \u961F\u4F0D \u5EFA\u4E00\u652F\u3002",
19990
20206
  "pop.squadSearch": "\u641C\u5C0F\u961F\uFF1A\u540D\u5B57 / \u522B\u540D / \u6210\u5458",
19991
20207
  "pop.squadNoMatch": "\u6CA1\u6709\u5339\u914D\u7684\u5C0F\u961F\u3002",
19992
- "pop.memberCount": "{count} \u4EBA"
20208
+ "pop.memberCount": "{count} \u4EBA",
20209
+ // ---- 定时任务:侧栏按钮 + 右侧管理页 ----
20210
+ "settings.showScheduleButton": "\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE",
20211
+ "settings.showScheduleButtonHint": "\u5173\u95ED\u540E\u4FA7\u680F\u4E0D\u518D\u663E\u793A\u300C\u5B9A\u65F6\u4EFB\u52A1\u300D\u6309\u94AE\uFF0C\u5E76\u505C\u6B62\u5168\u90E8\u5B9A\u65F6\u89E6\u53D1\uFF08\u4EFB\u52A1\u4E0E\u6267\u884C\u8BB0\u5F55\u4FDD\u7559\uFF0C\u91CD\u65B0\u6253\u5F00\u5373\u6062\u590D\uFF09",
20212
+ "sched.nav": "\u5B9A\u65F6\u4EFB\u52A1",
20213
+ "sched.title": "\u5B9A\u65F6\u4EFB\u52A1",
20214
+ "sched.intro": "\u7528 cron \u5B9A\u65F6\u5668\u628A\u63D0\u793A\u8BCD\u4EA4\u7ED9\u4E00\u4E2A\u5168\u65B0\u7684\u4F1A\u8BDD\u6267\u884C\u2014\u2014\u4E5F\u53EF\u4EE5\u7ACB\u5373\u6267\u884C\u3002\u6267\u884C\u4EA7\u751F\u7684\u4F1A\u8BDD\u51FA\u73B0\u5728\u5DE6\u4FA7\u5BF9\u5E94\u5DE5\u4F5C\u533A\u4E0B\u3002",
20215
+ "sched.tip": "\u542F\u7528\u7684\u4E8B\u9879\u4F1A\u5728\u540E\u53F0\u81EA\u52A8\u65B0\u5EFA\u4F1A\u8BDD\u5E76\u63D0\u4EA4\u63D0\u793A\u8BCD\uFF08\u7B49\u4E8E\u8BA9 agent \u81EA\u5DF1\u52A8\u624B\uFF09\uFF0C\u8BF7\u53EA\u5199\u4F60\u4FE1\u4EFB\u7684\u63D0\u793A\u8BCD\u3002",
20216
+ "sched.back": "\u8FD4\u56DE\u4F1A\u8BDD",
20217
+ "sched.refresh": "\u5237\u65B0",
20218
+ "sched.loading": "\u6B63\u5728\u52A0\u8F7D\u5B9A\u65F6\u4EFB\u52A1\u2026",
20219
+ "sched.error": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\u3002",
20220
+ "sched.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u5148\u65B0\u5EFA\u4E00\u4E2A\u5427\u3002",
20221
+ "sched.retry": "\u91CD\u8BD5",
20222
+ "sched.new": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
20223
+ "sched.edit": "\u7F16\u8F91\u5B9A\u65F6\u4EFB\u52A1",
20224
+ "sched.save": "\u4FDD\u5B58",
20225
+ "sched.saving": "\u4FDD\u5B58\u4E2D\u2026",
20226
+ "sched.cancel": "\u53D6\u6D88",
20227
+ "sched.delete": "\u5220\u9664",
20228
+ "sched.deleteConfirm": "\u786E\u5B9A\u5220\u9664\u8FD9\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF1F",
20229
+ "sched.runNow": "\u7ACB\u5373\u6267\u884C",
20230
+ "sched.running": "\u6267\u884C\u4E2D\u2026",
20231
+ "sched.runHistory": "\u6267\u884C\u8BB0\u5F55\uFF08{count}\uFF09",
20232
+ "sched.runOk": "\u6210\u529F",
20233
+ "sched.runFail": "\u5931\u8D25",
20234
+ "sched.lastRun": "\u4E0A\u6B21\u6267\u884C",
20235
+ "sched.neverRun": "\u4ECE\u672A\u6267\u884C",
20236
+ "sched.failed": "\u5931\u8D25",
20237
+ "sched.disabledTag": "\u5DF2\u505C\u7528",
20238
+ "sched.workspace": "\u5DE5\u4F5C\u533A",
20239
+ "sched.workspaceNone": "\u4E0D\u7ED1\u5B9A\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\u76EE\u5F55\uFF09",
20240
+ "sched.workspaceHint": "\u6267\u884C\u65F6\u4F1A\u5728\u8FD9\u4E2A\u5DE5\u4F5C\u533A\u4E0B\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u5E76\u663E\u793A\u5728\u5DE5\u4F5C\u533A\u5206\u7EC4\u91CC\u3002",
20241
+ "sched.cronLabel": "cron \u5B9A\u65F6\u5668",
20242
+ "sched.cronHint": "\u4E94\u6BB5 croner \u8868\u8FBE\u5F0F\uFF08\u5206 \u65F6 \u65E5 \u6708 \u5468\uFF09\uFF0C\u4F8B\u5982 \u201C0 9 * * *\u201D \u8868\u793A\u6BCF\u5929 09:00\u3002",
20243
+ "sched.cronHourly": "\u6BCF\u5C0F\u65F6",
20244
+ "sched.cronDaily": "\u6BCF\u5929",
20245
+ "sched.cronWeekly": "\u6BCF\u5468",
20246
+ "sched.cronCustom": "\u81EA\u5B9A\u4E49",
20247
+ "sched.cronEvery": "\u6BCF\u9694",
20248
+ "sched.cronAtMinute": "\u6BCF\u5C0F\u65F6\u7684\u7B2C",
20249
+ "sched.cronMinuteUnit": "\u5206",
20250
+ "sched.cronMinutesUnit": "\u5206\u949F",
20251
+ "sched.hourField": "\u5C0F\u65F6",
20252
+ "sched.minuteField": "\u5206\u949F",
20253
+ "sched.presetHourly": "\u6BCF\u5C0F\u65F6\u6574\u70B9",
20254
+ "sched.presetMin30": "\u6BCF 30 \u5206\u949F",
20255
+ "sched.presetDaily9": "\u6BCF\u5929 9:00",
20256
+ "sched.presetWeekday830": "\u5DE5\u4F5C\u65E5 8:30",
20257
+ "sched.presetMon10": "\u6BCF\u5468\u4E00 10:00",
20258
+ // 周几:键必须**逐行**写、并且在代码里以字面量引用(字典无人引用自检会盯着这一点)。
20259
+ "sched.wd1": "\u4E00",
20260
+ "sched.wd2": "\u4E8C",
20261
+ "sched.wd3": "\u4E09",
20262
+ "sched.wd4": "\u56DB",
20263
+ "sched.wd5": "\u4E94",
20264
+ "sched.wd6": "\u516D",
20265
+ "sched.wd0": "\u65E5",
20266
+ "sched.listSep": "\u3001",
20267
+ "sched.sumMin": "\u6BCF {n} \u5206\u949F\u6267\u884C\u4E00\u6B21",
20268
+ "sched.sumHour": "\u6BCF\u5C0F\u65F6\u7B2C {m} \u5206\u6267\u884C",
20269
+ "sched.sumDaily": "\u6BCF\u5929 {t} \u6267\u884C",
20270
+ "sched.sumWeekly": "\u6BCF\u5468{w} {t} \u6267\u884C",
20271
+ "sched.sumWeeklyWorkday": "\u5DE5\u4F5C\u65E5 {t} \u6267\u884C",
20272
+ "sched.sumCustom": "\u81EA\u5B9A\u4E49\u8868\u8FBE\u5F0F\uFF1A{raw}",
20273
+ "sched.sumEmpty": "\u9009\u62E9\u6216\u586B\u5199\u4E00\u4E2A\u6267\u884C\u65F6\u95F4",
20274
+ "sched.nextRuns": "\u6700\u8FD1 {n} \u6B21\u6267\u884C",
20275
+ "sched.titleLabel": "\u6807\u9898",
20276
+ "sched.titlePlaceholder": "\u4F8B\u5982\uFF1A\u6668\u4F1A\u7EAA\u8981",
20277
+ "sched.promptLabel": "\u63D0\u793A\u8BCD",
20278
+ "sched.promptPlaceholder": "\u5230\u70B9\u65F6\uFF0C\u8BA9 agent \u505A\u4EC0\u4E48\uFF1F",
20279
+ "sched.expertPick": "T\u4E13\u5BB6",
20280
+ "sched.expertPickHint": "\u70B9\u8FD9\u4E2A\u6309\u94AE\u4ECE\u5DF2\u542F\u7528\u4E13\u5BB6\u91CC\u6311\u4E00\u4F4D\uFF0C\u628A @\u4E13\u5BB6\u540D \u586B\u8FDB\u63D0\u793A\u8BCD\u3002",
20281
+ "sched.expertPickSearch": "\u641C\u7D22\u4E13\u5BB6\u540D\u6216 slug",
20282
+ "sched.expertPickEmpty": "\u6CA1\u6709\u5339\u914D\u7684\u5DF2\u542F\u7528\u4E13\u5BB6\u3002\u5148\u53BB \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u542F\u7528\u3002",
20283
+ "sched.expertInvokeHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u53EC\u5524\u300C{name}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
20284
+ "sched.expertInvokeManyHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u540C\u65F6\u53EC\u5524\u300C{names}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
20285
+ "sched.expertRemove": "\u79FB\u9664 {name}",
20286
+ "sched.enabledLabel": "\u542F\u7528",
20287
+ "sched.enabledHint": "\u505C\u7528\u7684\u4E8B\u9879\u4FDD\u7559\u6570\u636E\uFF0C\u4F46\u4E0D\u4F1A\u5B9A\u65F6\u89E6\u53D1\u3002",
20288
+ "sched.invalidForm": "\u6807\u9898\u3001\u63D0\u793A\u8BCD\u548C cron \u5B9A\u65F6\u5668\u90FD\u662F\u5FC5\u586B\u9879\u3002",
20289
+ "sched.off": "\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u5728 \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u91CC\u5173\u95ED\uFF1A\u73B0\u5728\u4E0D\u4F1A\u5B9A\u65F6\u89E6\u53D1\uFF0C\u4E5F\u4E0D\u80FD\u7ACB\u5373\u6267\u884C\u3002\u91CD\u65B0\u6253\u5F00\u300C\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE\u300D\u5373\u6062\u590D\u3002",
20290
+ "sched.noAgents": "\u5BBF\u4E3B\u6CA1\u6709\u53EF\u7528\u7684 agents \u670D\u52A1\uFF0C\u521B\u5EFA\u4F1A\u8BDD\u4F1A\u5931\u8D25\uFF1A\u8BF7\u68C0\u67E5\u5BBF\u4E3B\u88C5\u914D\u3002",
20291
+ "sched.file": "\u6570\u636E\u6587\u4EF6\uFF1A{path}"
19993
20292
  };
19994
20293
  var en = {
19995
20294
  "settings.title": "T Expert",
20295
+ "settings.showTaskBadge": "Show task badge",
20296
+ "settings.showTaskBadgeHint": "When off, the top-right task badge no longer appears (the Tasks tab in the input floater still works)",
20297
+ "settings.showTaskBadgeUnreadable": "Failed to read this setting",
19996
20298
  "settings.loading": "Loading roster\u2026",
19997
20299
  "settings.retry": "Retry",
19998
20300
  "settings.search": "Search expert name or description",
@@ -20033,6 +20335,31 @@ var en = {
20033
20335
  "tab.squads": "Squads",
20034
20336
  "tab.teams": "Teams",
20035
20337
  "tab.roster": "Roster",
20338
+ "tab.tasks": "Tasks",
20339
+ "tasks.hint": "Background jobs of the current conversation and its subagents, refreshed live from the host session/jobs push \u2014 read-only, no output view, no kill.",
20340
+ "tasks.empty": "No background jobs in this conversation yet.",
20341
+ "tasks.count": "{total} total",
20342
+ "tasks.countRunning": "{running} running \xB7 {total} total",
20343
+ "tasks.owner": "owner: {name}",
20344
+ "tasks.status.running": "running",
20345
+ "tasks.status.stopping": "stopping",
20346
+ "tasks.status.completed": "completed",
20347
+ "tasks.status.killed": "killed",
20348
+ "tasks.status.failed": "failed",
20349
+ "tasks.duration.seconds": "{seconds}s",
20350
+ "tasks.duration.minutes": "{minutes}m {seconds}s",
20351
+ "tasks.badgeTitle": "Background jobs \u2014 click to open the list (draggable)",
20352
+ "tasks.subagents": "Subagents",
20353
+ "tasks.subagentRunningCount": "{running} subagents running",
20354
+ "tasks.subagentCount": "{total} subagents",
20355
+ "tasks.jobRunningCount": "{running} jobs running",
20356
+ "tasks.jobCount": "{total} jobs",
20357
+ "tasks.noSubagents": "No subagents in this conversation.",
20358
+ "tasks.stateRunning": "running",
20359
+ "tasks.modeOneShot": "one-shot",
20360
+ "tasks.modeContinuable": "continuable",
20361
+ "tasks.stateInactive": "finished",
20362
+ "tasks.subagentOpen": "Open this subagent session",
20036
20363
  "roster.squads": "Squad templates (reusable)",
20037
20364
  "roster.squadsHint": "A pre-picked roster: members, aliases, enable/disable. Run it with /t <squad> <goal>, or tap Fill in the composer popup. Saving takes effect immediately, with no restart (the /t list refreshes at once and the engine hot-reloads in place); a failed save rolls back, so the old config stays on disk.",
20038
20365
  "roster.teams": "Running teams",
@@ -20134,7 +20461,89 @@ var en = {
20134
20461
  "pop.emptySquads": "No squads yet \u2014 build one in Settings \u2192 T Expert \u2192 Roster.",
20135
20462
  "pop.squadSearch": "Search squads: name / alias / member",
20136
20463
  "pop.squadNoMatch": "No matching squad.",
20137
- "pop.memberCount": "{count} members"
20464
+ "pop.memberCount": "{count} members",
20465
+ // ---- Scheduled tasks: sidebar entry + right-hand management surface ----
20466
+ "settings.showScheduleButton": "Show scheduled tasks button",
20467
+ "settings.showScheduleButtonHint": "When off, the sidebar no longer shows the Scheduled tasks button and every cron trigger stops (tasks and run history are kept; turning it back on restores the schedule)",
20468
+ "sched.nav": "Scheduled tasks",
20469
+ "sched.title": "Scheduled tasks",
20470
+ "sched.intro": "Send a prompt to a fresh agent session on a cron schedule \u2014 or run it right now. Each run appears under its workspace in the sidebar.",
20471
+ "sched.tip": "An enabled item creates a session and submits its prompt in the background (the agent acts on its own), so only write prompts you trust.",
20472
+ "sched.back": "Back to conversation",
20473
+ "sched.refresh": "Refresh",
20474
+ "sched.loading": "Loading scheduled tasks\u2026",
20475
+ "sched.error": "The scheduled tasks service is unavailable.",
20476
+ "sched.empty": "No scheduled tasks yet \u2014 create the first one.",
20477
+ "sched.retry": "Retry",
20478
+ "sched.new": "New scheduled task",
20479
+ "sched.edit": "Edit scheduled task",
20480
+ "sched.save": "Save",
20481
+ "sched.saving": "Saving\u2026",
20482
+ "sched.cancel": "Cancel",
20483
+ "sched.delete": "Delete",
20484
+ "sched.deleteConfirm": "Delete this scheduled task?",
20485
+ "sched.runNow": "Run now",
20486
+ "sched.running": "Running\u2026",
20487
+ "sched.runHistory": "Run history ({count})",
20488
+ "sched.runOk": "OK",
20489
+ "sched.runFail": "Failed",
20490
+ "sched.lastRun": "Last run",
20491
+ "sched.neverRun": "Never",
20492
+ "sched.failed": "failed",
20493
+ "sched.disabledTag": "Disabled",
20494
+ "sched.workspace": "Workspace",
20495
+ "sched.workspaceNone": "None (default directory)",
20496
+ "sched.workspaceHint": "Each run starts a new session in this workspace; sessions appear grouped under it in the sidebar.",
20497
+ "sched.cronLabel": "Cron schedule",
20498
+ "sched.cronHint": 'Five-field cron expression (minute hour day month weekday), e.g. "0 9 * * *" runs daily at 09:00.',
20499
+ "sched.cronHourly": "Hourly",
20500
+ "sched.cronDaily": "Daily",
20501
+ "sched.cronWeekly": "Weekly",
20502
+ "sched.cronCustom": "Custom",
20503
+ "sched.cronEvery": "Every",
20504
+ "sched.cronAtMinute": "hour at minute",
20505
+ "sched.cronMinuteUnit": "",
20506
+ "sched.cronMinutesUnit": "minutes",
20507
+ "sched.hourField": "Hour",
20508
+ "sched.minuteField": "Minute",
20509
+ "sched.presetHourly": "Every hour",
20510
+ "sched.presetMin30": "Every 30 min",
20511
+ "sched.presetDaily9": "Daily at 9:00",
20512
+ "sched.presetWeekday830": "Weekdays at 8:30",
20513
+ "sched.presetMon10": "Mondays at 10:00",
20514
+ "sched.wd1": "Mon",
20515
+ "sched.wd2": "Tue",
20516
+ "sched.wd3": "Wed",
20517
+ "sched.wd4": "Thu",
20518
+ "sched.wd5": "Fri",
20519
+ "sched.wd6": "Sat",
20520
+ "sched.wd0": "Sun",
20521
+ "sched.listSep": ", ",
20522
+ "sched.sumMin": "Every {n} minutes",
20523
+ "sched.sumHour": "Every hour at minute {m}",
20524
+ "sched.sumDaily": "Daily at {t}",
20525
+ "sched.sumWeekly": "Weekly on {w} at {t}",
20526
+ "sched.sumWeeklyWorkday": "Weekdays at {t}",
20527
+ "sched.sumCustom": "Custom: {raw}",
20528
+ "sched.sumEmpty": "Pick or type a schedule",
20529
+ "sched.nextRuns": "Next {n} runs",
20530
+ "sched.titleLabel": "Title",
20531
+ "sched.titlePlaceholder": "e.g. Morning standup notes",
20532
+ "sched.promptLabel": "Prompt",
20533
+ "sched.promptPlaceholder": "What should the agent do when this item runs?",
20534
+ "sched.expertPick": "T Expert",
20535
+ "sched.expertPickHint": "Pick one of the enabled experts here and its @name lands in the prompt.",
20536
+ "sched.expertPickSearch": "Search expert name or slug",
20537
+ "sched.expertPickEmpty": "No matching enabled expert. Enable some in Settings \u2192 T Expert.",
20538
+ "sched.expertInvokeHint": 'This run will summon "{name}" to carry out this prompt.',
20539
+ "sched.expertInvokeManyHint": 'This run will summon "{names}" together to carry out this prompt.',
20540
+ "sched.expertRemove": "Remove {name}",
20541
+ "sched.enabledLabel": "Enabled",
20542
+ "sched.enabledHint": "Disabled items keep their data but never run on schedule.",
20543
+ "sched.invalidForm": "Title, prompt, and cron schedule are required.",
20544
+ "sched.off": 'Scheduled tasks are turned off in Settings \u2192 T Expert: nothing triggers and nothing can be run by hand. Re-enable "Show scheduled tasks button" to restore it.',
20545
+ "sched.noAgents": "The host has no usable agents service, so creating a session will fail \u2014 check the host composition.",
20546
+ "sched.file": "Data file: {path}"
20138
20547
  };
20139
20548
  var CSS = `
20140
20549
  .t-team-editor-modal{width:min(860px,94vw);max-height:min(86vh,760px)}
@@ -20143,6 +20552,15 @@ var CSS = `
20143
20552
  .t-team-section-head{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}
20144
20553
  .t-team-section-head:first-child{border-top:0;padding-top:0}
20145
20554
  .t-team-tabs{display:flex;gap:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:6px}
20555
+ .t-team-setting-row{display:flex;flex-direction:column;gap:6px;padding:9px 11px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}
20556
+ .t-team-setting-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
20557
+ .t-team-setting-name{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20558
+ .t-team-setting-hint{font-size:12px;color:var(--dsw-alias-label-caption);line-height:1.35}
20559
+ .t-team-switch{flex:none;box-sizing:border-box;width:38px;min-width:38px;height:22px;min-height:22px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:11px;background:var(--dsw-alias-bg-layer-3);cursor:pointer;position:relative;line-height:0;transition:background-color .15s,border-color .15s}
20560
+ .t-team-switch[data-on="true"]{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);box-shadow:none}
20561
+ .t-team-switch-knob{position:absolute;top:2px;left:2px;box-sizing:border-box;display:block;width:16px;min-width:16px;height:16px;min-height:16px;border-radius:50%;background:#ffffff !important;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .15s}
20562
+ .t-team-switch[data-on="true"] .t-team-switch-knob{transform:translateX(16px)}
20563
+ .t-team-switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}
20146
20564
  .t-team-tab{border:0;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;padding:4px 10px;border-radius:6px;cursor:pointer}
20147
20565
  .t-team-tab[data-active="true"]{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:600}
20148
20566
  .t-team-tabbody{display:flex;flex-direction:column;gap:12px;min-height:0}
@@ -20179,6 +20597,17 @@ var CSS = `
20179
20597
  .t-team-picker-row:hover{background:var(--dsw-alias-bg-layer-3)}
20180
20598
  .t-team-picker-slug{color:var(--dsw-alias-label-caption);font-family:var(--dsw-font-markdown-code-block-small);font-size:11px}
20181
20599
  .t-team-selected-row{display:flex;align-items:center;gap:6px;font-size:12px;padding:3px 4px;border-bottom:1px solid var(--dsw-alias-border-l2)}
20600
+ .t-team-jobs{display:flex;flex-direction:column;gap:4px}
20601
+ .t-team-job-row{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:8px;background:var(--dsw-alias-bg-layer-2)}
20602
+ .t-team-job-dot{width:8px;height:8px;border-radius:50%;flex:none;background:var(--dsw-alias-label-caption)}
20603
+ .t-team-job-dot[data-state="running"]{background:var(--dsw-alias-state-success-primary)}
20604
+ .t-team-job-dot[data-state="stopping"]{background:var(--dsw-alias-state-warn-primary)}
20605
+ .t-team-job-dot[data-state="completed"]{background:var(--dsw-alias-label-secondary)}
20606
+ .t-team-job-dot[data-state="killed"]{background:var(--dsw-alias-state-warn-primary)}
20607
+ .t-team-job-dot[data-state="failed"]{background:var(--dsw-alias-state-error-primary)}
20608
+ .t-team-job-main{flex:1 1 auto;min-width:0;width:100%;display:flex;flex-direction:column;gap:2px}
20609
+ .t-team-job-label{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20610
+ .t-team-job-meta{font-size:12px;color:var(--dsw-alias-label-caption);display:flex;flex-direction:column;gap:1px;min-width:0}
20182
20611
  .t-team-teams{display:flex;flex-direction:column;gap:8px}
20183
20612
  .t-team-team{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2);padding:10px 12px;display:flex;flex-direction:column;gap:6px}
20184
20613
  .t-team-team-head{display:flex;align-items:center;gap:8px}
@@ -20239,11 +20668,15 @@ var CSS = `
20239
20668
  .t-team-cat-empty{padding:8px 10px;font-size:12px;color:var(--dsw-alias-label-caption)}
20240
20669
  .t-team-cat-list .t-team-badge{flex:none}
20241
20670
  .t-team-badge[data-tone="custom"]{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);background:transparent}
20242
- .t-team-switch{position:relative;flex:none;width:28px;height:16px;padding:0;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);cursor:pointer;transition:background .15s ease,border-color .15s ease}
20243
- .t-team-switch-knob{position:absolute;top:1px;left:1px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-label-tertiary);transition:transform .15s ease,background .15s ease}
20244
- .t-team-switch[data-enabled="true"]{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill)}
20245
- .t-team-switch[data-enabled="true"] .t-team-switch-knob{transform:translateX(12px);background:var(--dsw-alias-label-primary-foreground)}
20246
- .t-team-switch:disabled{opacity:.45;cursor:not-allowed}
20671
+ /* \u4E13\u5BB6\u5361\u7247\u4E0A\u7684\u542F\u7528\u5F00\u5173\u3002\u26A0\uFE0F class \u5FC5\u987B\u4E0E\u8BBE\u7F6E\u9875\u90A3\u5957**\u9519\u5F00**\uFF1A\u4E24\u5904\u66FE\u5171\u7528 .t-team-switch\uFF0C
20672
+ * \u4E8E\u662F\u540E\u5B9A\u4E49\u7684\u8FD9\u5957\uFF0828\xD716\u3001\u5F00\u542F\u8272\u6302\u5728 data-enabled \u4E0A\uFF09\u6574\u4F53\u8986\u76D6\u4E86\u8BBE\u7F6E\u9875\u90A3\u5957
20673
+ * \uFF0838\xD722\u3001\u5F00\u542F\u8272\u6302\u5728 data-on \u4E0A\uFF09\u2014\u2014 \u5BBD\u5EA6\u88AB\u538B\u6210 28px\u3001\u5F00\u542F\u8272\u6C38\u4E0D\u751F\u6548\uFF0C
20674
+ * \u8BBE\u7F6E\u9875\u90A3\u4E24\u4E2A\u5F00\u5173\u5728\u754C\u9762\u4E0A\u5C31\u53D8\u6210"\u770B\u4E0D\u89C1\u7684\u5C0F\u80F6\u56CA"\u3002\u73B0\u5728\u5404\u7528\u5404\u7684\u540D\u5B57\u3002 */
20675
+ .t-team-card-switch{position:relative;flex:none;width:28px;height:16px;padding:0;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);cursor:pointer;transition:background .15s ease,border-color .15s ease}
20676
+ .t-team-card-switch-knob{position:absolute;top:1px;left:1px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-label-tertiary);transition:transform .15s ease,background .15s ease}
20677
+ .t-team-card-switch[data-enabled="true"]{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill)}
20678
+ .t-team-card-switch[data-enabled="true"] .t-team-card-switch-knob{transform:translateX(12px);background:var(--dsw-alias-label-primary-foreground)}
20679
+ .t-team-card-switch:disabled{opacity:.45;cursor:not-allowed}
20247
20680
  .t-team-conflict{font-size:11px;color:var(--dsw-alias-state-warn-primary)}
20248
20681
  .t-team-error{font-size:12px;color:var(--dsw-alias-state-error-primary)}
20249
20682
  .t-team-btn{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:8px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;white-space:nowrap;cursor:pointer}
@@ -20258,6 +20691,39 @@ var CSS = `
20258
20691
  .t-team-pop .t-team-squad{padding:8px;gap:6px}
20259
20692
  .t-team-pop .t-team-squad-desc{font-size:12px}
20260
20693
  .t-team-pop .t-team-team{padding:8px}
20694
+ .t-team-pop .t-team-job-row{padding:5px 7px}
20695
+ .t-team-job-row[data-kind="subagent"] .t-team-job-label{font-weight:500}
20696
+ .t-team-job-desc{min-width:0;width:100%;display:block;font-size:11.5px;line-height:1.35;color:var(--dsw-alias-label-caption);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20697
+ .t-team-job-row[data-clickable="true"]{cursor:pointer}
20698
+ .t-team-job-row[data-clickable="true"]:hover{background:var(--dsw-alias-interactive-bg-hover)}
20699
+ /* shell.overlay \u91CC\u7684\u4EFB\u52A1\u6D6E\u5C42\uFF1A\u5FBD\u7AE0\u4E0E\u56E2\u961F\u5FBD\u7AE0\u540C\u4E00\u89C6\u89C9\u4F53\u7CFB\uFF08\u6BDB\u73BB\u7483+\u8109\u51B2\uFF09 */
20700
+ .t-team-job-badge{box-sizing:border-box;display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;margin-right:4px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;font-weight:600;line-height:18px;cursor:pointer;flex:none;transition:background-color .15s,border-color .15s}
20701
+ .t-team-job-badge:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}
20702
+ .t-team-job-badge:active{transform:translateY(0) scale(.98)}
20703
+ .t-team-job-badge-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--dsw-alias-label-tertiary)}
20704
+ .t-team-job-badge-dot[data-live="true"]{background:var(--dsw-alias-state-success-primary);animation:t-team-job-pulse 1.25s ease-in-out infinite}
20705
+ .t-team-job-badge-count{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}
20706
+ @keyframes t-team-job-pulse{0%,to{opacity:.42}50%{opacity:1}}
20707
+ .t-team-job-panel{position:fixed;z-index:60;display:flex;flex-direction:column;width:380px;max-height:min(460px,72vh);box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-3));backdrop-filter:blur(20px) saturate(1.08);box-shadow:0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent), 0 32px 72px color-mix(in srgb, var(--dsw-alias-label-primary) 16%, transparent);color:var(--dsw-alias-label-primary);animation:t-team-job-panel-in .16s ease-out}
20708
+ @keyframes t-team-job-panel-in{0%{opacity:0}to{opacity:1}}
20709
+ .t-team-job-panel-head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:44px;padding:0 10px 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);cursor:grab;touch-action:none;user-select:none}
20710
+ .t-team-job-panel-head:active{cursor:grabbing}
20711
+ .t-team-job-panel-title{font-size:14px;font-weight:600}
20712
+ .t-team-job-panel-close{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:0;border-radius:7px;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px;cursor:pointer}
20713
+ .t-team-job-panel-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
20714
+ .t-team-job-panel-tabs{display:flex;gap:4px;padding:6px 6px 0;border-bottom:1px solid var(--dsw-alias-border-l2)}
20715
+ .t-team-job-panel-tabs .t-team-tab{font-size:12px;padding:3px 9px}
20716
+ .t-team-job-tab-count{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:2px}
20717
+ .t-team-job-panel-body{display:flex;flex-direction:column;gap:6px;padding:6px;overflow:auto;min-height:0;scrollbar-width:thin;scrollbar-color:color-mix(in srgb, var(--dsw-alias-label-tertiary) 28%, transparent) transparent}
20718
+ .t-team-job-panel-body::-webkit-scrollbar{width:6px}
20719
+ .t-team-job-panel-body::-webkit-scrollbar-track{background:transparent}
20720
+ .t-team-job-panel-body::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 28%, transparent);background-clip:padding-box;border:2px solid transparent;border-radius:999px}
20721
+ .t-team-job-panel-body:hover::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 44%, transparent);background-clip:padding-box}
20722
+ .t-team-job-panel-body .t-team-jobs{gap:2px}
20723
+ .t-team-job-panel-body .t-team-job-row{padding:3px 6px;gap:6px;border-radius:6px;background:color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent)}
20724
+ .t-team-job-panel-body .t-team-job-meta{gap:2px}
20725
+ .t-team-job-panel-body .t-team-section-head{margin-top:2px}
20726
+ .t-team-pop[data-tab="tasks"]{width:420px;max-height:520px}
20261
20727
  .t-team-pop .t-team-picker-list{max-height:150px}
20262
20728
  .t-team-pop-list{display:flex;flex-direction:column;gap:6px;overflow:auto;min-height:0}
20263
20729
  .t-team-pop-item{display:flex;gap:8px;align-items:flex-start;text-align:left;padding:6px 8px;border-radius:8px;border:1px solid transparent;background:transparent;color:inherit;font:inherit;cursor:pointer}
@@ -20266,6 +20732,107 @@ var CSS = `
20266
20732
  .t-team-pop-desc{font-size:11px;color:var(--dsw-alias-label-tertiary);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}
20267
20733
  .t-team-pop-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px 2px}
20268
20734
  .t-team-pop-head{display:flex;align-items:center;justify-content:space-between;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}
20735
+ /* ---- \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u4FA7\u680F\u5165\u53E3\uFF08\u6CE8\u518C\u4E3A sidebar.panellist \u7684\u4E00\u884C\uFF0C\u4F4D\u4E8E\u300C\u65B0\u4F1A\u8BDD\u300D\u6309\u94AE\u4E0B\u65B9\uFF09 ---- */
20736
+ /*
20737
+ * \u90A3\u4E00\u884C\u672C\u8EAB\uFF08\u6309\u94AE\u3001\u6587\u5B57\u3001\u9009\u4E2D\u6001\u3001\u70B9\u51FB\u884C\u4E3A\uFF09\u7531\u5BBF\u4E3B sidebar \u6E32\u67D3\uFF0Cclass \u662F CSS Modules \u54C8\u5E0C\u5316\u7684\u3001
20738
+ * \u6307\u4E0D\u4E0A\uFF1B\u6240\u4EE5\u62FF\u6211\u4EEC\u81EA\u5DF1\u7684\u56FE\u6807\u7C7B\u5F53\u951A\u70B9\uFF08:has\uFF09\u628A\u8FD9\u4E00\u884C\u8C03\u6210\u300C\u65B0\u4F1A\u8BDD\u300D\u6309\u94AE\u7684\u89C2\u611F\uFF1A
20739
+ * \u540C\u9AD8 38px\u3001\u540C 12px \u5706\u89D2\u3001\u540C\u8FB9\u6846\u4E0E\u62AC\u5347\u586B\u5145\u3001\u540C\u5C45\u4E2D\u6392\u5E03\u3002
20740
+ *
20741
+ * \u26A0\uFE0F \u5BBD\u5EA6\u5FC5\u987B\u662F width:auto + align-self:stretch\uFF0C\u4E0D\u80FD\u6CBF\u7528\u5BBF\u4E3B panelRow \u7684 width:100%\uFF1A
20742
+ * \u300C\u65B0\u4F1A\u8BDD\u300D\u7684\u5BBD\u5EA6\u662F flex \u62C9\u4F38\u51FA\u6765\u7684\uFF08\u5BB9\u5668\u5BBD \u2212 \u5DE6\u53F3\u5404 2px \u7684 margin\uFF09\uFF0C\u800C width:100% \u662F
20743
+ * **\u5BB9\u5668\u5168\u5BBD\u518D\u53E0\u52A0\u90A3 2px margin** \u2014\u2014 \u4E24\u8FB9\u7684 margin \u65E0\u5904\u53EF\u53BB\uFF0C\u4E8E\u662F\u90A3\u4E00\u884C\u6BD4\u300C\u65B0\u4F1A\u8BDD\u300D\u5BBD\u51FA 4px\u3002
20744
+ * \u4FA7\u680F\u6536\u8D77\u65F6\u518D\u663E\u5F0F\u56DE\u5230 36px \u56FE\u6807\u4F4D\uFF0C\u5426\u5219 stretch \u4F1A\u8BA9\u5B83\u6491\u6EE1\u6574\u6761\u8FB9\u680F\u3002
20745
+ */
20746
+ .t-team-schedule-glyph{display:block}
20747
+ button:has(.t-team-schedule-glyph){box-sizing:border-box;width:auto;align-self:stretch;height:38px;min-height:38px;margin:0 2px 8px;padding:8px 16px;border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;justify-content:center;gap:6px}
20748
+ button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-button-floating-hover)}
20749
+ [data-sidebar-collapsed] button:has(.t-team-schedule-glyph){width:36px;align-self:flex-start;height:36px;min-height:36px;margin:0;padding:0;border-color:transparent;background:transparent}
20750
+ [data-sidebar-collapsed] button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-interactive-bg-hover)}
20751
+ /* ---- \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u53F3\u4FA7\u4E3B\u533A\u57DF\u7BA1\u7406\u9875\uFF08\u6CE8\u518C\u5728 main \u69FD\u7684 keyed \u9762\u677F\uFF09 ---- */
20752
+ .t-team-sched{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;gap:12px;width:100%;height:100%;min-height:0;padding:18px 22px 28px;overflow:auto;color:var(--dsw-alias-label-primary)}
20753
+ .t-team-sched-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex:none}
20754
+ .t-team-sched-title{font-size:18px;font-weight:600;margin:0}
20755
+ .t-team-sched-actions{display:flex;gap:8px;flex:none}
20756
+ .t-team-sched-intro{font-size:13px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
20757
+ .t-team-sched-tip{font-size:12px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
20758
+ .t-team-sched-note{font-size:13px;color:var(--dsw-alias-state-warn-primary);margin:0}
20759
+ .t-team-sched-error{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-state-error-primary);margin:0}
20760
+ .t-team-sched-file{font-size:11px;color:var(--dsw-alias-label-tertiary);font-family:var(--ds-font-family-code, monospace);word-break:break-all}
20761
+ .t-team-sched-body{display:flex;flex-direction:column;gap:12px;max-width:820px;width:100%}
20762
+ .t-team-sched-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
20763
+ .t-team-sched-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
20764
+ .t-team-sched-rowMain{display:flex;flex-direction:column;gap:3px;min-width:0}
20765
+ .t-team-sched-rowTitle{font-size:14px;font-weight:600}
20766
+ .t-team-sched-rowCron{font-size:12px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
20767
+ .t-team-sched-rowMeta{font-size:12px;color:var(--dsw-alias-label-secondary)}
20768
+ .t-team-sched-rowActions{display:flex;gap:8px;flex:none}
20769
+ .t-team-sched-runsToggle{align-self:flex-start;margin-top:2px;padding:0;border:none;background:transparent;color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary));font-size:12px;cursor:pointer}
20770
+ .t-team-sched-runsToggle:hover{text-decoration:underline}
20771
+ .t-team-sched-runs{list-style:none;margin:6px 0 0;padding:8px 0 0;border-top:1px solid var(--dsw-alias-border-l2);display:flex;flex-direction:column;gap:3px}
20772
+ .t-team-sched-run{display:flex;gap:8px;align-items:baseline;font-size:12px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
20773
+ .t-team-sched-runFail{color:var(--dsw-alias-state-error-primary);word-break:break-word}
20774
+ .t-team-sched-runSession{font-size:11px;color:var(--dsw-alias-label-tertiary)}
20775
+ .t-team-sched-btn{font-size:13px;padding:5px 10px;border-radius:7px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;cursor:pointer}
20776
+ .t-team-sched-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
20777
+ .t-team-sched-btn:disabled{opacity:.5;cursor:default}
20778
+ .t-team-sched-btn-primary{border-color:transparent;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);font-weight:600}
20779
+ .t-team-sched-btn-primary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-bg-base) 14%, var(--dsw-alias-label-primary))}
20780
+ .t-team-sched-btn-danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 32%, var(--dsw-alias-border-l2))}
20781
+ .t-team-sched-btn-danger:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}
20782
+ .t-team-sched-form{display:flex;flex-direction:column;gap:12px;padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
20783
+ .t-team-sched-formTitle{font-size:15px;font-weight:600;margin:0}
20784
+ .t-team-sched-field{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--dsw-alias-label-secondary)}
20785
+ .t-team-sched-field input,.t-team-sched-field textarea,.t-team-sched-field select{padding:8px 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:13px;font-family:inherit}
20786
+ .t-team-sched-field input:focus,.t-team-sched-field textarea:focus,.t-team-sched-field select:focus{outline:none;border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
20787
+ .t-team-sched-field textarea{resize:vertical;min-height:72px}
20788
+ .t-team-sched-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
20789
+ .t-team-sched-checkbox{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-secondary)}
20790
+ .t-team-sched-formActions{display:flex;gap:8px}
20791
+ /* cron \u9009\u62E9\u5668\uFF1A\u6A21\u677F chips + \u9891\u7387\u5206\u6BB5 + \u5404\u6A21\u5F0F\u5B57\u6BB5 + \u6458\u8981 + \u6700\u8FD1\u51E0\u6B21\u9884\u89C8 */
20792
+ .t-team-sched-cron{display:flex;flex-direction:column;gap:9px;width:100%}
20793
+ .t-team-sched-chips{display:flex;flex-wrap:wrap;gap:6px}
20794
+ .t-team-sched-chip{font-size:12px;padding:4px 11px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
20795
+ .t-team-sched-chip:hover:not(:disabled){border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}
20796
+ .t-team-sched-seg{display:inline-flex;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden;align-self:flex-start}
20797
+ .t-team-sched-seg button{border:none;border-right:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 14px;font:inherit;font-size:12px;cursor:pointer}
20798
+ .t-team-sched-seg button:last-child{border-right:none}
20799
+ .t-team-sched-seg button[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base)}
20800
+ .t-team-sched-cronRow{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:13px;color:var(--dsw-alias-label-secondary)}
20801
+ .t-team-sched-cronRow select,.t-team-sched-cronRow input{padding:6px 8px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;font-variant-numeric:tabular-nums}
20802
+ .t-team-sched-days{display:flex;gap:5px;flex-wrap:wrap}
20803
+ .t-team-sched-day{min-width:32px;height:30px;padding:0 6px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
20804
+ .t-team-sched-day[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);border-color:transparent}
20805
+ .t-team-sched-sum{font-size:12px;color:var(--dsw-alias-label-secondary)}
20806
+ .t-team-sched-next{display:flex;flex-direction:column;gap:4px}
20807
+ .t-team-sched-nextLabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
20808
+ .t-team-sched-nextList{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
20809
+ .t-team-sched-nextList li{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 8px;font-variant-numeric:tabular-nums}
20810
+ /* \u63D0\u793A\u8BCD\u8F93\u5165\u533A\uFF1A\u6846\u5185\u7B2C\u4E00\u884C\u662F\u4E13\u5BB6\u82AF\u7247\uFF08\u6807\u7B7E\u89C2\u611F\uFF0C\u4E0E\u5BF9\u8BDD\u8F93\u5165\u6846\u4E00\u81F4\uFF09\uFF0C\u4E0B\u9762\u662F\u6B63\u6587 */
20811
+ .t-team-sched-promptbox{box-sizing:border-box;display:flex;flex-direction:column;gap:6px;padding:8px 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);transition:border-color .16s}
20812
+ .t-team-sched-promptbox:focus-within{border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
20813
+ .t-team-sched-chips{display:flex;flex-wrap:wrap;gap:6px}
20814
+ .t-team-sched-chip{display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:2px 4px 2px 8px;border-radius:999px;background:color-mix(in srgb, var(--dsw-alias-brand-primary, #1677ff) 12%, transparent);color:var(--dsw-alias-brand-primary, #1677ff);font-size:12px;line-height:18px}
20815
+ .t-team-sched-chip-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20816
+ .t-team-sched-chip-remove{padding:0 3px;border:0;background:transparent;color:inherit;font:inherit;font-size:13px;line-height:1;cursor:pointer;opacity:.7}
20817
+ .t-team-sched-chip-remove:hover:not(:disabled){opacity:1}
20818
+ .t-team-sched-chip-remove:disabled{opacity:.35;cursor:default}
20819
+ /* \u26A0\uFE0F \u5FC5\u987B\u5E26 .t-team-sched-field \u524D\u7F00\uFF1A\u5426\u5219\u7279\u5F02\u6027\u4F4E\u4E8E\u901A\u7528\u7684 ".t-team-sched-field textarea" \u89C4\u5219\uFF0C
20820
+ * \u6B63\u6587\u4F1A\u5E26\u7740\u81EA\u5DF1\u90A3\u5708\u8FB9\u6846\uFF0C\u89C6\u89C9\u4E0A\u53D8\u6210\u300C\u6846\u91CC\u5957\u6846\u300D\u3002 */
20821
+ .t-team-sched-field .t-team-sched-prompt-input{box-sizing:border-box;width:100%;min-height:72px;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;resize:vertical}
20822
+ .t-team-sched-field .t-team-sched-prompt-input:focus{outline:none;border:0}
20823
+ /* \u63D0\u793A\u8BCD\u6846\u4E0B\u65B9\u7684\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\uFF1A\u6309\u94AE + \u53EA\u542B\u4E13\u5BB6\u5217\u8868\u7684\u6D6E\u5C42\uFF08\u7C7B\u540D\u72EC\u7ACB\uFF0C\u907F\u514D\u4E0E\u65E2\u6709\u7C7B\u4E92\u76F8\u8986\u76D6\uFF09 */
20824
+ .t-team-expert-pick{position:relative;display:flex;align-items:center;gap:8px;margin-top:2px}
20825
+ .t-team-expert-pick-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
20826
+ .t-team-expert-pick-panel{position:absolute;left:0;top:calc(100% + 6px);z-index:26;display:flex;flex-direction:column;gap:6px;width:min(420px,90vw);max-height:300px;box-sizing:border-box;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-3));box-shadow:0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent), 0 32px 72px color-mix(in srgb, var(--dsw-alias-label-primary) 16%, transparent)}
20827
+ .t-team-expert-pick-search{box-sizing:border-box;width:100%;padding:7px 9px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
20828
+ .t-team-expert-pick-search:focus{outline:none;border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
20829
+ .t-team-expert-pick-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;overflow:auto;min-height:0}
20830
+ .t-team-expert-pick-item{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;padding:6px 8px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;text-align:left;cursor:pointer}
20831
+ .t-team-expert-pick-item[data-active="true"]{background:var(--dsw-alias-interactive-bg-hover)}
20832
+ .t-team-expert-pick-item[data-picked="true"]{color:var(--dsw-alias-label-primary);font-weight:500}
20833
+ .t-team-expert-pick-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20834
+ .t-team-expert-pick-meta{flex:none;font-size:11px;color:var(--dsw-alias-label-tertiary)}
20835
+ .t-team-expert-pick-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px}
20269
20836
  `;
20270
20837
  function direct(method, parameters, typeSymbol, schema) {
20271
20838
  return {
@@ -20290,6 +20857,30 @@ var TYPERT_REMOTE = {
20290
20857
  { name: "slug", wire: "slug", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
20291
20858
  { name: "division", wire: "division", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(64) } }
20292
20859
  ], "TTeamPrompt", promptSchema),
20860
+ direct("getUiPrefs", [], "TTeamUiPrefs", uiPrefsSchema),
20861
+ // 入参是 patch 对象(与 host 侧 descriptor 一致):界面偏好不再只有任务徽章一项,
20862
+ // 加键不必再加方法。
20863
+ direct("setUiPrefs", [
20864
+ { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamUiPrefsPatch", schema: uiPrefsPatchSchema } }
20865
+ ], "TTeamUiPrefs", uiPrefsSchema),
20866
+ // 定时任务:读一份快照;写操作全部回传刷新后的整份快照,面板拿到直接重绘。
20867
+ direct("getSchedule", [], "TTeamSchedule", scheduleSnapshotSchema),
20868
+ direct("createScheduleItem", [
20869
+ { name: "input", wire: "input", source: "json", codec: { mode: "strict", typeSymbol: "TTeamScheduleInput", schema: scheduleInputSchema } }
20870
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20871
+ direct("updateScheduleItem", [
20872
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
20873
+ { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamSchedulePatch", schema: schedulePatchSchema } }
20874
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20875
+ direct("deleteScheduleItem", [
20876
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
20877
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20878
+ direct("runScheduleItem", [
20879
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
20880
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20881
+ direct("previewSchedule", [
20882
+ { name: "cron", wire: "cron", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(120) } }
20883
+ ], "TTeamSchedulePreview", schedulePreviewSchema),
20293
20884
  direct("getSquads", [], "TTeamSquads", squadsSnapshotSchema),
20294
20885
  direct("saveSquads", [
20295
20886
  { name: "squads", wire: "squads", source: "json", codec: { mode: "strict", typeSymbol: "TTeamSquadInput[]", schema: external_exports.array(squadInputSchema).min(1).max(48) } },
@@ -20374,6 +20965,26 @@ function displayDescription(expert, active) {
20374
20965
  function divisionLabel(expert, active) {
20375
20966
  return active === "en" ? expert.divisionEn || expert.division : expert.divisionZh || expert.division;
20376
20967
  }
20968
+ function splitExpertMentions(text, experts, active) {
20969
+ let rest = String(text ?? "");
20970
+ const mentions = [];
20971
+ for (let step = 0; step < 32; step += 1) {
20972
+ let matched;
20973
+ for (const expert of experts ?? []) {
20974
+ const names = [displayName(expert, active), expert?.name, expert?.nameEn, expert?.slug].filter((name) => typeof name === "string" && name !== "");
20975
+ for (const name of names) {
20976
+ if (!rest.startsWith(`@${name} `)) continue;
20977
+ if (matched === void 0 || name.length > matched.name.length) {
20978
+ matched = { name, display: displayName(expert, active) };
20979
+ }
20980
+ }
20981
+ }
20982
+ if (matched === void 0) break;
20983
+ rest = rest.slice(matched.name.length + 2);
20984
+ if (!mentions.includes(matched.display)) mentions.push(matched.display);
20985
+ }
20986
+ return { mentions, body: rest };
20987
+ }
20377
20988
  function matchExpert(expert, active, query) {
20378
20989
  if (query === "") return true;
20379
20990
  const haystack = `${expert.name} ${expert.nameEn} ${expert.description} ${expert.descriptionEn} ${expert.slug}`.toLowerCase();
@@ -20410,7 +21021,532 @@ var SectionBoundary = class extends import_react.default.Component {
20410
21021
  return this.props.children;
20411
21022
  }
20412
21023
  };
20413
- function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squadsPreview, teamsPreview, draftPreview }) {
21024
+ var SCHEDULE_PANEL_KEY = `${NS}-schedule`;
21025
+ var SCHEDULE_PRESET_LABELS = {
21026
+ hourly: "sched.presetHourly",
21027
+ min30: "sched.presetMin30",
21028
+ daily9: "sched.presetDaily9",
21029
+ weekday830: "sched.presetWeekday830",
21030
+ mon10: "sched.presetMon10"
21031
+ };
21032
+ var SCHEDULE_WEEKDAY_LABELS = {
21033
+ 1: "sched.wd1",
21034
+ 2: "sched.wd2",
21035
+ 3: "sched.wd3",
21036
+ 4: "sched.wd4",
21037
+ 5: "sched.wd5",
21038
+ 6: "sched.wd6",
21039
+ 0: "sched.wd0"
21040
+ };
21041
+ function errorText(cause) {
21042
+ return cause instanceof Error ? cause.message : String(cause);
21043
+ }
21044
+ function CronPicker({ t, remote, value, onChange, disabled }) {
21045
+ const [model, setModel] = import_react.default.useState(() => parseCron(value));
21046
+ const [fires, setFires] = import_react.default.useState([]);
21047
+ const [hint, setHint] = import_react.default.useState("");
21048
+ import_react.default.useEffect(() => {
21049
+ setModel(parseCron(value));
21050
+ }, [value]);
21051
+ import_react.default.useEffect(() => {
21052
+ const cron = String(value ?? "").trim();
21053
+ if (cron === "") {
21054
+ setFires([]);
21055
+ setHint("");
21056
+ return void 0;
21057
+ }
21058
+ let cancelled = false;
21059
+ const timer = setTimeout(() => {
21060
+ void (async () => {
21061
+ try {
21062
+ const payload = unwrap(await remote.previewSchedule(cron), "previewSchedule");
21063
+ if (cancelled) return;
21064
+ setFires(Array.isArray(payload?.fires) ? payload.fires : []);
21065
+ setHint("");
21066
+ } catch (cause) {
21067
+ if (cancelled) return;
21068
+ setFires([]);
21069
+ setHint(errorText(cause));
21070
+ }
21071
+ })();
21072
+ }, 250);
21073
+ return () => {
21074
+ cancelled = true;
21075
+ clearTimeout(timer);
21076
+ };
21077
+ }, [value, remote]);
21078
+ import_react.default.useEffect(() => {
21079
+ if (!value || String(value).trim() === "") onChange(buildCron(parseCron("")));
21080
+ }, []);
21081
+ const emit = (next) => {
21082
+ setModel(next);
21083
+ const cron = buildCron(next);
21084
+ if (cron !== "") onChange(cron);
21085
+ };
21086
+ const setMode = (mode) => {
21087
+ if (mode === model.mode) return;
21088
+ if (mode === "hourly") emit({ mode, step: 60, minute: model.minute ?? 0 });
21089
+ else if (mode === "daily") emit({ mode, hour: model.hour ?? 9, minute: model.minute ?? 0 });
21090
+ else if (mode === "weekly") emit({ mode, hour: model.hour ?? 9, minute: model.minute ?? 0, days: model.days && model.days.length ? model.days : [1, 2, 3, 4, 5] });
21091
+ else {
21092
+ const raw = buildCron(model) || "0 9 * * *";
21093
+ setModel({ mode, raw });
21094
+ onChange(raw);
21095
+ }
21096
+ };
21097
+ const toggleDay = (day) => {
21098
+ const current = model.days || [];
21099
+ const next = current.includes(day) ? current.filter((item) => item !== day) : WEEKDAY_KEYS.filter((item) => current.includes(item) || item === day);
21100
+ if (next.length === 0) return;
21101
+ emit({ ...model, days: next });
21102
+ };
21103
+ const pad2 = (n) => String(n).padStart(2, "0");
21104
+ const hours = Array.from({ length: 24 }, (_, i) => i);
21105
+ const minutes = Array.from({ length: 60 }, (_, i) => i);
21106
+ const time3 = `${pad2(model.hour ?? 9)}:${pad2(model.minute ?? 0)}`;
21107
+ let summary;
21108
+ if (model.mode === "hourly") {
21109
+ summary = model.step && model.step < 60 ? t("sched.sumMin", { n: model.step }) : t("sched.sumHour", { m: pad2(model.minute ?? 0) });
21110
+ } else if (model.mode === "daily") {
21111
+ summary = t("sched.sumDaily", { t: time3 });
21112
+ } else if (model.mode === "weekly") {
21113
+ const days = model.days || [];
21114
+ const isWorkday = days.length === 5 && [1, 2, 3, 4, 5].every((day) => days.includes(day));
21115
+ const week = isWorkday ? "" : days.map((day) => t(SCHEDULE_WEEKDAY_LABELS[day])).join(t("sched.listSep"));
21116
+ summary = t(isWorkday ? "sched.sumWeeklyWorkday" : "sched.sumWeekly", { w: week, t: time3 });
21117
+ } else {
21118
+ summary = model.raw ? t("sched.sumCustom", { raw: model.raw }) : t("sched.sumEmpty");
21119
+ }
21120
+ const timeSelects = /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("select", { "aria-label": t("sched.hourField"), value: model.hour ?? 9, disabled, onChange: (event) => emit({ ...model, hour: Number(event.target.value) }) }, hours.map((n) => /* @__PURE__ */ import_react.default.createElement("option", { key: n, value: n }, pad2(n)))), /* @__PURE__ */ import_react.default.createElement("span", null, ":"), /* @__PURE__ */ import_react.default.createElement("select", { "aria-label": t("sched.minuteField"), value: model.minute ?? 0, disabled, onChange: (event) => emit({ ...model, minute: Number(event.target.value) }) }, minutes.map((n) => /* @__PURE__ */ import_react.default.createElement("option", { key: n, value: n }, pad2(n)))));
21121
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-cron" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-chips" }, CRON_PRESETS.map((preset) => /* @__PURE__ */ import_react.default.createElement(
21122
+ "button",
21123
+ {
21124
+ key: preset.id,
21125
+ type: "button",
21126
+ className: "t-team-sched-chip",
21127
+ disabled,
21128
+ onClick: () => onChange(preset.cron)
21129
+ },
21130
+ t(SCHEDULE_PRESET_LABELS[preset.id])
21131
+ ))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-seg", role: "tablist" }, [["hourly", "sched.cronHourly"], ["daily", "sched.cronDaily"], ["weekly", "sched.cronWeekly"], ["custom", "sched.cronCustom"]].map(([mode, key]) => /* @__PURE__ */ import_react.default.createElement(
21132
+ "button",
21133
+ {
21134
+ key: mode,
21135
+ type: "button",
21136
+ role: "tab",
21137
+ "aria-selected": model.mode === mode,
21138
+ "data-on": model.mode === mode,
21139
+ disabled,
21140
+ onClick: () => setMode(mode)
21141
+ },
21142
+ t(key)
21143
+ ))), model.mode === "hourly" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-cronRow" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronEvery")), /* @__PURE__ */ import_react.default.createElement(
21144
+ "select",
21145
+ {
21146
+ value: model.step ?? 60,
21147
+ disabled,
21148
+ onChange: (event) => {
21149
+ const step = Number(event.target.value);
21150
+ emit(step === 60 ? { mode: "hourly", step, minute: model.minute ?? 0 } : { mode: "hourly", step });
21151
+ }
21152
+ },
21153
+ HOURLY_STEPS.map((step) => /* @__PURE__ */ import_react.default.createElement("option", { key: step, value: step }, step === 60 ? "1" : String(step)))
21154
+ ), (model.step ?? 60) === 60 ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronAtMinute")), /* @__PURE__ */ import_react.default.createElement(
21155
+ "select",
21156
+ {
21157
+ value: model.minute ?? 0,
21158
+ disabled,
21159
+ onChange: (event) => emit({ ...model, minute: Number(event.target.value) })
21160
+ },
21161
+ minutes.map((n) => /* @__PURE__ */ import_react.default.createElement("option", { key: n, value: n }, pad2(n)))
21162
+ ), /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronMinuteUnit"))) : /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronMinutesUnit"))), (model.mode === "daily" || model.mode === "weekly") && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-cronRow" }, model.mode === "weekly" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-days" }, WEEKDAY_KEYS.map((day) => /* @__PURE__ */ import_react.default.createElement(
21163
+ "button",
21164
+ {
21165
+ key: day,
21166
+ type: "button",
21167
+ className: "t-team-sched-day",
21168
+ "data-on": (model.days || []).includes(day),
21169
+ "aria-pressed": (model.days || []).includes(day),
21170
+ disabled,
21171
+ onClick: () => toggleDay(day)
21172
+ },
21173
+ t(SCHEDULE_WEEKDAY_LABELS[day])
21174
+ ))), timeSelects), model.mode === "custom" && /* @__PURE__ */ import_react.default.createElement(
21175
+ "input",
21176
+ {
21177
+ value: model.raw || "",
21178
+ disabled,
21179
+ placeholder: "0 9 * * *",
21180
+ spellCheck: false,
21181
+ onChange: (event) => {
21182
+ const raw = event.target.value;
21183
+ setModel({ mode: "custom", raw });
21184
+ onChange(raw);
21185
+ }
21186
+ }
21187
+ ), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-sum" }, hint === "" ? summary : hint), fires.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-next" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-nextLabel" }, t("sched.nextRuns", { n: fires.length })), /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-sched-nextList" }, fires.map((iso, index) => /* @__PURE__ */ import_react.default.createElement("li", { key: index }, new Date(iso).toLocaleString(void 0, { weekday: "short", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }))))));
21188
+ }
21189
+ function emptyScheduleForm() {
21190
+ return { editingId: null, title: "", prompt: "", cron: "", enabled: true, workspaceId: "" };
21191
+ }
21192
+ function scheduleLastRun(t, item) {
21193
+ if (!item.lastRunAt) return t("sched.neverRun");
21194
+ const time3 = new Date(item.lastRunAt).toLocaleString();
21195
+ return item.lastRunError === void 0 ? time3 : `${time3}\uFF08${t("sched.failed")}: ${item.lastRunError}\uFF09`;
21196
+ }
21197
+ function ExpertPicker({ t, active, experts, disabled, selected, onPick }) {
21198
+ const [open2, setOpen] = import_react.default.useState(false);
21199
+ const [query, setQuery] = import_react.default.useState("");
21200
+ const [index, setIndex] = import_react.default.useState(0);
21201
+ const wrapRef = import_react.default.useRef(null);
21202
+ const picked = selected ?? [];
21203
+ import_react.default.useEffect(() => {
21204
+ if (!open2) return void 0;
21205
+ const onDown = (event) => {
21206
+ const node2 = wrapRef.current;
21207
+ if (node2 !== null && !node2.contains(event.target)) setOpen(false);
21208
+ };
21209
+ document.addEventListener("pointerdown", onDown, true);
21210
+ return () => document.removeEventListener("pointerdown", onDown, true);
21211
+ }, [open2]);
21212
+ const needle = query.trim().toLowerCase();
21213
+ const candidates = (experts ?? []).filter((expert) => matchExpert(expert, active, needle)).slice(0, 50);
21214
+ const pick2 = (expert) => {
21215
+ if (expert === void 0) return;
21216
+ onPick(expert);
21217
+ setOpen(false);
21218
+ setQuery("");
21219
+ setIndex(0);
21220
+ };
21221
+ const onKeyDown = (event) => {
21222
+ if (event.key === "Escape") {
21223
+ event.preventDefault();
21224
+ setOpen(false);
21225
+ return;
21226
+ }
21227
+ if (candidates.length === 0) return;
21228
+ if (event.key === "ArrowDown") {
21229
+ event.preventDefault();
21230
+ setIndex((current) => (current + 1) % candidates.length);
21231
+ } else if (event.key === "ArrowUp") {
21232
+ event.preventDefault();
21233
+ setIndex((current) => (current - 1 + candidates.length) % candidates.length);
21234
+ } else if (event.key === "Enter") {
21235
+ event.preventDefault();
21236
+ pick2(candidates[Math.min(index, candidates.length - 1)]);
21237
+ }
21238
+ };
21239
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick", ref: wrapRef }, /* @__PURE__ */ import_react.default.createElement(
21240
+ "button",
21241
+ {
21242
+ type: "button",
21243
+ className: "t-team-chip",
21244
+ "data-active": open2,
21245
+ disabled,
21246
+ "aria-expanded": open2,
21247
+ onClick: () => {
21248
+ setOpen(!open2);
21249
+ setQuery("");
21250
+ setIndex(0);
21251
+ }
21252
+ },
21253
+ "\u{1F9E9} ",
21254
+ t("sched.expertPick")
21255
+ ), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-hint" }, t("sched.expertPickHint")), open2 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick-panel" }, /* @__PURE__ */ import_react.default.createElement(
21256
+ "input",
21257
+ {
21258
+ className: "t-team-expert-pick-search",
21259
+ value: query,
21260
+ autoFocus: true,
21261
+ spellCheck: false,
21262
+ placeholder: t("sched.expertPickSearch"),
21263
+ "aria-label": t("sched.expertPickSearch"),
21264
+ onChange: (event) => {
21265
+ setQuery(event.target.value);
21266
+ setIndex(0);
21267
+ },
21268
+ onKeyDown
21269
+ }
21270
+ ), candidates.length === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick-empty" }, t("sched.expertPickEmpty")) : /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-expert-pick-list", role: "listbox" }, candidates.map((expert, position) => /* @__PURE__ */ import_react.default.createElement("li", { key: expert.slug }, /* @__PURE__ */ import_react.default.createElement(
21271
+ "button",
21272
+ {
21273
+ type: "button",
21274
+ role: "option",
21275
+ "aria-selected": position === index,
21276
+ "data-active": position === index,
21277
+ "data-picked": picked.includes(displayName(expert, active)),
21278
+ className: "t-team-expert-pick-item",
21279
+ onMouseEnter: () => setIndex(position),
21280
+ onClick: () => pick2(expert)
21281
+ },
21282
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-name" }, picked.includes(displayName(expert, active)) ? "\u2713 " : "", expert.emoji, " ", displayName(expert, active)),
21283
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-meta" }, divisionLabel(expert, active))
21284
+ ))))));
21285
+ }
21286
+ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
21287
+ const showButton = useShowScheduleButton();
21288
+ const [snapshot, setSnapshot] = import_react.default.useState(null);
21289
+ const [error62, setError] = import_react.default.useState("");
21290
+ const [loading, setLoading] = import_react.default.useState(true);
21291
+ const [busy, setBusy] = import_react.default.useState(false);
21292
+ const [form, setForm] = import_react.default.useState(null);
21293
+ const [historyId, setHistoryId] = import_react.default.useState(null);
21294
+ const [runningId, setRunningId] = import_react.default.useState(null);
21295
+ const [experts, setExperts] = import_react.default.useState([]);
21296
+ const layout = () => hostCtx?.get?.("layout") ?? hostCtx?.layout;
21297
+ const backToConversation = () => layout()?.selectPanel?.(null);
21298
+ const load = import_react.default.useCallback(async () => {
21299
+ setLoading(true);
21300
+ try {
21301
+ setSnapshot(unwrap(await remote.getSchedule(), "getSchedule"));
21302
+ setError("");
21303
+ } catch (cause) {
21304
+ setError(errorText(cause));
21305
+ } finally {
21306
+ setLoading(false);
21307
+ }
21308
+ }, [remote]);
21309
+ import_react.default.useEffect(() => {
21310
+ void load();
21311
+ }, [load]);
21312
+ import_react.default.useEffect(() => {
21313
+ let alive = true;
21314
+ void (async () => {
21315
+ try {
21316
+ const catalogSnapshot = await refresh(remote);
21317
+ if (!alive) return;
21318
+ setExperts(catalogSnapshot.experts.filter((expert) => expert.conflict !== true && catalogSnapshot.enabledSet.has(expert.slug)));
21319
+ } catch (cause) {
21320
+ console.warn("[t-team] \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u8BFB\u53D6\u4E13\u5BB6\u540D\u518C\u5931\u8D25\uFF0C\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\u6682\u4E0D\u53EF\u7528\uFF1A", cause);
21321
+ }
21322
+ })();
21323
+ return () => {
21324
+ alive = false;
21325
+ };
21326
+ }, [remote]);
21327
+ const active = getActive();
21328
+ import_react.default.useEffect(() => {
21329
+ if (showButton) return;
21330
+ layout()?.selectPanel?.(null);
21331
+ }, [showButton]);
21332
+ const applySnapshot = (next) => {
21333
+ setSnapshot(next);
21334
+ setError("");
21335
+ };
21336
+ function fillExpert(expert) {
21337
+ const name = displayName(expert, active);
21338
+ setForm((current) => {
21339
+ if (current === null) return current;
21340
+ const { mentions, body } = splitExpertMentions(current.prompt, experts, active);
21341
+ const next = mentions.includes(name) ? mentions.filter((item) => item !== name) : [...mentions, name];
21342
+ return { ...current, prompt: `${next.map((item) => `@${item} `).join("")}${body}` };
21343
+ });
21344
+ }
21345
+ async function submitForm() {
21346
+ if (form === null || busy) return;
21347
+ if (form.title.trim() === "" || form.prompt.trim() === "" || form.cron.trim() === "") {
21348
+ window.alert(t("sched.invalidForm"));
21349
+ return;
21350
+ }
21351
+ setBusy(true);
21352
+ try {
21353
+ const payload = {
21354
+ title: form.title.trim(),
21355
+ prompt: form.prompt,
21356
+ cron: form.cron.trim(),
21357
+ enabled: form.enabled,
21358
+ // 空串 = 不绑定工作区(显式解绑也走这个值,宿主认得)。
21359
+ workspaceId: form.workspaceId === "" ? "" : form.workspaceId
21360
+ };
21361
+ const next = form.editingId === null ? unwrap(await remote.createScheduleItem(payload), "createScheduleItem") : unwrap(await remote.updateScheduleItem(form.editingId, payload), "updateScheduleItem");
21362
+ applySnapshot(next);
21363
+ setForm(null);
21364
+ } catch (cause) {
21365
+ setError(errorText(cause));
21366
+ } finally {
21367
+ setBusy(false);
21368
+ }
21369
+ }
21370
+ async function removeItem(id) {
21371
+ if (!window.confirm(t("sched.deleteConfirm"))) return;
21372
+ setBusy(true);
21373
+ try {
21374
+ applySnapshot(unwrap(await remote.deleteScheduleItem(id), "deleteScheduleItem"));
21375
+ } catch (cause) {
21376
+ setError(errorText(cause));
21377
+ } finally {
21378
+ setBusy(false);
21379
+ }
21380
+ }
21381
+ async function runItem(id) {
21382
+ setRunningId(id);
21383
+ try {
21384
+ applySnapshot(unwrap(await remote.runScheduleItem(id), "runScheduleItem"));
21385
+ } catch (cause) {
21386
+ setError(errorText(cause));
21387
+ } finally {
21388
+ setRunningId(null);
21389
+ }
21390
+ }
21391
+ const items = snapshot?.items ?? [];
21392
+ const workspaces = snapshot?.workspaces ?? [];
21393
+ const workspaceTitle = (id) => workspaces.find((workspace) => workspace.id === id)?.title ?? id;
21394
+ const rowMeta = (item) => {
21395
+ const parts = [];
21396
+ if (item.workspaceId !== void 0) parts.push(`${t("sched.workspace")}: ${workspaceTitle(item.workspaceId)}`);
21397
+ if (item.enabled !== true) parts.push(t("sched.disabledTag"));
21398
+ parts.push(`${t("sched.lastRun")}: ${scheduleLastRun(t, item)}`);
21399
+ return parts.join(" \xB7 ");
21400
+ };
21401
+ const disabled = busy || loading || !showButton;
21402
+ const parsedPrompt = form === null ? { mentions: [], body: "" } : splitExpertMentions(form.prompt, experts, active);
21403
+ const mentioned = parsedPrompt.mentions;
21404
+ const promptBody = parsedPrompt.body;
21405
+ function setPromptBody(nextBody) {
21406
+ setForm((current) => {
21407
+ if (current === null) return current;
21408
+ const { mentions } = splitExpertMentions(current.prompt, experts, active);
21409
+ return { ...current, prompt: `${mentions.map((item) => `@${item} `).join("")}${nextBody}` };
21410
+ });
21411
+ }
21412
+ function removeExpert(name) {
21413
+ setForm((current) => {
21414
+ if (current === null) return current;
21415
+ const { mentions, body } = splitExpertMentions(current.prompt, experts, active);
21416
+ return { ...current, prompt: `${mentions.filter((item) => item !== name).map((item) => `@${item} `).join("")}${body}` };
21417
+ });
21418
+ }
21419
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "t-team-sched-title" }, t("sched.title")), /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.intro"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", disabled: loading, onClick: () => void load() }, t("sched.refresh")), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: backToConversation }, t("sched.back")))), !showButton && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-note" }, t("sched.off")), snapshot !== null && snapshot.capabilities.agents !== true && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-note" }, t("sched.noAgents")), error62 !== "" && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-error", role: "alert" }, t("sched.error"), " ", error62, /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: () => void load() }, t("sched.retry"))), loading && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.loading")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-body" }, !loading && items.length === 0 && error62 === "" && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.empty")), /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-sched-list" }, items.map((item) => /* @__PURE__ */ import_react.default.createElement("li", { key: item.id, className: "t-team-sched-row" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-rowMain" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowTitle" }, item.title), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowCron" }, item.cron), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowMeta" }, rowMeta(item)), item.runs.length > 0 && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
21420
+ "button",
21421
+ {
21422
+ type: "button",
21423
+ className: "t-team-sched-runsToggle",
21424
+ "aria-expanded": historyId === item.id,
21425
+ onClick: () => setHistoryId(historyId === item.id ? null : item.id)
21426
+ },
21427
+ t("sched.runHistory", { count: item.runs.length })
21428
+ ), historyId === item.id && /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-sched-runs" }, [...item.runs].reverse().map((run, index) => /* @__PURE__ */ import_react.default.createElement("li", { key: index, className: "t-team-sched-run" }, /* @__PURE__ */ import_react.default.createElement("span", null, new Date(run.at).toLocaleString()), run.ok === true ? /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.runOk")) : /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-runFail" }, t("sched.runFail"), ": ", run.error ?? ""), run.sessionId !== void 0 && /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-runSession" }, run.sessionId)))))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-rowActions" }, /* @__PURE__ */ import_react.default.createElement(
21429
+ "button",
21430
+ {
21431
+ type: "button",
21432
+ className: "t-team-sched-btn",
21433
+ disabled: disabled || runningId === item.id || (snapshot?.running ?? []).includes(item.id),
21434
+ onClick: () => void runItem(item.id)
21435
+ },
21436
+ runningId === item.id || (snapshot?.running ?? []).includes(item.id) ? t("sched.running") : t("sched.runNow")
21437
+ ), /* @__PURE__ */ import_react.default.createElement(
21438
+ "button",
21439
+ {
21440
+ type: "button",
21441
+ className: "t-team-sched-btn",
21442
+ disabled,
21443
+ onClick: () => setForm({
21444
+ editingId: item.id,
21445
+ title: item.title,
21446
+ prompt: item.prompt,
21447
+ cron: item.cron,
21448
+ enabled: item.enabled === true,
21449
+ workspaceId: item.workspaceId ?? ""
21450
+ })
21451
+ },
21452
+ t("sched.edit")
21453
+ ), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-danger", disabled, onClick: () => void removeItem(item.id) }, t("sched.delete")))))), form === null ? /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-primary", disabled, onClick: () => setForm(emptyScheduleForm()) }, t("sched.new")) : /* @__PURE__ */ import_react.default.createElement(
21454
+ "form",
21455
+ {
21456
+ className: "t-team-sched-form",
21457
+ onSubmit: (event) => {
21458
+ event.preventDefault();
21459
+ void submitForm();
21460
+ }
21461
+ },
21462
+ /* @__PURE__ */ import_react.default.createElement("h3", { className: "t-team-sched-formTitle" }, form.editingId === null ? t("sched.new") : t("sched.edit")),
21463
+ /* @__PURE__ */ import_react.default.createElement("label", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.titleLabel")), /* @__PURE__ */ import_react.default.createElement(
21464
+ "input",
21465
+ {
21466
+ value: form.title,
21467
+ disabled: busy,
21468
+ placeholder: t("sched.titlePlaceholder"),
21469
+ onChange: (event) => setForm({ ...form, title: event.target.value })
21470
+ }
21471
+ )),
21472
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.promptLabel")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-promptbox" }, mentioned.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-chips" }, mentioned.map((name) => /* @__PURE__ */ import_react.default.createElement("span", { key: name, className: "t-team-sched-chip" }, /* @__PURE__ */ import_react.default.createElement("span", { "aria-hidden": "true" }, "\u{1F9E9}"), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-chip-name" }, name), /* @__PURE__ */ import_react.default.createElement(
21473
+ "button",
21474
+ {
21475
+ type: "button",
21476
+ className: "t-team-sched-chip-remove",
21477
+ disabled: busy,
21478
+ title: t("sched.expertRemove", { name }),
21479
+ "aria-label": t("sched.expertRemove", { name }),
21480
+ onClick: () => removeExpert(name)
21481
+ },
21482
+ "\xD7"
21483
+ )))), /* @__PURE__ */ import_react.default.createElement(
21484
+ "textarea",
21485
+ {
21486
+ className: "t-team-sched-prompt-input",
21487
+ value: promptBody,
21488
+ rows: 4,
21489
+ disabled: busy,
21490
+ placeholder: t("sched.promptPlaceholder"),
21491
+ onChange: (event) => setPromptBody(event.target.value)
21492
+ }
21493
+ )), /* @__PURE__ */ import_react.default.createElement(
21494
+ ExpertPicker,
21495
+ {
21496
+ t,
21497
+ active,
21498
+ experts,
21499
+ disabled: busy,
21500
+ selected: mentioned,
21501
+ onPick: fillExpert
21502
+ }
21503
+ ), mentioned.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick-hint" }, mentioned.length === 1 ? t("sched.expertInvokeHint", { name: mentioned[0] }) : t("sched.expertInvokeManyHint", { names: mentioned.join(t("sched.listSep")) }))),
21504
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronLabel")), /* @__PURE__ */ import_react.default.createElement(CronPicker, { t, remote, value: form.cron, disabled: busy, onChange: (cron) => setForm((current) => current === null ? current : { ...current, cron }) }), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.cronHint"))),
21505
+ workspaces.length > 0 && /* @__PURE__ */ import_react.default.createElement("label", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.workspace")), /* @__PURE__ */ import_react.default.createElement(
21506
+ "select",
21507
+ {
21508
+ value: form.workspaceId,
21509
+ disabled: busy,
21510
+ onChange: (event) => setForm({ ...form, workspaceId: event.target.value })
21511
+ },
21512
+ /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, t("sched.workspaceNone")),
21513
+ workspaces.map((workspace) => /* @__PURE__ */ import_react.default.createElement("option", { key: workspace.id, value: workspace.id }, workspace.title))
21514
+ ), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceHint"))),
21515
+ /* @__PURE__ */ import_react.default.createElement("label", { className: "t-team-sched-checkbox" }, /* @__PURE__ */ import_react.default.createElement(
21516
+ "input",
21517
+ {
21518
+ type: "checkbox",
21519
+ checked: form.enabled,
21520
+ disabled: busy,
21521
+ onChange: (event) => setForm({ ...form, enabled: event.target.checked })
21522
+ }
21523
+ ), /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.enabledLabel")), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.enabledHint"))),
21524
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-formActions" }, /* @__PURE__ */ import_react.default.createElement("button", { type: "submit", className: "t-team-sched-btn t-team-sched-btn-primary", disabled: busy }, busy ? t("sched.saving") : t("sched.save")), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", disabled: busy, onClick: () => setForm(null) }, t("sched.cancel")))
21525
+ ), /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-tip" }, t("sched.tip")), snapshot !== null && snapshot.file !== "" && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-file" }, t("sched.file", { path: snapshot.file }))));
21526
+ }
21527
+ function ScheduleGlyph({ size = 16 }) {
21528
+ return /* @__PURE__ */ import_react.default.createElement(
21529
+ "svg",
21530
+ {
21531
+ className: "t-team-schedule-glyph",
21532
+ width: size,
21533
+ height: size,
21534
+ viewBox: "0 0 16 16",
21535
+ fill: "none",
21536
+ stroke: "currentColor",
21537
+ strokeWidth: "1.4",
21538
+ strokeLinecap: "round",
21539
+ strokeLinejoin: "round",
21540
+ "aria-hidden": "true",
21541
+ focusable: "false"
21542
+ },
21543
+ /* @__PURE__ */ import_react.default.createElement("rect", { x: "2.2", y: "3.4", width: "11.6", height: "10.4", rx: "2.4" }),
21544
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M2.2 6.6h11.6" }),
21545
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M5.6 2.2v2.4M10.4 2.2v2.4" }),
21546
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.1 9.7l1.3 1.3 2.5-2.7" })
21547
+ );
21548
+ }
21549
+ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab, squadsPreview, teamsPreview, draftPreview }) {
20414
21550
  const [snapshot, setSnapshot] = import_react.default.useState(() => snapshotOf(remote) ?? null);
20415
21551
  const [query, setQuery] = import_react.default.useState("");
20416
21552
  const [division, setDivision] = import_react.default.useState("");
@@ -20621,8 +21757,78 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
20621
21757
  if (snapshot === null) {
20622
21758
  return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.loading")), error62 !== "" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, t("settings.loadFailed", { detail: error62 })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => void reload(true) }, t("settings.retry")))));
20623
21759
  }
21760
+ const [showTaskBadge, setShowTaskBadgeState] = import_react.default.useState(true);
21761
+ const [showScheduleButton, setShowScheduleButtonState] = import_react.default.useState(true);
21762
+ const [uiPrefsError, setUiPrefsError] = import_react.default.useState("");
21763
+ import_react.default.useEffect(() => {
21764
+ let alive = true;
21765
+ void (async () => {
21766
+ try {
21767
+ const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
21768
+ if (!alive) return;
21769
+ if (typeof data?.showTaskBadge !== "boolean" || typeof data?.showScheduleButton !== "boolean") {
21770
+ setUiPrefsError(t("settings.showTaskBadgeUnreadable"));
21771
+ return;
21772
+ }
21773
+ setUiPrefsError("");
21774
+ setShowTaskBadgeState(data.showTaskBadge);
21775
+ setShowScheduleButtonState(data.showScheduleButton);
21776
+ setUiPrefs({ showTaskBadge: data.showTaskBadge, showScheduleButton: data.showScheduleButton });
21777
+ } catch (cause) {
21778
+ console.error("[t-team] \u754C\u9762\u504F\u597D\u8BFB\u53D6\u5931\u8D25\uFF0C\u6682\u6309\u9ED8\u8BA4\uFF08\u663E\u793A\u5FBD\u7AE0\uFF09\u5904\u7406\uFF1A", cause);
21779
+ if (alive) setUiPrefsError(cause instanceof Error ? cause.message : String(cause));
21780
+ }
21781
+ })();
21782
+ return () => {
21783
+ alive = false;
21784
+ };
21785
+ }, [remote]);
21786
+ async function writeUiPref(patch, rollback) {
21787
+ setUiPrefs(patch);
21788
+ try {
21789
+ const next = unwrap(await remote.setUiPrefs(patch), "setUiPrefs");
21790
+ setUiPrefs(next);
21791
+ setShowTaskBadgeState(next.showTaskBadge);
21792
+ setShowScheduleButtonState(next.showScheduleButton);
21793
+ } catch (cause) {
21794
+ setUiPrefs(rollback);
21795
+ setShowTaskBadgeState(rollback.showTaskBadge ?? showTaskBadge);
21796
+ setShowScheduleButtonState(rollback.showScheduleButton ?? showScheduleButton);
21797
+ setError(cause instanceof Error ? cause.message : String(cause));
21798
+ }
21799
+ }
21800
+ async function setShowTaskBadge(next) {
21801
+ setShowTaskBadgeState(next);
21802
+ await writeUiPref({ showTaskBadge: next }, { showTaskBadge: !next });
21803
+ }
21804
+ async function setShowScheduleButton(next) {
21805
+ setShowScheduleButtonState(next);
21806
+ await writeUiPref({ showScheduleButton: next }, { showScheduleButton: !next });
21807
+ }
20624
21808
  const enabledCount = snapshot.enabled.length;
20625
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"], ["roster", "tab.roster"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
21809
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }), " \xB7 v", CLIENT_BUILD_VERSION)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-row" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-head" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-setting-name" }, t("settings.showTaskBadge")), /* @__PURE__ */ import_react.default.createElement(
21810
+ "button",
21811
+ {
21812
+ className: "t-team-switch",
21813
+ type: "button",
21814
+ role: "switch",
21815
+ "aria-checked": showTaskBadge,
21816
+ "data-on": showTaskBadge,
21817
+ onClick: () => void setShowTaskBadge(!showTaskBadge)
21818
+ },
21819
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
21820
+ )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showTaskBadgeHint")), uiPrefsError !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, t("settings.showTaskBadgeUnreadable"), "\uFF1A", uiPrefsError)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-row" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-head" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-setting-name" }, t("settings.showScheduleButton")), /* @__PURE__ */ import_react.default.createElement(
21821
+ "button",
21822
+ {
21823
+ className: "t-team-switch",
21824
+ type: "button",
21825
+ role: "switch",
21826
+ "aria-checked": showScheduleButton,
21827
+ "data-on": showScheduleButton,
21828
+ onClick: () => void setShowScheduleButton(!showScheduleButton)
21829
+ },
21830
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
21831
+ )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showScheduleButtonHint"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"], ["roster", "tab.roster"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
20626
21832
  "button",
20627
21833
  {
20628
21834
  className: "t-team-tab",
@@ -20725,7 +21931,7 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
20725
21931
  )), /* @__PURE__ */ import_react.default.createElement(
20726
21932
  "button",
20727
21933
  {
20728
- className: "t-team-switch",
21934
+ className: "t-team-card-switch",
20729
21935
  type: "button",
20730
21936
  role: "switch",
20731
21937
  "aria-checked": on,
@@ -20735,7 +21941,7 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
20735
21941
  disabled: locked,
20736
21942
  onClick: () => void toggle(expert)
20737
21943
  },
20738
- /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
21944
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-card-switch-knob" })
20739
21945
  )));
20740
21946
  })))), visible.length === 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react.default.createElement(
20741
21947
  "div",
@@ -20824,6 +22030,421 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
20824
22030
  )
20825
22031
  ));
20826
22032
  }
22033
+ function isJobRowLive(job) {
22034
+ return job.status === "running" || job.status === "stopping";
22035
+ }
22036
+ function inJobSessionTree(byId, sessionId, rootId) {
22037
+ const seen = /* @__PURE__ */ new Set();
22038
+ let cursor = sessionId;
22039
+ while (typeof cursor === "string" && cursor !== "" && !seen.has(cursor)) {
22040
+ if (cursor === rootId) return true;
22041
+ seen.add(cursor);
22042
+ const parent = byId?.[cursor]?.parentId;
22043
+ cursor = typeof parent === "string" ? parent : void 0;
22044
+ }
22045
+ return false;
22046
+ }
22047
+ function collectJobRows(byId, jobsBySession, rootId) {
22048
+ const rows = [];
22049
+ if (jobsBySession === void 0 || rootId === void 0) return rows;
22050
+ for (const [sessionId, jobs] of Object.entries(jobsBySession)) {
22051
+ if (!Array.isArray(jobs) || jobs.length === 0) continue;
22052
+ if (!inJobSessionTree(byId, sessionId, rootId)) continue;
22053
+ const ownerTitle = byId?.[sessionId]?.displayTitle ?? sessionId;
22054
+ for (const job of jobs) rows.push({ ownerSessionId: sessionId, ownerTitle, job });
22055
+ }
22056
+ return rows;
22057
+ }
22058
+ function orderJobRows(rows) {
22059
+ return [...rows].sort((left, right) => {
22060
+ const liveLeft = isJobRowLive(left.job);
22061
+ if (liveLeft !== isJobRowLive(right.job)) return liveLeft ? -1 : 1;
22062
+ if (liveLeft) return left.job.startedAt - right.job.startedAt;
22063
+ const settled = (right.job.finishedAt ?? right.job.startedAt) - (left.job.finishedAt ?? left.job.startedAt);
22064
+ return settled !== 0 ? settled : left.job.startedAt - right.job.startedAt;
22065
+ });
22066
+ }
22067
+ function jobRowDotState(status) {
22068
+ switch (status) {
22069
+ case "running":
22070
+ return "running";
22071
+ case "stopping":
22072
+ return "stopping";
22073
+ case "completed":
22074
+ return "completed";
22075
+ case "killed":
22076
+ return "killed";
22077
+ case "failed":
22078
+ return "failed";
22079
+ default:
22080
+ return "unknown";
22081
+ }
22082
+ }
22083
+ function jobRowStatusKey(status) {
22084
+ switch (status) {
22085
+ case "running":
22086
+ return "tasks.status.running";
22087
+ case "stopping":
22088
+ return "tasks.status.stopping";
22089
+ case "completed":
22090
+ return "tasks.status.completed";
22091
+ case "killed":
22092
+ return "tasks.status.killed";
22093
+ case "failed":
22094
+ return "tasks.status.failed";
22095
+ default:
22096
+ return void 0;
22097
+ }
22098
+ }
22099
+ function jobRowDetail(job) {
22100
+ const detail = typeof job.detail === "string" ? job.detail.trim() : "";
22101
+ if (detail === "") return void 0;
22102
+ if (job.status === "completed" && /^exit code:\s*0$/iu.test(detail)) return void 0;
22103
+ return detail;
22104
+ }
22105
+ function formatJobRowDuration(ms, t) {
22106
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
22107
+ const total = Math.floor(ms / 1e3);
22108
+ const minutes = Math.floor(total / 60);
22109
+ const seconds = total % 60;
22110
+ return minutes > 0 ? t("tasks.duration.minutes", { minutes, seconds }) : t("tasks.duration.seconds", { seconds });
22111
+ }
22112
+ function collectTreeSubagents(byId, subagentsByParent, rootId) {
22113
+ const out = [];
22114
+ if (rootId === void 0) return out;
22115
+ const now = Date.now();
22116
+ for (const summary of Object.values(byId ?? {})) {
22117
+ if (summary?.id === void 0 || summary.id === rootId) continue;
22118
+ if (!inJobSessionTree(byId, summary.id, rootId)) continue;
22119
+ const catalog = subagentsByParent?.[summary.parentId ?? ""];
22120
+ const entry = (catalog?.entries ?? []).find((row) => row?.kind === "child" && row.id === summary.id);
22121
+ const label = typeof entry?.label === "string" && entry.label !== "" ? entry.label : void 0;
22122
+ out.push({
22123
+ id: summary.id,
22124
+ parentId: summary.parentId,
22125
+ title: label ?? summary.displayTitle ?? summary.id,
22126
+ named: label !== void 0,
22127
+ // 请求文本前一段:会话标题就是从它生成的,官方也用同一份来当副标题
22128
+ request: summary.displayTitle ?? "",
22129
+ running: entry === void 0 ? summary.running === true : entry.activity === "running",
22130
+ mode: entry?.mode,
22131
+ direct: summary.parentId === rootId,
22132
+ // 目录数组里靠后的视为更新(排序时按倒序用),未收录的以 -1 沉底
22133
+ order: entry === void 0 ? -1 : (catalog?.entries ?? []).indexOf(entry),
22134
+ now
22135
+ });
22136
+ }
22137
+ return out.sort((left, right) => {
22138
+ if (left.order !== right.order) return right.order - left.order;
22139
+ return String(left.title).localeCompare(String(right.title));
22140
+ });
22141
+ }
22142
+ function renderSubagentRows({ subagents, t, onOpen }) {
22143
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-jobs" }, subagents.map((item) => /* @__PURE__ */ import_react.default.createElement(
22144
+ "div",
22145
+ {
22146
+ className: "t-team-job-row",
22147
+ "data-kind": "subagent",
22148
+ "data-clickable": onOpen === void 0 ? void 0 : "true",
22149
+ key: `subagent:${item.id}`,
22150
+ role: onOpen === void 0 ? void 0 : "button",
22151
+ tabIndex: onOpen === void 0 ? void 0 : 0,
22152
+ title: onOpen === void 0 ? item.id : `${item.id} \xB7 ${t("tasks.subagentOpen")}`,
22153
+ onClick: onOpen === void 0 ? void 0 : () => onOpen(item),
22154
+ onKeyDown: onOpen === void 0 ? void 0 : (event) => {
22155
+ if (event.key === "Enter" || event.key === " ") {
22156
+ event.preventDefault();
22157
+ onOpen(item);
22158
+ }
22159
+ }
22160
+ },
22161
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-dot", "data-state": item.running ? "running" : "completed", "aria-hidden": "true" }),
22162
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-main" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-label", title: `${item.id} \xB7 ${item.running ? t("tasks.stateRunning") : t("tasks.stateInactive")}` }, item.title), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-desc" }, [
22163
+ item.request !== "" ? item.request : void 0,
22164
+ // 目录没给 mode 就整段跳过,不要冒出一个孤零零的"可继续"
22165
+ item.mode === "one-shot" ? t("tasks.modeOneShot") : item.mode === void 0 ? void 0 : t("tasks.modeContinuable"),
22166
+ item.running ? t("tasks.stateRunning") : t("tasks.stateInactive")
22167
+ ].filter(Boolean).join(" \xB7 ")))
22168
+ )));
22169
+ }
22170
+ function useJobRows(ctx) {
22171
+ const list = ctx?.sessions?.list;
22172
+ const snapshot = import_react.default.useSyncExternalStore(
22173
+ import_react.default.useCallback((onChange) => typeof list?.subscribe === "function" ? list.subscribe(onChange) : () => {
22174
+ }, [list]),
22175
+ import_react.default.useCallback(() => typeof list?.getSnapshot === "function" ? list.getSnapshot() : void 0, [list]),
22176
+ // 首次渲染(含 SSR)也要立刻拿到数据,否则要先空一帧、等订阅推一次才出现。
22177
+ import_react.default.useCallback(() => typeof list?.getSnapshot === "function" ? list.getSnapshot() : void 0, [list])
22178
+ );
22179
+ const rootId = snapshot?.current;
22180
+ const byId = snapshot?.byId ?? {};
22181
+ const rows = import_react.default.useMemo(
22182
+ () => orderJobRows(collectJobRows(byId, snapshot?.jobsBySession, rootId)),
22183
+ [byId, snapshot?.jobsBySession, rootId]
22184
+ );
22185
+ const liveCount = rows.reduce((count, row) => count + (isJobRowLive(row.job) ? 1 : 0), 0);
22186
+ const [now, setNow] = import_react.default.useState(() => Date.now());
22187
+ import_react.default.useEffect(() => {
22188
+ if (liveCount === 0) return void 0;
22189
+ const timer = window.setInterval(() => setNow(Date.now()), 1e3);
22190
+ return () => window.clearInterval(timer);
22191
+ }, [liveCount]);
22192
+ const subagents = import_react.default.useMemo(
22193
+ () => collectTreeSubagents(byId, snapshot?.subagentsByParent, rootId),
22194
+ [byId, snapshot?.subagentsByParent, rootId]
22195
+ );
22196
+ const subagentsRunning = subagents.reduce((count, item) => count + (item.running ? 1 : 0), 0);
22197
+ return { rows, liveCount, subagents, subagentsRunning, now };
22198
+ }
22199
+ function renderJobRows({ rows, now, multiOwner, t }) {
22200
+ if (rows.length === 0) return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("tasks.empty"));
22201
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-jobs" }, rows.map((row) => {
22202
+ const job = row.job ?? {};
22203
+ const live = isJobRowLive(job);
22204
+ const elapsed = live ? now - job.startedAt : (job.finishedAt ?? job.startedAt) - job.startedAt;
22205
+ const statusKey = jobRowStatusKey(job.status);
22206
+ const statusText = statusKey === void 0 ? String(job.status ?? "") : t(statusKey);
22207
+ const meta3 = [
22208
+ live ? void 0 : statusText,
22209
+ jobRowDetail(job),
22210
+ formatJobRowDuration(elapsed, t),
22211
+ multiOwner ? t("tasks.owner", { name: row.ownerTitle }) : void 0
22212
+ ].filter(Boolean);
22213
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-row", key: `${row.ownerSessionId}:${job.id}` }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-dot", "data-state": jobRowDotState(job.status), "aria-hidden": "true" }), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-main" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-label", title: `${job.label ?? ""} \xB7 ${job.id ?? ""}` }, live ? `${statusText} \xB7 ${job.label ?? ""}` : job.label ?? ""), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-meta" }, meta3.map((part, index) => /* @__PURE__ */ import_react.default.createElement("span", { key: index }, part)))));
22214
+ }));
22215
+ }
22216
+ function JobsTab({ t, ctx, compact }) {
22217
+ const { rows, liveCount, subagents, now } = useJobRows(ctx);
22218
+ const multiOwner = new Set(rows.map((row) => row.ownerSessionId)).size > 1;
22219
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, compact !== true && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("tasks.hint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-team-meta" }, liveCount > 0 ? t("tasks.countRunning", { running: liveCount, total: rows.length }) : t("tasks.count", { total: rows.length })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("tasks.subagents")), subagents.length === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("tasks.noSubagents")) : renderSubagentRows({ subagents, t, onOpen: (item) => openSubagentSession(ctx, item) }), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("tab.tasks")), renderJobRows({ rows, now, multiOwner, t }));
22220
+ }
22221
+ function openSubagentSession(ctx, item) {
22222
+ const sessions = ctx?.sessions;
22223
+ if (sessions === void 0 || item?.id === void 0) return;
22224
+ const resolved = sessions.subagentAddress?.(item.id);
22225
+ const address = resolved ?? (item.parentId === void 0 ? void 0 : { parentSessionId: item.parentId, childSessionId: item.id, mode: item.mode ?? "continuable" });
22226
+ if (address === void 0) return;
22227
+ try {
22228
+ sessions.openSubagent?.(address);
22229
+ } catch (error62) {
22230
+ console.error("[t-team] \u6253\u5F00\u5B50\u4EE3\u7406\u4F1A\u8BDD\u5931\u8D25\uFF1A", error62);
22231
+ }
22232
+ }
22233
+ var JOB_DOCK_POS_KEY = "t-team:jobs-dock:v1";
22234
+ var JOB_DOCK_CLOSED_KEY = "t-team:jobs-closed:v1";
22235
+ var JOB_DOCK_DEFAULT = { left: 18, top: 112 };
22236
+ var JOB_DOCK_MARGIN = 8;
22237
+ var JOB_DOCK_PANEL_WIDTH = 380;
22238
+ var JOB_DOCK_FALLBACK_WIDTH = 320;
22239
+ var JOB_DOCK_FALLBACK_HEIGHT = 420;
22240
+ var JOB_DOCK_DRAG_THRESHOLD = 4;
22241
+ function nonNegative(value, fallback) {
22242
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback();
22243
+ }
22244
+ function clampJobDockPos(pos, panel) {
22245
+ const viewport = typeof document === "undefined" ? void 0 : document.documentElement;
22246
+ const width = nonNegative(viewport?.clientWidth, () => nonNegative(
22247
+ typeof window === "undefined" ? void 0 : window.innerWidth,
22248
+ () => JOB_DOCK_PANEL_WIDTH
22249
+ ));
22250
+ const height = nonNegative(viewport?.clientHeight, () => nonNegative(
22251
+ typeof window === "undefined" ? void 0 : window.innerHeight,
22252
+ () => JOB_DOCK_PANEL_WIDTH
22253
+ ));
22254
+ const measured = panel?.offsetWidth ?? 0;
22255
+ const panelWidth = measured > 0 ? measured : JOB_DOCK_FALLBACK_WIDTH;
22256
+ const measuredHeight = panel?.offsetHeight ?? 0;
22257
+ const panelHeight = measuredHeight > 0 ? measuredHeight : JOB_DOCK_FALLBACK_HEIGHT;
22258
+ const maxLeft = Math.max(JOB_DOCK_MARGIN, width - panelWidth - JOB_DOCK_MARGIN);
22259
+ const maxTop = Math.max(JOB_DOCK_MARGIN, height - panelHeight - JOB_DOCK_MARGIN);
22260
+ return {
22261
+ left: Math.max(JOB_DOCK_MARGIN, Math.min(pos.left, maxLeft)),
22262
+ top: Math.max(JOB_DOCK_MARGIN, Math.min(pos.top, maxTop))
22263
+ };
22264
+ }
22265
+ function readJobDockPos() {
22266
+ if (typeof window === "undefined") return JOB_DOCK_DEFAULT;
22267
+ try {
22268
+ const raw = window.localStorage.getItem(JOB_DOCK_POS_KEY);
22269
+ if (raw === null) return JOB_DOCK_DEFAULT;
22270
+ const parsed = JSON.parse(raw);
22271
+ if (typeof parsed?.left !== "number" || typeof parsed?.top !== "number") return JOB_DOCK_DEFAULT;
22272
+ return { left: parsed.left, top: parsed.top };
22273
+ } catch {
22274
+ return JOB_DOCK_DEFAULT;
22275
+ }
22276
+ }
22277
+ var dockUi = { open: false };
22278
+ var dockListeners = /* @__PURE__ */ new Set();
22279
+ function setDockOpen(open2) {
22280
+ if (open2 === dockUi.open) return;
22281
+ dockUi = { open: open2 };
22282
+ for (const listener of dockListeners) listener();
22283
+ }
22284
+ function useDockUi() {
22285
+ return import_react.default.useSyncExternalStore(
22286
+ (onChange) => {
22287
+ dockListeners.add(onChange);
22288
+ return () => dockListeners.delete(onChange);
22289
+ },
22290
+ () => dockUi,
22291
+ () => dockUi
22292
+ );
22293
+ }
22294
+ function jobDockPerfReset() {
22295
+ try {
22296
+ performance.clearMarks("t-team-jobs-open");
22297
+ performance.mark("t-team-jobs-open");
22298
+ } catch {
22299
+ }
22300
+ }
22301
+ function jobDockPerfReport(stage) {
22302
+ try {
22303
+ const marks = performance.getEntriesByName("t-team-jobs-open", "mark");
22304
+ const start = marks[marks.length - 1];
22305
+ if (start === void 0) return;
22306
+ console.debug(`[t-team] \u4EFB\u52A1\u9762\u677F${stage} ${Math.round(performance.now() - start.startTime)}ms`);
22307
+ } catch {
22308
+ }
22309
+ }
22310
+ function JobsBadge({ t, ctx }) {
22311
+ const { rows, liveCount, subagents, subagentsRunning } = useJobRows(ctx);
22312
+ const showBadge = useShowTaskBadge();
22313
+ const ui = useDockUi();
22314
+ import_react.default.useEffect(() => {
22315
+ if (!showBadge) setDockOpen(false);
22316
+ }, [showBadge]);
22317
+ if (!showBadge) return null;
22318
+ if (rows.length === 0 && subagents.length === 0) return null;
22319
+ const anyLive = liveCount > 0 || subagentsRunning > 0;
22320
+ const badgeText = [
22321
+ subagents.length > 0 ? subagentsRunning > 0 ? t("tasks.subagentRunningCount", { running: subagentsRunning }) : t("tasks.subagentCount", { total: subagents.length }) : void 0,
22322
+ rows.length > 0 ? liveCount > 0 ? t("tasks.jobRunningCount", { running: liveCount }) : t("tasks.jobCount", { total: rows.length }) : void 0
22323
+ ].filter(Boolean).join(" \xB7 ");
22324
+ return /* @__PURE__ */ import_react.default.createElement(
22325
+ "button",
22326
+ {
22327
+ className: "t-team-job-badge",
22328
+ type: "button",
22329
+ "data-testid": "t-team-job-badge",
22330
+ "data-live": anyLive,
22331
+ "aria-expanded": ui.open,
22332
+ title: t("tasks.badgeTitle"),
22333
+ onClick: () => {
22334
+ const next = !ui.open;
22335
+ setDockOpen(next);
22336
+ if (next) jobDockPerfReset();
22337
+ try {
22338
+ if (next) window.localStorage.removeItem(JOB_DOCK_CLOSED_KEY);
22339
+ else window.localStorage.setItem(JOB_DOCK_CLOSED_KEY, "1");
22340
+ } catch {
22341
+ }
22342
+ }
22343
+ },
22344
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-dot", "data-live": anyLive, "aria-hidden": "true" }),
22345
+ /* @__PURE__ */ import_react.default.createElement("span", null, t("tab.tasks")),
22346
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-count" }, badgeText)
22347
+ );
22348
+ }
22349
+ function JobsDock({ t, ctx, preview }) {
22350
+ const { rows, liveCount, subagents, subagentsRunning, now } = useJobRows(ctx);
22351
+ const showDock = useShowTaskBadge();
22352
+ const ui = useDockUi();
22353
+ const open2 = preview?.open === true ? true : ui.open;
22354
+ const [panelTab, setPanelTab] = import_react.default.useState(preview?.tab ?? "subagents");
22355
+ const [pos, setPos] = import_react.default.useState(() => clampJobDockPos(readJobDockPos(), { offsetWidth: JOB_DOCK_PANEL_WIDTH }));
22356
+ const dragRef = import_react.default.useRef(void 0);
22357
+ const panelRef = import_react.default.useRef(null);
22358
+ import_react.default.useEffect(() => {
22359
+ if (ui.open) return void 0;
22360
+ const rows_ = rows.length;
22361
+ const subs_ = subagents.length;
22362
+ return () => {
22363
+ void rows_;
22364
+ void subs_;
22365
+ };
22366
+ }, [ui.open, rows.length, subagents.length]);
22367
+ import_react.default.useEffect(() => {
22368
+ if (!open2) return void 0;
22369
+ const onResize = () => setPos((current) => clampJobDockPos(current, panelRef.current));
22370
+ window.addEventListener("resize", onResize);
22371
+ return () => window.removeEventListener("resize", onResize);
22372
+ }, [open2]);
22373
+ import_react.default.useEffect(() => {
22374
+ if (!open2) return void 0;
22375
+ const sessions = ctx?.sessions;
22376
+ const rootId = sessions?.list?.getSnapshot?.()?.current;
22377
+ if (rootId === void 0) return void 0;
22378
+ const timer = window.setTimeout(() => {
22379
+ try {
22380
+ sessions.setSubagentCatalogOpen?.(rootId, true);
22381
+ void sessions.refreshSubagents?.(rootId);
22382
+ } catch {
22383
+ }
22384
+ }, 120);
22385
+ return () => {
22386
+ window.clearTimeout(timer);
22387
+ try {
22388
+ sessions.setSubagentCatalogOpen?.(rootId, false);
22389
+ } catch {
22390
+ }
22391
+ };
22392
+ }, [open2, ctx]);
22393
+ import_react.default.useLayoutEffect(() => {
22394
+ if (open2) jobDockPerfReport("\u5DF2\u53EF\u89C1");
22395
+ return void 0;
22396
+ }, [open2]);
22397
+ if (!showDock) return null;
22398
+ if (!open2) return null;
22399
+ jobDockPerfReport("\u5DF2\u6E32\u67D3");
22400
+ if (rows.length === 0 && subagents.length === 0) return null;
22401
+ const multiOwner = new Set(rows.map((row) => row.ownerSessionId)).size > 1;
22402
+ function startDrag(event) {
22403
+ if (event.button !== void 0 && event.button !== 0) return;
22404
+ event.preventDefault();
22405
+ event.currentTarget.setPointerCapture?.(event.pointerId);
22406
+ dragRef.current = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, originLeft: pos.left, originTop: pos.top, moved: false };
22407
+ }
22408
+ function moveDrag(event) {
22409
+ const drag = dragRef.current;
22410
+ if (drag === void 0 || drag.pointerId !== event.pointerId) return;
22411
+ const dx = event.clientX - drag.startX;
22412
+ const dy = event.clientY - drag.startY;
22413
+ if (!drag.moved && Math.abs(dx) + Math.abs(dy) < JOB_DOCK_DRAG_THRESHOLD) return;
22414
+ drag.moved = true;
22415
+ setPos(clampJobDockPos({ left: drag.originLeft + dx, top: drag.originTop + dy }, panelRef.current));
22416
+ }
22417
+ function endDrag(event) {
22418
+ const drag = dragRef.current;
22419
+ dragRef.current = void 0;
22420
+ if (drag === void 0 || drag.pointerId !== event.pointerId) return;
22421
+ if (!drag.moved) return;
22422
+ try {
22423
+ window.localStorage.setItem(JOB_DOCK_POS_KEY, JSON.stringify(pos));
22424
+ } catch {
22425
+ }
22426
+ }
22427
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-panel", ref: panelRef, style: { left: pos.left, top: pos.top } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-panel-head", onPointerDown: startDrag, onPointerMove: moveDrag, onPointerUp: endDrag, onPointerCancel: endDrag }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-panel-title" }, t("tab.tasks")), /* @__PURE__ */ import_react.default.createElement(
22428
+ "button",
22429
+ {
22430
+ className: "t-team-job-panel-close",
22431
+ type: "button",
22432
+ title: t("button.close"),
22433
+ onPointerDown: (event) => event.stopPropagation(),
22434
+ onClick: () => {
22435
+ setDockOpen(false);
22436
+ try {
22437
+ window.localStorage.setItem(JOB_DOCK_CLOSED_KEY, "1");
22438
+ } catch {
22439
+ }
22440
+ }
22441
+ },
22442
+ "\u2715"
22443
+ )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-panel-tabs", role: "tablist" }, [
22444
+ ["subagents", "tasks.subagents", subagentsRunning > 0 ? `${subagents.length} \xB7 ${subagentsRunning}` : String(subagents.length)],
22445
+ ["jobs", "tab.tasks", liveCount > 0 ? `${rows.length} \xB7 ${liveCount}` : String(rows.length)]
22446
+ ].map(([key, labelKey, count]) => /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-tab", type: "button", role: "tab", key, "data-active": panelTab === key, "aria-selected": panelTab === key, onClick: () => setPanelTab(key) }, t(labelKey), " ", /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-tab-count" }, count)))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-panel-body" }, panelTab === "subagents" ? subagents.length === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("tasks.noSubagents")) : renderSubagentRows({ subagents, t, onOpen: (item) => openSubagentSession(ctx, item) }) : renderJobRows({ rows, now, multiOwner, t })));
22447
+ }
20827
22448
  function squadToInput(squad) {
20828
22449
  return {
20829
22450
  key: String(squad.key ?? "").trim(),
@@ -21209,7 +22830,7 @@ function insertAtTarget(target, reference) {
21209
22830
  const offset = referencePrefixEnd(snapshot);
21210
22831
  return target.insertReference(reference, { start: offset, end: offset, draftRev: snapshot.draftRev }) === true;
21211
22832
  }
21212
- function SummonButton({ t, remote, getActive, insertReference, fillSquadCommand, sessionId, preview }) {
22833
+ function SummonButton({ t, ctx, remote, getActive, insertReference, fillSquadCommand, sessionId, preview }) {
21213
22834
  const [open2, setOpen] = import_react.default.useState(preview?.open === true);
21214
22835
  const [popTab, setPopTab] = import_react.default.useState(preview?.tab ?? "experts");
21215
22836
  const [squads, setSquads] = import_react.default.useState(preview?.squads ?? null);
@@ -21267,7 +22888,7 @@ function SummonButton({ t, remote, getActive, insertReference, fillSquadCommand,
21267
22888
  }
21268
22889
  const active = getActive();
21269
22890
  const teamCount = teams?.length ?? 0;
21270
- const popTabs = [["experts", "tab.experts"], ["squads", "tab.squads"], ...teamCount > 0 ? [["teams", "tab.teams"]] : []];
22891
+ const popTabs = [["experts", "tab.experts"], ["squads", "tab.squads"], ...teamCount > 0 ? [["teams", "tab.teams"]] : [], ["tasks", "tab.tasks"]];
21271
22892
  import_react.default.useEffect(() => {
21272
22893
  if (popTab === "teams" && teamCount === 0) setPopTab("experts");
21273
22894
  }, [popTab, teamCount]);
@@ -21349,7 +22970,7 @@ function SummonButton({ t, remote, getActive, insertReference, fillSquadCommand,
21349
22970
  onClick: () => void fillSquad(squad)
21350
22971
  },
21351
22972
  starting === squad.key ? t("pop.picking") : t("pop.fill")
21352
- )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, squad.aliases.slice(0, 6).map((alias) => /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-member-chip", key: alias }, alias)), squad.aliases.length > 6 && /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-note" }, "+", squad.aliases.length - 6)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, squad.members.map((member) => /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-member-chip", "data-unknown": member.known === false, key: member.slug }, member.nameZh))))), squads !== null && visibleSquads.length === 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-pop-empty" }, squads.squads.length === 0 ? t("pop.emptySquads") : t("pop.squadNoMatch")))), popTab === "teams" && /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, compact: true, initialTeams: preview?.teams }), popTab === "experts" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
22973
+ )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, squad.aliases.slice(0, 6).map((alias) => /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-member-chip", key: alias }, alias)), squad.aliases.length > 6 && /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-note" }, "+", squad.aliases.length - 6)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, squad.members.map((member) => /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-member-chip", "data-unknown": member.known === false, key: member.slug }, member.nameZh))))), squads !== null && visibleSquads.length === 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-pop-empty" }, squads.squads.length === 0 ? t("pop.emptySquads") : t("pop.squadNoMatch")))), popTab === "teams" && /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, compact: true, initialTeams: preview?.teams }), popTab === "tasks" && /* @__PURE__ */ import_react.default.createElement(JobsTab, { t, ctx, compact: true }), popTab === "experts" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
21353
22974
  "input",
21354
22975
  {
21355
22976
  className: "t-team-input",
@@ -21422,6 +23043,14 @@ async function apply(ctx) {
21422
23043
  await refresh(remote, true).catch((cause) => {
21423
23044
  console.warn("[t-team] \u521D\u59CB\u540D\u518C\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BBE\u7F6E\u9875\u53EF\u91CD\u8BD5\uFF1A", cause);
21424
23045
  });
23046
+ void (async () => {
23047
+ try {
23048
+ const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
23049
+ setUiPrefs({ showTaskBadge: data?.showTaskBadge, showScheduleButton: data?.showScheduleButton });
23050
+ } catch (cause) {
23051
+ console.warn("[t-team] \u754C\u9762\u504F\u597D\u8BFB\u53D6\u5931\u8D25\uFF0C\u6682\u6309\u9ED8\u8BA4\uFF08\u663E\u793A\u5FBD\u7AE0\uFF09\u5904\u7406\uFF1A", cause);
23052
+ }
23053
+ })();
21425
23054
  const refreshCatalog = { current: void 0 };
21426
23055
  ctx.slots.inject("settings.section", () => ctx.slots.register({
21427
23056
  name: "settings.section",
@@ -21432,6 +23061,71 @@ async function apply(ctx) {
21432
23061
  locale: NS,
21433
23062
  icon: "expert"
21434
23063
  }, (props) => import_react.default.createElement(SettingsPanel, { ...props, t: ctx.locale.bind(NS), remote, getActive, refreshCatalog })));
23064
+ ctx.slots.inject("sidebar.panellist", () => {
23065
+ let disposeEntry;
23066
+ const sync = () => {
23067
+ const want = scheduleEntryVisible();
23068
+ if (want === (disposeEntry !== void 0)) return;
23069
+ if (!want) {
23070
+ disposeEntry?.();
23071
+ disposeEntry = void 0;
23072
+ return;
23073
+ }
23074
+ try {
23075
+ disposeEntry = ctx.slots.register({
23076
+ name: "sidebar.panellist",
23077
+ id: SCHEDULE_PANEL_KEY,
23078
+ // order 取最小:侧栏那一组里它排在最前,紧贴「新会话」按钮。
23079
+ order: 1,
23080
+ label: () => ctx.locale.bind(NS)("sched.nav"),
23081
+ locale: NS
23082
+ }, (props) => import_react.default.createElement(ScheduleGlyph, { size: props?.size ?? 16 }));
23083
+ } catch (cause) {
23084
+ console.warn("[t-team] \u4FA7\u680F\u5B9A\u65F6\u4EFB\u52A1\u5165\u53E3\u6CE8\u518C\u5931\u8D25\uFF1A", cause);
23085
+ disposeEntry = void 0;
23086
+ }
23087
+ };
23088
+ const unsubscribe = subscribeUiPrefs(sync);
23089
+ sync();
23090
+ return () => {
23091
+ unsubscribe();
23092
+ disposeEntry?.();
23093
+ disposeEntry = void 0;
23094
+ };
23095
+ });
23096
+ ctx.slots.inject("main", () => ctx.slots.register({
23097
+ name: "main",
23098
+ key: SCHEDULE_PANEL_KEY,
23099
+ locale: NS
23100
+ }, (props) => import_react.default.createElement(SchedulePanel, {
23101
+ ...props,
23102
+ t: ctx.locale.bind(NS),
23103
+ remote,
23104
+ getActive,
23105
+ ctx: props?.ctx ?? ctx
23106
+ })));
23107
+ ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
23108
+ name: "conversation.session.header.utilities",
23109
+ id: `${NS}-jobs-badge`,
23110
+ order: 10,
23111
+ label: () => ctx.locale.bind(NS)("tab.tasks"),
23112
+ locale: NS
23113
+ }, (props) => import_react.default.createElement(JobsBadge, {
23114
+ ...props,
23115
+ t: ctx.locale.bind(NS),
23116
+ ctx: props?.ctx ?? ctx
23117
+ })));
23118
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
23119
+ name: "shell.overlay",
23120
+ id: `${NS}-jobs`,
23121
+ order: 81,
23122
+ label: () => ctx.locale.bind(NS)("tab.tasks"),
23123
+ locale: NS
23124
+ }, (props) => import_react.default.createElement(JobsDock, {
23125
+ ...props,
23126
+ t: ctx.locale.bind(NS),
23127
+ ctx: props?.ctx ?? ctx
23128
+ })));
21435
23129
  ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
21436
23130
  name: "conversation.input.left",
21437
23131
  id: NS,