// screen_agent_chat.jsx — skill launch destination initialized from the workflow library
(function () {
  const { useState, useEffect } = React;
  const h = React.createElement;
  window.Screens = window.Screens || {};
  const { Badge, Button, PageHeader, Icon } = window;

  const COLORS = ["#2f7fe0", "#12a877", "#6f5be6", "#d98a12", "#e0484d", "#0e9fba", "#8b5cf6", "#2f9e44", "#c2410c", "#2563eb", "#7c3aed", "#0f766e"];
  const STAGE_TONE = { Start: "blue", Buy: "green", Extend: "violet", Build: "amber" };

  function textOf(v) { return String(v == null ? "" : v); }
  function useScenarioLang() {
    return window.useScenarioLang ? window.useScenarioLang() : "en";
  }
  function scenarioText(v, lang) {
    return window.scenarioText ? window.scenarioText(v, lang) : textOf(v);
  }
  function zhText(v, lang) {
    return window.scenarioZhText ? window.scenarioZhText(v, lang) : v;
  }
  function uiText(v, lang) {
    return window.scenarioUiText ? window.scenarioUiText(v, lang) : v;
  }
  function unique(arr) { return Array.from(new Set(arr.filter(Boolean))); }
  function capabilitiesOf(skill) { return unique(skill.products || []).slice(0, 5); }
  function stageLabel(skill, lang) { return (skill.stage && skill.stage.length) ? skill.stage.map((s) => scenarioText(s, lang)).join(" + ") : uiText("Task", lang); }
  function outputFormatText(value, lang) {
    const source = value || "Approval packet";
    const en = { "Approval packet": "My Desk item", "Work order": "Task" };
    const zh = { "Approval packet": "我的辦公桌項目", "Customer reply": "客戶回覆", "Internal brief": "內部摘要", "Table report": "表格報告", "Work order": "任務" };
    return lang === "en" ? (en[source] || source) : zhText(zh[source] || source, lang);
  }
  function stageTone(skill) { return STAGE_TONE[(skill.stage || [])[0]] || "neutral"; }
  function colorFor(skill, skills) {
    const slugs = unique(skills.map((s) => s.areaSlug));
    const idx = Math.max(0, slugs.indexOf(skill.areaSlug));
    return COLORS[idx % COLORS.length];
  }
  const AGENT_LAUNCH_INTENT_KEY = "emplix-agent-launch-intent";
  const AGENT_SETUP_DRAFT_KEY = "emplix-agent-setup-drafts-v1";
  const AGENT_LAUNCH_TTL_MS = 2 * 60 * 60 * 1000;
  const AGENT_SETUP_DRAFT_TTL_MS = 24 * 60 * 60 * 1000;
  function safeReadSessionJson(key) {
    try { return JSON.parse(sessionStorage.getItem(key) || "null"); } catch (e) { return null; }
  }
  function safeWriteSessionJson(key, value) {
    try { sessionStorage.setItem(key, JSON.stringify(value)); } catch (e) { /* best effort persistence */ }
  }
  function readAgentLaunchIntent(skillId) {
    try {
      const intent = safeReadSessionJson(AGENT_LAUNCH_INTENT_KEY);
      if (intent && intent.at && Date.now() - intent.at > AGENT_LAUNCH_TTL_MS) return null;
      return intent && intent.skillId === skillId ? intent : null;
    } catch (e) {
      return null;
    }
  }
  function agentSetupDraftScope(skillId, workOrderId) {
    return textOf(skillId) + "::" + (workOrderId ? textOf(workOrderId) : "new");
  }
  function readAgentSetupDraft(skillId, workOrderId) {
    if (!skillId) return null;
    const all = safeReadSessionJson(AGENT_SETUP_DRAFT_KEY) || {};
    const draft = all[agentSetupDraftScope(skillId, workOrderId)];
    if (!draft || draft.skillId !== skillId) return null;
    if (draft.at && Date.now() - draft.at > AGENT_SETUP_DRAFT_TTL_MS) return null;
    return draft;
  }
  function writeAgentSetupDraft(skillId, workOrderId, draft) {
    if (!skillId || !draft) return;
    const all = safeReadSessionJson(AGENT_SETUP_DRAFT_KEY) || {};
    const key = agentSetupDraftScope(skillId, workOrderId);
    all[key] = {
      skillId,
      workOrderId: workOrderId || "",
      setup: draft.setup || null,
      text: textOf(draft.text).slice(0, 4000),
      selectedStep: typeof draft.selectedStep === "number" ? draft.selectedStep : 0,
      at: Date.now(),
    };
    safeWriteSessionJson(AGENT_SETUP_DRAFT_KEY, all);
  }
  function clearAgentSetupDraft(skillId, workOrderId) {
    if (!skillId) return;
    const all = safeReadSessionJson(AGENT_SETUP_DRAFT_KEY) || {};
    delete all[agentSetupDraftScope(skillId, workOrderId)];
    if (workOrderId) delete all[agentSetupDraftScope(skillId, null)];
    safeWriteSessionJson(AGENT_SETUP_DRAFT_KEY, all);
  }
  function stepsOf(skill) { return skill.steps || []; }
  function finishSentence(value, mark) {
    const text = String(value == null ? "" : value).trim();
    if (!text || /[.!?。！？…]$/.test(text)) return text;
    return text + (mark || ".");
  }
  function starterPrompt(skill, lang) {
    if (lang !== "en") {
      return zhText("為 [團隊／客戶／情境] 完成「" + scenarioText(skill.title, lang) + "」。只使用已批准檔案。", lang);
    }
    return "Complete \"" + skill.title + "\" for [team/customer/context]. Use approved files.";
  }
  function stepPrompt(skill, step, index, total, lang) {
    if (!step) return starterPrompt(skill, lang);
    if (lang !== "en") {
      return zhText("第 " + (index + 1) + "/" + total + " 步：" + finishSentence(scenarioText(step.title, lang), "。") + "使用 " + finishSentence(scenarioText(step.tool || "指定應用程式", lang), "。") + "結果：" + finishSentence(scenarioText(step.outcome || step.detail || "準備下一步", lang), "。") + "列出所用或缺少的檔案。", lang);
    }
    return "Step " + (index + 1) + " of " + total + ": " + finishSentence(step.title) + " Use " + finishSentence(step.tool || "the assigned app") + " Result: " + finishSentence(step.outcome || step.detail || "prepare the next step") + " Name the file used or say what is missing.";
  }
  function roleForSkill(skill, ctx) {
    const area = textOf(skill.area).toLowerCase();
    if (/customer|service|support/.test(area) && ctx.office.roleById.cs) return "cs";
    if (/sales|retail|marketing|communications/.test(area) && ctx.office.roleById.sales) return "sales";
    if (/social|community/.test(area) && ctx.office.roleById.social) return "social";
    if (ctx.office.roleById.clerk) return "clerk";
    return ((ctx.office.roles || []).find((r) => r.hired) || (ctx.office.roles || [])[0] || {}).id || "clerk";
  }
	  function roleName(roleId, role) {
	    return (window.roleDisplayName && role) ? window.roleDisplayName(role, roleId, { name: (window.ROLE_SHORT_EN && window.ROLE_SHORT_EN[roleId]) || "AI Employee" }) : ((window.ROLE_SHORT_EN && window.ROLE_SHORT_EN[roleId]) || (role && role.title) || "AI Employee");
	  }
	  function agentSourceChoices(ctx, roleId) {
	    const files = (ctx.office && ctx.office.files) || [];
	    const roleFiles = files.filter((f) => (f.usedBy || []).indexOf(roleId) >= 0);
	    return (roleFiles.length ? roleFiles : files).slice(0, 12);
	  }
	  function agentOwnerChoices(ctx) {
	    const users = ((ctx.office && ctx.office.companyUsers) || []).filter((u) => u.status !== "Removed");
	    return users.length ? users : [{ id: "u-owner", name: "Business Owner", level: "owner" }];
	  }
	  function defaultAgentSetup(skill, ctx, persistedWo) {
	    const roleId = (persistedWo && persistedWo.emp && ctx.office.roleById[persistedWo.emp]) ? persistedWo.emp : (skill ? roleForSkill(skill, ctx) : "clerk");
	    const source = agentSourceChoices(ctx, roleId)[0] || null;
	    const owner = agentOwnerChoices(ctx).find((u) => u.level === "owner" && u.status === "Active") || agentOwnerChoices(ctx)[0] || {};
	    return {
	      roleId,
	      sourceFileId: source ? source.id : "",
	      outputFormat: "Approval packet",
	      ownerId: owner.id || "u-owner",
	      deadline: "Today 17:00",
	      risk: "Medium",
	      sla: "4h",
	    };
	  }
	  function agentSetupOwnerName(ctx, ownerId) {
	    const owner = agentOwnerChoices(ctx).find((u) => u.id === ownerId);
	    return (owner && owner.name) || "Business Owner";
	  }
	  function normalizedAgentSetup(setup, skill, ctx) {
	    const base = Object.assign(defaultAgentSetup(skill, ctx, null), setup || {});
	    const roleId = ctx.office.roleById[base.roleId] ? base.roleId : defaultAgentSetup(skill, ctx, null).roleId;
	    const sources = agentSourceChoices(ctx, roleId);
	    const sourceFileId = sources.some((f) => f.id === base.sourceFileId) ? base.sourceFileId : ((sources[0] || {}).id || "");
	    const owners = agentOwnerChoices(ctx);
	    const ownerId = owners.some((u) => u.id === base.ownerId) ? base.ownerId : ((owners[0] || {}).id || "u-owner");
	    return Object.assign({}, base, { roleId, sourceFileId, ownerId });
	  }
	  function workOrderId(ctx) {
    const board = ctx.office.workOrders || {};
    const ids = Object.keys(board).flatMap((col) => board[col] || [])
      .map((w) => parseInt(String(w.id || "").replace("WO-", ""), 10)).filter((n) => !isNaN(n));
    return "WO-" + ((ids.length ? Math.max.apply(null, ids) : 2040) + 1);
  }
  function parseAgentArg(arg) {
    const raw = textOf(arg);
    const parts = raw.split("~");
    return { skillId: parts[0] || "", workOrderId: parts[1] || null };
  }
  function agentRouteArg(skillId, workOrderId) {
    return skillId + (workOrderId ? "~" + workOrderId : "");
  }
  function allWorkOrders(ctx) {
    const board = (ctx.office && ctx.office.workOrders) || {};
    return ["Intake", "Planning", "Running", "Needs Approval", "Completed"].flatMap((col) => (board[col] || []).map((wo) => Object.assign({ col }, wo)));
  }
  function findSkillWorkOrder(ctx, skill, workOrderId) {
    if (!skill) return null;
    if (workOrderId) {
      const exact = allWorkOrders(ctx).find((wo) => wo.id === workOrderId);
      if (exact && exact.workflow && exact.workflow.skillId === skill.id) return exact;
      return null;
    }
    return latestSkillWorkOrder(ctx, skill);
  }
  function latestSkillWorkOrder(ctx, skill) {
    if (!skill) return null;
    const rows = allWorkOrders(ctx).filter((wo) => wo.workflow && wo.workflow.skillId === skill.id && !wo.workflow.cancelled && wo.workflow.approvalStatus !== "approved");
    rows.sort((a, b) => parseInt(String(b.id || "").replace("WO-", ""), 10) - parseInt(String(a.id || "").replace("WO-", ""), 10));
    return rows[0] || null;
  }
  function isRestartableWorkflow(wf) {
    return !!(wf && (wf.cancelled || wf.status === "revision_required" || wf.workflowState === "revision" || wf.approvalStatus === "rejected"));
  }
  function isApprovedWorkflow(wf, col) {
    return !!(wf && (wf.status === "approved" || wf.workflowState === "approved" || wf.approvalStatus === "approved")) || col === "Completed";
  }
  function eventsFromWorkOrder(wo, steps) {
    if (!wo || !wo.workflow) return [];
    if (isRestartableWorkflow(wo.workflow)) return [];
    const done = wo.workflow.completedSteps || [];
    const evidenceByIndex = {};
    (wo.workflow.evidence || []).forEach((ev) => { if (typeof ev.index === "number") evidenceByIndex[ev.index] = ev; });
    const evs = [{ kind: "run", id: wo.id, step: steps[wo.workflow.currentStep || 0] || steps[0] || null }];
    done.forEach((idx) => {
      const evidence = evidenceByIndex[idx] || null;
      if (evidence && evidence.note) evs.push({ kind: "user", index: idx, text: evidence.note });
      evs.push({ kind: "step", index: idx, step: steps[idx] || null, evidence });
    });
    if (wo.workflow.approvalId) evs.push({ kind: "approval", id: wo.workflow.approvalId });
    return evs;
  }
  function textForState(skill, wo, steps, lang) {
    if (!wo || !wo.workflow) return starterPrompt(skill, lang);
    if (isRestartableWorkflow(wo.workflow)) {
      return lang === "en"
        ? "Returned. Update the note or files, then restart this task."
        : zhText("已退回。更新備註或檔案，然後重新開始任務。", lang);
    }
    if (isApprovedWorkflow(wo.workflow, wo.col)) {
      return lang === "en"
        ? "Approved. The task, files, and History are still available."
        : zhText("已批准。任務、檔案和紀錄仍可查看。", lang);
    }
    if (wo.workflow.approvalId) {
      return lang === "en"
        ? "My Desk item ready for \"" + skill.title + "\". Review it before sending."
        : zhText("「" + scenarioText(skill.title, lang) + "」已送到我的辦公桌。發送前請覆核。", lang);
    }
    const step = steps[wo.workflow.currentStep || 0];
    return step ? stepPrompt(skill, step, wo.workflow.currentStep || 0, wo.workflow.totalSteps || steps.length || 1, lang) : starterPrompt(skill, lang);
  }
  function inputRows(skill, lang) {
    const rows = lang === "en" ? [
      "Who this is for",
      "Files or apps to use",
      "Owner, deadline, and approval rules",
      "Result: reply, note, report, table, or task",
    ] : [
      "用途和對象",
      "要使用的檔案或應用程式",
      "負責人、限期和批准規則",
      "結果：回覆、備註、報告、表格或任務",
    ].map((row) => zhText(row, lang));
    return rows.concat(capabilitiesOf(skill).slice(0, 1).map((c) => lang === "en" ? "Produces: " + c : zhText("產出：" + scenarioText(c, lang), lang)));
  }
  function suggestionText(skill, lang) {
    const caps = capabilitiesOf(skill);
    return lang === "en" ? unique([
      "Use the latest files",
      "Draft for approval",
      "List any assumptions",
      caps[0] ? "Use " + caps[0] : null,
    ]) : unique([
      zhText("使用最新檔案", lang),
      zhText("草擬供批准的版本", lang),
      zhText("列出任何假設", lang),
      caps[0] ? zhText("使用 " + scenarioText(caps[0], lang), lang) : null,
    ]);
  }
  function approvalLinesFor(skill, steps, completedSteps, text, lang, setup) {
    const done = (completedSteps || []).map((idx) => steps[idx]).filter(Boolean);
    const lines = [
      lang === "en" ? "My Desk item for: " + skill.title : zhText("我的辦公桌項目：" + scenarioText(skill.title, lang), lang),
      lang === "en" ? "Files: approved files only." : zhText("檔案：只使用已批准檔案。", lang),
    ];
    if (setup) {
      lines.push(lang === "en"
        ? "Task setup: " + (setup.sourceName || "Files") + " · " + outputFormatText(setup.outputFormat, lang) + " · owner " + (setup.ownerName || "Business Owner") + " · " + (setup.risk || "Medium") + " risk · target " + (setup.sla || "4h") + " · due " + (setup.deadline || "Today 17:00")
        : zhText("任務設定：" + (setup.sourceName || "檔案") + " · " + outputFormatText(setup.outputFormat, lang) + " · 負責人 " + (setup.ownerName || "Business Owner") + " · 風險 " + (setup.risk || "Medium") + " · 目標 " + (setup.sla || "4h") + " · 限期 " + (setup.deadline || "Today 17:00"), lang));
    }
    done.slice(0, 6).forEach((s, i) => {
      lines.push((i + 1) + ". " + scenarioText(s.title, lang) + " — " + scenarioText(s.outcome || s.detail || "Prepared the next task step.", lang));
    });
    const assumptions = String(text || "").split("\n").filter((line) => /^- /.test(line)).slice(0, 3).map((line) => line.replace(/^- /, ""));
    if (assumptions.length) lines.push((lang === "en" ? "Assumptions: " : zhText("假設：", lang)) + assumptions.join("; "));
    lines.push(lang === "en" ? "Next: the owner reviews this item in My Desk." : zhText("下一步：東主在我的辦公桌覆核此項目。", lang));
    return lines;
  }
  function sourceNameFromRun(run, lang) {
    const source = run && run.sources && run.sources[0];
    if (!source) return uiText("Files", lang);
    return scenarioText(source.file || source.name || "Files", lang);
  }
  function compactEvidenceNote(text, lang) {
    const clean = String(text || "").split("\n").map((line) => line.trim()).filter(Boolean).join(" ");
    if (clean) return clean.length > 190 ? clean.slice(0, 187) + "..." : clean;
    return uiText("No note added.", lang);
  }
  function evidenceSourceState(text, source) {
    const clean = String(text || "").toLowerCase();
    if (/missing source|source missing|no source|not enough source|not enough data|cannot verify|can't verify|unverified|unsupported|找不到|沒有來源|缺少來源|欠缺來源|未能核實/.test(clean)) return "missing";
    return (source && source.sourceState) || "matched";
  }
	  function evidenceRecord(step, index, run, lang, text) {
	    const s = step || {};
	    const source = run && run.sources && run.sources[0];
	    const sourceState = evidenceSourceState(text, source);
	    const sourceLabel = sourceNameFromRun(run, lang);
    const note = compactEvidenceNote(text, lang);
    const matched = sourceState !== "missing";
    return {
      index,
      title: scenarioText(s.title || "Step " + (index + 1), lang),
      tool: scenarioText(s.tool || "Assigned app", lang),
      outcome: scenarioText(s.outcome || s.detail || "Prepared the next task step.", lang),
      source: matched ? sourceLabel : sourceLabel + " · " + (lang === "en" ? "Missing file noted" : zhText("已記錄缺失檔案", lang)),
      sourceState,
      sourceOrigin: (source && (source.sourceOrigin || source.basis || source.source)) || "workspace",
      sourceSnippet: (source && source.snippet) || "",
      note,
	      summary: matched ? uiText("Note saved with this file check.", lang) : uiText("A file is missing. Add it or choose to continue without it.", lang),
      gate: matched ? (lang === "en" ? "File checked before approval" : zhText("審批前已檢查檔案", lang)) : (lang === "en" ? "Missing file recorded before approval" : zhText("審批前已記錄缺失檔案", lang)),
	      capturedAt: uiText("just now", lang),
	    };
	  }
	  function sourceGapEvidenceKey(ev, pos) {
	    const index = ev && typeof ev.index === "number" ? ev.index : pos;
	    return "evidence-" + (pos == null ? index : pos) + "-" + index;
	  }
	  function sourceGapKey(ev, pos) {
	    const index = ev && typeof ev.index === "number" ? ev.index : (typeof pos === "number" ? pos : 0);
	    return "step-" + index;
	  }
	  function sourceGapResolved(gap) {
	    if (!gap) return false;
	    const res = gap.resolution || gap.sourceGapResolution || {};
	    return gap.status === "source_attached" || gap.status === "owner_override" || res.type === "file-room-source" || res.type === "owner-override";
	  }
	  function sourceGapLabel(gap) {
	    const res = gap && (gap.resolution || gap.sourceGapResolution);
	    if (!res) return "";
	    if (res.type === "owner-override") return "Continued without file";
	    return res.fileName || res.file || "File attached";
	  }
	  function mergeSourceGaps(existing, evidence) {
	    const byKey = {};
	    (existing || []).forEach((gap) => {
	      if (!gap) return;
	      const key = gap.key || ("step-" + (typeof gap.stepIndex === "number" ? gap.stepIndex : 0));
	      byKey[key] = Object.assign({ key }, gap);
	    });
	    (evidence || []).forEach((ev, pos) => {
	      if (!ev || ev.sourceState !== "missing") return;
	      const key = sourceGapKey(ev, pos);
	      const prev = byKey[key] || {};
	      const resolution = prev.resolution || ev.sourceGapResolution || null;
	      const status = resolution
	        ? (resolution.type === "owner-override" ? "owner_override" : "source_attached")
	        : (sourceGapResolved(prev) ? prev.status : "open");
	      byKey[key] = Object.assign({}, prev, {
	        key,
	        evidenceKey: prev.evidenceKey || sourceGapEvidenceKey(ev, pos),
	        stepIndex: typeof ev.index === "number" ? ev.index : pos,
	        status,
	        title: ev.title || prev.title || ("Step " + ((typeof ev.index === "number" ? ev.index : pos) + 1)),
	        note: ev.note || prev.note || ev.summary || "Missing file recorded.",
	        source: ev.source || prev.source || "",
	        createdAt: prev.createdAt || ev.capturedAt || "just now",
	        resolution,
	      });
	    });
	    return Object.keys(byKey).sort((a, b) => {
	      const ai = typeof byKey[a].stepIndex === "number" ? byKey[a].stepIndex : 0;
	      const bi = typeof byKey[b].stepIndex === "number" ? byKey[b].stepIndex : 0;
	      return ai - bi;
	    }).map((key) => byKey[key]);
	  }
	  function unresolvedSourceGaps(workflow) {
	    return mergeSourceGaps((workflow && workflow.sourceGaps) || [], (workflow && workflow.evidence) || []).filter((gap) => !sourceGapResolved(gap));
	  }
	  window.agentSourceGapHelpers = {
	    evidenceKey: sourceGapEvidenceKey,
	    key: sourceGapKey,
	    merge: mergeSourceGaps,
	    unresolved: unresolvedSourceGaps,
	    resolved: sourceGapResolved,
	    label: sourceGapLabel,
	  };

	  function ChatMessage({ type, children }) {
    const isUser = type === "user";
    return h("div", { className: "ac-msg" + (isUser ? " user" : "") },
      h("div", { className: "ac-avatar" }, h(Icon, { name: isUser ? "user" : "sparkle", size: 15 })),
      h("div", { className: "ac-bubble" }, children));
  }

  function ContextPanel({ skill, color, currentStep, completedSteps, selectedStep, onInspectStep, onUseStep, canUsePrompts = true, denyReason = "", lang }) {
    const steps = stepsOf(skill);
    const inspected = steps[Math.max(0, Math.min(steps.length - 1, selectedStep || 0))] || null;
    const stepRows = steps.map((s, i) => {
      const done = completedSteps.indexOf(i) >= 0;
      const current = i === currentStep;
      const isInspected = i === selectedStep;
      return h("button", { key: i, type: "button", className: "ac-step" + (current ? " current" : "") + (done ? " done" : "") + (isInspected ? " inspected" : ""),
        "data-agent-context-step": String(i),
        "data-agent-step-index": String(i),
        "data-agent-step-current": current ? "true" : "false",
        "data-agent-step-done": done ? "true" : "false",
        "data-agent-step-inspected": isInspected ? "true" : "false",
        onClick: () => onInspectStep(i), "aria-expanded": isInspected ? "true" : "false", "aria-controls": isInspected ? "ac-step-detail-" + i : undefined, title: lang === "en" ? "Inspect step " + (i + 1) : zhText("檢視第 " + (i + 1) + " 步", lang) },
        h("i", null, done ? h(Icon, { name: "check", size: 12 }) : i + 1),
        h("div", null,
          h("b", null, scenarioText(s.title, lang)),
          h("span", null, scenarioText(s.outcome || s.detail || "Prepare the next task step.", lang)),
          current && h("span", { style: { color: "var(--blue-deep)", fontWeight: 800 } }, uiText("Current step · click Complete step in chat", lang)),
          isInspected && !current && h("span", { style: { color: "var(--green)", fontWeight: 800 } }, uiText("Inspecting step detail", lang)),
          h("span", { style: { marginTop: 4 } }, scenarioText(s.tool || "Assigned app", lang))));
    });
    return h("aside", { className: "ac-side" },
      h("section", { className: "ac-panel ac-context", style: { "--cat": color } },
        h("div", { className: "ac-context-head" },
          h("div", { className: "row gap6 wrap" },
            h(Badge, { tone: "blue" }, lang === "en" ? "Task guide" : zhText("任務指引", lang)),
            h(Badge, { tone: stageTone(skill) }, stageLabel(skill, lang))),
          h("h2", null, scenarioText(skill.title, lang)),
          h("p", null, scenarioText(skill.summary, lang))),
        h("div", { className: "ac-context-body" },
          h("div", null,
            h("div", { className: "ac-mini-title", style: { marginBottom: 8 } }, lang === "en" ? "What it can produce" : zhText("可產出的結果", lang)),
            h("div", { className: "row gap6 wrap" }, capabilitiesOf(skill).map((c) => h(Badge, { key: c, tone: "neutral" }, scenarioText(c, lang))))),
          h("div", null,
            h("div", { className: "ac-mini-title", style: { marginBottom: 6 } }, uiText("Task steps", lang)),
            stepRows,
            inspected && h("div", { id: "ac-step-detail-" + selectedStep, className: "ac-step-detail", "data-agent-context-step-detail": String(selectedStep), "data-agent-step-current": selectedStep === currentStep ? "true" : "false", "data-agent-step-done": completedSteps.indexOf(selectedStep) >= 0 ? "true" : "false" },
              h("div", { className: "ac-step-detail-head" },
                h("div", null,
                  h("b", null, scenarioText(inspected.title, lang)),
                  h("span", null, scenarioText(inspected.detail || inspected.outcome || "Prepare the next task step.", lang))),
                h(Badge, { tone: selectedStep === currentStep ? "blue" : completedSteps.indexOf(selectedStep) >= 0 ? "green" : "neutral" },
                  completedSteps.indexOf(selectedStep) >= 0 ? uiText("Done", lang) : selectedStep === currentStep ? uiText("Current", lang) : uiText("Queued", lang))),
              h("div", { className: "ac-evidence-grid" },
                h("div", { className: "ac-evidence-card" }, h("b", null, uiText("App", lang)), h("span", null, scenarioText(inspected.tool || "Assigned app", lang))),
                h("div", { className: "ac-evidence-card" }, h("b", null, lang === "en" ? "Result" : zhText("結果", lang)), h("span", null, scenarioText(inspected.outcome || inspected.detail || "Prepared the next task step.", lang)))),
              h("div", { className: "ac-control-row" },
                h("button", { type: "button", className: "ac-chip", disabled: !canUsePrompts, title: canUsePrompts ? "" : denyReason, "aria-disabled": canUsePrompts ? "false" : "true", "data-agent-action": "load-context-step-prompt", "data-agent-step-index": String(selectedStep), "data-agent-rbac-disabled": canUsePrompts ? "false" : "true", onClick: () => onUseStep(selectedStep) }, uiText("Load step prompt", lang)),
                h("span", { style: { color: "var(--text-faint)", fontSize: 12 } }, lang === "en" ? "Viewing this does not change task progress." : zhText("查看此項不會改變任務進度。", lang))))),
          h("div", null,
            h("div", { className: "ac-mini-title", style: { marginBottom: 8 } }, uiText("Suggested inputs", lang)),
            h("div", { className: "ac-inputs" }, inputRows(skill, lang).map((row) => h("div", { key: row, className: "ac-input-row" },
              h("span", { className: "inline-icon" }, h(Icon, { name: "check", size: 12 })),
              h("span", null, row))))),
          h("div", { className: "ac-control-row" },
            h("button", { type: "button", className: "ac-chip", disabled: !canUsePrompts, title: canUsePrompts ? "" : denyReason, "aria-disabled": canUsePrompts ? "false" : "true", "data-agent-action": "load-current-step-prompt", "data-agent-step-index": String(currentStep), "data-agent-rbac-disabled": canUsePrompts ? "false" : "true", onClick: () => onUseStep(currentStep) }, uiText("Load current step prompt", lang)),
            h("button", { type: "button", className: "ac-chip", "data-agent-action": "inspect-next-step", "data-agent-step-index": String(Math.min(steps.length - 1, currentStep + 1)), onClick: () => onInspectStep(Math.min(steps.length - 1, currentStep + 1)) }, uiText("Inspect next step", lang))))),
      h("section", { className: "ac-panel", style: { padding: 14 } },
        h("div", { className: "ac-mini-title", style: { marginBottom: 8 } }, lang === "en" ? "Approval" : zhText("審批", lang)),
        h("div", { className: "row gap6 wrap" },
          h(Badge, { tone: "amber" }, uiText("Approval required", lang)),
          h(Badge, { tone: "green" }, lang === "en" ? "File check first" : zhText("先檢查檔案", lang))),
        h("p", { style: { marginTop: 9, color: "var(--text-dim)", fontSize: 12.5, lineHeight: 1.5 } },
          lang === "en" ? "Starting the guide creates a task. Drafts still wait in My Desk." : zhText("開始指引會建立任務。草稿仍會在我的辦公桌等待審批。", lang))));
  }

  function AgentChat({ ctx }) {
    const lang = useScenarioLang();
    const skills = window.SCENARIO_SKILLS || [];
    const route = parseAgentArg(ctx.pageArg);
    const skill = skills.find((s) => s.id === route.skillId) || null;
    const persistedWo = findSkillWorkOrder(ctx, skill, route.workOrderId);
    const persistedWorkflow = (persistedWo && persistedWo.workflow) || {};
    const initialRestartable = isRestartableWorkflow(persistedWorkflow);
    const hydratedSteps = skill ? stepsOf(skill) : [];
    const initialDraft = skill && (!persistedWo || initialRestartable) ? readAgentSetupDraft(skill.id, route.workOrderId) : null;
    const [text, setText] = useState(skill ? ((initialDraft && initialDraft.text) || textForState(skill, persistedWo, hydratedSteps, lang)) : "");
    const [started, setStarted] = useState(!!persistedWo && !initialRestartable);
    const [lastWo, setLastWo] = useState(persistedWo ? persistedWo.id : null);
    const [runId, setRunId] = useState(initialRestartable ? null : (persistedWorkflow.runId || null));
    const [approvalId, setApprovalId] = useState(persistedWorkflow.approvalId || null);
    const [currentStep, setCurrentStep] = useState(initialRestartable ? 0 : (persistedWorkflow.currentStep || 0));
    const [selectedStep, setSelectedStep] = useState(initialDraft && typeof initialDraft.selectedStep === "number" ? Math.max(0, Math.min((hydratedSteps.length || 1) - 1, initialDraft.selectedStep)) : (initialRestartable ? 0 : (persistedWorkflow.currentStep || 0)));
	    const [completedSteps, setCompletedSteps] = useState(initialRestartable ? [] : (persistedWorkflow.completedSteps || []));
	    const [events, setEvents] = useState(eventsFromWorkOrder(persistedWo, hydratedSteps));
	    const [openEvent, setOpenEvent] = useState(null);
	    const [showActiveTrace, setShowActiveTrace] = useState(false);
	    const [runSetup, setRunSetup] = useState(() => normalizedAgentSetup((!initialRestartable && persistedWorkflow && persistedWorkflow.setup) || (initialDraft && initialDraft.setup) || (persistedWorkflow && persistedWorkflow.setup) || null, skill, ctx));

	    useEffect(() => {
	      if (skill) {
		        const existing = findSkillWorkOrder(ctx, skill, route.workOrderId);
		        const wf = (existing && existing.workflow) || {};
	        const restartable = isRestartableWorkflow(wf);
	        const draft = (!existing || restartable) ? readAgentSetupDraft(skill.id, route.workOrderId) : null;
	        const nextSteps = stepsOf(skill);
	        setText((draft && draft.text) || textForState(skill, existing, nextSteps, lang));
	        setStarted(!!existing && !restartable);
	        setLastWo(existing ? existing.id : null);
	        setRunId(restartable ? null : (wf.runId || null));
	        setApprovalId(wf.approvalId || null);
	        setCurrentStep(restartable ? 0 : (wf.currentStep || 0));
	        setSelectedStep(draft && typeof draft.selectedStep === "number" ? Math.max(0, Math.min((nextSteps.length || 1) - 1, draft.selectedStep)) : (restartable ? 0 : (wf.currentStep || 0)));
	        setCompletedSteps(restartable ? [] : (wf.completedSteps || []));
		        setEvents(eventsFromWorkOrder(existing, nextSteps));
		        setOpenEvent(null);
		        setShowActiveTrace(false);
		        setRunSetup(normalizedAgentSetup((!restartable && wf && wf.setup) || (draft && draft.setup) || (wf && wf.setup) || null, skill, ctx));
		      }
		    }, [ctx.pageArg, skill && skill.id, lang]);

		    const setupDraftEditable = !!skill && ctx.can("workOrder") && (!persistedWo || initialRestartable);
		    useEffect(() => {
		      if (!skill || !setupDraftEditable) return;
		      writeAgentSetupDraft(skill.id, route.workOrderId, {
		        setup: normalizedAgentSetup(runSetup, skill, ctx),
		        text,
		        selectedStep,
		      });
		    }, [skill && skill.id, route.workOrderId, setupDraftEditable, text, runSetup, selectedStep]);

    if (!skill) {
      return h("div", null,
        h(PageHeader, { eyebrow: "Step-by-step guide", title: "Task not found", icon: "message",
          sub: "The selected task is no longer in the Task Library.",
          right: h(Button, { sm: true, onClick: () => ctx.openPage("training") }, "Back to Task Library") }),
        h("div", { className: "ac-panel", style: { padding: 24 } }, "Choose a task from the library to start the guide."));
    }
    if (route.workOrderId && !persistedWo) {
      return h("div", null,
        h(PageHeader, { eyebrow: "Step-by-step guide", title: "Task link not found", icon: "message",
          sub: route.workOrderId + " is not linked to this Task Library item.",
          right: [
            h(Button, { key: "workorders", sm: true, variant: "ghost", "data-agent-recovery-action": "back-to-workorders", "data-agent-skill-id": skill.id, "data-agent-missing-workorder-id": route.workOrderId || "", onClick: () => ctx.openPage("workorders") }, "Back to Tasks"),
            h(Button, { key: "library", sm: true, variant: "primary", "data-agent-recovery-action": "open-skill-library", "data-agent-skill-id": skill.id, "data-agent-missing-workorder-id": route.workOrderId || "", onClick: () => ctx.openPage("training", skill.id) }, "Open Task Library"),
          ] }),
        h("div", { className: "ac-panel", style: { padding: 24 } }, "Open the task and start or continue the guide from there."));
    }

	    const color = colorFor(skill, skills);
		    const setup = normalizedAgentSetup(runSetup, skill, ctx);
		    const lockedRoleId = (persistedWo && persistedWo.emp && ctx.office.roleById[persistedWo.emp]) ? persistedWo.emp : null;
		    const roleId = lockedRoleId || setup.roleId || roleForSkill(skill, ctx);
	    const role = ctx.office.roleById[roleId] || {};
	    const assignedRole = roleName(roleId, role);
	    const canStart = ctx.can("workOrder");
	    const workOrderReason = ctx.denyReason ? ctx.denyReason("workOrder") : "Viewers have read-only access";
    const restartable = isRestartableWorkflow((persistedWo && persistedWo.workflow) || null);
    const suggestions = suggestionText(skill, lang);
    const steps = stepsOf(skill);
    const totalSteps = steps.length || 1;
    const activeStep = steps[currentStep] || null;
    const completeCount = restartable ? 0 : completedSteps.length;
    const allComplete = !restartable && steps.length > 0 && completeCount >= steps.length;
	    const progressPct = Math.round((completeCount / totalSteps) * 100);
		    const activeRun = runId ? (ctx.office.runs || []).find((r) => r.id === runId) : null;
		    const approvalPacket = approvalId ? (ctx.office.inbox || []).find((item) => item.id === approvalId) : null;
		    const displayStep = allComplete ? null : activeStep;
		    const loadedOutOfOrder = started && !restartable && !allComplete && selectedStep !== currentStep;
		    const setupSources = agentSourceChoices(ctx, setup.roleId);
		    const setupOwners = agentOwnerChoices(ctx);
		    const setupSource = setupSources.find((f) => f.id === setup.sourceFileId) || setupSources[0] || null;
		    const setupEditable = canStart && (!started || restartable);
		    const liveWorkflow = (persistedWo && persistedWo.workflow) || {};
		    const approvedWorkflow = isApprovedWorkflow(liveWorkflow, persistedWo && persistedWo.col);
		    const sourceGaps = mergeSourceGaps(liveWorkflow.sourceGaps || [], liveWorkflow.evidence || []);
		    const openSourceGaps = sourceGaps.filter((gap) => !sourceGapResolved(gap));
		    const hasOpenSourceGap = openSourceGaps.length > 0;
		    const canCreateResolvedPacket = started && !restartable && allComplete && !approvalId && !hasOpenSourceGap;
		    const launchIntent = readAgentLaunchIntent(skill.id);
			    const agentRunState = restartable
			      ? "revision"
			      : started
			        ? (approvedWorkflow ? "approved" : (allComplete ? (hasOpenSourceGap ? "source-gap" : (approvalId ? "awaiting-approval" : "ready-for-approval")) : "running"))
			        : "initialized";
			    function rememberDraft(next) {
			      if (!skill || !setupDraftEditable) return;
			      writeAgentSetupDraft(skill.id, route.workOrderId, Object.assign({
			        setup,
			        text,
			        selectedStep,
			      }, next || {}));
			    }
			    function updateSetup(patch) {
		      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
		      setRunSetup((cur) => {
		        const next = normalizedAgentSetup(Object.assign({}, cur, patch), skill, ctx);
		        rememberDraft({ setup: next });
		        return next;
		      });
		    }
	    function updateSetupRole(nextRoleId) {
	      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
	      const nextSources = agentSourceChoices(ctx, nextRoleId);
	      updateSetup({ roleId: nextRoleId, sourceFileId: (nextSources[0] || {}).id || "" });
	    }

		    function appendSuggestion(s) {
	      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
	      setText((cur) => {
	        const next = (cur.trim() ? cur.trim() + "\n" : "") + "- " + s;
	        rememberDraft({ text: next });
	        return next;
	      });
	    }
    function openApprovalDesk(id) {
      if (id && ctx.setHighlight) ctx.setHighlight(id);
      ctx.openPage("approvals");
    }
    function openSourceFile(src) {
      if (src && src.fileId && ctx.setHighlight) ctx.setHighlight(src.fileId);
      ctx.openPage("files", src && src.fileId);
    }
    function label(en, zh) {
      return lang === "en" ? en : zhText(zh, lang);
    }
	    function checkpointCount(count, enNoun, zhNoun) {
	      return lang === "en" ? count + " " + enNoun : zhText(count + " 個" + zhNoun, lang);
	    }
		    function launchReceipt() {
		      const origin = launchIntent && launchIntent.source === "training-library"
	        ? label("Task Library", "任務庫")
		        : launchIntent && launchIntent.source === "command-palette"
		          ? label("Command palette", "命令面板")
		          : label("Direct route", "直接路由");
	      const launchWorkOrder = (launchIntent && launchIntent.workOrderId) || lastWo || "";
	      return h("div", {
	        className: "ac-evidence-grid",
	        "data-agent-launch-intent": launchIntent ? launchIntent.source : "direct-route",
	        "data-agent-launch-state": agentRunState,
	        "data-agent-skill-id": skill.id,
	        "data-agent-workorder-id": launchWorkOrder,
	        "data-agent-step-count": totalSteps,
	      },
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Handoff", "交接")), h("span", null, origin)),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Task", "任務")), h("span", null, scenarioText(skill.title, lang))),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Steps", "步驟")), h("span", null, totalSteps)),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Task status", "任務狀態")), h("span", null, agentRunState.replace(/-/g, " "))));
	    }
	    function setupSummaryCards() {
	      const ownerName = agentSetupOwnerName(ctx, setup.ownerId);
	      return h("div", { className: "ac-evidence-grid", "data-agent-setup-summary": "true" },
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Employee", "員工")), h("span", null, roleName(setup.roleId, ctx.office.roleById[setup.roleId]))),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("File", "檔案")), h("span", null, setupSource ? setupSource.name : label("Files", "檔案"))),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Result", "結果")), h("span", null, outputFormatText(setup.outputFormat, lang))),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Owner", "負責人")), h("span", null, ownerName)),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Target time", "目標時間")), h("span", null, setup.sla + " · " + setup.deadline)),
	        h("div", { className: "ac-evidence-card" }, h("b", null, label("Risk", "風險")), h("span", null, setup.risk)));
		    }
		    function setupControlPanel() {
		      return h("div", {
		        className: "ac-run-card",
		        "data-agent-setup": "true",
		        "data-agent-setup-draft": setupDraftEditable ? "true" : "locked",
		        "data-agent-setup-skill-id": skill.id,
		        "data-agent-setup-workorder-id": lastWo || route.workOrderId || "",
		        "data-agent-setup-role-id": setup.roleId,
		        "data-agent-setup-source-id": setup.sourceFileId,
		        "data-agent-setup-output-value": setup.outputFormat,
		        "data-agent-setup-owner-id": setup.ownerId,
		        "data-agent-setup-deadline-value": setup.deadline,
		        "data-agent-setup-risk-value": setup.risk,
		        "data-agent-setup-sla-value": setup.sla,
		        style: { marginTop: 10 },
		      },
	        h("div", { className: "ac-run-title" },
	          h("span", null, label("Task setup", "任務設定")),
	          h(Badge, { tone: setupEditable ? "blue" : "green" }, setupEditable ? label("Review before start", "開始前覆核") : label("Started", "已開始"))),
		        h("div", { className: "ac-evidence-grid" },
		          h("label", { className: "ac-evidence-card" },
		            h("b", null, label("Employee", "員工")),
		            h("select", { className: "field", "data-agent-setup-role": "true", value: setup.roleId, disabled: !setupEditable, onChange: (e) => updateSetupRole(e.target.value) },
	              (ctx.office.roles || []).filter((r) => r.hired).map((r) => h("option", { key: r.id, value: r.id }, roleName(r.id, r))))),
	          h("label", { className: "ac-evidence-card" },
	            h("b", null, label("File", "檔案")),
	            h("select", { className: "field", "data-agent-setup-source": "true", value: setup.sourceFileId, disabled: !setupEditable, onChange: (e) => updateSetup({ sourceFileId: e.target.value }) },
	              setupSources.map((f) => h("option", { key: f.id, value: f.id }, f.name)))),
	          h("label", { className: "ac-evidence-card" },
	            h("b", null, label("Result", "結果")),
	            h("select", { className: "field", "data-agent-setup-output": "true", value: setup.outputFormat, disabled: !setupEditable, onChange: (e) => updateSetup({ outputFormat: e.target.value }) },
              ["Approval packet", "Customer reply", "Internal brief", "Table report", "Work order"].map((v) => h("option", { key: v, value: v }, outputFormatText(v, lang))))),
	          h("label", { className: "ac-evidence-card" },
	            h("b", null, label("Owner", "負責人")),
	            h("select", { className: "field", "data-agent-setup-owner": "true", value: setup.ownerId, disabled: !setupEditable, onChange: (e) => updateSetup({ ownerId: e.target.value }) },
	              setupOwners.map((u) => h("option", { key: u.id, value: u.id }, u.name + " · " + u.level)))),
	          h("label", { className: "ac-evidence-card" },
	            h("b", null, label("Deadline", "限期")),
	            h("input", { className: "field", "data-agent-setup-deadline": "true", value: setup.deadline, disabled: !setupEditable, onChange: (e) => updateSetup({ deadline: e.target.value }) })),
	          h("label", { className: "ac-evidence-card" },
	            h("b", null, label("Risk and timing", "風險與時間")),
	            h("div", { className: "row gap6" },
	              h("select", { className: "field", "data-agent-setup-risk": "true", value: setup.risk, disabled: !setupEditable, onChange: (e) => updateSetup({ risk: e.target.value }) },
	                ["Low", "Medium", "High"].map((v) => h("option", { key: v, value: v }, v))),
	              h("select", { className: "field", "data-agent-setup-sla": "true", value: setup.sla, disabled: !setupEditable, onChange: (e) => updateSetup({ sla: e.target.value }) },
	                ["2h", "4h", "8h", "1d"].map((v) => h("option", { key: v, value: v }, v)))))),
		        h("div", { className: "ac-run-note" }, label("Saved with the Task and My Desk item.", "已儲存到任務和我的辦公桌項目。")));
		    }
		    function createApprovalPacket(doneOverride, noteText) {
		      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return null; }
		      if (!lastWo || !ctx.completeAgentChatRun) return null;
		      const done = (doneOverride || completedSteps || []).slice();
		      const lines = approvalLinesFor(skill, steps, done, noteText == null ? text : noteText, lang, setup);
		      const packet = ctx.completeAgentChatRun(lastWo, {
		        roleId,
		        skillId: skill.id,
		        skillName: scenarioText(skill.title, lang),
	        title: scenarioText(skill.title, lang) + " — My Desk item",
		        lines,
		        setup,
		      });
		      if (packet && packet.runId) setRunId(packet.runId);
		      if (packet && packet.blocked) {
		        setApprovalId(null);
		        setText(label("A file is missing. Attach it, request it, or continue without it.", "尚缺檔案。請附加、要求檔案，或在沒有檔案下繼續。"));
		        setEvents((cur) => cur.concat([{ kind: "sourcegap", gaps: packet.sourceGaps || openSourceGaps || [] }]));
		        return packet;
		      }
		      if (packet && packet.approvalId) {
		        setApprovalId(packet.approvalId);
		        setText(lang === "en"
		          ? "My Desk item ready for \"" + skill.title + "\". Review the files and details before sending."
		          : zhText("「" + scenarioText(skill.title, lang) + "」已送到我的辦公桌。發送前請覆核檔案和詳情。", lang));
		        setEvents((cur) => cur.concat([{ kind: "done" }, { kind: "approval", id: packet.approvalId }]));
		      }
		      return packet;
		    }
		    function attachGapSource(gap) {
		      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
		      if (!gap || !lastWo || !ctx.attachAgentChatSourceGap) return;
		      const src = setupSource || (agentSourceChoices(ctx, roleId)[0] || null);
		      if (!src || !src.id) {
	        if (ctx.showToast) ctx.showToast("No file is available for this employee.");
		        return;
		      }
		      const result = ctx.attachAgentChatSourceGap(lastWo, gap.key || gap.evidenceKey || gap.stepIndex, src.id);
		      if (result && result.runId) setRunId(result.runId);
		      if (result && result.approvalId) setApprovalId(result.approvalId);
		      setEvents((cur) => cur.concat([{ kind: "sourcegap-resolved", mode: "source", title: gap.title, sourceName: src.name }]));
	      setText(label("File attached. Resolve any other file issues, then send to My Desk.", "已附加檔案。解決其他檔案問題後，送到我的辦公桌。"));
		    }
		    function overrideGap(gap) {
		      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
		      if (!gap || !lastWo || !ctx.recordAgentChatSourceGapOverride) return;
	      const result = ctx.recordAgentChatSourceGapOverride(lastWo, gap.key || gap.evidenceKey || gap.stepIndex, "Owner reviewed the missing file and chose to continue.");
		      if (result && result.runId) setRunId(result.runId);
		      if (result && result.approvalId) setApprovalId(result.approvalId);
		      setEvents((cur) => cur.concat([{ kind: "sourcegap-resolved", mode: "override", title: gap.title }]));
	      setText(label("Owner chose to continue without this file. Resolve any other file issues.", "東主已選擇在沒有此檔案下繼續。請解決其他檔案問題。"));
		    }
		    function stageGapSource(gap) {
		      if (!gap || !ctx.stageMissingSource) return;
		      ctx.stageMissingSource({
		        source: "agent-chat",
		        workOrderId: lastWo,
		        runId,
		        evidenceKey: gap.evidenceKey,
		        stepIndex: gap.stepIndex,
		        roleId,
		        skillId: skill.id,
		        skill: scenarioText(skill.title, lang),
		        title: gap.title,
		        sourceStatement: gap.source || gap.note,
		        topic: gap.title || scenarioText(skill.title, lang),
		      });
		    }
		    function sourceGapPanel() {
		      if (!sourceGaps.length) return null;
		      const unresolved = sourceGaps.filter((gap) => !sourceGapResolved(gap));
		      return h("div", { className: "ac-source-gap" + (unresolved.length ? "" : " resolved"), "data-agent-source-gap": unresolved.length ? "true" : "resolved" },
		        h("div", { className: "ac-source-gap-head" },
		          h("div", null,
		            h("b", null, unresolved.length ? label("File needed before approval", "批准前需要檔案") : label("File issue resolved", "檔案問題已解決")),
		            h("span", null, unresolved.length
		              ? label("Add each file, request it, or choose to continue without it.", "附加每個檔案、提交要求，或選擇在沒有檔案下繼續。")
		              : label("History keeps the issue and decision.", "紀錄會保留問題和決定。"))),
		          h(Badge, { tone: unresolved.length ? "amber" : "green" }, unresolved.length ? unresolved.length + " unresolved" : label("Resolved", "已解決"))),
		        sourceGaps.map((gap) => {
		          const resolved = sourceGapResolved(gap);
		          return h("div", { key: gap.key || gap.evidenceKey, className: "ac-source-gap-row", "data-agent-source-gap-step": gap.stepIndex },
		            h("div", { className: "ac-source-gap-title" },
		              h("b", null, "Step " + ((gap.stepIndex || 0) + 1) + ": " + (gap.title || label("Task step", "任務步驟"))),
		              h(Badge, { tone: resolved ? "green" : "amber" }, resolved ? (sourceGapLabel(gap) || label("Resolved", "已解決")) : label("File needed", "需要檔案"))),
		            h("div", { className: "ac-source-gap-note" }, gap.note || label("Missing file recorded during the task.", "任務期間已記錄缺失檔案。")),
		            !resolved && h("div", { className: "ac-control-row" },
		              h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-source-gap-action": "attach-source", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => attachGapSource(gap) }, label("Attach file", "附加檔案")),
		              h("button", { type: "button", className: "ac-chip", "data-agent-source-gap-action": "stage-source", disabled: !ctx.can("addUpload"), title: ctx.can("addUpload") ? "" : ctx.denyReason("addUpload"), onClick: () => stageGapSource(gap) }, label("Request missing file", "要求缺失檔案")),
		              h("button", { type: "button", className: "ac-chip", "data-agent-source-gap-action": "owner-override", disabled: !canStart || !ctx.can("sourceGapOverride"), title: !canStart ? workOrderReason : ctx.can("sourceGapOverride") ? "" : ctx.denyReason("sourceGapOverride"), "aria-disabled": (!canStart || !ctx.can("sourceGapOverride")) ? "true" : "false", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => overrideGap(gap) }, label("Continue without file", "沒有檔案也繼續"))));
		        }),
		        canCreateResolvedPacket && h("div", { className: "ac-control-row" },
		          h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-source-gap-action": "create-approval", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => createApprovalPacket(completedSteps, text) }, label("Send to My Desk", "送到我的辦公桌"))));
		    }
		    function focusSourceGapControls() {
		      setOpenEvent(null);
	      setText(label("Attach the file, request it, or continue without it.", "附加檔案、提交要求，或在沒有檔案下繼續。"));
		      setTimeout(() => {
		        const panel = document.querySelector('[data-agent-source-gap]');
		        if (!panel) return;
		        try { panel.scrollIntoView({ block: "center", behavior: "smooth" }); } catch (e) { panel.scrollIntoView(); }
		        const next = panel.querySelector('[data-agent-source-gap-action]:not([disabled])');
		        if (next && next.focus) next.focus();
		      }, 80);
		    }
		    function packetPreview(packet) {
      if (!packet) return null;
      const lines = (packet.lines || []).slice(0, 5);
      return h("div", { className: "ac-packet" },
        h("div", { className: "row gap6 wrap" },
	          h(Badge, { tone: "green" }, label("My Desk item", "我的辦公桌項目")),
          packet.workOrderId && h(Badge, { tone: "neutral" }, packet.workOrderId),
          packet.runId && h(Badge, { tone: "neutral" }, packet.runId)),
        h("ul", { className: "ac-packet-lines" },
          lines.map((line, i) => h("li", { key: i },
            h("span", { className: "inline-icon" }, h(Icon, { name: "check", size: 12 })),
            h("span", null, line)))),
        h("div", { className: "ac-evidence-grid" },
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("File", "檔案")), h("span", null, packet.source || sourceNameFromRun(activeRun, lang))),
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("File checks", "檔案檢查")), h("span", null, checkpointCount(((packet.evidence || []).length || completeCount), "steps", "步驟")))));
    }
    function stepEventDetail(ev, eventIndex) {
      const evidence = ev.evidence || evidenceRecord(ev.step, ev.index, activeRun, lang);
      const source = activeRun && activeRun.sources && activeRun.sources[0];
      const missing = evidence.sourceState === "missing";
      return h("div", { id: "ac-event-detail-" + eventIndex, className: "ac-step-detail", "data-agent-step-evidence-detail": String(ev.index), "data-agent-event-index": String(eventIndex), "data-agent-step-index": String(ev.index) },
        h("div", { className: "ac-step-detail-head" },
          h("div", null,
            h("b", null, lang === "en" ? "Step " + (ev.index + 1) + " details" : zhText("第 " + (ev.index + 1) + " 步詳情", lang)),
	            h("span", null, evidence.outcome || scenarioText((ev.step && (ev.step.outcome || ev.step.detail)) || "Prepared the next task step.", lang))),
          h(Badge, { tone: missing ? "amber" : "green" }, missing ? label("Missing file", "缺失檔案") : label("Saved", "已儲存"))),
        h("div", { className: "ac-evidence-grid" },
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("App", "應用程式")), h("span", null, evidence.tool)),
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("File", "檔案")), h("span", null, evidence.source)),
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("Result", "結果")), h("span", null, evidence.outcome)),
	          h("div", { className: "ac-evidence-card" }, h("b", null, label("Approval", "審批")), h("span", null, evidence.gate))),
        h("div", { className: "ac-control-row" },
          h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "load-evidence-step-prompt", "data-agent-step-index": String(ev.index), "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => loadStepPrompt(ev.index) }, uiText("Load step prompt", lang)),
	          lastWo && h("button", { type: "button", className: "ac-chip", "data-agent-action": "open-workorder-from-evidence", "data-workorder-id": lastWo, onClick: () => ctx.openPage("workorder", lastWo) }, label("Open Task", "開啟任務")),
	          source && source.fileId && h("button", { type: "button", className: "ac-chip", "data-agent-action": "open-file-from-evidence", "data-file-id": source.fileId, onClick: () => openSourceFile(source) }, label("Open Files", "開啟檔案"))));
    }
	    function loadStepPrompt(index) {
	      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
	      const safeIndex = Math.max(0, Math.min(steps.length - 1, index || 0));
	      const step = steps[safeIndex];
	      if (!step) return;
	      const nextText = stepPrompt(skill, step, safeIndex, totalSteps, lang);
	      setSelectedStep(safeIndex);
	      setText(nextText);
	      rememberDraft({ text: nextText, selectedStep: safeIndex });
	    }
    function activateStep(index) {
      const safeIndex = Math.max(0, Math.min(steps.length - 1, index || 0));
      setCurrentStep(safeIndex);
      loadStepPrompt(safeIndex);
    }
	    function startRun() {
	      if (!canStart || (started && !restartable)) return;
	      const setupPayload = Object.assign({}, setup, {
	        ownerName: agentSetupOwnerName(ctx, setup.ownerId),
	        sourceName: setupSource ? setupSource.name : "Files",
	      });
	      if (lastWo && persistedWo && ctx.startWorkOrderAgentChat) {
	        const result = ctx.startWorkOrderAgentChat(lastWo, skill.id, setupPayload);
	        if (!result) return;
	        setLastWo(result.workOrderId);
	        setRunId(result.runId || null);
        setApprovalId(null);
        setStarted(true);
        setCurrentStep(0);
        setSelectedStep(0);
        setCompletedSteps([]);
        setEvents([{ kind: "run", id: result.workOrderId, index: 0, step: steps[0] || null }]);
	        setOpenEvent(null);
	        setShowActiveTrace(false);
	        setText(stepPrompt(skill, steps[0] || {}, 0, totalSteps, lang));
	        clearAgentSetupDraft(skill.id, route.workOrderId);
	        ctx.openPage("agent", agentRouteArg(skill.id, result.workOrderId));
	        return;
	      }
      const id = workOrderId(ctx);
	      const wo = {
	        id,
	        title: scenarioText(skill.title, lang),
	        emp: setupPayload.roleId,
	        sla: setupPayload.sla,
	        conf: 0,
	        owner: setupPayload.ownerName,
	        deadline: setupPayload.deadline,
	        outputFormat: setupPayload.outputFormat,
	        sources: [setupPayload.sourceName, label("Task Library", "任務庫"), outputFormatText(setupPayload.outputFormat, lang)].concat(capabilitiesOf(skill).slice(0, 1).map((c) => scenarioText(c, lang))),
	        step: activeStep ? (lang === "en" ? "Step " + (currentStep + 1) + "/" + totalSteps + " queued: " + activeStep.title : zhText("第 " + (currentStep + 1) + "/" + totalSteps + " 步已排入佇列：" + scenarioText(activeStep.title, lang), lang)) : label("Guide started", "指引已開始"),
	        risk: setupPayload.risk,
	        workflow: {
	          skillId: skill.id,
	          currentStep,
	          totalSteps,
		          runId: null,
		          completedSteps: [],
		          evidence: [],
		          sourceGaps: [],
			          assumptions: text.split("\n").filter((line) => /^- /.test(line)).slice(0, 8),
			          setup: setupPayload,
			          sourceFileId: setupPayload.sourceFileId,
			          outputFormat: setupPayload.outputFormat,
	          ownerId: setupPayload.ownerId,
	          ownerName: setupPayload.ownerName,
	          deadline: setupPayload.deadline,
	          risk: setupPayload.risk,
	          sla: setupPayload.sla,
	        },
	        future: activeStep
	          ? (lang === "en" ? "Next: check " + activeStep.title + " against " + setupPayload.sourceName + ", save the details, then continue the guide." : zhText("下一步：對「" + setupPayload.sourceName + "」核查「" + scenarioText(activeStep.title, lang) + "」、儲存詳情，然後繼續指引。", lang))
	          : uiText("Next: review inputs, confirm files, then send the draft to My Desk.", lang),
	      };
	      const result = ctx.startAgentChatRun ? ctx.startAgentChatRun(wo, {
	        skillId: skill.id,
	        roleId: setupPayload.roleId,
	        title: scenarioText(skill.title, lang),
	        skillSummary: scenarioText(skill.summary || (activeStep && activeStep.detail) || "Task details", lang),
	        setup: setupPayload,
	      }) : null;
      const nextWo = result && result.workOrderId ? result.workOrderId : id;
      setLastWo(nextWo);
      setRunId(result && result.runId ? result.runId : null);
      setApprovalId(null);
      setStarted(true);
      setSelectedStep(currentStep);
	      setEvents((cur) => cur.concat([{ kind: "run", id, index: currentStep, step: activeStep }]));
	      setOpenEvent(null);
	      setShowActiveTrace(false);
	      clearAgentSetupDraft(skill.id, route.workOrderId);
	      clearAgentSetupDraft(skill.id, nextWo);
	      ctx.openPage("agent", agentRouteArg(skill.id, nextWo));
	    }
    function completeStep() {
      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
      if (!started || restartable || !activeStep || allComplete) return;
      if (selectedStep !== currentStep) {
        loadStepPrompt(currentStep);
        if (ctx.showToast) ctx.showToast("Current step restored · complete step " + (currentStep + 1) + " before viewing another prompt");
        return;
      }
      const nextRequired = steps.findIndex((s, i) => completedSteps.indexOf(i) < 0);
      if (nextRequired >= 0 && currentStep !== nextRequired) {
        activateStep(nextRequired);
        if (ctx.showToast) ctx.showToast("Complete task steps in order · loaded step " + (nextRequired + 1));
        return;
      }
      const idx = currentStep;
      const submittedText = text.trim();
      const done = completedSteps.indexOf(idx) >= 0 ? completedSteps : completedSteps.concat([idx]).sort((a, b) => a - b);
      setCompletedSteps(done);
      const stepEvidence = evidenceRecord(activeStep, idx, activeRun, lang, submittedText);
      setEvents((cur) => cur.concat([
        submittedText ? { kind: "user", index: idx, text: submittedText } : null,
        { kind: "step", index: idx, step: activeStep, evidence: stepEvidence },
      ].filter(Boolean)));
      const nextAfter = steps.findIndex((s, i) => i > idx && done.indexOf(i) < 0);
      const next = nextAfter >= 0 ? nextAfter : steps.findIndex((s, i) => done.indexOf(i) < 0);
      if (lastWo) {
        const evidenceByIndex = {};
        ((persistedWo && persistedWo.workflow && persistedWo.workflow.evidence) || []).forEach((ev) => { if (typeof ev.index === "number") evidenceByIndex[ev.index] = ev; });
        (events || []).forEach((ev) => { if (ev && ev.kind === "step" && ev.evidence && typeof ev.index === "number") evidenceByIndex[ev.index] = ev.evidence; });
        evidenceByIndex[idx] = stepEvidence;
	        const evidence = done.map((stepIndex) => {
	          const s = steps[stepIndex] || {};
	          return evidenceByIndex[stepIndex] || evidenceRecord(s, stepIndex, activeRun, lang);
	        });
	        const nextSourceGaps = mergeSourceGaps((persistedWo && persistedWo.workflow && persistedWo.workflow.sourceGaps) || [], evidence);
	        const openGaps = nextSourceGaps.filter((gap) => !sourceGapResolved(gap));
	        const blockedAtFinish = done.length >= steps.length && openGaps.length > 0;
	        ctx.updateWorkOrder(lastWo, {
	          conf: Math.round((done.length / totalSteps) * 100),
	          step: blockedAtFinish
		            ? label("File needed before My Desk", "送到我的辦公桌前需要檔案")
	            : done.length >= steps.length
		            ? (lang === "en" ? "My Desk item ready after " + steps.length + " file checks" : zhText("完成 " + steps.length + " 個檔案檢查後，我的辦公桌項目已準備好", lang))
	            : (lang === "en" ? "Step " + (next + 1) + "/" + totalSteps + " queued: " + ((steps[next] || {}).title || "Next step") : zhText("第 " + (next + 1) + "/" + totalSteps + " 步已排入佇列：" + scenarioText(((steps[next] || {}).title || "Next step"), lang), lang)),
          workflow: {
            skillId: skill.id,
	            currentStep: next >= 0 ? next : idx,
	            totalSteps,
	            completedSteps: done,
	            evidence,
	            sourceGaps: nextSourceGaps,
	            assumptions: submittedText.split("\n").filter((line) => /^- /.test(line)).slice(0, 8),
	            status: blockedAtFinish ? "source_gap_blocked" : "running",
	            workflowState: blockedAtFinish ? "source_gap_blocked" : "running",
	          },
	          future: blockedAtFinish
		            ? label("Next: add the file, request it, or continue without it.", "下一步：附加檔案、提交要求，或在沒有檔案下繼續。")
		            : done.length >= steps.length
		            ? label("Next: review the files and My Desk item.", "下一步：覆核檔案和我的辦公桌項目。")
		            : (lang === "en" ? "Next: check " + (((steps[next] || {}).title) || "the next step") + " and save it." : zhText("下一步：核查「" + scenarioText((((steps[next] || {}).title) || "the next step"), lang) + "」並儲存。", lang)),
	          historyEvent: {
	            type: done.length >= steps.length ? "check" : "step",
		            title: done.length >= steps.length ? "File checks complete" : "Step " + (idx + 1) + " complete",
		            note: stepEvidence.summary + " · " + scenarioText(activeStep.outcome || activeStep.detail || activeStep.title || "Prepared the next task step.", lang),
	            runId,
	            stepIndex: idx,
	          },
        });
      }
	      if (next >= 0) activateStep(next);
	      else {
	        setSelectedStep(idx);
	        createApprovalPacket(done, text);
	      }
    }
    function resetRun() {
      if (!canStart) { if (ctx.showToast) ctx.showToast(workOrderReason); return; }
      const resetWo = lastWo;
      if (resetWo && ctx.resetAgentChatRun) ctx.resetAgentChatRun(resetWo);
      setStarted(false);
      setLastWo(resetWo || null);
      setRunId(null);
      setApprovalId(null);
      setCurrentStep(0);
      setSelectedStep(0);
      setCompletedSteps([]);
      setEvents([]);
      setOpenEvent(null);
      setShowActiveTrace(false);
      setText(starterPrompt(skill, lang));
    }

    return h("div", null,
      h(PageHeader, {
	        eyebrow: "Task Library / Step-by-step guide",
	        title: "Step-by-step guide",
        icon: "message",
		        sub: "Follow each step, then send the draft to My Desk.",
        right: [
          h(Button, { key: "library", sm: true, variant: "ghost", "data-agent-action": "back-to-library", onClick: () => ctx.openPage("training") }, uiText("Back to library", lang)),
	          h(Button, { key: "skill", sm: true, variant: "ghost", "data-agent-action": "skill-detail", "data-agent-skill-id": skill.id, onClick: () => ctx.openPage("training", skill.id) }, label("Task details", "任務詳情")),
	          h(Button, { key: "work", sm: true, iconRight: "arrowRight", "data-agent-action": "open-workorder-header", "data-workorder-id": lastWo || "", onClick: () => lastWo ? ctx.openPage("workorder", lastWo) : ctx.openPage("workorders") }, lastWo ? label("Task", "任務") : label("Tasks", "任務")),
        ],
      }),
      h("div", { className: "ac-shell" },
        h("section", { className: "ac-main ac-panel ac-chat" },
          h("div", { className: "ac-thread-head" },
            h("div", { className: "ac-thread-title" },
              h("span", { className: "ac-avatar" }, h(Icon, { name: "sparkle", size: 15 })),
	              h("div", null, h("b", null, label("Task ready", "任務已準備")), h("div", { style: { color: "var(--text-faint)", fontSize: 12 } }, scenarioText(skill.area, lang) + " · " + assignedRole))),
            h("div", { className: "row gap6 wrap" },
              h(Badge, { tone: "blue" }, uiText("Review inputs", lang)),
              h(Badge, { tone: "amber" }, uiText("Approval required", lang)),
              h(Badge, { tone: restartable ? "amber" : allComplete ? "green" : "neutral" }, restartable ? label("Revision required", "需要修訂") : (lang === "en" ? completeCount + "/" + steps.length + " steps" : zhText(completeCount + "/" + steps.length + " 步", lang))))),
	          h("div", { className: "ac-log", role: "log", "aria-live": "polite", "aria-label": "Guide messages" },
            h(ChatMessage, { type: "agent" },
	              h("h3", null, label("I loaded this task.", "我已載入此任務。")),
	              h("div", null, lang === "en"
	                ? [h("b", { key: "t" }, skill.title), " is ready. Check the files, owner, and result."]
		                : [h("b", { key: "t" }, scenarioText(skill.title, lang)), zhText("已準備。請檢查檔案、負責人和結果。", lang)]),
              launchReceipt(),
              h("div", {
                className: "ac-run-card",
                style: { marginTop: 10 },
                "data-agent-run-state": agentRunState,
                "data-agent-skill-id": skill.id,
                "data-agent-workorder-id": lastWo || "",
                "data-agent-run-id": runId || "",
                "data-agent-approval-status": liveWorkflow.approvalStatus || "",
                "data-agent-resolved-approval-id": liveWorkflow.resolvedApprovalId || "",
                "data-agent-audit-id": liveWorkflow.auditId || "",
                "data-agent-terminal-status": activeRun ? (activeRun.status || "") : "",
                "data-agent-current-step": allComplete ? "" : currentStep,
                "data-agent-completed-steps": completeCount,
                "data-agent-total-steps": totalSteps,
                "data-agent-loaded-out-of-order": loadedOutOfOrder ? "true" : "false",
                "data-agent-selected-step": String(selectedStep),
              },
	                h("div", { className: "ac-run-title" },
	                  h("span", null, displayStep ? (lang === "en" ? "Current step: " + displayStep.title : zhText("目前步驟：" + scenarioText(displayStep.title, lang), lang)) : allComplete ? (approvedWorkflow ? label("Task approved", "任務已批准") : (hasOpenSourceGap ? label("Missing file blocks approval", "缺失檔案阻擋審批") : label("My Desk item ready", "我的辦公桌項目已準備"))) : label("Task ready", "任務已準備")),
	                  h(Badge, { tone: restartable ? "amber" : allComplete ? (hasOpenSourceGap && !approvedWorkflow ? "amber" : "green") : started ? "blue" : "neutral" }, restartable ? label("Revision required", "需要修訂") : started ? (approvedWorkflow ? label("Approved", "已批准") : (allComplete ? (hasOpenSourceGap ? label("Missing file", "缺失檔案") : uiText("Approval waiting", lang)) : label("In progress", "進行中"))) : uiText("Not started", lang))),
                h("div", { className: "ac-progress" },
                  h("div", { className: "ac-progress-bar" }, h("div", { className: "ac-progress-fill", style: { "--p": progressPct + "%" } })),
                  h("span", null, completeCount + "/" + steps.length)),
	                h("div", { className: "ac-run-note" }, displayStep
	                  ? scenarioText(displayStep.outcome || displayStep.detail || "Prepare the next task step.", lang)
		                  : allComplete ? (approvedWorkflow ? label("Approved and complete. Task and History remain available.", "已批准並完成。任務和紀錄仍可查看。") : (hasOpenSourceGap ? label("Add the file or choose to continue without it.", "附加檔案，或選擇在沒有檔案下繼續。") : label("Owner approval is needed before anything is sent.", "發送任何內容前需要東主審批。"))) : label("Load the first step to begin.", "載入第一個步驟開始。")),
	                h("div", { className: "ac-control-row" },
	                  displayStep && h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "load-step-prompt", "data-agent-step-index": currentStep, "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => loadStepPrompt(currentStep) }, uiText("Load step prompt", lang)),
	                  started && !restartable && !allComplete && h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "complete-step", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: completeStep }, uiText("Complete current step", lang)),
	                  lastWo && !restartable && h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "reset-run", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: resetRun }, label("Start over", "重新開始"))),
	                activeRun && h("div", { style: { marginTop: 10, display: "grid", gap: 8 } },
		                  h("div", { className: "ac-control-row" },
		                    h("button", { type: "button", className: "ac-chip", "data-agent-action": "toggle-run-trace", "data-agent-run-trace-open": showActiveTrace ? "true" : "false", onClick: () => setShowActiveTrace((v) => !v), "aria-expanded": showActiveTrace ? "true" : "false" },
	                      showActiveTrace ? label("Hide details", "隱藏詳情") : label("Show details", "顯示詳情")),
	                    approvalId && h("button", { type: "button", className: "ac-chip", "data-agent-action": "open-approval-packet", "data-approval-id": approvalId, onClick: () => openApprovalDesk(approvalId) }, label("Open My Desk", "開啟我的辦公桌"))),
		                  h(window.RunTrace, { run: activeRun, compact: !showActiveTrace, onOpenSource: openSourceFile, onOpenInbox: openApprovalDesk }))),
		              sourceGapPanel(),
		              setupEditable ? setupControlPanel() : setupSummaryCards(),
		              h("div", { className: "ac-suggestions", "aria-label": "Suggested inputs" },
		                suggestions.map((s, i) => h("button", { key: s, type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "append-suggestion", "data-agent-suggestion-index": String(i), "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => appendSuggestion(s) }, s)))),
            h(ChatMessage, { type: "user" }, text || starterPrompt(skill, lang)),
            events.map((ev, i) => ev.kind === "run"
              ? h(ChatMessage, { key: i, type: "agent" },
	                  h("h3", null, label("Task created.", "任務已建立。")),
                  h("div", null, lang === "en"
	                    ? ["I created ", h("b", { key: "id" }, ev.id), " for ", h("b", { key: "role" }, assignedRole), ". First step: ", h("b", { key: "step" }, ev.step ? ev.step.title : "file review"), "."]
	                    : [zhText("我已為 ", lang), h("b", { key: "role" }, assignedRole), zhText(" 建立 ", lang), h("b", { key: "id" }, ev.id), zhText("。第一個步驟：", lang), h("b", { key: "step" }, ev.step ? scenarioText(ev.step.title, lang) : zhText("檔案覆核", lang)), "。"]),
                  h("div", { className: "ac-control-row", style: { marginTop: 9 } },
	                    h("button", { type: "button", className: "ac-chip", "data-agent-action": "open-workorder", "data-workorder-id": ev.id, onClick: () => ctx.openPage("workorder", ev.id) }, label("Open Task", "開啟任務")),
	                    h("button", { type: "button", className: "ac-chip", "data-agent-action": "inspect-first-checkpoint", "data-agent-step-index": ev.index || 0, onClick: () => setSelectedStep(ev.index || 0) }, label("View first step", "查看第一個步驟")),
	                    activeRun && h("button", { type: "button", className: "ac-chip", "data-agent-action": "inspect-run-trace", onClick: () => setShowActiveTrace(true) }, label("Show details", "顯示詳情"))))
              : ev.kind === "user"
                ? h(ChatMessage, { key: i, type: "user" },
                    h("div", { className: "ac-mini-title", style: { color: "rgba(255,255,255,.72)", marginBottom: 5 } },
	                      lang === "en" ? "Step note · Step " + (ev.index + 1) : zhText("步驟備註 · 第 " + (ev.index + 1) + " 步", lang)),
                    h("div", null, ev.text))
              : ev.kind === "step"
                ? h(ChatMessage, { key: i, type: "agent" },
                    h("h3", null, lang === "en" ? "Step " + (ev.index + 1) + " complete." : zhText("第 " + (ev.index + 1) + " 步已完成。", lang)),
                    h("div", null, lang === "en"
		                      ? [h("b", { key: "s" }, ev.step.title), " is done. ", ev.evidence && ev.evidence.sourceState === "missing" ? "The missing file was noted." : "The file check was saved."]
		                      : [h("b", { key: "s" }, scenarioText(ev.step.title, lang)), ev.evidence && ev.evidence.sourceState === "missing" ? zhText(" 已完成。已記錄缺少的檔案。", lang) : zhText(" 已完成。檔案檢查已儲存。", lang)]),
                    ev.evidence && h("div", { className: "ac-evidence-grid" },
	                      h("div", { className: "ac-evidence-card" }, h("b", null, label("App", "應用程式")), h("span", null, ev.evidence.tool)),
	                      h("div", { className: "ac-evidence-card" }, h("b", null, label("File", "檔案")), h("span", null, ev.evidence.source)),
	                      h("div", { className: "ac-evidence-card" }, h("b", null, label("Result", "結果")), h("span", null, ev.evidence.outcome)),
	                      h("div", { className: "ac-evidence-card" }, h("b", null, label("Approval", "審批")), h("span", null, ev.evidence.gate))),
                    h("ul", null,
	                      h("li", null, (lang === "en" ? "Result: " : zhText("結果：", lang)) + scenarioText(ev.step.outcome || "Prepared next action.", lang)),
	                      h("li", null, label("The file check stays with the Task.", "檔案檢查會保留在任務中。"))),
                    h("div", { className: "ac-control-row", style: { marginTop: 9 } },
                      h("button", { type: "button", className: "ac-chip", "data-agent-action": "inspect-step-evidence", "data-agent-step-index": String(ev.index), "data-agent-event-index": String(i), onClick: () => setOpenEvent(openEvent === i ? null : i), "aria-expanded": openEvent === i ? "true" : "false", "aria-controls": openEvent === i ? "ac-event-detail-" + i : undefined },
	                        openEvent === i ? label("Hide step details", "隱藏步驟詳情") : label("View step details", "查看步驟詳情")),
                      h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "load-step-prompt", "data-agent-step-index": ev.index, "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: () => loadStepPrompt(ev.index) }, uiText("Load step prompt", lang))),
                    openEvent === i && stepEventDetail(ev, i))
	                : ev.kind === "approval"
	                  ? h(ChatMessage, { key: i, type: "agent" },
	                      h("h3", null, label("Sent to My Desk.", "已送到我的辦公桌。")),
	                      h("div", null, lang === "en"
		                        ? [h("b", { key: "id" }, ev.id), " is waiting in My Desk for approval."]
		                        : [h("b", { key: "id" }, ev.id), zhText(" 正在我的辦公桌等候批准。", lang)]),
	                      packetPreview(approvalPacket),
	                      h("div", { className: "ac-control-row", style: { marginTop: 9 } },
	                        h("button", { type: "button", className: "ac-chip", onClick: () => openApprovalDesk(ev.id) }, label("Open My Desk", "開啟我的辦公桌")),
	                        activeRun && h("button", { type: "button", className: "ac-chip", onClick: () => setShowActiveTrace(true) }, label("Show details", "顯示詳情"))))
	                : ev.kind === "sourcegap"
	                  ? h(ChatMessage, { key: i, type: "agent" },
		                      h("h3", null, label("File needed before My Desk.", "送到我的辦公桌前需要檔案。")),
		                      h("div", null, label("Add the file or choose to continue without it.", "附加檔案，或選擇在沒有檔案下繼續。")),
	                      sourceGapPanel())
	                : ev.kind === "sourcegap-resolved"
	                  ? h(ChatMessage, { key: i, type: "agent" },
		                      h("h3", null, label("File decision saved.", "檔案決定已儲存。")),
		                      h("div", null, ev.mode === "override"
		                        ? label("The choice to continue is saved in History.", "繼續的決定已儲存到紀錄。")
		                        : label("The file was added to this step.", "檔案已加入此步驟。")))
	                : h(ChatMessage, { key: i, type: "agent" },
		                    h("h3", null, label("Ready for review.", "已準備覆核。")),
		                    h("div", null, label("Waiting in My Desk. Nothing sends before approval.", "正在我的辦公桌等待。批准前不會發送。")))),
            restartable && h(ChatMessage, { type: "agent" },
              h("h3", null, label("Revision required before approval.", "審批前需要修訂。")),
		              h("div", null, label("The Task and History stay. Restarting clears completed steps.", "任務和紀錄會保留。重新開始會清除已完成步驟。")),
              h("div", { className: "ac-suggestions" },
	                h("button", { type: "button", className: "ac-chip", disabled: !canStart, title: canStart ? "" : workOrderReason, "aria-disabled": canStart ? "false" : "true", "data-agent-action": "restart-run-inline", "data-agent-rbac-disabled": canStart ? "false" : "true", onClick: startRun }, label("Restart task", "重新開始任務")),
	                h("button", { type: "button", className: "ac-chip", onClick: () => lastWo ? ctx.openPage("workorder", lastWo) : ctx.openPage("workorders") }, lastWo ? label("Open Task", "開啟任務") : label("Open Tasks", "開啟任務")))),
	            started && !restartable && h(ChatMessage, { type: "agent" },
		              h("h3", null, allComplete ? (approvedWorkflow ? label("Task approved and complete.", "任務已批准並完成。") : (hasOpenSourceGap ? label("Task needs a file decision.", "任務需要檔案決定。") : label("Task ready for owner review.", "任務已準備好，等待東主覆核。"))) : label("Task is active.", "任務進行中。")),
	              h("div", null, allComplete
		                ? (approvedWorkflow ? label("Approved in My Desk. The result is saved in History.", "已在我的辦公桌批准。結果已儲存到紀錄。") : (hasOpenSourceGap ? label("Add the file or choose to continue without it.", "附加檔案，或選擇在沒有檔案下繼續。") : label("Waiting in My Desk. Review the files before sending.", "正在我的辦公桌等待。發送前請覆核檔案。")))
		                : label("Continue the current step here.", "在此繼續目前步驟。")),
              h("div", { className: "ac-suggestions" },
	                h("button", { type: "button", className: "ac-chip", onClick: () => lastWo ? ctx.openPage("workorder", lastWo) : ctx.openPage("workorders") }, lastWo ? label("Open Task", "開啟任務") : label("Open Tasks", "開啟任務")),
	                approvalId && h("button", { type: "button", className: "ac-chip", "data-agent-action": "open-approval-packet", "data-approval-id": approvalId, onClick: () => openApprovalDesk(approvalId) }, lang === "en" ? "Open My Desk · " + approvalId : zhText("開啟我的辦公桌 · " + approvalId, lang))))),
          h("div", { className: "ac-composer" },
	            h("div", { className: "ac-mini-title" }, displayStep ? (lang === "en" ? "Step note · Step " + (currentStep + 1) + " of " + steps.length : zhText("步驟備註 · 第 " + (currentStep + 1) + "/" + steps.length + " 步", lang)) : allComplete ? (approvedWorkflow ? label("Completed summary", "完成摘要") : label("Approval summary ready", "審批摘要已準備")) : label("Ask the guide", "向指引提問")),
	            h("div", { className: "ac-input-wrap" },
		              h("textarea", { className: "field", value: text, rows: 3, "data-agent-composer": "evidence-note", "data-agent-rbac-disabled": canStart ? "false" : "true", disabled: !canStart, title: canStart ? "" : workOrderReason, onChange: (e) => { setText(e.target.value); rememberDraft({ text: e.target.value }); }, "aria-label": "Starter prompt for this task" }),
	              h(Button, { variant: "primary", icon: "send", "data-agent-action": restartable ? "restart-run" : started ? (approvedWorkflow ? "complete" : (allComplete ? (hasOpenSourceGap ? "resolve-source-gap" : "approval-waiting") : "complete-step")) : "start-run", "data-agent-rbac-disabled": canStart ? "false" : "true", title: canStart ? "" : workOrderReason, disabled: !canStart || !text.trim() || loadedOutOfOrder || approvedWorkflow || (started && !restartable && allComplete && !hasOpenSourceGap), onClick: started && !restartable ? (allComplete && hasOpenSourceGap ? focusSourceGapControls : completeStep) : startRun }, restartable ? label("Restart task", "重新開始任務") : started ? (approvedWorkflow ? uiText("Complete", lang) : (allComplete ? (hasOpenSourceGap ? label("Fix missing file", "解決缺失檔案") : uiText("Approval waiting", lang)) : loadedOutOfOrder ? uiText("Load current step", lang) : uiText("Complete step", lang))) : label("Start task", "開始任務"))),
	            loadedOutOfOrder && h("div", { "data-agent-out-of-order-guard": "true", style: { color: "var(--amber)", fontSize: 12 } }, lang === "en" ? "Load the current step before completing it." : zhText("完成前請載入目前步驟。", lang)),
            !canStart && h("div", { style: { color: "var(--text-faint)", fontSize: 12 } }, ctx.denyReason("workOrder")))),
        h(ContextPanel, { skill, color, currentStep, completedSteps, selectedStep, onInspectStep: setSelectedStep, onUseStep: loadStepPrompt, canUsePrompts: canStart, denyReason: workOrderReason, lang })));
  }

  window.Screens.agent = AgentChat;
})();
