dsh-plugin-t-expert 0.2.16 → 0.3.24

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,99 @@ 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
+ /** 可选工作区(下拉选项);path 是目录,面板显示给用户看落地位置。 */
19982
+ workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string().optional() }))
19983
+ });
19984
+ var scheduleInputSchema = external_exports.object({
19985
+ title: external_exports.string().min(1).max(200),
19986
+ prompt: external_exports.string().min(1).max(2e4),
19987
+ cron: external_exports.string().min(1).max(120),
19988
+ enabled: external_exports.boolean(),
19989
+ /** 空串 = 不绑定工作区(显式解绑也走这个值)。 */
19990
+ workspaceId: external_exports.string().max(200).optional()
19991
+ });
19992
+ var schedulePatchSchema = scheduleInputSchema.partial();
19993
+ var schedulePreviewSchema = external_exports.object({ fires: external_exports.array(external_exports.string()) });
19994
+ var scheduleArmedSchema = external_exports.object({ armed: external_exports.boolean() });
19995
+ var scheduleWorkspaceSchema = external_exports.object({
19996
+ workspace: external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string() })
19997
+ });
19843
19998
 
19844
19999
  // src/client.jsx
19845
20000
  var NS = "t-team";
20001
+ var CLIENT_BUILD_VERSION = "0.3.24";
20002
+ var uiPrefs = { showTaskBadge: true, showScheduleButton: true };
20003
+ var uiPrefsListeners = /* @__PURE__ */ new Set();
20004
+ function setUiPrefs(next) {
20005
+ let changed = false;
20006
+ for (const key of Object.keys(uiPrefs)) {
20007
+ const value = next?.[key];
20008
+ if (typeof value !== "boolean" || value === uiPrefs[key]) continue;
20009
+ uiPrefs[key] = value;
20010
+ changed = true;
20011
+ }
20012
+ if (!changed) return;
20013
+ for (const listener of uiPrefsListeners) listener();
20014
+ }
20015
+ function subscribeUiPrefs(listener) {
20016
+ uiPrefsListeners.add(listener);
20017
+ return () => uiPrefsListeners.delete(listener);
20018
+ }
20019
+ function scheduleEntryVisible() {
20020
+ return uiPrefs.showScheduleButton !== false;
20021
+ }
20022
+ function useUiPref(key, fallback = true) {
20023
+ return import_react.default.useSyncExternalStore(
20024
+ (onChange) => {
20025
+ uiPrefsListeners.add(onChange);
20026
+ return () => uiPrefsListeners.delete(onChange);
20027
+ },
20028
+ () => uiPrefs[key],
20029
+ () => fallback
20030
+ );
20031
+ }
20032
+ function useShowTaskBadge() {
20033
+ return useUiPref("showTaskBadge", true);
20034
+ }
20035
+ function useShowScheduleButton() {
20036
+ return useUiPref("showScheduleButton", true);
20037
+ }
19846
20038
  var PLUGIN_ID = "dsh-plugin-t-expert";
19847
20039
  var DIVISION_FALLBACK = "specialized";
19848
20040
  var NEW_DIVISION = "__new";
19849
20041
  var zh = {
19850
20042
  "settings.title": "T\u4E13\u5BB6",
20043
+ "settings.showTaskBadge": "\u663E\u793A\u4EFB\u52A1\u5FBD\u7AE0",
20044
+ "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",
20045
+ "settings.showTaskBadgeUnreadable": "\u8BFB\u53D6\u8BE5\u8BBE\u7F6E\u5931\u8D25",
19851
20046
  "settings.loading": "\u6B63\u5728\u8BFB\u53D6\u540D\u518C\u2026",
19852
20047
  "settings.retry": "\u91CD\u8BD5",
19853
20048
  "settings.search": "\u641C\u7D22\u4E13\u5BB6\u540D\u6216\u7B80\u4ECB",
@@ -20014,10 +20209,101 @@ var zh = {
20014
20209
  "pop.emptySquads": "\u8FD8\u6CA1\u6709\u5C0F\u961F\uFF0C\u53BB \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u2192 \u961F\u4F0D \u5EFA\u4E00\u652F\u3002",
20015
20210
  "pop.squadSearch": "\u641C\u5C0F\u961F\uFF1A\u540D\u5B57 / \u522B\u540D / \u6210\u5458",
20016
20211
  "pop.squadNoMatch": "\u6CA1\u6709\u5339\u914D\u7684\u5C0F\u961F\u3002",
20017
- "pop.memberCount": "{count} \u4EBA"
20212
+ "pop.memberCount": "{count} \u4EBA",
20213
+ // ---- 定时任务:侧栏按钮 + 右侧管理页 ----
20214
+ "settings.showScheduleButton": "\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE",
20215
+ "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",
20216
+ "sched.nav": "\u5B9A\u65F6\u4EFB\u52A1",
20217
+ "sched.title": "\u5B9A\u65F6\u4EFB\u52A1",
20218
+ "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",
20219
+ "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",
20220
+ "sched.back": "\u8FD4\u56DE\u4F1A\u8BDD",
20221
+ "sched.refresh": "\u5237\u65B0",
20222
+ "sched.loading": "\u6B63\u5728\u52A0\u8F7D\u5B9A\u65F6\u4EFB\u52A1\u2026",
20223
+ "sched.error": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\u3002",
20224
+ "sched.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u5148\u65B0\u5EFA\u4E00\u4E2A\u5427\u3002",
20225
+ "sched.retry": "\u91CD\u8BD5",
20226
+ "sched.new": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
20227
+ "sched.edit": "\u7F16\u8F91\u5B9A\u65F6\u4EFB\u52A1",
20228
+ "sched.save": "\u4FDD\u5B58",
20229
+ "sched.saving": "\u4FDD\u5B58\u4E2D\u2026",
20230
+ "sched.cancel": "\u53D6\u6D88",
20231
+ "sched.delete": "\u5220\u9664",
20232
+ "sched.deleteConfirm": "\u786E\u5B9A\u5220\u9664\u8FD9\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF1F",
20233
+ "sched.runNow": "\u7ACB\u5373\u6267\u884C",
20234
+ "sched.running": "\u6267\u884C\u4E2D\u2026",
20235
+ "sched.runHistory": "\u6267\u884C\u8BB0\u5F55\uFF08{count}\uFF09",
20236
+ "sched.runOk": "\u6210\u529F",
20237
+ "sched.runFail": "\u5931\u8D25",
20238
+ "sched.lastRun": "\u4E0A\u6B21\u6267\u884C",
20239
+ "sched.neverRun": "\u4ECE\u672A\u6267\u884C",
20240
+ "sched.failed": "\u5931\u8D25",
20241
+ "sched.disabledTag": "\u5DF2\u505C\u7528",
20242
+ "sched.workspace": "\u5DE5\u4F5C\u533A",
20243
+ "sched.workspaceNone": "\u4E0D\u7ED1\u5B9A\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\u76EE\u5F55\uFF09",
20244
+ "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",
20245
+ "sched.workspacePath": "\u76EE\u5F55\uFF1A{path}",
20246
+ "sched.workspaceCustom": "\uFF0B \u81EA\u5B9A\u4E49\u76EE\u5F55\u2026",
20247
+ "sched.workspaceCustomPlaceholder": "\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /Users/\u4F60/tasks",
20248
+ "sched.workspaceCustomHint": "\u76EE\u5F55\u4E0D\u5B58\u5728\u65F6\u4F1A\u81EA\u52A8\u521B\u5EFA\uFF0C\u5E76\u6CE8\u518C\u6210\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002",
20249
+ "sched.workspaceCustomEmpty": "\u8BF7\u5148\u586B\u5199\u81EA\u5B9A\u4E49\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002",
20250
+ "sched.cronLabel": "cron \u5B9A\u65F6\u5668",
20251
+ "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",
20252
+ "sched.cronHourly": "\u6BCF\u5C0F\u65F6",
20253
+ "sched.cronDaily": "\u6BCF\u5929",
20254
+ "sched.cronWeekly": "\u6BCF\u5468",
20255
+ "sched.cronCustom": "\u81EA\u5B9A\u4E49",
20256
+ "sched.cronEvery": "\u6BCF\u9694",
20257
+ "sched.cronAtMinute": "\u6BCF\u5C0F\u65F6\u7684\u7B2C",
20258
+ "sched.cronMinuteUnit": "\u5206",
20259
+ "sched.cronMinutesUnit": "\u5206\u949F",
20260
+ "sched.hourField": "\u5C0F\u65F6",
20261
+ "sched.minuteField": "\u5206\u949F",
20262
+ "sched.presetHourly": "\u6BCF\u5C0F\u65F6\u6574\u70B9",
20263
+ "sched.presetMin30": "\u6BCF 30 \u5206\u949F",
20264
+ "sched.presetDaily9": "\u6BCF\u5929 9:00",
20265
+ "sched.presetWeekday830": "\u5DE5\u4F5C\u65E5 8:30",
20266
+ "sched.presetMon10": "\u6BCF\u5468\u4E00 10:00",
20267
+ // 周几:键必须**逐行**写、并且在代码里以字面量引用(字典无人引用自检会盯着这一点)。
20268
+ "sched.wd1": "\u4E00",
20269
+ "sched.wd2": "\u4E8C",
20270
+ "sched.wd3": "\u4E09",
20271
+ "sched.wd4": "\u56DB",
20272
+ "sched.wd5": "\u4E94",
20273
+ "sched.wd6": "\u516D",
20274
+ "sched.wd0": "\u65E5",
20275
+ "sched.listSep": "\u3001",
20276
+ "sched.sumMin": "\u6BCF {n} \u5206\u949F\u6267\u884C\u4E00\u6B21",
20277
+ "sched.sumHour": "\u6BCF\u5C0F\u65F6\u7B2C {m} \u5206\u6267\u884C",
20278
+ "sched.sumDaily": "\u6BCF\u5929 {t} \u6267\u884C",
20279
+ "sched.sumWeekly": "\u6BCF\u5468{w} {t} \u6267\u884C",
20280
+ "sched.sumWeeklyWorkday": "\u5DE5\u4F5C\u65E5 {t} \u6267\u884C",
20281
+ "sched.sumCustom": "\u81EA\u5B9A\u4E49\u8868\u8FBE\u5F0F\uFF1A{raw}",
20282
+ "sched.sumEmpty": "\u9009\u62E9\u6216\u586B\u5199\u4E00\u4E2A\u6267\u884C\u65F6\u95F4",
20283
+ "sched.nextRuns": "\u6700\u8FD1 {n} \u6B21\u6267\u884C",
20284
+ "sched.titleLabel": "\u6807\u9898",
20285
+ "sched.titlePlaceholder": "\u4F8B\u5982\uFF1A\u6668\u4F1A\u7EAA\u8981",
20286
+ "sched.promptLabel": "\u63D0\u793A\u8BCD",
20287
+ "sched.promptPlaceholder": "\u5230\u70B9\u65F6\uFF0C\u8BA9 agent \u505A\u4EC0\u4E48\uFF1F",
20288
+ "sched.expertPick": "T\u4E13\u5BB6",
20289
+ "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",
20290
+ "sched.expertPickSearch": "\u641C\u7D22\u4E13\u5BB6\u540D\u6216 slug",
20291
+ "sched.expertPickEmpty": "\u6CA1\u6709\u5339\u914D\u7684\u5DF2\u542F\u7528\u4E13\u5BB6\u3002\u5148\u53BB \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u542F\u7528\u3002",
20292
+ "sched.expertInvokeHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u53EC\u5524\u300C{name}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
20293
+ "sched.expertInvokeManyHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u540C\u65F6\u53EC\u5524\u300C{names}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
20294
+ "sched.expertRemove": "\u79FB\u9664 {name}",
20295
+ "sched.enabledLabel": "\u542F\u7528",
20296
+ "sched.enabledHint": "\u505C\u7528\u7684\u4E8B\u9879\u4FDD\u7559\u6570\u636E\uFF0C\u4F46\u4E0D\u4F1A\u5B9A\u65F6\u89E6\u53D1\u3002",
20297
+ "sched.invalidForm": "\u6807\u9898\u3001\u63D0\u793A\u8BCD\u548C cron \u5B9A\u65F6\u5668\u90FD\u662F\u5FC5\u586B\u9879\u3002",
20298
+ "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",
20299
+ "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",
20300
+ "sched.file": "\u6570\u636E\u6587\u4EF6\uFF1A{path}"
20018
20301
  };
20019
20302
  var en = {
20020
20303
  "settings.title": "T Expert",
20304
+ "settings.showTaskBadge": "Show task badge",
20305
+ "settings.showTaskBadgeHint": "When off, the top-right task badge no longer appears (the Tasks tab in the input floater still works)",
20306
+ "settings.showTaskBadgeUnreadable": "Failed to read this setting",
20021
20307
  "settings.loading": "Loading roster\u2026",
20022
20308
  "settings.retry": "Retry",
20023
20309
  "settings.search": "Search expert name or description",
@@ -20184,7 +20470,94 @@ var en = {
20184
20470
  "pop.emptySquads": "No squads yet \u2014 build one in Settings \u2192 T Expert \u2192 Roster.",
20185
20471
  "pop.squadSearch": "Search squads: name / alias / member",
20186
20472
  "pop.squadNoMatch": "No matching squad.",
20187
- "pop.memberCount": "{count} members"
20473
+ "pop.memberCount": "{count} members",
20474
+ // ---- Scheduled tasks: sidebar entry + right-hand management surface ----
20475
+ "settings.showScheduleButton": "Show scheduled tasks button",
20476
+ "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)",
20477
+ "sched.nav": "Scheduled tasks",
20478
+ "sched.title": "Scheduled tasks",
20479
+ "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.",
20480
+ "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.",
20481
+ "sched.back": "Back to conversation",
20482
+ "sched.refresh": "Refresh",
20483
+ "sched.loading": "Loading scheduled tasks\u2026",
20484
+ "sched.error": "The scheduled tasks service is unavailable.",
20485
+ "sched.empty": "No scheduled tasks yet \u2014 create the first one.",
20486
+ "sched.retry": "Retry",
20487
+ "sched.new": "New scheduled task",
20488
+ "sched.edit": "Edit scheduled task",
20489
+ "sched.save": "Save",
20490
+ "sched.saving": "Saving\u2026",
20491
+ "sched.cancel": "Cancel",
20492
+ "sched.delete": "Delete",
20493
+ "sched.deleteConfirm": "Delete this scheduled task?",
20494
+ "sched.runNow": "Run now",
20495
+ "sched.running": "Running\u2026",
20496
+ "sched.runHistory": "Run history ({count})",
20497
+ "sched.runOk": "OK",
20498
+ "sched.runFail": "Failed",
20499
+ "sched.lastRun": "Last run",
20500
+ "sched.neverRun": "Never",
20501
+ "sched.failed": "failed",
20502
+ "sched.disabledTag": "Disabled",
20503
+ "sched.workspace": "Workspace",
20504
+ "sched.workspaceNone": "None (default directory)",
20505
+ "sched.workspaceHint": "Each run starts a new session in this workspace; sessions appear grouped under it in the sidebar.",
20506
+ "sched.workspacePath": "Directory: {path}",
20507
+ "sched.workspaceCustom": "+ Custom directory\u2026",
20508
+ "sched.workspaceCustomPlaceholder": "Absolute path, e.g. /Users/you/tasks",
20509
+ "sched.workspaceCustomHint": "The directory is created when missing, then registered as a workspace.",
20510
+ "sched.workspaceCustomEmpty": "Enter an absolute path for the custom directory first.",
20511
+ "sched.cronLabel": "Cron schedule",
20512
+ "sched.cronHint": 'Five-field cron expression (minute hour day month weekday), e.g. "0 9 * * *" runs daily at 09:00.',
20513
+ "sched.cronHourly": "Hourly",
20514
+ "sched.cronDaily": "Daily",
20515
+ "sched.cronWeekly": "Weekly",
20516
+ "sched.cronCustom": "Custom",
20517
+ "sched.cronEvery": "Every",
20518
+ "sched.cronAtMinute": "hour at minute",
20519
+ "sched.cronMinuteUnit": "",
20520
+ "sched.cronMinutesUnit": "minutes",
20521
+ "sched.hourField": "Hour",
20522
+ "sched.minuteField": "Minute",
20523
+ "sched.presetHourly": "Every hour",
20524
+ "sched.presetMin30": "Every 30 min",
20525
+ "sched.presetDaily9": "Daily at 9:00",
20526
+ "sched.presetWeekday830": "Weekdays at 8:30",
20527
+ "sched.presetMon10": "Mondays at 10:00",
20528
+ "sched.wd1": "Mon",
20529
+ "sched.wd2": "Tue",
20530
+ "sched.wd3": "Wed",
20531
+ "sched.wd4": "Thu",
20532
+ "sched.wd5": "Fri",
20533
+ "sched.wd6": "Sat",
20534
+ "sched.wd0": "Sun",
20535
+ "sched.listSep": ", ",
20536
+ "sched.sumMin": "Every {n} minutes",
20537
+ "sched.sumHour": "Every hour at minute {m}",
20538
+ "sched.sumDaily": "Daily at {t}",
20539
+ "sched.sumWeekly": "Weekly on {w} at {t}",
20540
+ "sched.sumWeeklyWorkday": "Weekdays at {t}",
20541
+ "sched.sumCustom": "Custom: {raw}",
20542
+ "sched.sumEmpty": "Pick or type a schedule",
20543
+ "sched.nextRuns": "Next {n} runs",
20544
+ "sched.titleLabel": "Title",
20545
+ "sched.titlePlaceholder": "e.g. Morning standup notes",
20546
+ "sched.promptLabel": "Prompt",
20547
+ "sched.promptPlaceholder": "What should the agent do when this item runs?",
20548
+ "sched.expertPick": "T Expert",
20549
+ "sched.expertPickHint": "Pick one of the enabled experts here and its @name lands in the prompt.",
20550
+ "sched.expertPickSearch": "Search expert name or slug",
20551
+ "sched.expertPickEmpty": "No matching enabled expert. Enable some in Settings \u2192 T Expert.",
20552
+ "sched.expertInvokeHint": 'This run will summon "{name}" to carry out this prompt.',
20553
+ "sched.expertInvokeManyHint": 'This run will summon "{names}" together to carry out this prompt.',
20554
+ "sched.expertRemove": "Remove {name}",
20555
+ "sched.enabledLabel": "Enabled",
20556
+ "sched.enabledHint": "Disabled items keep their data but never run on schedule.",
20557
+ "sched.invalidForm": "Title, prompt, and cron schedule are required.",
20558
+ "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.',
20559
+ "sched.noAgents": "The host has no usable agents service, so creating a session will fail \u2014 check the host composition.",
20560
+ "sched.file": "Data file: {path}"
20188
20561
  };
20189
20562
  var CSS = `
20190
20563
  .t-team-editor-modal{width:min(860px,94vw);max-height:min(86vh,760px)}
@@ -20193,6 +20566,15 @@ var CSS = `
20193
20566
  .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}
20194
20567
  .t-team-section-head:first-child{border-top:0;padding-top:0}
20195
20568
  .t-team-tabs{display:flex;gap:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:6px}
20569
+ .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)}
20570
+ .t-team-setting-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
20571
+ .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}
20572
+ .t-team-setting-hint{font-size:12px;color:var(--dsw-alias-label-caption);line-height:1.35}
20573
+ .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}
20574
+ .t-team-switch[data-on="true"]{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);box-shadow:none}
20575
+ .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}
20576
+ .t-team-switch[data-on="true"] .t-team-switch-knob{transform:translateX(16px)}
20577
+ .t-team-switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}
20196
20578
  .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}
20197
20579
  .t-team-tab[data-active="true"]{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:600}
20198
20580
  .t-team-tabbody{display:flex;flex-direction:column;gap:12px;min-height:0}
@@ -20300,11 +20682,15 @@ var CSS = `
20300
20682
  .t-team-cat-empty{padding:8px 10px;font-size:12px;color:var(--dsw-alias-label-caption)}
20301
20683
  .t-team-cat-list .t-team-badge{flex:none}
20302
20684
  .t-team-badge[data-tone="custom"]{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);background:transparent}
20303
- .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}
20304
- .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}
20305
- .t-team-switch[data-enabled="true"]{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill)}
20306
- .t-team-switch[data-enabled="true"] .t-team-switch-knob{transform:translateX(12px);background:var(--dsw-alias-label-primary-foreground)}
20307
- .t-team-switch:disabled{opacity:.45;cursor:not-allowed}
20685
+ /* \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
20686
+ * \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
20687
+ * \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
20688
+ * \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 */
20689
+ .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}
20690
+ .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}
20691
+ .t-team-card-switch[data-enabled="true"]{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill)}
20692
+ .t-team-card-switch[data-enabled="true"] .t-team-card-switch-knob{transform:translateX(12px);background:var(--dsw-alias-label-primary-foreground)}
20693
+ .t-team-card-switch:disabled{opacity:.45;cursor:not-allowed}
20308
20694
  .t-team-conflict{font-size:11px;color:var(--dsw-alias-state-warn-primary)}
20309
20695
  .t-team-error{font-size:12px;color:var(--dsw-alias-state-error-primary)}
20310
20696
  .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}
@@ -20325,9 +20711,8 @@ var CSS = `
20325
20711
  .t-team-job-row[data-clickable="true"]{cursor:pointer}
20326
20712
  .t-team-job-row[data-clickable="true"]:hover{background:var(--dsw-alias-interactive-bg-hover)}
20327
20713
  /* 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 */
20328
- .t-team-job-badge{position:fixed;z-index:55;cursor:grab;touch-action:none;box-sizing:border-box;display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-3));backdrop-filter:blur(16px);box-shadow:0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;font-weight:600;line-height:20px;cursor:pointer;transition:border-color .15s,transform .12s}
20329
- .t-team-job-badge:hover{border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}
20330
- .t-team-job-badge:active{cursor:grabbing}
20714
+ .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}
20715
+ .t-team-job-badge:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}
20331
20716
  .t-team-job-badge:active{transform:translateY(0) scale(.98)}
20332
20717
  .t-team-job-badge-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--dsw-alias-label-tertiary)}
20333
20718
  .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}
@@ -20361,6 +20746,112 @@ var CSS = `
20361
20746
  .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}
20362
20747
  .t-team-pop-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px 2px}
20363
20748
  .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)}
20749
+ /* ---- \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 ---- */
20750
+ /*
20751
+ * \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
20752
+ * \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
20753
+ * \u540C\u9AD8 38px\u3001\u540C 12px \u5706\u89D2\u3001\u540C\u8FB9\u6846\u4E0E\u62AC\u5347\u586B\u5145\u3001\u540C\u5C45\u4E2D\u6392\u5E03\u3002
20754
+ *
20755
+ * \u26A0\uFE0F \u5BBD\u5EA6\u5FC5\u987B\u662F width:auto + align-self:stretch\uFF0C\u4E0D\u80FD\u6CBF\u7528\u5BBF\u4E3B panelRow \u7684 width:100%\uFF1A
20756
+ * \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
20757
+ * **\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
20758
+ * \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
20759
+ */
20760
+ .t-team-schedule-glyph{display:block}
20761
+ 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}
20762
+ button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-button-floating-hover)}
20763
+ [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}
20764
+ [data-sidebar-collapsed] button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-interactive-bg-hover)}
20765
+ /* ---- \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u53F3\u4FA7\u4E3B\u533A\u57DF\u7BA1\u7406\u9875\uFF08\u6CE8\u518C\u5728 main \u69FD\u7684 keyed \u9762\u677F\uFF09 ---- */
20766
+ .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)}
20767
+ .t-team-sched-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex:none}
20768
+ .t-team-sched-title{font-size:18px;font-weight:600;margin:0}
20769
+ .t-team-sched-actions{display:flex;gap:8px;flex:none}
20770
+ .t-team-sched-intro{font-size:13px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
20771
+ .t-team-sched-tip{font-size:12px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
20772
+ .t-team-sched-note{font-size:13px;color:var(--dsw-alias-state-warn-primary);margin:0}
20773
+ .t-team-sched-error{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-state-error-primary);margin:0}
20774
+ .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}
20775
+ .t-team-sched-body{display:flex;flex-direction:column;gap:12px;max-width:820px;width:100%}
20776
+ .t-team-sched-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
20777
+ .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)}
20778
+ .t-team-sched-rowMain{display:flex;flex-direction:column;gap:3px;min-width:0}
20779
+ .t-team-sched-rowTitle{font-size:14px;font-weight:600}
20780
+ .t-team-sched-rowCron{font-size:12px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
20781
+ .t-team-sched-rowMeta{font-size:12px;color:var(--dsw-alias-label-secondary)}
20782
+ .t-team-sched-rowActions{display:flex;gap:8px;flex:none}
20783
+ .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}
20784
+ .t-team-sched-runsToggle:hover{text-decoration:underline}
20785
+ .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}
20786
+ .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}
20787
+ .t-team-sched-runFail{color:var(--dsw-alias-state-error-primary);word-break:break-word}
20788
+ .t-team-sched-runSession{font-size:11px;color:var(--dsw-alias-label-tertiary)}
20789
+ .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}
20790
+ .t-team-sched-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
20791
+ .t-team-sched-btn:disabled{opacity:.5;cursor:default}
20792
+ .t-team-sched-btn-primary{border-color:transparent;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);font-weight:600}
20793
+ .t-team-sched-btn-primary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-bg-base) 14%, var(--dsw-alias-label-primary))}
20794
+ .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))}
20795
+ .t-team-sched-btn-danger:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}
20796
+ .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)}
20797
+ .t-team-sched-formTitle{font-size:15px;font-weight:600;margin:0}
20798
+ .t-team-sched-field{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--dsw-alias-label-secondary)}
20799
+ .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}
20800
+ .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))}
20801
+ .t-team-sched-field textarea{resize:vertical;min-height:72px}
20802
+ .t-team-sched-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
20803
+ .t-team-sched-checkbox{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-secondary)}
20804
+ .t-team-sched-formActions{display:flex;gap:8px}
20805
+ /* 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 */
20806
+ .t-team-sched-cron{display:flex;flex-direction:column;gap:9px;width:100%}
20807
+ .t-team-sched-chips{display:flex;flex-wrap:wrap;gap:6px}
20808
+ .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}
20809
+ .t-team-sched-chip:hover:not(:disabled){border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}
20810
+ .t-team-sched-seg{display:inline-flex;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden;align-self:flex-start}
20811
+ .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}
20812
+ .t-team-sched-seg button:last-child{border-right:none}
20813
+ .t-team-sched-seg button[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base)}
20814
+ .t-team-sched-cronRow{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:13px;color:var(--dsw-alias-label-secondary)}
20815
+ .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}
20816
+ .t-team-sched-days{display:flex;gap:5px;flex-wrap:wrap}
20817
+ .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}
20818
+ .t-team-sched-day[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);border-color:transparent}
20819
+ .t-team-sched-sum{font-size:12px;color:var(--dsw-alias-label-secondary)}
20820
+ .t-team-sched-next{display:flex;flex-direction:column;gap:4px}
20821
+ .t-team-sched-nextLabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
20822
+ .t-team-sched-nextList{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
20823
+ .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}
20824
+ /* \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 */
20825
+ .t-team-sched-promptbox{box-sizing:border-box;display:flex;flex-direction:column;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}
20826
+ .t-team-sched-promptbox:focus-within{border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
20827
+ /* \u82AF\u7247\u89C2\u611F\u5BF9\u9F50\u5BF9\u8BDD\u8F93\u5165\u6846\u91CC\u7684\u5F15\u7528\u82AF\u7247\uFF1A\u6D45\u7070\u5E95\u3001\u5706\u89D2\u77E9\u5F62\uFF08\u4E0D\u662F\u5168\u80F6\u56CA\uFF09\u3001\u84DD\u8272\u6587\u5B57\u3001
20828
+ * \u5DE6\u4FA7\u4E00\u4E2A\u5706\u5F62\u7EBF\u6761\u5C0F\u56FE\u6807\uFF1B\xD7 \u5E73\u65F6\u4E0D\u663E\u793A\uFF0C\u60AC\u505C\u624D\u6D6E\u51FA\u6765\uFF08\u622A\u56FE\u91CC\u5C31\u662F\u6CA1\u6709 \xD7 \u7684\u6837\u5B50\uFF09\u3002 */
20829
+ .t-team-sched-chip{box-sizing:border-box;display:inline-flex;align-items:center;gap:3px;max-width:100%;margin:0 2px;padding:0 4px;border:1px solid transparent;border-radius:6px;background:color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);color:var(--dsw-alias-brand-primary, #1677ff);font-size:12px;line-height:18px;vertical-align:middle;user-select:none}
20830
+ /* \u60AC\u505C\u7ED9\u4E00\u5708\u6DE1\u63CF\u8FB9\uFF1A\u8BA9"\u9F20\u6807\u5728\u8FD9\u679A\u82AF\u7247\u4E0A"\u8FD9\u4EF6\u4E8B\u6709\u786E\u5B9A\u7684\u89C6\u89C9\u53CD\u9988\uFF08\u522B\u9760\u6D4F\u89C8\u5668\u9ED8\u8BA4\uFF09\u3002 */
20831
+ .t-team-sched-chip:hover{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary, #1677ff) 35%, transparent)}
20832
+ .t-team-sched-chip-icon{flex:none;display:block}
20833
+ .t-team-sched-chip-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20834
+ .t-team-sched-chip-remove{padding:0 1px;border:0;background:transparent;color:inherit;font:inherit;font-size:12px;line-height:1;cursor:pointer;opacity:.6;transition:opacity .12s}
20835
+ .t-team-sched-chip-remove:hover{opacity:1}
20836
+ /* \u63D0\u793A\u8BCD\u7F16\u8F91\u533A\uFF1Acontenteditable \u7684\u5BCC\u6587\u672C\u6D41\uFF08\u7EAF\u6587\u5B57 + \u82AF\u7247\uFF09\uFF0C\u82AF\u7247\u56E0\u6B64\u80FD\u63D2\u5728\u6B63\u6587\u4EFB\u610F\u4F4D\u7F6E\u3002
20837
+ * \u26A0\uFE0F \u7C7B\u540D\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"
20838
+ * \u90A3\u7C7B\u89C4\u5219\uFF0C\u7F16\u8F91\u533A\u4F1A\u81EA\u5E26\u4E00\u5708\u8FB9\u6846\uFF08\u8E29\u8FC7\uFF1A\u6846\u91CC\u5957\u6846\uFF09\u3002 */
20839
+ .t-team-sched-field .t-team-sched-prompt-input{box-sizing:border-box;width:100%;min-height:72px;max-height:320px;overflow-y:auto;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:22px;white-space:pre-wrap;word-break:break-word;cursor:text;resize:none}
20840
+ .t-team-sched-field .t-team-sched-prompt-input:focus{outline:none;border:0}
20841
+ .t-team-sched-field .t-team-sched-prompt-input[data-empty="true"]::before{content:attr(data-placeholder);color:var(--dsw-alias-label-tertiary);pointer-events:none}
20842
+ /* \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 */
20843
+ .t-team-expert-pick{position:relative;display:flex;align-items:center;gap:8px;margin-top:2px}
20844
+ .t-team-expert-pick-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
20845
+ .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)}
20846
+ .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}
20847
+ .t-team-expert-pick-search:focus{outline:none;border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
20848
+ .t-team-expert-pick-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;overflow:auto;min-height:0}
20849
+ .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}
20850
+ .t-team-expert-pick-item[data-active="true"]{background:var(--dsw-alias-interactive-bg-hover)}
20851
+ .t-team-expert-pick-item[data-picked="true"]{color:var(--dsw-alias-label-primary);font-weight:500}
20852
+ .t-team-expert-pick-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
20853
+ .t-team-expert-pick-meta{flex:none;font-size:11px;color:var(--dsw-alias-label-tertiary)}
20854
+ .t-team-expert-pick-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px}
20364
20855
  `;
20365
20856
  function direct(method, parameters, typeSymbol, schema) {
20366
20857
  return {
@@ -20385,6 +20876,33 @@ var TYPERT_REMOTE = {
20385
20876
  { name: "slug", wire: "slug", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
20386
20877
  { name: "division", wire: "division", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(64) } }
20387
20878
  ], "TTeamPrompt", promptSchema),
20879
+ direct("getUiPrefs", [], "TTeamUiPrefs", uiPrefsSchema),
20880
+ // 入参是 patch 对象(与 host 侧 descriptor 一致):界面偏好不再只有任务徽章一项,
20881
+ // 加键不必再加方法。
20882
+ direct("setUiPrefs", [
20883
+ { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamUiPrefsPatch", schema: uiPrefsPatchSchema } }
20884
+ ], "TTeamUiPrefs", uiPrefsSchema),
20885
+ // 定时任务:读一份快照;写操作全部回传刷新后的整份快照,面板拿到直接重绘。
20886
+ direct("getSchedule", [], "TTeamSchedule", scheduleSnapshotSchema),
20887
+ direct("createScheduleItem", [
20888
+ { name: "input", wire: "input", source: "json", codec: { mode: "strict", typeSymbol: "TTeamScheduleInput", schema: scheduleInputSchema } }
20889
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20890
+ direct("updateScheduleItem", [
20891
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
20892
+ { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamSchedulePatch", schema: schedulePatchSchema } }
20893
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20894
+ direct("deleteScheduleItem", [
20895
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
20896
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20897
+ direct("runScheduleItem", [
20898
+ { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
20899
+ ], "TTeamSchedule", scheduleSnapshotSchema),
20900
+ direct("ensureScheduleWorkspace", [
20901
+ { name: "path", wire: "path", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(1024) } }
20902
+ ], "TTeamScheduleWorkspace", scheduleWorkspaceSchema),
20903
+ direct("previewSchedule", [
20904
+ { name: "cron", wire: "cron", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(120) } }
20905
+ ], "TTeamSchedulePreview", schedulePreviewSchema),
20388
20906
  direct("getSquads", [], "TTeamSquads", squadsSnapshotSchema),
20389
20907
  direct("saveSquads", [
20390
20908
  { name: "squads", wire: "squads", source: "json", codec: { mode: "strict", typeSymbol: "TTeamSquadInput[]", schema: external_exports.array(squadInputSchema).min(1).max(48) } },
@@ -20445,11 +20963,7 @@ function onCatalogLoaded(listener) {
20445
20963
  catalogListeners.add(listener);
20446
20964
  return () => catalogListeners.delete(listener);
20447
20965
  }
20448
- async function refresh(remote, force = false) {
20449
- const cached2 = catalogCache.get(remote);
20450
- if (cached2 !== void 0 && !force) return cached2;
20451
- const next = unwrap(await remote.getCatalog(), "getCatalog");
20452
- next.enabledSet = new Set(next.enabled);
20966
+ function publishCatalog(remote, next) {
20453
20967
  catalogCache.set(remote, next);
20454
20968
  for (const listener of catalogListeners) {
20455
20969
  try {
@@ -20460,6 +20974,13 @@ async function refresh(remote, force = false) {
20460
20974
  }
20461
20975
  return next;
20462
20976
  }
20977
+ async function refresh(remote, force = false) {
20978
+ const cached2 = catalogCache.get(remote);
20979
+ if (cached2 !== void 0 && !force) return cached2;
20980
+ const next = unwrap(await remote.getCatalog(), "getCatalog");
20981
+ next.enabledSet = new Set(next.enabled);
20982
+ return publishCatalog(remote, next);
20983
+ }
20463
20984
  function displayName(expert, active) {
20464
20985
  return active === "en" ? expert.nameEn || expert.name : expert.name || expert.nameEn;
20465
20986
  }
@@ -20469,6 +20990,51 @@ function displayDescription(expert, active) {
20469
20990
  function divisionLabel(expert, active) {
20470
20991
  return active === "en" ? expert.divisionEn || expert.division : expert.divisionZh || expert.division;
20471
20992
  }
20993
+ function matchExpertAtHead(text, experts, active) {
20994
+ if (!text.startsWith("@")) return void 0;
20995
+ let matched;
20996
+ for (const expert of experts ?? []) {
20997
+ const names = [displayName(expert, active), expert?.name, expert?.nameEn, expert?.slug].filter((name) => typeof name === "string" && name !== "");
20998
+ for (const name of names) {
20999
+ if (!text.startsWith(`@${name}`)) continue;
21000
+ if (matched === void 0 || name.length > matched.name.length) {
21001
+ matched = { name, display: displayName(expert, active) };
21002
+ }
21003
+ }
21004
+ }
21005
+ return matched;
21006
+ }
21007
+ function tokenizePrompt(text, experts, active) {
21008
+ const raw = String(text ?? "");
21009
+ const tokens = [];
21010
+ let buffer = "";
21011
+ let rest = raw;
21012
+ const flush = () => {
21013
+ if (buffer === "") return;
21014
+ tokens.push({ type: "text", text: buffer });
21015
+ buffer = "";
21016
+ };
21017
+ while (rest !== "") {
21018
+ const hit = rest.startsWith("@") ? matchExpertAtHead(rest, experts, active) : void 0;
21019
+ if (hit === void 0) {
21020
+ buffer += rest[0];
21021
+ rest = rest.slice(1);
21022
+ continue;
21023
+ }
21024
+ flush();
21025
+ tokens.push({ type: "expert", name: hit.display });
21026
+ rest = rest.slice(hit.name.length + 1);
21027
+ }
21028
+ flush();
21029
+ return tokens;
21030
+ }
21031
+ function collectExpertMentions(text, experts, active) {
21032
+ const names = [];
21033
+ for (const token of tokenizePrompt(text, experts, active)) {
21034
+ if (token.type === "expert" && !names.includes(token.name)) names.push(token.name);
21035
+ }
21036
+ return names;
21037
+ }
20472
21038
  function matchExpert(expert, active, query) {
20473
21039
  if (query === "") return true;
20474
21040
  const haystack = `${expert.name} ${expert.nameEn} ${expert.description} ${expert.descriptionEn} ${expert.slug}`.toLowerCase();
@@ -20505,6 +21071,762 @@ var SectionBoundary = class extends import_react.default.Component {
20505
21071
  return this.props.children;
20506
21072
  }
20507
21073
  };
21074
+ var CUSTOM_WORKSPACE = "__custom__";
21075
+ var SCHEDULE_PANEL_KEY = `${NS}-schedule`;
21076
+ var SCHEDULE_PRESET_LABELS = {
21077
+ hourly: "sched.presetHourly",
21078
+ min30: "sched.presetMin30",
21079
+ daily9: "sched.presetDaily9",
21080
+ weekday830: "sched.presetWeekday830",
21081
+ mon10: "sched.presetMon10"
21082
+ };
21083
+ var SCHEDULE_WEEKDAY_LABELS = {
21084
+ 1: "sched.wd1",
21085
+ 2: "sched.wd2",
21086
+ 3: "sched.wd3",
21087
+ 4: "sched.wd4",
21088
+ 5: "sched.wd5",
21089
+ 6: "sched.wd6",
21090
+ 0: "sched.wd0"
21091
+ };
21092
+ function errorText(cause) {
21093
+ return cause instanceof Error ? cause.message : String(cause);
21094
+ }
21095
+ function CronPicker({ t, remote, value, onChange, disabled }) {
21096
+ const [model, setModel] = import_react.default.useState(() => parseCron(value));
21097
+ const [fires, setFires] = import_react.default.useState([]);
21098
+ const [hint, setHint] = import_react.default.useState("");
21099
+ import_react.default.useEffect(() => {
21100
+ setModel(parseCron(value));
21101
+ }, [value]);
21102
+ import_react.default.useEffect(() => {
21103
+ const cron = String(value ?? "").trim();
21104
+ if (cron === "") {
21105
+ setFires([]);
21106
+ setHint("");
21107
+ return void 0;
21108
+ }
21109
+ let cancelled = false;
21110
+ const timer = setTimeout(() => {
21111
+ void (async () => {
21112
+ try {
21113
+ const payload = unwrap(await remote.previewSchedule(cron), "previewSchedule");
21114
+ if (cancelled) return;
21115
+ setFires(Array.isArray(payload?.fires) ? payload.fires : []);
21116
+ setHint("");
21117
+ } catch (cause) {
21118
+ if (cancelled) return;
21119
+ setFires([]);
21120
+ setHint(errorText(cause));
21121
+ }
21122
+ })();
21123
+ }, 250);
21124
+ return () => {
21125
+ cancelled = true;
21126
+ clearTimeout(timer);
21127
+ };
21128
+ }, [value, remote]);
21129
+ import_react.default.useEffect(() => {
21130
+ if (!value || String(value).trim() === "") onChange(buildCron(parseCron("")));
21131
+ }, []);
21132
+ const emit = (next) => {
21133
+ setModel(next);
21134
+ const cron = buildCron(next);
21135
+ if (cron !== "") onChange(cron);
21136
+ };
21137
+ const setMode = (mode) => {
21138
+ if (mode === model.mode) return;
21139
+ if (mode === "hourly") emit({ mode, step: 60, minute: model.minute ?? 0 });
21140
+ else if (mode === "daily") emit({ mode, hour: model.hour ?? 9, minute: model.minute ?? 0 });
21141
+ 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] });
21142
+ else {
21143
+ const raw = buildCron(model) || "0 9 * * *";
21144
+ setModel({ mode, raw });
21145
+ onChange(raw);
21146
+ }
21147
+ };
21148
+ const toggleDay = (day) => {
21149
+ const current = model.days || [];
21150
+ const next = current.includes(day) ? current.filter((item) => item !== day) : WEEKDAY_KEYS.filter((item) => current.includes(item) || item === day);
21151
+ if (next.length === 0) return;
21152
+ emit({ ...model, days: next });
21153
+ };
21154
+ const pad2 = (n) => String(n).padStart(2, "0");
21155
+ const hours = Array.from({ length: 24 }, (_, i) => i);
21156
+ const minutes = Array.from({ length: 60 }, (_, i) => i);
21157
+ const time3 = `${pad2(model.hour ?? 9)}:${pad2(model.minute ?? 0)}`;
21158
+ let summary;
21159
+ if (model.mode === "hourly") {
21160
+ summary = model.step && model.step < 60 ? t("sched.sumMin", { n: model.step }) : t("sched.sumHour", { m: pad2(model.minute ?? 0) });
21161
+ } else if (model.mode === "daily") {
21162
+ summary = t("sched.sumDaily", { t: time3 });
21163
+ } else if (model.mode === "weekly") {
21164
+ const days = model.days || [];
21165
+ const isWorkday = days.length === 5 && [1, 2, 3, 4, 5].every((day) => days.includes(day));
21166
+ const week = isWorkday ? "" : days.map((day) => t(SCHEDULE_WEEKDAY_LABELS[day])).join(t("sched.listSep"));
21167
+ summary = t(isWorkday ? "sched.sumWeeklyWorkday" : "sched.sumWeekly", { w: week, t: time3 });
21168
+ } else {
21169
+ summary = model.raw ? t("sched.sumCustom", { raw: model.raw }) : t("sched.sumEmpty");
21170
+ }
21171
+ 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)))));
21172
+ 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(
21173
+ "button",
21174
+ {
21175
+ key: preset.id,
21176
+ type: "button",
21177
+ className: "t-team-sched-chip",
21178
+ disabled,
21179
+ onClick: () => onChange(preset.cron)
21180
+ },
21181
+ t(SCHEDULE_PRESET_LABELS[preset.id])
21182
+ ))), /* @__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(
21183
+ "button",
21184
+ {
21185
+ key: mode,
21186
+ type: "button",
21187
+ role: "tab",
21188
+ "aria-selected": model.mode === mode,
21189
+ "data-on": model.mode === mode,
21190
+ disabled,
21191
+ onClick: () => setMode(mode)
21192
+ },
21193
+ t(key)
21194
+ ))), 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(
21195
+ "select",
21196
+ {
21197
+ value: model.step ?? 60,
21198
+ disabled,
21199
+ onChange: (event) => {
21200
+ const step = Number(event.target.value);
21201
+ emit(step === 60 ? { mode: "hourly", step, minute: model.minute ?? 0 } : { mode: "hourly", step });
21202
+ }
21203
+ },
21204
+ HOURLY_STEPS.map((step) => /* @__PURE__ */ import_react.default.createElement("option", { key: step, value: step }, step === 60 ? "1" : String(step)))
21205
+ ), (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(
21206
+ "select",
21207
+ {
21208
+ value: model.minute ?? 0,
21209
+ disabled,
21210
+ onChange: (event) => emit({ ...model, minute: Number(event.target.value) })
21211
+ },
21212
+ minutes.map((n) => /* @__PURE__ */ import_react.default.createElement("option", { key: n, value: n }, pad2(n)))
21213
+ ), /* @__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(
21214
+ "button",
21215
+ {
21216
+ key: day,
21217
+ type: "button",
21218
+ className: "t-team-sched-day",
21219
+ "data-on": (model.days || []).includes(day),
21220
+ "aria-pressed": (model.days || []).includes(day),
21221
+ disabled,
21222
+ onClick: () => toggleDay(day)
21223
+ },
21224
+ t(SCHEDULE_WEEKDAY_LABELS[day])
21225
+ ))), timeSelects), model.mode === "custom" && /* @__PURE__ */ import_react.default.createElement(
21226
+ "input",
21227
+ {
21228
+ value: model.raw || "",
21229
+ disabled,
21230
+ placeholder: "0 9 * * *",
21231
+ spellCheck: false,
21232
+ onChange: (event) => {
21233
+ const raw = event.target.value;
21234
+ setModel({ mode: "custom", raw });
21235
+ onChange(raw);
21236
+ }
21237
+ }
21238
+ ), /* @__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" }))))));
21239
+ }
21240
+ function emptyScheduleForm() {
21241
+ return { editingId: null, title: "", prompt: "", cron: "", enabled: true, workspaceId: "", customDir: "" };
21242
+ }
21243
+ function scheduleLastRun(t, item) {
21244
+ if (!item.lastRunAt) return t("sched.neverRun");
21245
+ const time3 = new Date(item.lastRunAt).toLocaleString();
21246
+ return item.lastRunError === void 0 ? time3 : `${time3}\uFF08${t("sched.failed")}: ${item.lastRunError}\uFF09`;
21247
+ }
21248
+ function PromptEditor({ editorRef, t, active, experts, value, disabled, onChange }) {
21249
+ const boxRef = import_react.default.useRef(null);
21250
+ const lastWritten = import_react.default.useRef(null);
21251
+ const savedRange = import_react.default.useRef(null);
21252
+ const buildChipIcon = () => {
21253
+ const NS2 = "http://www.w3.org/2000/svg";
21254
+ const svg = document.createElementNS(NS2, "svg");
21255
+ svg.setAttribute("class", "t-team-sched-chip-icon");
21256
+ svg.setAttribute("viewBox", "0 0 16 16");
21257
+ svg.setAttribute("width", "13");
21258
+ svg.setAttribute("height", "13");
21259
+ svg.setAttribute("fill", "none");
21260
+ svg.setAttribute("stroke", "currentColor");
21261
+ svg.setAttribute("stroke-width", "1.4");
21262
+ svg.setAttribute("stroke-linecap", "round");
21263
+ svg.setAttribute("aria-hidden", "true");
21264
+ const circle = document.createElementNS(NS2, "circle");
21265
+ circle.setAttribute("cx", "8");
21266
+ circle.setAttribute("cy", "8");
21267
+ circle.setAttribute("r", "6");
21268
+ const line1 = document.createElementNS(NS2, "line");
21269
+ line1.setAttribute("x1", "5.4");
21270
+ line1.setAttribute("y1", "6.6");
21271
+ line1.setAttribute("x2", "10.6");
21272
+ line1.setAttribute("y2", "6.6");
21273
+ const line2 = document.createElementNS(NS2, "line");
21274
+ line2.setAttribute("x1", "5.4");
21275
+ line2.setAttribute("y1", "9.4");
21276
+ line2.setAttribute("x2", "9");
21277
+ line2.setAttribute("y2", "9.4");
21278
+ svg.append(circle, line1, line2);
21279
+ return svg;
21280
+ };
21281
+ const buildChip = (name) => {
21282
+ const chip = document.createElement("span");
21283
+ chip.className = "t-team-sched-chip";
21284
+ chip.contentEditable = "false";
21285
+ chip.dataset.expert = name;
21286
+ const label = document.createElement("span");
21287
+ label.className = "t-team-sched-chip-name";
21288
+ label.textContent = name;
21289
+ const remove = document.createElement("button");
21290
+ remove.type = "button";
21291
+ remove.className = "t-team-sched-chip-remove";
21292
+ remove.dataset.remove = name;
21293
+ remove.textContent = "\xD7";
21294
+ remove.title = t("sched.expertRemove", { name });
21295
+ chip.append(buildChipIcon(), label, remove);
21296
+ return chip;
21297
+ };
21298
+ const serialize = () => {
21299
+ const box = boxRef.current;
21300
+ if (box === null) return "";
21301
+ let out = "";
21302
+ for (const node2 of box.childNodes) {
21303
+ if (node2.nodeType === 3) {
21304
+ out += node2.textContent ?? "";
21305
+ continue;
21306
+ }
21307
+ if (node2.nodeType !== 1) continue;
21308
+ const el = (
21309
+ /** @type {HTMLElement} */
21310
+ node2
21311
+ );
21312
+ if (el.dataset?.expert !== void 0) {
21313
+ out += `@${el.dataset.expert}`;
21314
+ continue;
21315
+ }
21316
+ if (el.tagName === "BR") {
21317
+ out += "\n";
21318
+ continue;
21319
+ }
21320
+ out += el.textContent ?? "";
21321
+ }
21322
+ return out;
21323
+ };
21324
+ const refreshEmpty = () => {
21325
+ const box = boxRef.current;
21326
+ if (box !== null) box.dataset.empty = box.textContent === "" ? "true" : "false";
21327
+ };
21328
+ const pushOut = () => {
21329
+ const text = serialize();
21330
+ lastWritten.current = text;
21331
+ refreshEmpty();
21332
+ onChange(text);
21333
+ };
21334
+ const rebuild = () => {
21335
+ const box = boxRef.current;
21336
+ if (box === null) return;
21337
+ box.textContent = "";
21338
+ for (const token of tokenizePrompt(value, experts, active)) {
21339
+ box.append(token.type === "text" ? document.createTextNode(token.text ?? "") : buildChip(token.name ?? ""));
21340
+ }
21341
+ refreshEmpty();
21342
+ };
21343
+ const removeExpert = (name) => {
21344
+ const box = boxRef.current;
21345
+ if (box === null) return;
21346
+ for (const el of box.querySelectorAll("[data-expert]")) {
21347
+ if (
21348
+ /** @type {HTMLElement} */
21349
+ el.dataset.expert === name
21350
+ ) {
21351
+ el.remove();
21352
+ break;
21353
+ }
21354
+ }
21355
+ pushOut();
21356
+ };
21357
+ const insertExpert = (name) => {
21358
+ const box = boxRef.current;
21359
+ if (box === null || disabled) return;
21360
+ const chip = buildChip(name);
21361
+ const space = document.createTextNode(" ");
21362
+ box.focus();
21363
+ const selection = window.getSelection();
21364
+ if (selection !== null && savedRange.current !== null && box.contains(savedRange.current.commonAncestorContainer)) {
21365
+ selection.removeAllRanges();
21366
+ selection.addRange(savedRange.current);
21367
+ }
21368
+ const inside = selection !== null && selection.rangeCount > 0 && box.contains(selection.anchorNode);
21369
+ if (inside) {
21370
+ const range = selection.getRangeAt(0);
21371
+ range.deleteContents();
21372
+ range.insertNode(chip);
21373
+ chip.after(space);
21374
+ range.setStartAfter(space);
21375
+ range.collapse(true);
21376
+ selection.removeAllRanges();
21377
+ selection.addRange(range);
21378
+ savedRange.current = range.cloneRange();
21379
+ } else {
21380
+ box.append(chip, space);
21381
+ }
21382
+ pushOut();
21383
+ };
21384
+ import_react.default.useEffect(() => {
21385
+ if (editorRef === void 0) return void 0;
21386
+ editorRef.current = { insertExpert, removeExpert, focus: () => boxRef.current?.focus() };
21387
+ return () => {
21388
+ editorRef.current = null;
21389
+ };
21390
+ });
21391
+ import_react.default.useEffect(() => {
21392
+ if (lastWritten.current === value) return;
21393
+ rebuild();
21394
+ }, [value, experts, active]);
21395
+ import_react.default.useEffect(() => {
21396
+ const onSelectionChange = () => {
21397
+ const box = boxRef.current;
21398
+ if (box === null) return;
21399
+ const selection = window.getSelection();
21400
+ if (selection === null || selection.rangeCount === 0) return;
21401
+ const range = selection.getRangeAt(0);
21402
+ if (box.contains(range.commonAncestorContainer)) savedRange.current = range.cloneRange();
21403
+ };
21404
+ document.addEventListener("selectionchange", onSelectionChange);
21405
+ return () => document.removeEventListener("selectionchange", onSelectionChange);
21406
+ }, []);
21407
+ const onPaste = (event) => {
21408
+ const text = event.clipboardData?.getData("text/plain") ?? "";
21409
+ if (text === "") return;
21410
+ event.preventDefault();
21411
+ const selection = window.getSelection();
21412
+ if (selection === null || selection.rangeCount === 0) return;
21413
+ const range = selection.getRangeAt(0);
21414
+ range.deleteContents();
21415
+ const node2 = document.createTextNode(text);
21416
+ range.insertNode(node2);
21417
+ range.setStartAfter(node2);
21418
+ range.collapse(true);
21419
+ selection.removeAllRanges();
21420
+ selection.addRange(range);
21421
+ pushOut();
21422
+ };
21423
+ return /* @__PURE__ */ import_react.default.createElement(
21424
+ "div",
21425
+ {
21426
+ ref: boxRef,
21427
+ className: "t-team-sched-prompt-input",
21428
+ contentEditable: !disabled,
21429
+ suppressContentEditableWarning: true,
21430
+ role: "textbox",
21431
+ "aria-multiline": "true",
21432
+ "aria-label": t("sched.promptLabel"),
21433
+ "data-placeholder": t("sched.promptPlaceholder"),
21434
+ "data-empty": "true",
21435
+ onInput: () => {
21436
+ if (!disabled) pushOut();
21437
+ },
21438
+ onPaste,
21439
+ onBlur: () => {
21440
+ if (!disabled) pushOut();
21441
+ },
21442
+ onMouseDownCapture: (event) => {
21443
+ const target = (
21444
+ /** @type {HTMLElement} */
21445
+ event.target
21446
+ );
21447
+ const name = target?.dataset?.remove;
21448
+ if (name === void 0 || disabled) return;
21449
+ event.preventDefault();
21450
+ removeExpert(name);
21451
+ }
21452
+ }
21453
+ );
21454
+ }
21455
+ function ExpertPicker({ t, active, experts, disabled, selected, onPick }) {
21456
+ const [open2, setOpen] = import_react.default.useState(false);
21457
+ const [query, setQuery] = import_react.default.useState("");
21458
+ const [index, setIndex] = import_react.default.useState(0);
21459
+ const wrapRef = import_react.default.useRef(null);
21460
+ const picked = selected ?? [];
21461
+ import_react.default.useEffect(() => {
21462
+ if (!open2) return void 0;
21463
+ const onDown = (event) => {
21464
+ const node2 = wrapRef.current;
21465
+ if (node2 !== null && !node2.contains(event.target)) setOpen(false);
21466
+ };
21467
+ document.addEventListener("pointerdown", onDown, true);
21468
+ return () => document.removeEventListener("pointerdown", onDown, true);
21469
+ }, [open2]);
21470
+ const needle = query.trim().toLowerCase();
21471
+ const candidates = (experts ?? []).filter((expert) => matchExpert(expert, active, needle)).slice(0, 50);
21472
+ const pick2 = (expert) => {
21473
+ if (expert === void 0) return;
21474
+ onPick(expert);
21475
+ setOpen(false);
21476
+ setQuery("");
21477
+ setIndex(0);
21478
+ };
21479
+ const onKeyDown = (event) => {
21480
+ if (event.key === "Escape") {
21481
+ event.preventDefault();
21482
+ setOpen(false);
21483
+ return;
21484
+ }
21485
+ if (candidates.length === 0) return;
21486
+ if (event.key === "ArrowDown") {
21487
+ event.preventDefault();
21488
+ setIndex((current) => (current + 1) % candidates.length);
21489
+ } else if (event.key === "ArrowUp") {
21490
+ event.preventDefault();
21491
+ setIndex((current) => (current - 1 + candidates.length) % candidates.length);
21492
+ } else if (event.key === "Enter") {
21493
+ event.preventDefault();
21494
+ pick2(candidates[Math.min(index, candidates.length - 1)]);
21495
+ }
21496
+ };
21497
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick", ref: wrapRef }, /* @__PURE__ */ import_react.default.createElement(
21498
+ "button",
21499
+ {
21500
+ type: "button",
21501
+ className: "t-team-chip",
21502
+ "data-active": open2,
21503
+ disabled,
21504
+ "aria-expanded": open2,
21505
+ onClick: () => {
21506
+ setOpen(!open2);
21507
+ setQuery("");
21508
+ setIndex(0);
21509
+ }
21510
+ },
21511
+ "\u{1F9E9} ",
21512
+ t("sched.expertPick")
21513
+ ), /* @__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(
21514
+ "input",
21515
+ {
21516
+ className: "t-team-expert-pick-search",
21517
+ value: query,
21518
+ autoFocus: true,
21519
+ spellCheck: false,
21520
+ placeholder: t("sched.expertPickSearch"),
21521
+ "aria-label": t("sched.expertPickSearch"),
21522
+ onChange: (event) => {
21523
+ setQuery(event.target.value);
21524
+ setIndex(0);
21525
+ },
21526
+ onKeyDown
21527
+ }
21528
+ ), 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(
21529
+ "button",
21530
+ {
21531
+ type: "button",
21532
+ role: "option",
21533
+ "aria-selected": position === index,
21534
+ "data-active": position === index,
21535
+ "data-picked": picked.includes(displayName(expert, active)),
21536
+ className: "t-team-expert-pick-item",
21537
+ onMouseEnter: () => setIndex(position),
21538
+ onMouseDown: (event) => event.preventDefault(),
21539
+ onClick: () => pick2(expert)
21540
+ },
21541
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-name" }, picked.includes(displayName(expert, active)) ? "\u2713 " : "", expert.emoji, " ", displayName(expert, active)),
21542
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-meta" }, divisionLabel(expert, active))
21543
+ ))))));
21544
+ }
21545
+ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
21546
+ const showButton = useShowScheduleButton();
21547
+ const [snapshot, setSnapshot] = import_react.default.useState(null);
21548
+ const [error62, setError] = import_react.default.useState("");
21549
+ const [loading, setLoading] = import_react.default.useState(true);
21550
+ const [busy, setBusy] = import_react.default.useState(false);
21551
+ const [form, setForm] = import_react.default.useState(null);
21552
+ const [historyId, setHistoryId] = import_react.default.useState(null);
21553
+ const [runningId, setRunningId] = import_react.default.useState(null);
21554
+ const [experts, setExperts] = import_react.default.useState([]);
21555
+ const promptEditorRef = import_react.default.useRef(null);
21556
+ const [extraWorkspaces, setExtraWorkspaces] = import_react.default.useState([]);
21557
+ const layout = () => hostCtx?.get?.("layout") ?? hostCtx?.layout;
21558
+ const backToConversation = () => layout()?.selectPanel?.(null);
21559
+ const load = import_react.default.useCallback(async () => {
21560
+ setLoading(true);
21561
+ try {
21562
+ setSnapshot(unwrap(await remote.getSchedule(), "getSchedule"));
21563
+ setError("");
21564
+ } catch (cause) {
21565
+ setError(errorText(cause));
21566
+ } finally {
21567
+ setLoading(false);
21568
+ }
21569
+ }, [remote]);
21570
+ import_react.default.useEffect(() => {
21571
+ void load();
21572
+ }, [load]);
21573
+ import_react.default.useEffect(() => {
21574
+ let alive = true;
21575
+ const sync = () => {
21576
+ const current = snapshotOf(remote);
21577
+ if (current === void 0 || !alive) return;
21578
+ setExperts(current.experts.filter((expert) => expert.conflict !== true && current.enabledSet.has(expert.slug)));
21579
+ };
21580
+ const stop = onCatalogLoaded(sync);
21581
+ void (async () => {
21582
+ try {
21583
+ await refresh(remote);
21584
+ sync();
21585
+ } catch (cause) {
21586
+ 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);
21587
+ }
21588
+ })();
21589
+ return () => {
21590
+ alive = false;
21591
+ stop();
21592
+ };
21593
+ }, [remote]);
21594
+ const active = getActive();
21595
+ import_react.default.useEffect(() => {
21596
+ if (showButton) return;
21597
+ layout()?.selectPanel?.(null);
21598
+ }, [showButton]);
21599
+ const applySnapshot = (next) => {
21600
+ setSnapshot(next);
21601
+ setError("");
21602
+ };
21603
+ function fillExpert(expert) {
21604
+ const editor = promptEditorRef.current;
21605
+ if (editor === null) return;
21606
+ const name = displayName(expert, active);
21607
+ if (mentioned.includes(name)) editor.removeExpert(name);
21608
+ else editor.insertExpert(name);
21609
+ }
21610
+ function rememberWorkspace(workspace) {
21611
+ if (workspace === void 0 || workspace === null) return "";
21612
+ setExtraWorkspaces((current) => current.some((item) => item.id === workspace.id) ? current : [...current, workspace]);
21613
+ return workspace.id;
21614
+ }
21615
+ async function openNewForm() {
21616
+ setBusy(true);
21617
+ let workspaceId = "";
21618
+ try {
21619
+ workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(""), "ensureScheduleWorkspace")?.workspace);
21620
+ } catch (cause) {
21621
+ setError(errorText(cause));
21622
+ } finally {
21623
+ setBusy(false);
21624
+ }
21625
+ setForm({ ...emptyScheduleForm(), workspaceId });
21626
+ }
21627
+ async function submitForm() {
21628
+ if (form === null || busy) return;
21629
+ if (form.title.trim() === "" || form.prompt.trim() === "" || form.cron.trim() === "") {
21630
+ window.alert(t("sched.invalidForm"));
21631
+ return;
21632
+ }
21633
+ setBusy(true);
21634
+ try {
21635
+ let workspaceId = form.workspaceId;
21636
+ if (workspaceId === CUSTOM_WORKSPACE) {
21637
+ const dir = form.customDir.trim();
21638
+ if (dir === "") {
21639
+ window.alert(t("sched.workspaceCustomEmpty"));
21640
+ return;
21641
+ }
21642
+ workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(dir), "ensureScheduleWorkspace")?.workspace);
21643
+ }
21644
+ const payload = {
21645
+ title: form.title.trim(),
21646
+ prompt: form.prompt,
21647
+ cron: form.cron.trim(),
21648
+ enabled: form.enabled,
21649
+ // 空串 = 不绑定工作区(显式解绑也走这个值,宿主认得)。
21650
+ workspaceId: workspaceId === void 0 || workspaceId === null ? "" : workspaceId
21651
+ };
21652
+ const next = form.editingId === null ? unwrap(await remote.createScheduleItem(payload), "createScheduleItem") : unwrap(await remote.updateScheduleItem(form.editingId, payload), "updateScheduleItem");
21653
+ applySnapshot(next);
21654
+ setForm(null);
21655
+ } catch (cause) {
21656
+ setError(errorText(cause));
21657
+ } finally {
21658
+ setBusy(false);
21659
+ }
21660
+ }
21661
+ async function removeItem(id) {
21662
+ if (!window.confirm(t("sched.deleteConfirm"))) return;
21663
+ setBusy(true);
21664
+ try {
21665
+ applySnapshot(unwrap(await remote.deleteScheduleItem(id), "deleteScheduleItem"));
21666
+ } catch (cause) {
21667
+ setError(errorText(cause));
21668
+ } finally {
21669
+ setBusy(false);
21670
+ }
21671
+ }
21672
+ async function runItem(id) {
21673
+ setRunningId(id);
21674
+ try {
21675
+ applySnapshot(unwrap(await remote.runScheduleItem(id), "runScheduleItem"));
21676
+ } catch (cause) {
21677
+ setError(errorText(cause));
21678
+ } finally {
21679
+ setRunningId(null);
21680
+ }
21681
+ }
21682
+ const items = snapshot?.items ?? [];
21683
+ const workspaces = snapshot?.workspaces ?? [];
21684
+ const allWorkspaces = [...workspaces];
21685
+ for (const workspace of extraWorkspaces) {
21686
+ if (!allWorkspaces.some((item) => item.id === workspace.id)) allWorkspaces.push(workspace);
21687
+ }
21688
+ const workspaceTitle = (id) => allWorkspaces.find((workspace) => workspace.id === id)?.title ?? id;
21689
+ const rowMeta = (item) => {
21690
+ const parts = [];
21691
+ if (item.workspaceId !== void 0) parts.push(`${t("sched.workspace")}: ${workspaceTitle(item.workspaceId)}`);
21692
+ if (item.enabled !== true) parts.push(t("sched.disabledTag"));
21693
+ parts.push(`${t("sched.lastRun")}: ${scheduleLastRun(t, item)}`);
21694
+ return parts.join(" \xB7 ");
21695
+ };
21696
+ const disabled = busy || loading || !showButton;
21697
+ const mentioned = form === null ? [] : collectExpertMentions(form.prompt, experts, active);
21698
+ const selectedWorkspacePath = form === null ? "" : allWorkspaces.find((workspace) => workspace.id === form.workspaceId)?.path ?? "";
21699
+ 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(
21700
+ "button",
21701
+ {
21702
+ type: "button",
21703
+ className: "t-team-sched-runsToggle",
21704
+ "aria-expanded": historyId === item.id,
21705
+ onClick: () => setHistoryId(historyId === item.id ? null : item.id)
21706
+ },
21707
+ t("sched.runHistory", { count: item.runs.length })
21708
+ ), 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(
21709
+ "button",
21710
+ {
21711
+ type: "button",
21712
+ className: "t-team-sched-btn",
21713
+ disabled: disabled || runningId === item.id || (snapshot?.running ?? []).includes(item.id),
21714
+ onClick: () => void runItem(item.id)
21715
+ },
21716
+ runningId === item.id || (snapshot?.running ?? []).includes(item.id) ? t("sched.running") : t("sched.runNow")
21717
+ ), /* @__PURE__ */ import_react.default.createElement(
21718
+ "button",
21719
+ {
21720
+ type: "button",
21721
+ className: "t-team-sched-btn",
21722
+ disabled,
21723
+ onClick: () => setForm({
21724
+ editingId: item.id,
21725
+ title: item.title,
21726
+ prompt: item.prompt,
21727
+ cron: item.cron,
21728
+ enabled: item.enabled === true,
21729
+ workspaceId: item.workspaceId ?? "",
21730
+ customDir: ""
21731
+ })
21732
+ },
21733
+ t("sched.edit")
21734
+ ), /* @__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: () => void openNewForm() }, t("sched.new")) : /* @__PURE__ */ import_react.default.createElement(
21735
+ "form",
21736
+ {
21737
+ className: "t-team-sched-form",
21738
+ onSubmit: (event) => {
21739
+ event.preventDefault();
21740
+ void submitForm();
21741
+ }
21742
+ },
21743
+ /* @__PURE__ */ import_react.default.createElement("h3", { className: "t-team-sched-formTitle" }, form.editingId === null ? t("sched.new") : t("sched.edit")),
21744
+ /* @__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(
21745
+ "input",
21746
+ {
21747
+ value: form.title,
21748
+ disabled: busy,
21749
+ placeholder: t("sched.titlePlaceholder"),
21750
+ onChange: (event) => setForm({ ...form, title: event.target.value })
21751
+ }
21752
+ )),
21753
+ /* @__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" }, /* @__PURE__ */ import_react.default.createElement(
21754
+ PromptEditor,
21755
+ {
21756
+ editorRef: promptEditorRef,
21757
+ t,
21758
+ active,
21759
+ experts,
21760
+ value: form.prompt,
21761
+ disabled: busy,
21762
+ onChange: (prompt) => setForm((current) => current === null ? current : { ...current, prompt })
21763
+ }
21764
+ )), /* @__PURE__ */ import_react.default.createElement(
21765
+ ExpertPicker,
21766
+ {
21767
+ t,
21768
+ active,
21769
+ experts,
21770
+ disabled: busy,
21771
+ selected: mentioned,
21772
+ onPick: fillExpert
21773
+ }
21774
+ ), 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")) }))),
21775
+ /* @__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"))),
21776
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.workspace")), /* @__PURE__ */ import_react.default.createElement(
21777
+ "select",
21778
+ {
21779
+ value: form.workspaceId,
21780
+ disabled: busy,
21781
+ onChange: (event) => setForm({ ...form, workspaceId: event.target.value })
21782
+ },
21783
+ /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, t("sched.workspaceNone")),
21784
+ allWorkspaces.map((workspace) => /* @__PURE__ */ import_react.default.createElement("option", { key: workspace.id, value: workspace.id }, workspace.title)),
21785
+ form.workspaceId !== "" && form.workspaceId !== CUSTOM_WORKSPACE && !allWorkspaces.some((workspace) => workspace.id === form.workspaceId) && /* @__PURE__ */ import_react.default.createElement("option", { value: form.workspaceId }, form.workspaceId),
21786
+ /* @__PURE__ */ import_react.default.createElement("option", { value: CUSTOM_WORKSPACE }, t("sched.workspaceCustom"))
21787
+ ), form.workspaceId === CUSTOM_WORKSPACE ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
21788
+ "input",
21789
+ {
21790
+ value: form.customDir,
21791
+ disabled: busy,
21792
+ placeholder: t("sched.workspaceCustomPlaceholder"),
21793
+ onChange: (event) => setForm({ ...form, customDir: event.target.value })
21794
+ }
21795
+ ), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceCustomHint"))) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceHint")), selectedWorkspacePath !== "" && /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspacePath", { path: selectedWorkspacePath })))),
21796
+ /* @__PURE__ */ import_react.default.createElement("label", { className: "t-team-sched-checkbox" }, /* @__PURE__ */ import_react.default.createElement(
21797
+ "input",
21798
+ {
21799
+ type: "checkbox",
21800
+ checked: form.enabled,
21801
+ disabled: busy,
21802
+ onChange: (event) => setForm({ ...form, enabled: event.target.checked })
21803
+ }
21804
+ ), /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.enabledLabel")), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.enabledHint"))),
21805
+ /* @__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")))
21806
+ ), /* @__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 }))));
21807
+ }
21808
+ function ScheduleGlyph({ size = 16 }) {
21809
+ return /* @__PURE__ */ import_react.default.createElement(
21810
+ "svg",
21811
+ {
21812
+ className: "t-team-schedule-glyph",
21813
+ width: size,
21814
+ height: size,
21815
+ viewBox: "0 0 16 16",
21816
+ fill: "none",
21817
+ stroke: "currentColor",
21818
+ strokeWidth: "1.4",
21819
+ strokeLinecap: "round",
21820
+ strokeLinejoin: "round",
21821
+ "aria-hidden": "true",
21822
+ focusable: "false"
21823
+ },
21824
+ /* @__PURE__ */ import_react.default.createElement("rect", { x: "2.2", y: "3.4", width: "11.6", height: "10.4", rx: "2.4" }),
21825
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M2.2 6.6h11.6" }),
21826
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M5.6 2.2v2.4M10.4 2.2v2.4" }),
21827
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.1 9.7l1.3 1.3 2.5-2.7" })
21828
+ );
21829
+ }
20508
21830
  function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab, squadsPreview, teamsPreview, draftPreview }) {
20509
21831
  const [snapshot, setSnapshot] = import_react.default.useState(() => snapshotOf(remote) ?? null);
20510
21832
  const [query, setQuery] = import_react.default.useState("");
@@ -20700,7 +22022,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
20700
22022
  setSnapshot({ ...snapshot, enabled: list });
20701
22023
  try {
20702
22024
  const state = unwrap(await remote.setEnabled(list, snapshot.revision), "setEnabled");
20703
- catalogCache.set(remote, { ...snapshot, enabled: state.enabled, enabledSet: new Set(state.enabled), revision: state.revision });
22025
+ publishCatalog(remote, { ...snapshot, enabled: state.enabled, enabledSet: new Set(state.enabled), revision: state.revision });
20704
22026
  setSnapshot({ ...snapshot, enabled: state.enabled, revision: state.revision });
20705
22027
  setError("");
20706
22028
  } catch (cause) {
@@ -20716,8 +22038,78 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
20716
22038
  if (snapshot === null) {
20717
22039
  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")))));
20718
22040
  }
22041
+ const [showTaskBadge, setShowTaskBadgeState] = import_react.default.useState(true);
22042
+ const [showScheduleButton, setShowScheduleButtonState] = import_react.default.useState(true);
22043
+ const [uiPrefsError, setUiPrefsError] = import_react.default.useState("");
22044
+ import_react.default.useEffect(() => {
22045
+ let alive = true;
22046
+ void (async () => {
22047
+ try {
22048
+ const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
22049
+ if (!alive) return;
22050
+ if (typeof data?.showTaskBadge !== "boolean" || typeof data?.showScheduleButton !== "boolean") {
22051
+ setUiPrefsError(t("settings.showTaskBadgeUnreadable"));
22052
+ return;
22053
+ }
22054
+ setUiPrefsError("");
22055
+ setShowTaskBadgeState(data.showTaskBadge);
22056
+ setShowScheduleButtonState(data.showScheduleButton);
22057
+ setUiPrefs({ showTaskBadge: data.showTaskBadge, showScheduleButton: data.showScheduleButton });
22058
+ } catch (cause) {
22059
+ 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);
22060
+ if (alive) setUiPrefsError(cause instanceof Error ? cause.message : String(cause));
22061
+ }
22062
+ })();
22063
+ return () => {
22064
+ alive = false;
22065
+ };
22066
+ }, [remote]);
22067
+ async function writeUiPref(patch, rollback) {
22068
+ setUiPrefs(patch);
22069
+ try {
22070
+ const next = unwrap(await remote.setUiPrefs(patch), "setUiPrefs");
22071
+ setUiPrefs(next);
22072
+ setShowTaskBadgeState(next.showTaskBadge);
22073
+ setShowScheduleButtonState(next.showScheduleButton);
22074
+ } catch (cause) {
22075
+ setUiPrefs(rollback);
22076
+ setShowTaskBadgeState(rollback.showTaskBadge ?? showTaskBadge);
22077
+ setShowScheduleButtonState(rollback.showScheduleButton ?? showScheduleButton);
22078
+ setError(cause instanceof Error ? cause.message : String(cause));
22079
+ }
22080
+ }
22081
+ async function setShowTaskBadge(next) {
22082
+ setShowTaskBadgeState(next);
22083
+ await writeUiPref({ showTaskBadge: next }, { showTaskBadge: !next });
22084
+ }
22085
+ async function setShowScheduleButton(next) {
22086
+ setShowScheduleButtonState(next);
22087
+ await writeUiPref({ showScheduleButton: next }, { showScheduleButton: !next });
22088
+ }
20719
22089
  const enabledCount = snapshot.enabled.length;
20720
- 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(
22090
+ 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(
22091
+ "button",
22092
+ {
22093
+ className: "t-team-switch",
22094
+ type: "button",
22095
+ role: "switch",
22096
+ "aria-checked": showTaskBadge,
22097
+ "data-on": showTaskBadge,
22098
+ onClick: () => void setShowTaskBadge(!showTaskBadge)
22099
+ },
22100
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
22101
+ )), /* @__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(
22102
+ "button",
22103
+ {
22104
+ className: "t-team-switch",
22105
+ type: "button",
22106
+ role: "switch",
22107
+ "aria-checked": showScheduleButton,
22108
+ "data-on": showScheduleButton,
22109
+ onClick: () => void setShowScheduleButton(!showScheduleButton)
22110
+ },
22111
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
22112
+ )), /* @__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(
20721
22113
  "button",
20722
22114
  {
20723
22115
  className: "t-team-tab",
@@ -20820,7 +22212,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
20820
22212
  )), /* @__PURE__ */ import_react.default.createElement(
20821
22213
  "button",
20822
22214
  {
20823
- className: "t-team-switch",
22215
+ className: "t-team-card-switch",
20824
22216
  type: "button",
20825
22217
  role: "switch",
20826
22218
  "aria-checked": on,
@@ -20830,7 +22222,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
20830
22222
  disabled: locked,
20831
22223
  onClick: () => void toggle(expert)
20832
22224
  },
20833
- /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
22225
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-card-switch-knob" })
20834
22226
  )));
20835
22227
  })))), visible.length === 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react.default.createElement(
20836
22228
  "div",
@@ -21120,9 +22512,7 @@ function openSubagentSession(ctx, item) {
21120
22512
  }
21121
22513
  }
21122
22514
  var JOB_DOCK_POS_KEY = "t-team:jobs-dock:v1";
21123
- var JOB_BADGE_POS_KEY = "t-team:jobs-badge:v1";
21124
- var JOB_BADGE_DEFAULT = { left: 0, top: 108 };
21125
- var JOB_BADGE_ESTIMATE_WIDTH = 180;
22515
+ var JOB_DOCK_CLOSED_KEY = "t-team:jobs-closed:v1";
21126
22516
  var JOB_DOCK_DEFAULT = { left: 18, top: 112 };
21127
22517
  var JOB_DOCK_MARGIN = 8;
21128
22518
  var JOB_DOCK_PANEL_WIDTH = 380;
@@ -21132,26 +22522,6 @@ var JOB_DOCK_DRAG_THRESHOLD = 4;
21132
22522
  function nonNegative(value, fallback) {
21133
22523
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback();
21134
22524
  }
21135
- function readBadgePos() {
21136
- const fallback = { left: JOB_DOCK_MARGIN, top: JOB_BADGE_DEFAULT.top };
21137
- if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
21138
- try {
21139
- const raw = window.localStorage.getItem(JOB_BADGE_POS_KEY);
21140
- if (raw !== null) {
21141
- const parsed = JSON.parse(raw);
21142
- if (typeof parsed?.left === "number" && typeof parsed?.top === "number") {
21143
- return clampJobDockPos(parsed, { offsetWidth: JOB_BADGE_ESTIMATE_WIDTH });
21144
- }
21145
- }
21146
- } catch {
21147
- }
21148
- }
21149
- const computed = clampJobDockPos({
21150
- left: (typeof window === "undefined" ? JOB_DOCK_MARGIN : window.innerWidth) - JOB_BADGE_ESTIMATE_WIDTH,
21151
- top: JOB_BADGE_DEFAULT.top
21152
- }, { offsetWidth: JOB_BADGE_ESTIMATE_WIDTH });
21153
- return Number.isFinite(computed.left) && Number.isFinite(computed.top) ? computed : fallback;
21154
- }
21155
22525
  function clampJobDockPos(pos, panel) {
21156
22526
  const viewport = typeof document === "undefined" ? void 0 : document.documentElement;
21157
22527
  const width = nonNegative(viewport?.clientWidth, () => nonNegative(
@@ -21185,124 +22555,136 @@ function readJobDockPos() {
21185
22555
  return JOB_DOCK_DEFAULT;
21186
22556
  }
21187
22557
  }
22558
+ var dockUi = { open: false };
22559
+ var dockListeners = /* @__PURE__ */ new Set();
22560
+ function setDockOpen(open2) {
22561
+ if (open2 === dockUi.open) return;
22562
+ dockUi = { open: open2 };
22563
+ for (const listener of dockListeners) listener();
22564
+ }
22565
+ function useDockUi() {
22566
+ return import_react.default.useSyncExternalStore(
22567
+ (onChange) => {
22568
+ dockListeners.add(onChange);
22569
+ return () => dockListeners.delete(onChange);
22570
+ },
22571
+ () => dockUi,
22572
+ () => dockUi
22573
+ );
22574
+ }
22575
+ function jobDockPerfReset() {
22576
+ try {
22577
+ performance.clearMarks("t-team-jobs-open");
22578
+ performance.mark("t-team-jobs-open");
22579
+ } catch {
22580
+ }
22581
+ }
22582
+ function jobDockPerfReport(stage) {
22583
+ try {
22584
+ const marks = performance.getEntriesByName("t-team-jobs-open", "mark");
22585
+ const start = marks[marks.length - 1];
22586
+ if (start === void 0) return;
22587
+ console.debug(`[t-team] \u4EFB\u52A1\u9762\u677F${stage} ${Math.round(performance.now() - start.startTime)}ms`);
22588
+ } catch {
22589
+ }
22590
+ }
22591
+ function JobsBadge({ t, ctx }) {
22592
+ const { rows, liveCount, subagents, subagentsRunning } = useJobRows(ctx);
22593
+ const showBadge = useShowTaskBadge();
22594
+ const ui = useDockUi();
22595
+ import_react.default.useEffect(() => {
22596
+ if (!showBadge) setDockOpen(false);
22597
+ }, [showBadge]);
22598
+ if (!showBadge) return null;
22599
+ if (rows.length === 0 && subagents.length === 0) return null;
22600
+ const anyLive = liveCount > 0 || subagentsRunning > 0;
22601
+ const badgeText = [
22602
+ subagents.length > 0 ? subagentsRunning > 0 ? t("tasks.subagentRunningCount", { running: subagentsRunning }) : t("tasks.subagentCount", { total: subagents.length }) : void 0,
22603
+ rows.length > 0 ? liveCount > 0 ? t("tasks.jobRunningCount", { running: liveCount }) : t("tasks.jobCount", { total: rows.length }) : void 0
22604
+ ].filter(Boolean).join(" \xB7 ");
22605
+ return /* @__PURE__ */ import_react.default.createElement(
22606
+ "button",
22607
+ {
22608
+ className: "t-team-job-badge",
22609
+ type: "button",
22610
+ "data-testid": "t-team-job-badge",
22611
+ "data-live": anyLive,
22612
+ "aria-expanded": ui.open,
22613
+ title: t("tasks.badgeTitle"),
22614
+ onClick: () => {
22615
+ const next = !ui.open;
22616
+ setDockOpen(next);
22617
+ if (next) jobDockPerfReset();
22618
+ try {
22619
+ if (next) window.localStorage.removeItem(JOB_DOCK_CLOSED_KEY);
22620
+ else window.localStorage.setItem(JOB_DOCK_CLOSED_KEY, "1");
22621
+ } catch {
22622
+ }
22623
+ }
22624
+ },
22625
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-dot", "data-live": anyLive, "aria-hidden": "true" }),
22626
+ /* @__PURE__ */ import_react.default.createElement("span", null, t("tab.tasks")),
22627
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-count" }, badgeText)
22628
+ );
22629
+ }
21188
22630
  function JobsDock({ t, ctx, preview }) {
21189
22631
  const { rows, liveCount, subagents, subagentsRunning, now } = useJobRows(ctx);
21190
- const [open2, setOpen] = import_react.default.useState(preview?.open === true);
22632
+ const showDock = useShowTaskBadge();
22633
+ const ui = useDockUi();
22634
+ const open2 = preview?.open === true ? true : ui.open;
21191
22635
  const [panelTab, setPanelTab] = import_react.default.useState(preview?.tab ?? "subagents");
21192
22636
  const [pos, setPos] = import_react.default.useState(() => clampJobDockPos(readJobDockPos(), { offsetWidth: JOB_DOCK_PANEL_WIDTH }));
21193
22637
  const dragRef = import_react.default.useRef(void 0);
21194
22638
  const panelRef = import_react.default.useRef(null);
21195
- const badgeRef = import_react.default.useRef(null);
21196
- const badgeDragRef = import_react.default.useRef(void 0);
21197
- const badgeMovedRef = import_react.default.useRef(false);
21198
- const [badgePos, setBadgePos] = import_react.default.useState(readBadgePos);
21199
- const closedByUserRef = import_react.default.useRef(false);
21200
- const wasEmptyRef = import_react.default.useRef(true);
21201
22639
  import_react.default.useEffect(() => {
21202
- const empty = rows.length === 0;
21203
- const wasEmpty = wasEmptyRef.current;
21204
- wasEmptyRef.current = empty;
21205
- if (empty) {
21206
- closedByUserRef.current = false;
21207
- return;
21208
- }
21209
- if (wasEmpty && !closedByUserRef.current) setOpen(true);
21210
- }, [rows.length]);
21211
- const badgePlacedRef = import_react.default.useRef(false);
22640
+ if (ui.open) return void 0;
22641
+ const rows_ = rows.length;
22642
+ const subs_ = subagents.length;
22643
+ return () => {
22644
+ void rows_;
22645
+ void subs_;
22646
+ };
22647
+ }, [ui.open, rows.length, subagents.length]);
21212
22648
  import_react.default.useEffect(() => {
21213
- if (badgePlacedRef.current) return;
21214
- badgePlacedRef.current = true;
21215
- const el = badgeRef.current;
21216
- let saved;
21217
- try {
21218
- saved = window.localStorage.getItem(JOB_BADGE_POS_KEY);
21219
- } catch {
21220
- saved = null;
21221
- }
21222
- if (saved !== null) {
21223
- setBadgePos((current) => clampJobDockPos(current, el));
21224
- return;
21225
- }
21226
- const width = el?.offsetWidth ?? JOB_BADGE_ESTIMATE_WIDTH;
21227
- setBadgePos(clampJobDockPos({
21228
- left: window.innerWidth - width - JOB_DOCK_MARGIN,
21229
- top: JOB_BADGE_DEFAULT.top
21230
- }, el));
21231
- }, []);
22649
+ if (!open2) return void 0;
22650
+ const onResize = () => setPos((current) => clampJobDockPos(current, panelRef.current));
22651
+ window.addEventListener("resize", onResize);
22652
+ return () => window.removeEventListener("resize", onResize);
22653
+ }, [open2]);
21232
22654
  import_react.default.useEffect(() => {
21233
22655
  if (!open2) return void 0;
21234
22656
  const sessions = ctx?.sessions;
21235
- const list = sessions?.list?.getSnapshot?.();
21236
- const rootId = list?.current;
22657
+ const rootId = sessions?.list?.getSnapshot?.()?.current;
21237
22658
  if (rootId === void 0) return void 0;
21238
- try {
21239
- sessions.setSubagentCatalogOpen?.(rootId, true);
21240
- void sessions.refreshSubagents?.(rootId);
21241
- } catch {
21242
- }
22659
+ const timer = window.setTimeout(() => {
22660
+ try {
22661
+ sessions.setSubagentCatalogOpen?.(rootId, true);
22662
+ void sessions.refreshSubagents?.(rootId);
22663
+ } catch {
22664
+ }
22665
+ }, 120);
21243
22666
  return () => {
22667
+ window.clearTimeout(timer);
21244
22668
  try {
21245
22669
  sessions.setSubagentCatalogOpen?.(rootId, false);
21246
22670
  } catch {
21247
22671
  }
21248
22672
  };
21249
22673
  }, [open2, ctx]);
21250
- import_react.default.useEffect(() => {
21251
- if (!open2) return void 0;
21252
- const onResize = () => setPos((current) => clampJobDockPos(current, panelRef.current));
21253
- window.addEventListener("resize", onResize);
21254
- return () => window.removeEventListener("resize", onResize);
22674
+ import_react.default.useLayoutEffect(() => {
22675
+ if (open2) jobDockPerfReport("\u5DF2\u53EF\u89C1");
22676
+ return void 0;
21255
22677
  }, [open2]);
21256
- const multiOwner = new Set(rows.map((row) => row.ownerSessionId)).size > 1;
22678
+ if (!showDock) return null;
22679
+ if (!open2) return null;
22680
+ jobDockPerfReport("\u5DF2\u6E32\u67D3");
21257
22681
  if (rows.length === 0 && subagents.length === 0) return null;
21258
- const anyLive = liveCount > 0 || subagentsRunning > 0;
21259
- const badgeText = [
21260
- subagents.length > 0 ? subagentsRunning > 0 ? t("tasks.subagentRunningCount", { running: subagentsRunning }) : t("tasks.subagentCount", { total: subagents.length }) : void 0,
21261
- rows.length > 0 ? liveCount > 0 ? t("tasks.jobRunningCount", { running: liveCount }) : t("tasks.jobCount", { total: rows.length }) : void 0
21262
- ].filter(Boolean).join(" \xB7 ");
21263
- function startBadgeDrag(event) {
21264
- if (event.button !== void 0 && event.button !== 0) return;
21265
- event.currentTarget.setPointerCapture?.(event.pointerId);
21266
- badgeMovedRef.current = false;
21267
- badgeDragRef.current = {
21268
- pointerId: event.pointerId,
21269
- startX: event.clientX,
21270
- startY: event.clientY,
21271
- originLeft: badgePos.left,
21272
- originTop: badgePos.top
21273
- };
21274
- }
21275
- function moveBadgeDrag(event) {
21276
- const drag = badgeDragRef.current;
21277
- if (drag === void 0 || drag.pointerId !== event.pointerId) return;
21278
- const dx = event.clientX - drag.startX;
21279
- const dy = event.clientY - drag.startY;
21280
- if (Math.abs(dx) + Math.abs(dy) >= JOB_DOCK_DRAG_THRESHOLD) badgeMovedRef.current = true;
21281
- if (!badgeMovedRef.current) return;
21282
- setBadgePos(clampJobDockPos({ left: drag.originLeft + dx, top: drag.originTop + dy }, badgeRef.current));
21283
- }
21284
- function endBadgeDrag(event) {
21285
- const drag = badgeDragRef.current;
21286
- badgeDragRef.current = void 0;
21287
- if (drag === void 0 || drag.pointerId !== event.pointerId) return;
21288
- if (!badgeMovedRef.current) return;
21289
- try {
21290
- window.localStorage.setItem(JOB_BADGE_POS_KEY, JSON.stringify(badgePos));
21291
- } catch {
21292
- }
21293
- }
22682
+ const multiOwner = new Set(rows.map((row) => row.ownerSessionId)).size > 1;
21294
22683
  function startDrag(event) {
21295
22684
  if (event.button !== void 0 && event.button !== 0) return;
21296
22685
  event.preventDefault();
21297
22686
  event.currentTarget.setPointerCapture?.(event.pointerId);
21298
- dragRef.current = {
21299
- pointerId: event.pointerId,
21300
- startX: event.clientX,
21301
- startY: event.clientY,
21302
- originLeft: pos.left,
21303
- originTop: pos.top,
21304
- moved: false
21305
- };
22687
+ dragRef.current = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, originLeft: pos.left, originTop: pos.top, moved: false };
21306
22688
  }
21307
22689
  function moveDrag(event) {
21308
22690
  const drag = dragRef.current;
@@ -21311,10 +22693,7 @@ function JobsDock({ t, ctx, preview }) {
21311
22693
  const dy = event.clientY - drag.startY;
21312
22694
  if (!drag.moved && Math.abs(dx) + Math.abs(dy) < JOB_DOCK_DRAG_THRESHOLD) return;
21313
22695
  drag.moved = true;
21314
- setPos(clampJobDockPos(
21315
- { left: drag.originLeft + dx, top: drag.originTop + dy },
21316
- panelRef.current
21317
- ));
22696
+ setPos(clampJobDockPos({ left: drag.originLeft + dx, top: drag.originTop + dy }, panelRef.current));
21318
22697
  }
21319
22698
  function endDrag(event) {
21320
22699
  const drag = dragRef.current;
@@ -21326,34 +22705,7 @@ function JobsDock({ t, ctx, preview }) {
21326
22705
  } catch {
21327
22706
  }
21328
22707
  }
21329
- return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
21330
- "button",
21331
- {
21332
- className: "t-team-job-badge",
21333
- type: "button",
21334
- ref: badgeRef,
21335
- "data-testid": "t-team-job-badge",
21336
- "data-live": anyLive,
21337
- "data-dragging": badgeDragRef.current === void 0 ? void 0 : "true",
21338
- style: { left: badgePos.left, top: badgePos.top },
21339
- "aria-expanded": open2,
21340
- title: t("tasks.badgeTitle"),
21341
- onPointerDown: startBadgeDrag,
21342
- onPointerMove: moveBadgeDrag,
21343
- onPointerUp: endBadgeDrag,
21344
- onPointerCancel: endBadgeDrag,
21345
- onClick: () => {
21346
- if (badgeMovedRef.current) {
21347
- badgeMovedRef.current = false;
21348
- return;
21349
- }
21350
- setOpen((value) => !value);
21351
- }
21352
- },
21353
- /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-dot", "data-live": anyLive, "aria-hidden": "true" }),
21354
- /* @__PURE__ */ import_react.default.createElement("span", null, t("tab.tasks")),
21355
- /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-badge-count" }, badgeText)
21356
- ), open2 && /* @__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(
22708
+ 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(
21357
22709
  "button",
21358
22710
  {
21359
22711
  className: "t-team-job-panel-close",
@@ -21361,29 +22713,18 @@ function JobsDock({ t, ctx, preview }) {
21361
22713
  title: t("button.close"),
21362
22714
  onPointerDown: (event) => event.stopPropagation(),
21363
22715
  onClick: () => {
21364
- closedByUserRef.current = true;
21365
- setOpen(false);
22716
+ setDockOpen(false);
22717
+ try {
22718
+ window.localStorage.setItem(JOB_DOCK_CLOSED_KEY, "1");
22719
+ } catch {
22720
+ }
21366
22721
  }
21367
22722
  },
21368
22723
  "\u2715"
21369
22724
  )), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-job-panel-tabs", role: "tablist" }, [
21370
22725
  ["subagents", "tasks.subagents", subagentsRunning > 0 ? `${subagents.length} \xB7 ${subagentsRunning}` : String(subagents.length)],
21371
22726
  ["jobs", "tab.tasks", liveCount > 0 ? `${rows.length} \xB7 ${liveCount}` : String(rows.length)]
21372
- ].map(([key, labelKey, count]) => /* @__PURE__ */ import_react.default.createElement(
21373
- "button",
21374
- {
21375
- className: "t-team-tab",
21376
- type: "button",
21377
- role: "tab",
21378
- key,
21379
- "data-active": panelTab === key,
21380
- "aria-selected": panelTab === key,
21381
- onClick: () => setPanelTab(key)
21382
- },
21383
- t(labelKey),
21384
- " ",
21385
- /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-job-tab-count" }, count)
21386
- ))), /* @__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 }))));
22727
+ ].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 })));
21387
22728
  }
21388
22729
  function squadToInput(squad) {
21389
22730
  return {
@@ -21772,7 +23113,7 @@ function insertAtTarget(target, reference) {
21772
23113
  }
21773
23114
  function SummonButton({ t, ctx, remote, getActive, insertReference, fillSquadCommand, sessionId, preview }) {
21774
23115
  const [open2, setOpen] = import_react.default.useState(preview?.open === true);
21775
- const [popTab, setPopTab] = import_react.default.useState(preview?.tab ?? "tasks");
23116
+ const [popTab, setPopTab] = import_react.default.useState(preview?.tab ?? "experts");
21776
23117
  const [squads, setSquads] = import_react.default.useState(preview?.squads ?? null);
21777
23118
  const [teams, setTeams] = import_react.default.useState(preview?.teams ?? null);
21778
23119
  const [squadQuery, setSquadQuery] = import_react.default.useState("");
@@ -21828,9 +23169,9 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, fillSquadCom
21828
23169
  }
21829
23170
  const active = getActive();
21830
23171
  const teamCount = teams?.length ?? 0;
21831
- const popTabs = [["tasks", "tab.tasks"], ["experts", "tab.experts"], ["squads", "tab.squads"], ...teamCount > 0 ? [["teams", "tab.teams"]] : []];
23172
+ const popTabs = [["experts", "tab.experts"], ["squads", "tab.squads"], ...teamCount > 0 ? [["teams", "tab.teams"]] : [], ["tasks", "tab.tasks"]];
21832
23173
  import_react.default.useEffect(() => {
21833
- if (popTab === "teams" && teamCount === 0) setPopTab("tasks");
23174
+ if (popTab === "teams" && teamCount === 0) setPopTab("experts");
21834
23175
  }, [popTab, teamCount]);
21835
23176
  const squadNeedle = squadQuery.trim().toLowerCase();
21836
23177
  const visibleSquads = (squads?.squads ?? []).filter((squad) => {
@@ -21983,6 +23324,14 @@ async function apply(ctx) {
21983
23324
  await refresh(remote, true).catch((cause) => {
21984
23325
  console.warn("[t-team] \u521D\u59CB\u540D\u518C\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BBE\u7F6E\u9875\u53EF\u91CD\u8BD5\uFF1A", cause);
21985
23326
  });
23327
+ void (async () => {
23328
+ try {
23329
+ const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
23330
+ setUiPrefs({ showTaskBadge: data?.showTaskBadge, showScheduleButton: data?.showScheduleButton });
23331
+ } catch (cause) {
23332
+ 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);
23333
+ }
23334
+ })();
21986
23335
  const refreshCatalog = { current: void 0 };
21987
23336
  ctx.slots.inject("settings.section", () => ctx.slots.register({
21988
23337
  name: "settings.section",
@@ -21993,6 +23342,60 @@ async function apply(ctx) {
21993
23342
  locale: NS,
21994
23343
  icon: "expert"
21995
23344
  }, (props) => import_react.default.createElement(SettingsPanel, { ...props, t: ctx.locale.bind(NS), remote, getActive, refreshCatalog })));
23345
+ ctx.slots.inject("sidebar.panellist", () => {
23346
+ let disposeEntry;
23347
+ const sync = () => {
23348
+ const want = scheduleEntryVisible();
23349
+ if (want === (disposeEntry !== void 0)) return;
23350
+ if (!want) {
23351
+ disposeEntry?.();
23352
+ disposeEntry = void 0;
23353
+ return;
23354
+ }
23355
+ try {
23356
+ disposeEntry = ctx.slots.register({
23357
+ name: "sidebar.panellist",
23358
+ id: SCHEDULE_PANEL_KEY,
23359
+ // order 取最小:侧栏那一组里它排在最前,紧贴「新会话」按钮。
23360
+ order: 1,
23361
+ label: () => ctx.locale.bind(NS)("sched.nav"),
23362
+ locale: NS
23363
+ }, (props) => import_react.default.createElement(ScheduleGlyph, { size: props?.size ?? 16 }));
23364
+ } catch (cause) {
23365
+ console.warn("[t-team] \u4FA7\u680F\u5B9A\u65F6\u4EFB\u52A1\u5165\u53E3\u6CE8\u518C\u5931\u8D25\uFF1A", cause);
23366
+ disposeEntry = void 0;
23367
+ }
23368
+ };
23369
+ const unsubscribe = subscribeUiPrefs(sync);
23370
+ sync();
23371
+ return () => {
23372
+ unsubscribe();
23373
+ disposeEntry?.();
23374
+ disposeEntry = void 0;
23375
+ };
23376
+ });
23377
+ ctx.slots.inject("main", () => ctx.slots.register({
23378
+ name: "main",
23379
+ key: SCHEDULE_PANEL_KEY,
23380
+ locale: NS
23381
+ }, (props) => import_react.default.createElement(SchedulePanel, {
23382
+ ...props,
23383
+ t: ctx.locale.bind(NS),
23384
+ remote,
23385
+ getActive,
23386
+ ctx: props?.ctx ?? ctx
23387
+ })));
23388
+ ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
23389
+ name: "conversation.session.header.utilities",
23390
+ id: `${NS}-jobs-badge`,
23391
+ order: 10,
23392
+ label: () => ctx.locale.bind(NS)("tab.tasks"),
23393
+ locale: NS
23394
+ }, (props) => import_react.default.createElement(JobsBadge, {
23395
+ ...props,
23396
+ t: ctx.locale.bind(NS),
23397
+ ctx: props?.ctx ?? ctx
23398
+ })));
21996
23399
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({
21997
23400
  name: "shell.overlay",
21998
23401
  id: `${NS}-jobs`,