@surething/cockpit 1.0.265 → 1.0.266

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.
Files changed (57) hide show
  1. package/.next-prod/BUILD_ID +1 -1
  2. package/.next-prod/app-path-routes-manifest.json +3 -3
  3. package/.next-prod/build-manifest.json +2 -2
  4. package/.next-prod/cockpit-build.json +1 -1
  5. package/.next-prod/prerender-manifest.json +4 -4
  6. package/.next-prod/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next-prod/server/app/_global-error.html +1 -1
  8. package/.next-prod/server/app/_global-error.rsc +1 -1
  9. package/.next-prod/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next-prod/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  11. package/.next-prod/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next-prod/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next-prod/server/app/_not-found.html +2 -2
  14. package/.next-prod/server/app/_not-found.rsc +3 -3
  15. package/.next-prod/server/app/_not-found.segments/_full.segment.rsc +3 -3
  16. package/.next-prod/server/app/_not-found.segments/_index.segment.rsc +3 -3
  17. package/.next-prod/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/.next-prod/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/.next-prod/server/app/m/page.js +1 -1
  20. package/.next-prod/server/app/m/page_client-reference-manifest.js +1 -1
  21. package/.next-prod/server/app/page_client-reference-manifest.js +1 -1
  22. package/.next-prod/server/app/project/page_client-reference-manifest.js +1 -1
  23. package/.next-prod/server/app/review/[id]/page_client-reference-manifest.js +1 -1
  24. package/.next-prod/server/app-paths-manifest.json +3 -3
  25. package/.next-prod/server/chunks/5750.js +11 -11
  26. package/.next-prod/server/chunks/6548.js +1 -1
  27. package/.next-prod/server/middleware-build-manifest.js +1 -1
  28. package/.next-prod/server/pages/404.html +2 -2
  29. package/.next-prod/server/pages/500.html +1 -1
  30. package/.next-prod/server/server-reference-manifest.json +1 -1
  31. package/.next-prod/static/chunks/33940-9631b513c48757f4.js +35 -0
  32. package/.next-prod/static/chunks/46784-031e2d50dc5f9fba.js +716 -0
  33. package/.next-prod/static/chunks/{14333-ced10f36441c568c.js → 5504-583edbefcb22ed17.js} +7 -7
  34. package/.next-prod/static/chunks/{86160-b6431f3093820d49.js → 56819-56e9c6ff8d86d236.js} +1 -1
  35. package/.next-prod/static/chunks/72353-f1aaa693ddc49568.js +15 -0
  36. package/.next-prod/static/chunks/app/{layout-2e2ffdc76c7f77f6.js → layout-60f41d682cd860e9.js} +1 -1
  37. package/.next-prod/static/chunks/app/m/page-7eabf179a8b13f49.js +1 -0
  38. package/.next-prod/static/chunks/app/{page-8b3591aba80eac74.js → page-e83cd7365efbf878.js} +1 -1
  39. package/.next-prod/static/chunks/app/project/{page-8b3591aba80eac74.js → page-e83cd7365efbf878.js} +1 -1
  40. package/.next-prod/static/css/45835d91c2519c62.css +1 -0
  41. package/.next-prod/trace +14 -14
  42. package/.next-prod/trace-build +1 -1
  43. package/apps/file-viewer/app.jsx +83 -8
  44. package/apps/file-viewer/index.html +23 -1
  45. package/dist/scheduledTasks.mjs +38 -12
  46. package/dist/wsServer.mjs +12 -2
  47. package/package.json +1 -1
  48. package/public/html-lib/csv-viewer.css +416 -0
  49. package/public/html-lib/csv-viewer.js +100 -0
  50. package/public/html-lib/json-viewer.js +14 -14
  51. package/.next-prod/static/chunks/21372-8169ef641d8dec08.js +0 -15
  52. package/.next-prod/static/chunks/33940-eab092c09e660ac7.js +0 -35
  53. package/.next-prod/static/chunks/46784-55eed87a21c4c989.js +0 -716
  54. package/.next-prod/static/chunks/app/m/page-25cd9633a00ed40d.js +0 -1
  55. package/.next-prod/static/css/50c1581bbbec6990.css +0 -1
  56. /package/.next-prod/static/{kwmbFJqrsOBSPJpMWySD2 → YOIsQRqVhYPuRyXlhwhoY}/_buildManifest.js +0 -0
  57. /package/.next-prod/static/{kwmbFJqrsOBSPJpMWySD2 → YOIsQRqVhYPuRyXlhwhoY}/_ssgManifest.js +0 -0
@@ -0,0 +1,716 @@
1
+ "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[46784],{2111:(e,t,o)=>{o.d(t,{D:()=>l,h:()=>d});var n=o(12115),a=o(91281),i=o(36196);a.EV(i.YA(1),1.5).pipe(a.gP(a.ji(i.YA(10))),a.y$(a.t5(10))),a.EV(i.ne(200),2).pipe(a.gP(a.ji(i.YA(5))),a.y$(a.t5(5))),a.EV(i.YA(1),2).pipe(a.et,a.gP(a.ji(i.YA(30))),a.y$(a.t5(8))),a.ji(i.YA(30)),a.ji(i.YA(1)),a.ji(i.YA(30)),i.ne(50),a.BW;let r=new Map,s=new Set;function l(e){return s.add(e),()=>{s.delete(e)}}function d({url:e,onMessage:t,enabled:o=!0}){let a=(0,n.useRef)(t);(0,n.useEffect)(()=>{a.current=t}),(0,n.useEffect)(()=>{if(!o)return;let t=e=>a.current(e),n=function(e){let t=r.get(e);if(t)return t;let o={ws:null,listeners:new Set,retryCount:0,retryTimer:null,connect(){let t="https:"===window.location.protocol?"wss:":"ws:",n=new WebSocket(`${t}//${window.location.host}${e}`);n.onopen=()=>{let e=o.retryCount>0;o.retryCount=0,e&&s.forEach(e=>{try{e()}catch(e){console.error("[useWebSocket] reconnect listener threw",e)}})},n.onmessage=e=>{let t;try{t=JSON.parse(e.data)}catch{return}t?.type!=="ping"&&o.listeners.forEach(e=>{try{e(t)}catch(e){console.error("[useWebSocket] listener threw; other listeners unaffected",e)}})},n.onclose=()=>{if(0===o.listeners.size)return;let e=Math.min(1e3*Math.pow(1.5,o.retryCount),1e4);o.retryCount++,o.retryTimer=setTimeout(()=>o.connect(),e)},n.onerror=()=>{},o.ws=n},destroy(){o.retryTimer&&clearTimeout(o.retryTimer),o.ws&&o.ws.close(),o.ws=null,r.delete(e)}};return r.set(e,o),o.connect(),o}(e);return n.listeners.add(t),()=>{n.listeners.delete(t),0===n.listeners.size&&n.destroy()}},[e,o])}},3238:(e,t,o)=>{o.d(t,{DP:()=>r,NP:()=>l,Ql:()=>s});var n=o(95155),a=o(12115);let i=(0,a.createContext)(null);function r(){let e=(0,a.useContext)(i);if(!e)throw Error("useTheme must be used within a ThemeProvider");return e}function s(){return(0,a.useContext)(i)}function l({children:e}){let[t,o]=(0,a.useState)("system"),[r,s]=(0,a.useState)("light"),d=(0,a.useCallback)(()=>window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light",[]),c=(0,a.useCallback)(e=>{let t=document.documentElement;t.classList.remove("light","dark"),t.classList.add(e),s(e);let o=document.querySelector('meta[name="theme-color"]'),n="dark"===e?"#111113":"#f9f9fb";o&&o.setAttribute("content",n)},[]),u=(0,a.useCallback)(e=>{o(e),localStorage.setItem("theme",e),c("system"===e?d():e),document.querySelectorAll("iframe").forEach(t=>{t.contentWindow?.postMessage({type:"THEME_CHANGE",theme:e},"*")})},[d,c]);return(0,a.useEffect)(()=>{let e=localStorage.getItem("theme")||"dark";queueMicrotask(()=>{o(e),c("system"===e?d():e)})},[d,c]),(0,a.useEffect)(()=>{if("system"!==t)return;let e=window.matchMedia("(prefers-color-scheme: dark)"),o=e=>{c(e.matches?"dark":"light")};return e.addEventListener("change",o),()=>e.removeEventListener("change",o)},[t,c]),(0,a.useEffect)(()=>{let e=e=>{if(e.data?.type==="THEME_CHANGE"){let t=e.data.theme;o(t),localStorage.setItem("theme",t),c("system"===t?d():t)}};return window.addEventListener("message",e),()=>window.removeEventListener("message",e)},[d,c]),(0,n.jsx)(i.Provider,{value:{theme:t,resolvedTheme:r,setTheme:u},children:e})}},11890:(e,t,o)=>{function n(e){return e.trim().toLowerCase().replace(/[\s]+/g,"-").replace(/[^\w一-鿿぀-ヿ가-힯-]/g,"").replace(/-{2,}/g,"-").replace(/^-+|-+$/g,"")}function a(e,t){if(!e)return!1;let o=t;try{o=decodeURIComponent(t)}catch{}let a=n(o);if(!a)return!1;for(let t of e.querySelectorAll("h1, h2, h3, h4, h5, h6"))if(n(t.textContent||"")===a)return t.scrollIntoView({behavior:"smooth",block:"start"}),!0;return!1}o.d(t,{O:()=>a})},13219:(e,t,o)=>{o.d(t,{T:()=>N});var n=o(95155),a=o(46361),i=o(79204),r=o(98164),s=o(77815),l=o(97720),d=o(88374);o(84559),o(21227);var c=o(91334),u=o(38194),p=o(88522),h=o(12115),m=o(34582),g=o(3238),f=o(11890),w=o(73620);function y(e){return{type:"tableCell",children:[{type:"text",value:e}]}}let v=[o(54152).A,function(){return e=>{let t=e.children;for(let e=0;e<t.length;e++){let o=t[e];if("yaml"!==o.type)continue;let n=null;try{let e=w.Ay.load(o.value??"");e&&"object"==typeof e&&!Array.isArray(e)&&(n=e)}catch{n=null}let a=n?Object.entries(n):[];if(0===a.length){t.splice(e,1),e--;continue}let i={type:"tableRow",children:[y("Field"),y("Value")]},r=a.map(([e,t])=>({type:"tableRow",children:[y(e),y(function(e){if(null==e)return"";if("string"==typeof e)return e.replace(/\s*\n\s*/g," ").trim();if("number"==typeof e||"boolean"==typeof e)return String(e);try{return JSON.stringify(e)}catch{return String(e)}}(t))]}));t[e]={type:"table",align:["left","left"],children:[i,...r]}}}}],b=[...v,i.A,r.A,s.jb],C=[...v,i.A,s.jb],k=[l.A,d.A],S=[l.A];function x(e){let t=[],o=e=>(t.push(e),` MASK${t.length-1} `);return e.replace(/```[\s\S]*?```/g,e=>o(e)).replace(/~~~[\s\S]*?~~~/g,e=>o(e)).replace(/^(\|.+\|)$/gm,e=>/^\|[\s:|-]+\|$/.test(e)?e:e.replace(/`([^`]*)`/g,(e,t)=>t.includes("|")?"`"+t.replace(/\|/g,"\\|")+"`":e)).replace(/ MASK(\d+) /g,(e,o)=>t[+o])}function T(e){return e.replace(/\$(\d)/g,"\\$$1")}let E=new Set(["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","blockquote","body","br","button","canvas","caption","cite","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","label","legend","li","link","main","map","mark","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","progress","q","rp","rt","ruby","s","samp","script","section","select","slot","small","source","span","strong","style","sub","summary","sup","svg","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","clippath","defs","ellipse","g","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan","use"]);function A(e){let t=[],o=e=>(t.push(e),`\u0000MASK${t.length-1}\u0000`);return e.replace(/```[\s\S]*?```/g,e=>o(e)).replace(/~~~[\s\S]*?~~~/g,e=>o(e)).replace(/`[^`\n]+`/g,e=>o(e)).replace(/<\/?([a-zA-Z][a-zA-Z0-9-]*)(\s[^>]*)?\/?>/g,(e,t)=>{let o=t.toLowerCase();return E.has(o)||o.includes("-")?e:e.replace(/</g,"&lt;").replace(/>/g,"&gt;")}).replace(/\u0000MASK(\d+)\u0000/g,(e,o)=>t[+o])}let N=(0,h.memo)(function({content:e,isUser:t=!1,isStreaming:o=!1,enableMath:i=!0,isDark:r,rehypePlugins:s,onLinkClick:l,basePath:d}){let w=(0,g.Ql)(),y=r??w?.resolvedTheme==="dark",v=(0,h.useRef)(null),E=(0,h.useMemo)(()=>({code({className:e,children:t,node:o,...a}){let i=/language-(\w+)/.exec(e||"");if(!("string"==typeof t||"number"==typeof t||Array.isArray(t)&&t.every(e=>"string"==typeof e||"number"==typeof e)))return(0,n.jsx)("code",{className:"px-1.5 py-0.5 mx-0.5 rounded bg-accent text-sm font-mono",...a,children:t});let r=String(t);if(!i&&!e&&!r.includes("\n"))return(0,n.jsx)("code",{className:"px-1.5 py-0.5 mx-0.5 rounded bg-accent text-sm font-mono",...a,children:t});let s=r.replace(/\n$/,""),l=i?.[1]||"text",d=Number(a["data-source-start"])||0,h=d?d+1:0,m=0;return(0,n.jsx)(c.A,{style:y?u.A:p.A,language:l,PreTag:"div",customStyle:{margin:"0.75rem 0",borderRadius:"0.375rem",fontSize:"0.875rem"},wrapLines:!0,lineProps:()=>{let e=h+m;return m++,{"data-source-start":e,"data-source-end":e,style:{display:"block"}}},children:s})},p:({children:e,node:t,...o})=>(0,n.jsx)("p",{className:"mb-3 last:mb-0",...o,children:e}),h1:({children:e,node:t,...o})=>(0,n.jsx)("h1",{className:"text-xl font-bold mb-3 mt-4 first:mt-0",...o,children:e}),h2:({children:e,node:t,...o})=>(0,n.jsx)("h2",{className:"text-lg font-bold mb-2 mt-3 first:mt-0",...o,children:e}),h3:({children:e,node:t,...o})=>(0,n.jsx)("h3",{className:"text-base font-bold mb-2 mt-3 first:mt-0",...o,children:e}),ul:({children:e,node:t,...o})=>(0,n.jsx)("ul",{className:"list-disc list-inside mb-3 space-y-1",...o,children:e}),ol:({children:e,node:t,...o})=>(0,n.jsx)("ol",{className:"list-decimal list-inside mb-3 space-y-1",...o,children:e}),li:({children:e,node:t,...o})=>(0,n.jsx)("li",{className:"leading-relaxed",...o,children:e}),blockquote:({children:e,node:t,...o})=>(0,n.jsx)("blockquote",{className:"border-l-4 border-border pl-4 my-3 italic text-muted-foreground",...o,children:e}),a:({href:e,children:t,node:o,...a})=>(0,n.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:underline",...a,onClick:t=>{if(e){if(e.startsWith("#")){(0,f.O)(v.current,e.slice(1))&&t.preventDefault();return}l?.(e)&&t.preventDefault()}},children:t}),table:({children:e,node:t,...o})=>(0,n.jsx)("div",{className:"overflow-x-auto my-3",...o,children:(0,n.jsx)("table",{className:"min-w-full border border-border",children:e})}),thead:({children:e,node:t,...o})=>(0,n.jsx)("thead",{className:"bg-accent",...o,children:e}),th:({children:e,node:t,...o})=>(0,n.jsx)("th",{className:"px-4 py-2 text-left font-semibold border-b border-border",...o,children:e}),td:({children:e,node:t,...o})=>(0,n.jsx)("td",{className:"px-4 py-2 border-b border-border",...o,children:e}),hr:({node:e,...t})=>(0,n.jsx)("hr",{className:"my-4 border-border",...t}),img:({src:e,alt:t,node:o,height:a,width:i,style:r,...s})=>{let l=d&&"string"==typeof e?(0,m.xh)(e,d):e;if(!(a||i||r))return(0,n.jsx)("img",{src:l,alt:t||"",className:"max-w-full h-auto rounded-lg my-3",...s});let c=e=>e?/^\d+$/.test(String(e))?`${e}px`:String(e):void 0,u={...r,height:c(a)??r?.height,width:c(i)??r?.width};return(0,n.jsx)("img",{src:l,alt:t||"",style:u,className:"inline-block align-middle",...s})},strong:({children:e,node:t,...o})=>(0,n.jsx)("strong",{className:"font-bold",...o,children:e}),em:({children:e,node:t,...o})=>(0,n.jsx)("em",{className:"italic",...o,children:e}),del:({children:e,node:t,...o})=>(0,n.jsx)("del",{className:"line-through",...o,children:e})}),[y,l,d]),N=i?b:C,F=i?k:S,P=(0,h.useMemo)(()=>{if(t||o)return A(e);let n=A(x(!function(e){if(/^\|[\s:|-]+\|$/m.test(e))return!1;if(/[┌┐└┘│─├┤┬┴┼╔╗╚╝║═╭╮╯╰▲▼◀▶△▽◁▷]/.test(e)||/\+[-=]{2,}\+/.test(e))return!0;let t=e.split("\n").filter(e=>/^\s*\||\|\s*$/.test(e));if(t.length>=3){let e=t.map(e=>(e.match(/\|/g)||[]).length);return!e.every(t=>t===e[0])||!(e[0]>=3)}return!1}(e)||/^```[\s\S]*```$/m.test(e.trim())?e:"```text\n"+e.trim()+"\n```"));return i?T(n):n},[e,t,o,i]),L=(0,h.useMemo)(()=>s?.length?[...F,...s]:F,[s,F]);if(t)return(0,n.jsx)("div",{className:"whitespace-pre-wrap break-words",children:e});if(o){let t=e.lastIndexOf("\n");if(-1===t)return(0,n.jsx)("div",{className:"whitespace-pre-wrap break-words",children:e});let o=e.slice(0,t+1),r=e.slice(t+1);return(0,n.jsxs)("div",{className:"markdown-body",ref:v,children:[(0,n.jsx)(a.oz,{remarkPlugins:N,rehypePlugins:F,components:E,children:i?T(A(x(o))):A(x(o))}),r&&(0,n.jsx)("span",{className:"whitespace-pre-wrap",children:r})]})}return(0,n.jsx)("div",{className:"markdown-body",ref:v,children:(0,n.jsx)(a.oz,{remarkPlugins:N,rehypePlugins:L,components:E,children:P})})})},34075:(e,t,o)=>{o.d(t,{dj:()=>s,lJ:()=>u,oR:()=>h,tE:()=>l});var n=o(95155),a=o(12115),i=o(69809);let r=(0,a.createContext)(null);function s(){let e=(0,a.useContext)(r);if(!e)throw Error("useToast must be used within a ToastProvider");return e}function l({children:e}){let[t,o]=(0,a.useState)([]),i=(0,a.useCallback)((e,t="success")=>{let n=`toast-${Date.now()}`;o(o=>[...o,{id:n,message:e,type:t}])},[]),s=(0,a.useCallback)(e=>{o(t=>t.filter(t=>t.id!==e))},[]);return(0,n.jsxs)(r.Provider,{value:{showToast:i},children:[e,(0,n.jsx)(d,{toasts:t,onRemove:s})]})}function d({toasts:e,onRemove:t}){return(0,n.jsx)("div",{className:"fixed top-4 left-1/2 -translate-x-1/2 z-[100] flex flex-col items-center gap-2 max-w-[26rem]",children:e.map(e=>(0,n.jsx)(c,{toast:e,onRemove:t},e.id))})}function c({toast:e,onRemove:t}){(0,a.useEffect)(()=>{let o=setTimeout(()=>{t(e.id)},3e3);return()=>clearTimeout(o)},[e.id,t]);let o={success:"bg-green-9",error:"bg-red-9",info:"bg-brand"}[e.type],i={success:(0,n.jsx)("svg",{className:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M5 13l4 4L19 7"})}),error:(0,n.jsx)("svg",{className:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})}),info:(0,n.jsx)("svg",{className:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})})}[e.type];return(0,n.jsxs)("div",{className:`${o} text-white px-4 py-3 rounded-lg shadow-lv2 flex items-center gap-3 min-w-[200px] animate-slide-in`,style:{animation:"slideIn 0.3s ease-out"},children:[i,(0,n.jsx)("span",{className:"text-sm",children:e.message}),(0,n.jsx)("button",{onClick:()=>t(e.id),className:"ml-auto p-1 hover:bg-white/20 rounded transition-colors",children:(0,n.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]})}function u(e,t){let{title:o=i.A.t("confirm.title",{defaultValue:"Confirm"}),confirmText:n=i.A.t("confirm.ok",{defaultValue:"OK"}),cancelText:a=i.A.t("confirm.cancel",{defaultValue:"Cancel"}),danger:r=!1}=t||{};return new Promise(t=>{let i=document.createElement("div");i.className="fixed inset-0 z-[200] flex items-center justify-center",i.style.animation="confirmFadeIn 0.15s ease-out";let s=e=>{i.style.animation="confirmFadeOut 0.12s ease-in",i.addEventListener("animationend",()=>{document.body.removeChild(i),t(e)},{once:!0})};i.addEventListener("mousedown",e=>{e.target===i&&s(!1)});let l=e=>{"Escape"===e.key?(e.stopPropagation(),document.removeEventListener("keydown",l,!0),s(!1)):"Enter"===e.key&&(e.stopPropagation(),document.removeEventListener("keydown",l,!0),s(!0))};document.addEventListener("keydown",l,!0),i.innerHTML=`
2
+ <div class="fixed inset-0 bg-scrim"></div>
3
+ <div class="relative bg-card border border-border rounded-xl shadow-lv3 p-6 max-w-sm w-full mx-4" style="animation: confirmScaleIn 0.15s ease-out">
4
+ <div class="text-base font-medium text-foreground mb-2">${o}</div>
5
+ <div class="text-sm text-muted-foreground mb-6">${e}</div>
6
+ <div class="flex justify-end gap-3">
7
+ <button data-action="cancel" class="px-4 py-2 text-sm rounded-lg border border-border text-foreground hover:bg-hover transition-colors">${a}</button>
8
+ <button data-action="confirm" class="px-4 py-2 text-sm rounded-lg ${r?"bg-red-9 hover:bg-red-10 text-white":"bg-brand hover:bg-brand/90 text-white"} transition-colors">${n}</button>
9
+ </div>
10
+ </div>
11
+ `,i.querySelector('[data-action="cancel"]').addEventListener("click",()=>{document.removeEventListener("keydown",l,!0),s(!1)}),i.querySelector('[data-action="confirm"]').addEventListener("click",()=>{document.removeEventListener("keydown",l,!0),s(!0)}),document.body.appendChild(i),i.querySelector('[data-action="confirm"]')?.focus()})}let p=null;function h(e,t="success"){let o=(p||((p=document.createElement("div")).id="toast-container",p.className="fixed top-4 left-1/2 -translate-x-1/2 z-[100] flex flex-col items-center gap-2 max-w-[26rem]",document.body.appendChild(p)),p),n=document.createElement("div");n.className=`${"success"===t?"bg-green-9":"error"===t?"bg-red-9":"bg-brand"} text-white px-4 py-3 rounded-lg shadow-lv2 flex items-center gap-3 min-w-[200px]`,n.style.animation="slideIn 0.3s ease-out",n.innerHTML=`
12
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">${"success"===t?'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />':"error"===t?'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />':'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />'}</svg>
13
+ <span class="text-sm">${e}</span>
14
+ `,o.appendChild(n),setTimeout(()=>{n.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{o.removeChild(n)},300)},3e3)}},34582:(e,t,o)=>{o.d(t,{J4:()=>r,Kx:()=>m,OP:()=>w,PB:()=>f,Xe:()=>c,hE:()=>g,qF:()=>s,xh:()=>p});let n=`
15
+ (function () {
16
+ if (window.cockpit) return;
17
+
18
+ // Language — parked on <html data-cockpit-lang>, NOT delivered by listener
19
+ // alone. The host pushes cockpit:language-change once, on the iframe's load
20
+ // event. Anything registering a listener later misses it forever, and the
21
+ // widget bundles (/html-lib markdown / json / pdf) are lazily fetched — they
22
+ // always register after load, so they used to fall back to navigator.language
23
+ // and disagree with the Cockpit setting until the user toggled it. This script
24
+ // is injected at the very start of <head>, so it is guaranteed to be listening
25
+ // first; parking the value turns a one-shot message into order-independent
26
+ // state any later reader can just read.
27
+ //
28
+ // A DEDICATED attribute, not <html lang>: pages ship their own lang="en" (the
29
+ // built-in file-viewer does), so <html lang> cannot distinguish "the host told
30
+ // us" from "the document's own default" — reading it would pin every reader to
31
+ // the page's hardcoded value and silently kill the navigator fallback.
32
+ var applyLang = function (lang) {
33
+ if (!lang) return;
34
+ try {
35
+ document.documentElement.setAttribute('data-cockpit-lang', lang);
36
+ document.documentElement.lang = lang; // keep the document honest for a11y
37
+ } catch (e) {}
38
+ };
39
+ window.addEventListener('message', function (ev) {
40
+ var d = ev && ev.data;
41
+ if (d && d.type === 'cockpit:language-change') applyLang(d.lang);
42
+ });
43
+
44
+ // Dock — the one floating container every piece of host chrome mounts into
45
+ // (theme toggle, bash call log). Independent floating buttons do not work:
46
+ // they all default to the same corner and cover each other, and the user then
47
+ // has to drag each one separately off whatever the app put underneath.
48
+ //
49
+ // The dock is DRAGGABLE and snaps to whichever of the 4 viewport corners it
50
+ // was released nearest to. A fixed corner is unworkable: the host picks the
51
+ // spot, the app owns the content, and any app with its own corner affordance
52
+ // (close button, toolbar, TOC) had it permanently covered with no escape.
53
+ // Only the CORNER is persisted, never pixels: on resize/rotate a remembered
54
+ // coordinate can land off-screen, while a corner is always re-derivable. It is
55
+ // remembered GLOBALLY (not per app) — one gesture then holds for every HTML
56
+ // app, which is the common case since apps tend to crowd the same corner.
57
+ //
58
+ // Created lazily on the first add(), so a page that activates neither feature
59
+ // gets no DOM at all.
60
+ var DOCK_BTN_CSS = 'width:36px;height:36px;border-radius:8px;flex:none;' +
61
+ 'border:1px solid rgba(128,128,128,.3);background:rgba(128,128,128,.14);' +
62
+ 'color:inherit;cursor:pointer;font-size:14px;line-height:1;display:flex;' +
63
+ 'align-items:center;justify-content:center;padding:0';
64
+ var dock = (function () {
65
+ // Key predates the dock: a user who already dragged the lone theme button
66
+ // keeps that choice instead of silently getting reset to the default corner.
67
+ var CORNER_KEY = 'htmlapp-theme-corner'; // 'tl' | 'tr' | 'bl' | 'br'
68
+ var CORNER_MARGIN = 10;
69
+ var corner = 'tr'; // default = the historic position
70
+ try {
71
+ var storedCorner = localStorage.getItem(CORNER_KEY);
72
+ if (storedCorner === 'tl' || storedCorner === 'tr' ||
73
+ storedCorner === 'bl' || storedCorner === 'br') corner = storedCorner;
74
+ } catch (e) {}
75
+
76
+ var el = null;
77
+ var queued = [];
78
+ var watchers = [];
79
+
80
+ var applyCorner = function () {
81
+ if (el) {
82
+ var s = el.style;
83
+ var atTop = corner.charAt(0) === 't';
84
+ var atLeft = corner.charAt(1) === 'l';
85
+ s.top = atTop ? CORNER_MARGIN + 'px' : 'auto';
86
+ s.bottom = atTop ? 'auto' : CORNER_MARGIN + 'px';
87
+ s.left = atLeft ? CORNER_MARGIN + 'px' : 'auto';
88
+ s.right = atLeft ? 'auto' : CORNER_MARGIN + 'px';
89
+ }
90
+ for (var i = 0; i < watchers.length; i++) {
91
+ try { watchers[i](corner); } catch (e) {}
92
+ }
93
+ };
94
+
95
+ var dragging = false; // past the slop threshold for THIS gesture
96
+ var didDrag = false; // a drag happened -> swallow the trailing click
97
+ var held = null; // element holding the pointer capture; see pointerdown
98
+ var startX = 0, startY = 0, grabX = 0, grabY = 0;
99
+
100
+ var build = function () {
101
+ el = document.createElement('div');
102
+ // touch-action:none — the drag is pointer-driven, so the browser must not
103
+ // also treat the gesture as a scroll. Without it a touch-drag inside an
104
+ // iframe can scroll-chain to the Cockpit shell behind it.
105
+ el.style.cssText = 'position:fixed;z-index:2147483647;display:flex;' +
106
+ 'flex-direction:column;gap:8px;touch-action:none';
107
+ applyCorner();
108
+
109
+ // Pointer LISTENERS sit on the container (one set for every button), but
110
+ // the CAPTURE has to stay on the pressed button: per Pointer Events, a
111
+ // click is dispatched to the capture target, so capturing on the container
112
+ // silently eats every button click — the buttons render and do nothing.
113
+ // Capturing the child instead keeps click on the button, and the moves it
114
+ // now receives still bubble up to these listeners.
115
+ el.addEventListener('pointerdown', function (ev) {
116
+ if (ev.button) return; // primary button / touch / pen only
117
+ dragging = false;
118
+ didDrag = false; // reset here, so a swallowed click
119
+ // can never leak into the next press
120
+ startX = ev.clientX; startY = ev.clientY;
121
+ var r = el.getBoundingClientRect();
122
+ grabX = ev.clientX - r.left; grabY = ev.clientY - r.top;
123
+ var target = ev.target && ev.target.setPointerCapture ? ev.target : el;
124
+ held = null;
125
+ // No capture (or a refused one) just means no drag this gesture — the
126
+ // click still works, which is the one thing that must never break.
127
+ try { target.setPointerCapture(ev.pointerId); held = target; } catch (e) {}
128
+ });
129
+
130
+ el.addEventListener('pointermove', function (ev) {
131
+ if (!held || !held.hasPointerCapture || !held.hasPointerCapture(ev.pointerId)) return;
132
+ if (!dragging) {
133
+ // Slop before a press becomes a drag: a finger never holds as still as
134
+ // a mouse, so touch needs the looser threshold or taps turn into drags.
135
+ var slop = ev.pointerType === 'touch' ? 8 : 5;
136
+ if (Math.abs(ev.clientX - startX) < slop &&
137
+ Math.abs(ev.clientY - startY) < slop) return;
138
+ dragging = true; didDrag = true;
139
+ }
140
+ ev.preventDefault();
141
+ var s = el.style;
142
+ s.right = 'auto'; s.bottom = 'auto'; // free-float while held
143
+ s.left = (ev.clientX - grabX) + 'px';
144
+ s.top = (ev.clientY - grabY) + 'px';
145
+ });
146
+
147
+ var release = function (ev) {
148
+ if (!held) return;
149
+ try { held.releasePointerCapture(ev.pointerId); } catch (e) {}
150
+ held = null;
151
+ };
152
+
153
+ el.addEventListener('pointerup', function (ev) {
154
+ release(ev);
155
+ if (!dragging) return;
156
+ dragging = false;
157
+ var r = el.getBoundingClientRect();
158
+ corner = ((r.top + r.height / 2) < window.innerHeight / 2 ? 't' : 'b') +
159
+ ((r.left + r.width / 2) < window.innerWidth / 2 ? 'l' : 'r');
160
+ try { localStorage.setItem(CORNER_KEY, corner); } catch (e) {}
161
+ applyCorner();
162
+ });
163
+
164
+ el.addEventListener('pointercancel', function (ev) {
165
+ dragging = false;
166
+ release(ev);
167
+ applyCorner(); // snap back rather than strand it
168
+ });
169
+
170
+ // Capture phase on the container, so the click that trails a drag is
171
+ // swallowed BEFORE it reaches the button it was released over. Buttons
172
+ // keep plain click handlers, so keyboard activation still toggles.
173
+ el.addEventListener('click', function (ev) {
174
+ if (!didDrag) return;
175
+ didDrag = false;
176
+ ev.stopPropagation();
177
+ ev.preventDefault();
178
+ }, true);
179
+
180
+ window.addEventListener('resize', applyCorner);
181
+ document.body.appendChild(el);
182
+ };
183
+
184
+ var flush = function () {
185
+ if (!document.body) return; // retried on DOMContentLoaded
186
+ if (!el) build();
187
+ for (var i = 0; i < queued.length; i++) el.appendChild(queued[i]);
188
+ queued = [];
189
+ };
190
+ document.addEventListener('DOMContentLoaded', flush);
191
+
192
+ return {
193
+ // The order fixes the slot regardless of WHEN a button is added — the theme
194
+ // toggle waits for DOMContentLoaded, the log button for the page's first
195
+ // bash call, so append order alone would shuffle them around.
196
+ add: function (node, order) {
197
+ node.style.order = String(order);
198
+ queued.push(node);
199
+ flush();
200
+ },
201
+ corner: function () { return corner; },
202
+ // Panels anchored to the dock re-place themselves on every corner change.
203
+ watch: function (fn) { watchers.push(fn); }
204
+ };
205
+ })();
206
+
207
+ // Host theme, tracked UNCONDITIONALLY — deliberately separate from the opt-in
208
+ // theme block below. Host chrome (the call-log panel) has to match Cockpit on
209
+ // EVERY previewed page, but the .dark class is only maintained for pages that
210
+ // declared <meta name="cockpit-theme">, which most previewed files never do.
211
+ // Reading the class alone would leave the panel stuck dark on a light page.
212
+ var hostDark = null; // null = the host has not told us anything yet
213
+ var themeActive = false; // page opted into theming -> .dark is authoritative
214
+ window.addEventListener('message', function (ev) {
215
+ var d = ev && ev.data;
216
+ if (!d || d.type !== 'THEME_CHANGE') return;
217
+ hostDark = d.theme === 'dark' || (d.theme === 'system' &&
218
+ !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches));
219
+ applyAuditTheme();
220
+ });
221
+
222
+ // Effective dark/light for host chrome: the page's own theme when it opted in
223
+ // (so its toggle — and any stored per-app choice — drives the panel too), else
224
+ // whatever the host last pushed, else the OS preference.
225
+ function chromeDark() {
226
+ try {
227
+ if (themeActive) return document.documentElement.classList.contains('dark');
228
+ if (hostDark !== null) return hostDark;
229
+ return !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
230
+ } catch (e) { return false; }
231
+ }
232
+
233
+ // Theme — OPT-IN. The floating toggle + any .dark class management
234
+ // happen ONLY when the page declares <meta name="cockpit-theme" content="...">.
235
+ // Rationale: injection is by file type, not by SDK usage, so plain one-off pages
236
+ // (notes, reports) with no dark styling used to get a dead button that toggled a
237
+ // .dark class nothing responds to. Requiring an explicit opt-in marker keeps the
238
+ // button off those pages, while apps that provide :root/.dark tokens just add the
239
+ // meta to get a free host-managed toggle — no per-app button code needed.
240
+ // content="auto" → first load with no stored choice follows the OS preference
241
+ // content="light" → first load defaults to light (still user-toggleable)
242
+ // content="dark" → first load defaults to dark
243
+ // The user's explicit toggle is REMEMBERED per app (key namespaced by cockpit-name,
244
+ // else page path) across reloads, and wins over the content default on next load.
245
+ // localStorage is SHARED with Cockpit + every other app, hence the namespaced key.
246
+ // Apps can also drive it programmatically via window.cockpit.toggleTheme().
247
+ var toggleTheme = function () {};
248
+ var initTheme = function () {
249
+ try {
250
+ var themeMeta = function (n) {
251
+ var el = document.querySelector('meta[name="' + n + '"]');
252
+ return el ? el.content : '';
253
+ };
254
+ var themeSetting = (themeMeta('cockpit-theme') || '').toLowerCase().trim();
255
+ if (themeSetting) {
256
+ themeActive = true;
257
+ var themeKey = 'htmlapp-theme:' + (themeMeta('cockpit-name') || location.pathname);
258
+ // Store the explicit choice both ways so it round-trips regardless of the
259
+ // content default (a bare "store only dark" model would lose a user's light
260
+ // choice under content="auto" on a dark OS).
261
+ var themeStore = function (d) {
262
+ try { localStorage.setItem(themeKey, d ? 'dark' : 'light'); } catch (e) {}
263
+ };
264
+ var themeBtn = null;
265
+ var setDark = function (d, persist) {
266
+ document.documentElement.classList.toggle('dark', !!d);
267
+ if (persist) themeStore(!!d);
268
+ if (themeBtn) themeBtn.textContent = d ? '☀️' : '\u{1F319}';
269
+ applyAuditTheme(); // host chrome follows the page it is sitting on
270
+ };
271
+ toggleTheme = function () {
272
+ setDark(!document.documentElement.classList.contains('dark'), true);
273
+ };
274
+ // Init: remembered user choice wins; else the content default; "auto" follows OS.
275
+ var stored = null;
276
+ try { stored = localStorage.getItem(themeKey); } catch (e) {}
277
+ var initDark;
278
+ if (stored === 'dark' || stored === 'light') initDark = stored === 'dark';
279
+ else if (themeSetting === 'dark') initDark = true;
280
+ else if (themeSetting === 'auto') initDark = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
281
+ else initDark = false; // light / unknown
282
+ setDark(initDark, false);
283
+ // Follow the Cockpit host theme by default: the console bubble pushes a
284
+ // THEME_CHANGE on iframe load and ThemeProvider broadcasts it on toggle.
285
+ // An explicit per-app user choice (stored) always wins over the host.
286
+ window.addEventListener('message', function (ev) {
287
+ var d = ev && ev.data;
288
+ if (!d || d.type !== 'THEME_CHANGE') return;
289
+ var userChoice = null;
290
+ try { userChoice = localStorage.getItem(themeKey); } catch (e) {}
291
+ if (userChoice === 'dark' || userChoice === 'light') return;
292
+ var hostDark = d.theme === 'dark' || (d.theme === 'system' &&
293
+ !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches));
294
+ setDark(hostDark, false);
295
+ });
296
+ // Positioning, dragging and corner memory all belong to the dock — this
297
+ // button only has to look like one and say what it does.
298
+ themeBtn = document.createElement('button');
299
+ themeBtn.type = 'button';
300
+ themeBtn.setAttribute('aria-label', 'Toggle theme');
301
+ themeBtn.textContent = document.documentElement.classList.contains('dark') ? '☀️' : '\u{1F319}';
302
+ themeBtn.style.cssText = DOCK_BTN_CSS;
303
+ // A click handler rather than pointerup, so keyboard activation
304
+ // (Enter/Space on the focused button) still toggles. The click that
305
+ // trails a drag is swallowed by the dock before it gets here.
306
+ themeBtn.onclick = function () { toggleTheme(); };
307
+ dock.add(themeBtn, 0);
308
+ }
309
+ } catch (e) {}
310
+ };
311
+ // This script is injected at the START of <head>, BEFORE the page's own
312
+ // <meta> tags are parsed — reading them synchronously here always misses
313
+ // them. Defer theme init until the DOM is ready so the opt-in meta is seen.
314
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initTheme);
315
+ else initTheme();
316
+
317
+ var CWD = __CWD__;
318
+ var WS_URL = __WS_URL__;
319
+
320
+ var ws = null;
321
+ var ready = false;
322
+ var queue = []; // [{ id, s }] — pending frames, drained on open
323
+ var handlers = {}; // id -> { onStdout, onStderr, onExit, onError, gen }
324
+ var seq = 0;
325
+ var gen = 0; // connection generation; see ensureWs
326
+
327
+ function resolveWsUrl() {
328
+ if (WS_URL) return WS_URL;
329
+ var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
330
+ return proto + '//' + location.host + '/ws/bash?cwd=' + encodeURIComponent(CWD);
331
+ }
332
+
333
+ function failAll(reason) {
334
+ var ids = Object.keys(handlers);
335
+ for (var i = 0; i < ids.length; i++) {
336
+ var h = handlers[ids[i]];
337
+ delete handlers[ids[i]];
338
+ if (h && h.onError) h.onError(reason);
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Fail only the commands carried by ONE connection. Handlers are tagged with
344
+ * the generation of the socket that actually wrote them, so a socket that has
345
+ * been replaced can report its own losses without touching its successor's
346
+ * in-flight work.
347
+ */
348
+ function failGen(g, reason) {
349
+ var ids = Object.keys(handlers);
350
+ for (var i = 0; i < ids.length; i++) {
351
+ var h = handlers[ids[i]];
352
+ if (!h || h.gen !== g) continue;
353
+ delete handlers[ids[i]];
354
+ if (h.onError) h.onError(reason);
355
+ }
356
+ }
357
+
358
+ function ensureWs() {
359
+ if (ws && (ws.readyState === 0 || ws.readyState === 1)) return;
360
+ // A socket in CLOSING(2) is replaced here rather than waited on, so two
361
+ // sockets can briefly coexist. Shared state (\`ready\`, \`queue\`) may only
362
+ // be touched by the CURRENT socket — otherwise a replaced socket's late
363
+ // onclose flips \`ready\` to false while its successor is already open, and
364
+ // since the successor's onopen has long since fired nothing ever sets it
365
+ // back: every later bash() then queues forever with no error at all.
366
+ var myGen = ++gen;
367
+ var sock;
368
+ try { sock = new WebSocket(resolveWsUrl()); }
369
+ catch (e) { failAll(String(e)); return; }
370
+ ws = sock;
371
+ ready = false;
372
+ sock.onopen = function () {
373
+ if (ws !== sock) return;
374
+ ready = true;
375
+ var q = queue; queue = [];
376
+ for (var i = 0; i < q.length; i++) {
377
+ // Re-tag: this socket, not the one queued them, is the carrier.
378
+ if (handlers[q[i].id]) handlers[q[i].id].gen = myGen;
379
+ sock.send(q[i].s);
380
+ }
381
+ };
382
+ // NOT generation-guarded: ids are globally unique, so a late frame can only
383
+ // belong to the command this very socket carried. Dropping it would leave
384
+ // that command's promise unsettled forever.
385
+ sock.onmessage = function (ev) {
386
+ var msg;
387
+ try { msg = JSON.parse(ev.data); } catch (e) { return; }
388
+ if (msg.type === 'ping') return;
389
+ var h = handlers[msg.id];
390
+ if (!h) return;
391
+ if (msg.type === 'stdout') { if (h.onStdout) h.onStdout(msg.data); }
392
+ else if (msg.type === 'stderr') { if (h.onStderr) h.onStderr(msg.data); }
393
+ else if (msg.type === 'exit') { delete handlers[msg.id]; if (h.onExit) h.onExit(msg.code); }
394
+ else if (msg.type === 'error') { delete handlers[msg.id]; if (h.onError) h.onError(msg.message); }
395
+ };
396
+ sock.onclose = function () {
397
+ if (ws === sock) {
398
+ ready = false;
399
+ // Drop anything still queued and fail it here. These are shell commands
400
+ // with side effects: letting a later reconnect drain this queue would
401
+ // re-run them with their handlers already gone, so the output would go
402
+ // nowhere and the caller would never learn it ran twice.
403
+ var q = queue; queue = [];
404
+ for (var i = 0; i < q.length; i++) {
405
+ var qh = handlers[q[i].id];
406
+ if (!qh) continue;
407
+ delete handlers[q[i].id];
408
+ if (qh.onError) qh.onError('connection closed');
409
+ }
410
+ }
411
+ // Always report THIS connection's own losses, current or replaced — a
412
+ // replaced socket still owes an answer to whatever it was carrying.
413
+ failGen(myGen, 'connection closed');
414
+ };
415
+ sock.onerror = function () { /* onclose follows */ };
416
+ }
417
+
418
+ function send(obj) {
419
+ var s = JSON.stringify(obj);
420
+ ensureWs();
421
+ // Tag AFTER ensureWs — it may have opened a new connection, and what
422
+ // matters is which socket ends up carrying this command.
423
+ if (obj.id && handlers[obj.id]) handlers[obj.id].gen = gen;
424
+ if (ready && ws && ws.readyState === 1) ws.send(s);
425
+ else queue.push({ id: obj.id, s: s });
426
+ }
427
+
428
+ // ── Bash call log ─────────────────────────────────────────────────────────
429
+ // Every bash() the page issues is recorded and shown in a floating panel, so
430
+ // the user can audit what a previewed page actually ran. Previewing a local
431
+ // .html RUNS it, with full shell access, and until now that happened with no
432
+ // trace anywhere: /ws/bash deliberately stays out of terminal history and logs
433
+ // only the cwd of a connection, never a command.
434
+ //
435
+ // NOT opt-in via <meta>, unlike the theme toggle: a page that could switch the
436
+ // log off by omitting a tag would simply omit it. Instead the button stays
437
+ // hidden until the page's FIRST bash call — so a plain note/report still gets
438
+ // no chrome, and the button appearing is itself the signal that this page ran
439
+ // something.
440
+ //
441
+ // In memory, per page: a reload clears the log, and so does the panel's Clear
442
+ // button. NOT localStorage — that store is shared with Cockpit and writable by
443
+ // the page, so a persisted log would be forgeable by the very code it audits.
444
+ // Nothing is exposed on window.cockpit for the same reason: this is host
445
+ // chrome reporting on the page, not a feature the page gets to drive.
446
+ var AUDIT_MAX = 300; // ring bound — a page can call bash() in a loop
447
+ // Two palettes, applied as custom properties on the panel: every descendant
448
+ // reads var(--cpk-*), so a theme flip is one property write instead of a
449
+ // re-render, and rows built earlier restyle themselves.
450
+ var AUDIT_THEME = {
451
+ dark: {
452
+ bg: 'rgba(28,28,30,.97)', fg: '#e8e8ea', bd: 'rgba(255,255,255,.14)',
453
+ line: 'rgba(255,255,255,.09)', btn: 'rgba(255,255,255,.22)',
454
+ shadow: '0 8px 30px rgba(0,0,0,.45)',
455
+ running: '#e0a648', exit: '#4ea774', error: '#e0605c', killed: '#8a8a8e'
456
+ },
457
+ light: {
458
+ bg: 'rgba(255,255,255,.98)', fg: '#1c1c1e', bd: 'rgba(0,0,0,.16)',
459
+ line: 'rgba(0,0,0,.09)', btn: 'rgba(0,0,0,.22)',
460
+ shadow: '0 8px 30px rgba(0,0,0,.18)',
461
+ // Darker than their dark-mode counterparts — the same green/amber that
462
+ // reads well on near-black washes out entirely on near-white.
463
+ running: '#9a6510', exit: '#2f7d52', error: '#c0392b', killed: '#6b6b70'
464
+ }
465
+ };
466
+ var AUDIT_HEAD_BTN_CSS = 'border:1px solid var(--cpk-btn);background:transparent;' +
467
+ 'color:inherit;border-radius:6px;padding:2px 8px;font-size:11px;cursor:pointer;flex:none';
468
+ var calls = [];
469
+ var callIndex = {}; // id -> record, only while in flight
470
+ var auditBtn = null, auditPanel = null, auditList = null, auditTitle = null;
471
+ var auditOpen = false;
472
+
473
+ function auditStart(id, command, cwd, background) {
474
+ try {
475
+ var rec = {
476
+ command: String(command),
477
+ cwd: cwd,
478
+ background: !!background,
479
+ startedAt: Date.now(),
480
+ endedAt: 0,
481
+ state: 'running', // running | exit | error | killed
482
+ code: null,
483
+ message: ''
484
+ };
485
+ calls.push(rec);
486
+ if (calls.length > AUDIT_MAX) calls.shift();
487
+ callIndex[id] = rec;
488
+ mountAuditBtn();
489
+ renderAudit();
490
+ } catch (e) {}
491
+ }
492
+
493
+ // The state is terminal once set: kill() settles the record itself, and a real
494
+ // exit frame may still arrive afterwards for the same id.
495
+ function auditSettle(id, state, detail) {
496
+ try {
497
+ var rec = callIndex[id];
498
+ if (!rec) return;
499
+ delete callIndex[id];
500
+ if (rec.state !== 'running') return;
501
+ rec.state = state;
502
+ rec.endedAt = Date.now();
503
+ if (state === 'exit') rec.code = detail;
504
+ else if (detail != null) rec.message = String(detail);
505
+ renderAudit();
506
+ } catch (e) {}
507
+ }
508
+
509
+ function auditStatusText(rec) {
510
+ if (rec.state === 'running') return 'running';
511
+ if (rec.state === 'killed') return 'killed';
512
+ if (rec.state === 'error') return rec.message ? 'error: ' + rec.message : 'error';
513
+ return 'exit ' + rec.code;
514
+ }
515
+
516
+ function auditRow(rec) {
517
+ var row = document.createElement('div');
518
+ row.style.cssText = 'padding:8px 10px;border-top:1px solid var(--cpk-line)';
519
+ var cmd = document.createElement('div');
520
+ // textContent, never innerHTML — this string comes from the page being audited.
521
+ cmd.textContent = rec.command;
522
+ cmd.style.cssText = 'font-family:ui-monospace,SFMono-Regular,Menlo,monospace;' +
523
+ 'font-size:12px;line-height:1.45;white-space:pre-wrap;word-break:break-all';
524
+ var bits = [];
525
+ try { bits.push(new Date(rec.startedAt).toTimeString().slice(0, 8)); } catch (e) {}
526
+ bits.push(auditStatusText(rec));
527
+ if (rec.endedAt) bits.push(((rec.endedAt - rec.startedAt) / 1000).toFixed(2) + 's');
528
+ if (rec.background) bits.push('background');
529
+ // Only when it differs from the page's own cwd — otherwise it is noise on
530
+ // every single row.
531
+ if (rec.cwd && rec.cwd !== CWD) bits.push(rec.cwd);
532
+ var bad = rec.state === 'error' || (rec.state === 'exit' && rec.code !== 0);
533
+ var meta = document.createElement('div');
534
+ meta.textContent = bits.join(' \xb7 ');
535
+ meta.style.cssText = 'margin-top:3px;font-size:11px;color:var(--cpk-' +
536
+ (bad ? 'error' : rec.state) + ')';
537
+ row.appendChild(cmd);
538
+ row.appendChild(meta);
539
+ return row;
540
+ }
541
+
542
+ // Records accumulate whether or not anyone is looking; this only paints, and
543
+ // a closed panel is repainted once on open instead. That is not a micro
544
+ // optimization: a page can call bash() in a loop, and rebuilding every row per
545
+ // call behind a hidden panel is quadratic work for nobody.
546
+ function renderAudit() {
547
+ if (!auditPanel || !auditOpen) return;
548
+ auditTitle.textContent = 'Bash calls (' + calls.length + ')';
549
+ while (auditList.firstChild) auditList.removeChild(auditList.firstChild);
550
+ if (!calls.length) {
551
+ var empty = document.createElement('div');
552
+ empty.style.cssText = 'padding:14px 10px;font-size:12px;opacity:.6';
553
+ empty.textContent = 'No calls recorded.';
554
+ auditList.appendChild(empty);
555
+ return;
556
+ }
557
+ // Newest first: the reason to open this panel is almost always "what did it
558
+ // just run".
559
+ for (var i = calls.length - 1; i >= 0; i--) auditList.appendChild(auditRow(calls[i]));
560
+ }
561
+
562
+ // Called on every host theme change, including before the panel exists.
563
+ function applyAuditTheme() {
564
+ if (!auditPanel) return;
565
+ var tone = AUDIT_THEME[chromeDark() ? 'dark' : 'light'];
566
+ for (var k in tone) auditPanel.style.setProperty('--cpk-' + k, tone[k]);
567
+ }
568
+
569
+ function placeAuditPanel() {
570
+ if (!auditPanel) return;
571
+ var c = dock.corner();
572
+ var s = auditPanel.style;
573
+ var atTop = c.charAt(0) === 't';
574
+ var atLeft = c.charAt(1) === 'l';
575
+ s.top = atTop ? '10px' : 'auto';
576
+ s.bottom = atTop ? 'auto' : '10px';
577
+ // 56px = dock margin (10) + button (36) + gap (10): beside the dock, never
578
+ // under it, on whichever side the dock currently sits.
579
+ s.left = atLeft ? '56px' : 'auto';
580
+ s.right = atLeft ? 'auto' : '56px';
581
+ }
582
+
583
+ function buildAuditPanel() {
584
+ auditPanel = document.createElement('div');
585
+ // z-index one below the dock, so the panel can never bury its own toggle.
586
+ auditPanel.style.cssText = 'position:fixed;z-index:2147483646;width:380px;' +
587
+ 'max-width:calc(100vw - 76px);max-height:60vh;display:none;flex-direction:column;' +
588
+ 'background:var(--cpk-bg);color:var(--cpk-fg);border:1px solid var(--cpk-bd);' +
589
+ 'border-radius:10px;box-shadow:var(--cpk-shadow);overflow:hidden;' +
590
+ 'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif';
591
+ applyAuditTheme();
592
+ var head = document.createElement('div');
593
+ head.style.cssText = 'display:flex;align-items:center;gap:8px;padding:8px 10px;flex:none;' +
594
+ 'border-bottom:1px solid var(--cpk-line);font-size:12px';
595
+ auditTitle = document.createElement('div');
596
+ auditTitle.style.cssText = 'flex:1;font-weight:600';
597
+ var clearBtn = document.createElement('button');
598
+ clearBtn.type = 'button';
599
+ clearBtn.textContent = 'Clear';
600
+ clearBtn.style.cssText = AUDIT_HEAD_BTN_CSS;
601
+ clearBtn.onclick = function () {
602
+ // Still-running calls survive the clear: they have no result yet, and
603
+ // dropping their rows would make a command that is at this moment
604
+ // executing look like it never happened.
605
+ var keep = [];
606
+ for (var i = 0; i < calls.length; i++) {
607
+ if (calls[i].state === 'running') keep.push(calls[i]);
608
+ }
609
+ calls = keep;
610
+ renderAudit();
611
+ };
612
+ var closeBtn = document.createElement('button');
613
+ closeBtn.type = 'button';
614
+ closeBtn.textContent = '✕';
615
+ closeBtn.setAttribute('aria-label', 'Close');
616
+ closeBtn.style.cssText = AUDIT_HEAD_BTN_CSS;
617
+ closeBtn.onclick = function () { setAuditOpen(false); };
618
+ head.appendChild(auditTitle);
619
+ head.appendChild(clearBtn);
620
+ head.appendChild(closeBtn);
621
+ auditList = document.createElement('div');
622
+ auditList.style.cssText = 'overflow:auto;flex:1';
623
+ auditPanel.appendChild(head);
624
+ auditPanel.appendChild(auditList);
625
+ placeAuditPanel();
626
+ dock.watch(placeAuditPanel);
627
+ document.body.appendChild(auditPanel);
628
+ }
629
+
630
+ function setAuditOpen(open) {
631
+ auditOpen = !!open;
632
+ if (auditOpen && !auditPanel) buildAuditPanel();
633
+ if (auditPanel) auditPanel.style.display = auditOpen ? 'flex' : 'none';
634
+ if (auditBtn) auditBtn.setAttribute('aria-expanded', auditOpen ? 'true' : 'false');
635
+ if (auditOpen) renderAudit();
636
+ }
637
+
638
+ function mountAuditBtn() {
639
+ if (auditBtn) return;
640
+ auditBtn = document.createElement('button');
641
+ auditBtn.type = 'button';
642
+ auditBtn.setAttribute('aria-label', 'Bash call log');
643
+ auditBtn.setAttribute('aria-expanded', 'false');
644
+ auditBtn.title = 'Bash call log';
645
+ auditBtn.textContent = '\u{1F4DC}';
646
+ auditBtn.style.cssText = DOCK_BTN_CSS;
647
+ auditBtn.onclick = function () { setAuditOpen(!auditOpen); };
648
+ dock.add(auditBtn, 1); // below the theme toggle, whichever mounts first
649
+ }
650
+
651
+ function run(command, opts) {
652
+ opts = opts || {};
653
+ var id = 'c' + (++seq);
654
+ var cwd = opts.cwd || CWD;
655
+ auditStart(id, command, cwd, opts.background);
656
+ handlers[id] = {
657
+ onStdout: opts.onStdout,
658
+ onStderr: opts.onStderr,
659
+ // Settle the record BEFORE handing control to the app's own callback: a
660
+ // callback that throws must not leave the log stuck showing "running".
661
+ onExit: function (code) { auditSettle(id, 'exit', code); if (opts.onExit) opts.onExit(code); },
662
+ onError: function (m) { auditSettle(id, 'error', m); if (opts.onError) opts.onError(m); }
663
+ };
664
+ send({ type: 'exec', id: id, command: command, cwd: cwd });
665
+ return id;
666
+ }
667
+
668
+ function bash(command, opts) {
669
+ opts = opts || {};
670
+ if (opts.background) {
671
+ var id = run(command, {
672
+ cwd: opts.cwd,
673
+ background: true,
674
+ onStdout: opts.onOutput,
675
+ onStderr: opts.onStderr || opts.onOutput,
676
+ onExit: opts.onExit,
677
+ onError: opts.onError
678
+ });
679
+ return { kill: function () {
680
+ send({ type: 'kill', id: id });
681
+ delete handlers[id];
682
+ // Settle here rather than waiting for the exit frame: the handler is
683
+ // gone, so nothing else will ever settle this record.
684
+ auditSettle(id, 'killed');
685
+ } };
686
+ }
687
+ return new Promise(function (resolve, reject) {
688
+ var out = '', err = '';
689
+ run(command, {
690
+ cwd: opts.cwd,
691
+ onStdout: function (d) { out += d; },
692
+ onStderr: function (d) { err += d; },
693
+ onExit: function (code) { resolve({ stdout: out, stderr: err, exitCode: code }); },
694
+ onError: function (m) { reject(new Error(m)); }
695
+ });
696
+ });
697
+ }
698
+
699
+ // toggleTheme is reassigned by the deferred initTheme — forward lazily so the
700
+ // exported function always calls the current implementation, not the no-op.
701
+ window.cockpit = {
702
+ cwd: CWD,
703
+ bash: bash,
704
+ toggleTheme: function () { toggleTheme(); },
705
+ // Current host language ('' until the host's first push, so apps can fall
706
+ // back to navigator themselves). Apps PERCEIVE the language and own their
707
+ // own strings — this is not an i18n runtime.
708
+ get lang() {
709
+ return document.documentElement.getAttribute('data-cockpit-lang') || '';
710
+ }
711
+ };
712
+ window.addEventListener('beforeunload', function () {
713
+ try { if (ws) ws.close(); } catch (e) {}
714
+ });
715
+ })();
716
+ `;function a(e){return/^([/\\]|[A-Za-z]:)/.test(e)}function i(e,t){let o=e.replace(/[/\\]+$/,"");return t?`${o}/${t}`:o}function r(e,t){let o,n=(o=Math.max(e.lastIndexOf("/"),e.lastIndexOf("\\")))<0?"":0===o?"/":e.slice(0,o);return a(e)?n:t?i(t,n):n}function s(e,t){return a(e)||!!t}let l="/apps/local/",d="/apps/builtin/";function c(e,t){let o=e.trim();return l+(a(o)?o:i(t??"",o)).replace(/\\/g,"/").split("/").map(encodeURIComponent).join("/").replace(/^\//,"")}let u=/^([a-z][a-z0-9+.-]*:|\/\/|\/)/i;function p(e,t,o){let n=e.trim();if(!n||u.test(n)||!s(t,o))return e;let r=a(t)?t:i(o,t),l=n.search(/[?#]/),d=l<0?n:n.slice(0,l),p=l<0?"":n.slice(l);if(!d)return e;let h=d;try{h=decodeURIComponent(d)}catch{}return c(function(e){let t=/^[A-Za-z]:/.exec(e)?.[0]??"",o=t?e.slice(t.length):e,n=/^[/\\]/.test(o),a=[];for(let e of o.split(/[/\\]/))if(e&&"."!==e){if(".."===e){a.length&&".."!==a[a.length-1]?a.pop():n||t||a.push("..");continue}a.push(e)}return t+(n||t?"/":"")+a.join("/")}(i(r,h)))+p}let h=/\.(md|png|jpe?g|gif|webp|svg|pdf|json|csv|tsv)$/i;function m(e){return h.test(e.trim())}function g(e,t){let o=e.trim();return d+"file-viewer/index.html?file="+encodeURIComponent((a(o)?o:i(t??"",o)).replace(/\\/g,"/"))}function f(e,t){try{let o=new URL(e,t);if(!o.pathname.startsWith(d)&&!o.pathname.startsWith(l))return e;return"localhost"===o.hostname&&(o.hostname="127.0.0.1"),o.toString()}catch{return e}}function w(e,t){let o=e=>JSON.stringify(e).replace(/</g,"\\u003c"),a="<script>"+n.replaceAll("__CWD__",o(t.cwd)).replaceAll("__WS_URL__",o(t.wsUrl??""))+"<\/script>",i=e.match(/<head[^>]*>/i);if(i&&void 0!==i.index){let t=i.index+i[0].length;return e.slice(0,t)+a+e.slice(t)}let r=e.match(/<html[^>]*>/i);if(r&&void 0!==r.index){let t=r.index+r[0].length;return e.slice(0,t)+a+e.slice(t)}return a+e}},47176:(e,t,o)=>{o.d(t,{l:()=>l});var n=o(95155),a=o(12115),i=o(79114),r=o(94287);let s=e=>`h1[data-source-start="${e}"], h2[data-source-start="${e}"], h3[data-source-start="${e}"], h4[data-source-start="${e}"], h5[data-source-start="${e}"], h6[data-source-start="${e}"]`;function l({content:e,containerRef:t,width:o="w-80"}){let{t:d}=(0,i.Bd)(),c=(0,a.useMemo)(()=>(function(e){let t=[],o=e.split("\n"),n=!1;for(let e=0;e<o.length;e++){let a=o[e];if(a.trimStart().startsWith("```")){n=!n;continue}if(n)continue;let i=/^(#{1,6})\s+(.+)$/.exec(a);i&&t.push({level:i[1].length,text:i[2].replace(/\s*#+\s*$/,"").replace(/\\([!-\/:-@[-`{-~])/g,"$1"),sourceLine:e+1})}return t})(e),[e]),[u,p]=(0,a.useState)(!1),[h,m]=(0,a.useState)(null),g=(0,a.useCallback)(e=>{let o=t.current;if(!o)return;let n=o.querySelector(s(e));n&&n.scrollIntoView({behavior:"smooth",block:"start"})},[t]);return((0,a.useEffect)(()=>{let e=t.current;if(!e||0===c.length)return;let o=()=>{let t=[];for(let o of c){let n=e.querySelector(s(o.sourceLine));if(n){let a=n.getBoundingClientRect().top-e.getBoundingClientRect().top;t.push({line:o.sourceLine,top:a})}}let o=null;for(let e of t)e.top<=60&&(o=e.line);null===o&&t.length>0&&(o=t[0].line),m(o)},n=setTimeout(o,150);return e.addEventListener("scroll",o,{passive:!0}),()=>{clearTimeout(n),e.removeEventListener("scroll",o)}},[c,e,t]),0===c.length)?null:(0,n.jsxs)("div",{className:`border-r border-border flex-shrink-0 flex flex-col transition-[width] duration-200 ${u?"w-8":o}`,children:[(0,n.jsxs)("div",{className:"flex items-center justify-between px-2 py-1.5 border-b border-border flex-shrink-0",children:[!u&&(0,n.jsx)("span",{className:"text-xs font-medium text-muted-foreground",children:d("editor.toc")}),(0,n.jsx)("button",{onClick:()=>p(e=>!e),className:"p-0.5 text-muted-foreground hover:text-foreground hover:bg-hover rounded transition-colors",title:d(u?"editor.expandToc":"editor.collapseToc"),children:(0,n.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:u?(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"}):(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15 19l-7-7 7-7"})})})]}),!u&&(0,n.jsx)("nav",{className:"flex-1 overflow-y-auto py-1",children:c.map((e,t)=>(0,n.jsx)(r.m,{content:e.text,delay:400,children:(0,n.jsx)("button",{onClick:()=>g(e.sourceLine),className:`block w-full text-left text-sm py-1 px-2 truncate transition-colors hover:bg-hover ${h===e.sourceLine?"text-brand font-medium bg-brand/5":"text-muted-foreground"}`,style:{paddingLeft:`${(e.level-1)*12+8}px`},children:e.text})},t))})]})}},64428:(e,t,o)=>{o.d(t,{F2:()=>p,ZL:()=>c,a9:()=>u});var n=o(95155),a=o(12115),i=o(47650);let r=()=>()=>{},s=()=>document.body,l=()=>null,d=(0,a.createContext)(null);function c({children:e}){let t=(0,a.useContext)(d),o=(0,a.useSyncExternalStore)(r,s,l),n=t??o;return n?(0,i.createPortal)(e,n):null}function u({children:e}){let[t,o]=(0,a.useState)(null);return(0,n.jsxs)("div",{className:"relative w-full h-full",style:{transform:"translateZ(0)"},children:[(0,n.jsx)(d.Provider,{value:t,children:e}),(0,n.jsx)("div",{ref:o,className:"absolute inset-0 pointer-events-none [&>*]:pointer-events-auto"})]})}function p(){return(0,a.useContext)(d)}},69809:(e,t,o)=>{o.d(t,{A:()=>r});var n=o(50931);let a=JSON.parse('{"common":{"save":"Save","cancel":"Cancel","delete":"Delete","close":"Close","minimize":"Minimize","copy":"Copy","edit":"Edit","file":"File","codeMap":"Code Map","diff":"Diff","confirm":"Confirm","loading":"Loading...","search":"Search","refresh":"Refresh","retry":"Retry","submit":"Submit","copied":"Copied","saved":"Saved","failed":"Failed","noMatch":"No matches","noData":"No data","done":"Done","justNow":"just now","minutesAgo":"{{count}}m ago","hoursAgo":"{{count}}h ago","daysAgo":"{{count}}d ago","monthsAgo":"{{count}}mo ago","yearsAgo":"{{count}}y ago","saveFailed":"Save failed","copyFailed":"Copy failed","deleteFailed":"Delete failed","operationFailed":"Operation failed","copiedPath":"Path copied","copyPath":"Copy path","openInConsole":"Open in Console bubble","copyAbsPath":"Copy absolute path","loadMore":"Load more","noResult":"No results","selected":"Selected","selectAll":"Select all","hint":"Notice","confirmBtn":"OK","cancelBtn":"Cancel","preview":"Preview","readable":"Readable","previous":"Previous","next":"Next","all":"All","input":"Input","result":"Result","line":"Line","lines":"lines","running":"Running","connecting":"Connecting","connected":"Connected","connectionFailed":"Connection failed","builtin":"Built-in","global":"Global","project":"Project","current":"Current","code":"Code"},"htmlApps":{"title":"HTML Apps","addTooltip":"Add to HTML panel","added":"Added to HTML panel","alreadyAdded":"Already added","addFailed":"Failed to add","add":"Add","adding":"Adding...","addHtmlApp":"Add HTML app","searchPlaceholder":"Search HTML apps...","pathLabel":"Absolute path to the .html file","invalid":"Invalid","builtin":"Built-in","noDescription":"No description","emptyNoApps":"No custom HTML apps yet.","emptyCreatePrefix":"Use","emptyCreateSuffix":"in chat to create a new app.","addExisting":"add an existing HTML file","viewDocs":"view docs","emptyNoMatch":"No HTML apps match your search."},"skills":{"addTooltip":"Add to Skills panel","added":"Added to Skills panel","alreadyAdded":"Already added","addFailed":"Failed to add","title":"Skills","searchPlaceholder":"Search skills...","clearSearch":"Clear","addSkill":"Add Skill","emptyNoSkills":"No skills yet.","emptyIntroPrefix":"Use","emptyIntroSuffix":"in chat to distil a reusable workflow into a SKILL.md file.","emptyNoMatch":"No skills match your search.","viewDocs":"view docs","pathLabel":"Absolute path to SKILL.md","pathPlaceholder":"/Users/you/.../skills/foo/SKILL.md","add":"Add","adding":"Adding...","invalid":"Invalid","copyPath":"Copy path","noDescription":"No description","previewTitle":"Skill Preview","source":"Source","cannotRead":"File cannot be read."},"toast":{"savedSuccess":"Saved","saveFailed":"Save failed","copiedName":"Copied: {{name}}","copyFailed":"Copy failed","deleteFailed":"Delete failed","operationFailed":"Operation failed","staged":"Staged","stageFailed":"Stage failed","unstaged":"Unstaged","unstageFailed":"Unstage failed","stagedNFiles":"Staged {{count}} files","unstagedNFiles":"Unstaged {{count}} files","discardFailed":"Discard failed","discardedNFiles":"Discarded changes in {{count}} files","deletedFile":"File deleted","discardedChanges":"Changes discarded","pastedFile":"Pasted: {{name}}","pasteFailed":"Paste failed","noFileToPaste":"No file to paste","createdFile":"Created: {{name}}","createFailed":"Create failed","movedToTrash":"Moved to trash: {{name}}","copiedPageUrl":"Page URL copied","copiedDirPath":"Directory path copied","switchedToBranch":"Switched to {{branch}}","switchBranchFailed":"Branch switch failed","loadBranchFailed":"Failed to load branches","copiedCommand":"Copied: {{command}}","copiedMessage":"Message copied","forkFailed":"Failed to fork session","excerptFailed":"Failed to excerpt this turn","copiedUrl":"URL copied","copiedOutput":"Output copied","copiedCmd":"Command copied","copiedComment":"Comment copied","copiedAllComments":"All comments copied","copiedFileContent":"File content copied","copiedQA":"Copied {{count}} Q&A","copiedAllQA":"All Q&A copied","sentQA":"Sent to AI","readFileFailed":"Failed to read file","fileOutsideProject":"File is outside this project — only Markdown, CSV and images can be previewed","reviewCreated":"Review created, link copied","reviewUpdated":"Review updated, link copied","reviewCreateFailed":"Failed to create review","sharingClosed":"Sharing disabled","sharingCloseFailed":"Failed to disable sharing","linkCopied":"Link copied","addCommentFailed":"Failed to add comment","deleteCommentFailed":"Failed to delete comment","editCommentFailed":"Failed to edit comment","addReplyFailed":"Failed to add reply","deleteReplyFailed":"Failed to delete reply","editReplyFailed":"Failed to edit reply","disconnected":"Disconnected: {{id}}","pluginReloading":"Reloading extension...","worktreeCreateSuccess":"Worktree created: {{name}}","worktreeCreateFailed":"Failed to create worktree","worktreeLoadFailed":"Failed to load worktree list","worktreeDeleted":"Worktree deleted","worktreeDeleteFailed":"Failed to delete worktree","worktreeLocked":"Locked","worktreeUnlocked":"Unlocked"},"workspace":{"selectProject":"Select a project to start","searchProjectPath":"Search project path...","loadingProjects":"Loading projects...","projectNotFound":"No projects found","sessions":"{{count}} sessions","loadingSessions":"Loading sessions...","noSessions":"No sessions","loadingText":"Loading...","openProject":"Open Project","expandSidebar":"Expand sidebar","collapseSidebar":"Collapse sidebar","notes":"Notes","skills":"Skills","apps":"Apps","settings":"Settings","help":"Help","updateAvailable":"v{{version}} available","copyUpgradeCommand":"Copy cockpit update","updateNow":"Update now","updating":"Updating…","updateComplete":"Update complete","updateFailed":"Update failed","updateCardPreparing":"Preparing update…","updateCardInstalling":"Downloading and installing","updateCardRepairing":"Repairing native dependency","updateCardUpToDate":"Already on the latest version, v{{version}}","updateCardCopyFix":"Copy fix command","updateCardFixCopied":"Fix command copied","updateCardRollingBack":"Install failed, rolling back","updateCardRestarting":"Restarting Cockpit…","updateCardDone":"Updated to v{{version}}","updateCardElapsed":"{{seconds}}s elapsed","updateCardBaseline":"last time ~{{seconds}}s","updateCardNoLiveStatus":"Live status unavailable; the update is still running","updateCardRolledBack":"Rolled back to the previous version; Cockpit is usable.","updateCardManualHint":"You can retry from a terminal:","updateCardLogHint":"Log: {{path}}","updateRestartNote":"Cockpit will restart in the background.","viewChangelog":"View changelog","serverRestarted":"Cockpit was updated in the background.","reloadNow":"Reload","upgradeCommandCopied":"Copied `cockpit update`","projectNotes":"Project Notes","closeProject":"Close project"},"mobile":{"useDesktop":"Desktop","messagePlaceholder":"Message…","send":"Send","stop":"Stop","enableNotifications":"Enable notifications","disableNotifications":"Disable notifications","notifyError":"Could not enable notifications"},"sessions":{"recentSessions":"Recent Sessions","favorites":"Favorite Sessions","noFavorites":"No favorite sessions yet. Click the star in the tab bar to add.","addFavorite":"Add to favorites","removeFavorite":"Remove from favorites","runningCount":"{{count}} running","unreadCount":"{{count}} unread","noSessions":"No sessions yet","running":"Running","done":"Done","editTitle":"Edit title","projectSessions":"Project Sessions","browseAllSessions":"Browse all sessions","sessionList":"Session List","search":"Search","searchSessions":"Search sessions...","searchRecentSessions":"Search recent sessions","loadSessionsFailed":"Failed to load sessions","loadingSessions":"Loading sessions...","noMatchingSessions":"No matching sessions","noSessionsYet":"No sessions yet","projectList":"Project List","openFolder":"Open Folder","selectingFolder":"Selecting...","loadingHistory":"Loading history..."},"scheduledTasks":{"title":"Scheduled Tasks","aboutToTrigger":"About to trigger","secondsLater":"in {{count}}s","minutesLater":"in {{count}}m","hoursMinutesLater":"in {{h}}h {{m}}m","hoursLater":"in {{h}}h","onceType":"Once ({{minutes}}min)","everyNMinutes":"Every {{minutes}}min","completed":"Completed","paused":"Paused","activeCount":"{{running}} active","pausedCount":"{{paused}} paused","noScheduledTasks":"No scheduled tasks. Click the clock button in the chat input to create one.","lastResult":"Last","runNow":"Run now","resume":"Resume","pause":"Pause","completedCount":"Completed ({{count}})","success":"Success","failure":"Failed","createTask":"Create Scheduled Task","editTask":"Edit Scheduled Task","sendMessage":"Message","messagePlaceholder":"Enter message to send...","taskFile":"Task File","taskFilePlaceholder":"/Users/you/project/tasks/daily-report.md","taskFileHint":"Absolute path. On each fire the agent reads this file first and acts on what it describes — edits take effect on the next run.","taskFilePromptHeader":"Read this task file first, then act accordingly:","type":"Type","once":"Once","interval":"Interval","quickSelect":"Quick Select","customCron":"Custom Cron Expression","customMinutes":"Custom minutes","cronPlaceholder":"e.g. 0 9 * * 1-5 (weekdays at 9am)","cronFormat":"Format: min hour day month weekday (e.g. 0 9 * * 1-5)","minutesPlaceholder":"Minutes","limitTimeRange":"Limit execution time range","to":"to","saveBtn":"Save ({{modKey}}↩)","createBtn":"Create ({{modKey}}↩)","5minLater":"In 5 minutes","15minLater":"In 15 minutes","30minLater":"In 30 minutes","1hourLater":"In 1 hour","every15min":"Every 15 min","every30min":"Every 30 min","every1hour":"Every 1 hour","every2hours":"Every 2 hours","daily9am":"Daily 09:00","daily6pm":"Daily 18:00","weeklyMon9am":"Mon 09:00","monthly1st9am":"1st of month 09:00"},"cron":{"everyNMinutes":"Every {{n}} minutes","everyNHours":"Every {{n}} hours","everyMinute":"Every minute","everyHourAtMin":"Every hour at minute {{m}}","hourlyEveryMin":"{{h}}:xx every minute","daily":"Daily at {{time}}","weekdays":"Weekdays","weekends":"Weekends","dowSun":"Sun","dowMon":"Mon","dowTue":"Tue","dowWed":"Wed","dowThu":"Thu","dowFri":"Fri","dowSat":"Sat","monthPrefix":"","dayOfMonth":"","dayRange":"{{a}}th to {{b}}th","weekdayPrefix":"","weekdayRange":"{{a}} to {{b}}"},"blockViewer":{"empty":{"body":"Select a file in the left tree to see its code map.","hint":"or press ⌘K to search."},"fileMode":{"loading":"Loading…","notFound":"This file is not indexed (unsupported language or beyond the file cap)."},"buildProgress":{"listing":"Listing files…","contexts":"Reading project config…","parsing":"Parsing files","resolving":"Resolving imports…","edges":"Building call graph…","done":"Finishing up…"},"search":{"tooltip":"Search (⌘K)","hint":"Start typing to search","noResults":"No matches","files":"Files","symbols":"Symbols"},"viewerToggle":{"toBlock":"Show code map","toCode":"Back to code view"},"toc":{"title":"this file","empty":"No functions detected.","notIndexed":"File not in project graph (unsupported language / not in git tracked set / file cap reached)."},"history":{"title":"history","empty":"Click an input or output pin to begin tracing.","clear":"Clear history"},"refresh":"Rebuild project graph","retry":"Retry"},"blockDiffViewer":{"loading":"Building code map…","unsupported":"Code map diff is not available for this file type.","unsupportedHint":"Switch back to the regular diff view to read it.","error":"Code map diff failed: {{message}}","noBlockChanges":"No code-map changes (formatting / whitespace only).","noBefore":"(new)","noAfter":"(removed)","kind":{"added":"added","deleted":"deleted","modified":"modified"}},"fileBrowser":{"directoryTree":"Tree","searchTab":"Search","recentTab":"Recent","changesTab":"Status","historyTab":"History","searchFiles":"Search files...","clear":"Clear","exactMatchOn":"Exact match (on)","exactMatchOff":"Exact match (off)","refreshTree":"Refresh directory tree","collapseAll":"Collapse all directories","searchFileContent":"Search file contents...","caseSensitive":"Case sensitive","wholeWord":"Whole word","regex":"Regex","fileTypes":"File types (ts,tsx)","compareMode":"Compare","compareModeOff":"Close branch comparison","compareModeOn":"Compare with selected branch","createFile":"New File","createFileIn":"New File (in {{path}}/)","fileName":"File name...","noRecentFiles":"No recent files","stagingArea":"Staged ({{count}})","changesSummary_one":"{{count}} change","changesSummary_other":"{{count}} changes","noChanges":"No changes in working tree","refreshChanges":"Refresh changes","unstageAll":"Unstage all","noStagedFiles":"No staged files","unstageNFiles":"Unstage {{count}} files","unstageFile":"Unstage","workspace":"Workspace ({{count}})","discardAll":"Discard all","stageAll":"Stage all","noUnstagedChanges":"No unstaged changes","discardNFiles":"Discard changes in {{count}} files","stageNFiles":"Stage {{count}} files","discardChanges":"Discard changes","stageFile":"Stage file","loadingDiff":"Loading diff...","noDiffFiles":"No diff files","nFilesChanged":"{{count}} files changed (vs {{branch}})","loadingCommits":"Loading commits...","noCommits":"No commits","allLoaded":"All {{count}} records loaded","locateInTree":"Locate in directory tree","unsaved":"Unsaved","saveBeforeSwitch":"Current file has unsaved changes. Save before switching?","saveAndSwitch":"Save and switch","closeEdit":"Close edit (ESC)","closeBtn":"Close","copyFileContent":"Copy file content","toggleJsonReadable":"Toggle JSON readable mode","previewMarkdown":"Preview Markdown","exitPreview":"Exit Preview","viewBlame":"View line-by-line change history","viewDiff":"View changes against HEAD","exitDiff":"Exit Diff","diffLoadFailed":"Failed to load diff","editFile":"Edit file","backToPreview":"Back to preview","cannotPreview":"Cannot preview this file","selectFileToPreview":"Select a file to preview","staged":"Staged","unstaged":"Unstaged","selectFileToViewDiff":"Select a file to view diff","loadingDiffContent":"Loading diff...","clickCompareToLoad":"Click \\"Compare\\" to load branch diff","selectCommitToView":"Select a commit to view details","confirmDelete":"Confirm Delete","confirmDeleteMessage":"Move <file>{{name}}</file> to trash?","nFilesNMatches":"{{files}} files, {{matches}} matches","resultsTruncated":"Results truncated","noContentSearchResults":"No results","enterKeywordToSearch":"Enter keyword to search file contents","searchMinChars":"Search requires at least 2 characters"},"csv":{"table":"Table","raw":"Raw","empty":"Empty table","summary":"{{rows}} rows \xb7 {{cols}} columns","summaryFiltered":"{{rows}} / {{total}} rows matched \xb7 {{cols}} columns","loadMore":"Load more ({{shown}} / {{total}} shown)","filterPlaceholder":"Filter rows…","filterColumn":"Filter column","clearFilter":"Clear filter","allColumns":"All columns","noMatch":"No matching rows","sortHint":"Click to sort (asc / desc / off)"},"codeViewer":{"fileModifiedExternally":"File was modified externally. Saving will overwrite external changes.","useDiskVersion":"Use disk version","forceOverwrite":"Force overwrite","searchPlaceholder":"Search...","caseSensitive":"Case sensitive","wholeWordMatch":"Whole word match","unsavedConfirm":"You have unsaved changes. Close anyway?","discardChanges":"Discard changes","continueEditing":"Continue editing","unsavedExitConfirm":"You have unsaved changes. Exit edit mode?","clickToViewDetails":"Click to view details","clickToViewCommit":"Click to view commit details","nComments":"{{count}} comments","searchChat":"Search chat...","prevShiftEnter":"Previous (Shift+Enter)","nextEnter":"Next (Enter)","closeEsc":"Close (Esc)"},"chat":{"startConversation":"Start a conversation","loadMoreHistory":"Load more...","scrollUpForMore":"↑ Scroll up to load more history","jumpToStart":"Jump to start","jumpToLatest":"Jump to latest","copyMessage":"Copy message","copyImage":"Copy image","copiedImage":"Image copied","forkSession":"Fork session from here","excerptTurn":"Excerpt this turn to a new session","imageN":"Image {{index}}","imagePreview":"Image preview","toolCalls":"{{count}} tool calls","collapse":"▲ Collapse","expand":"▼ Expand","subagent":"Subagent","subagentEmpty":"No subagent transcript found","subagentViewTitle":"View subagent transcript","workflowRun":"Run details","workflowViewTitle":"View workflow run details","workflowEmpty":"No workflow run journal found","workflowAgents":"agents","workflowViewAgent":"View","workflowUngrouped":"Ungrouped","viewQuestions":"View questions","viewAllFileChanges":"View all file changes","requestFailed":"Request failed","cannotReadStream":"Cannot read response stream","errorRetry":"An error occurred, please retry","placeholder":"Type a message, Enter to send (Shift+Enter for new line, paste images; start a line with / (main session) or @ (subagent) for commands, multiple allowed)","placeholderDisabled":"Generating... you can keep typing (ESC to cancel; if stuck, cancel and resend \'continue\')","imageSizeLimit":"Image size exceeds limit (max 5MB), current: {{size}}MB","viewGitChanges":"View Git changes","viewAllComments":"View all comments","userMessages":"User messages","projectNotes":"Project Notes","scheduledTasks":"Scheduled Tasks","quickPrompts":"Quick Prompts","globalPrompts":"Global Prompts","projectPrompts":"Project Prompts","noQuickPrompts":"No quick prompts yet","addQuickPrompt":"Add quick prompt","quickPromptPlaceholder":"One-line prompt — Enter to save, Esc to cancel","context":"Context","output":"Output","copiedCommandTooltip":"Copied!","copyCommandTooltip":"Copy command: {{command}}","executedCommand":"Executed `{{command}}`{{exitInfo}}, output:\\n```\\n{{output}}\\n```","executedCommandFailed":"Failed to execute `{{command}}`: {{error}}","executionMode":"Execution Mode","checkBalance":"Check balance","balanceFailed":"Query failed — check the API key","balanceNeedsKey":"Set a DeepSeek API key first","balanceUnavailable":"Account is not available for requests","balanceEmpty":"No balance returned","openUsagePage":"Open DeepSeek usage console","checkQuota":"Check quota","quotaFailed":"Quota unavailable — check the API key","quotaNeedsKey":"Set an API key first","quotaEmpty":"No quota returned","quotaResetAt":"Resets {{time}}","openProviderConsole":"Open the provider console","planMode":"Plan mode","planModeDesc":"read-only \xb7 plan first, no edits","planModeOn":"Plan mode on — read-only; send a task to get a plan","planModeOff":"Plan mode off","planModeHint":"Plan mode: read-only exploration that produces a plan without editing. Uncheck and resend to implement.","noHistory":"Independent task","noHistoryDesc":"no history sent","noHistoryHint":"Independent task: each message is sent to the model on its own, with no prior conversation. The transcript above still records everything.","planTitle":"Plan (awaiting your review)","approvePlan":"Approve & run","planApproveHint":"No approval dialog here — click to exit plan mode and execute","approvePlanPrompt":"Approved — proceed with the plan above."},"console":{"enterCommandOrUrl":"Enter a command or URL to start","emptyIntro":"Type any of the following in the input bar to create a bubble:","bubbleCommand":"Command","bubbleInteractive":"Interactive","bubbleBrowser":"Browser","bubbleBrowserNoteIframe":"Some sites block iframe embedding — install Cockpit Bridge under Settings → Browser Extension before opening.","bubbleBrowserNoteCookie":"If a logged-in site first shows as signed out, refresh a few times to restore it.","bubbleDatabase":"Database","bubbleNotebook":"Notebook","loadingMore":"Loading...","loadMoreHistory":"Load more history","quickCommands":"Quick Commands","singleColumn":"Single column","dualColumn":"Dual column","envVars":"Environment Variables","launchShell":"Launch interactive shell","htmlApps":"HTML apps","inputPlaceholder":"Enter command or URL and press Enter... (↑↓ history, Tab complete)","scopeProject":"Project","scopeGlobal":"Global","tabSwitchEscClose":"Tab to switch \xb7 Esc to close","copyOutput":"Copy output","copyCommand":"Copy command","rerun":"Re-run","deleteRecord":"Delete record","searchPlaceholder":"Search...","searchMode":"Search","filterMode":"Filter","prevShiftEnter":"Previous (Shift+Enter)","nextEnter":"Next (Enter)","loadingTerminal":"Loading terminal...","clickToInput":"Click terminal area to type","stdinPlaceholder":"stdin input...","runningText":"Running...","exitCode":"Exit code: {{code}}","totalLines":"{{count}} lines total","globalCommands":"Global Commands","projectCommands":"Project Commands","noCustomCommands":"No custom commands yet","namePlaceholder":"Name","commandPlaceholder":"Command","restoreTooltip":"Restore ({{modKey}}M / ESC)","screenshotting":"Screenshotting...","outputFileDeleted":"[Output file deleted]"},"browser":{"blankPage":"Blank page","copyUrl":"Copy URL","openInNewWindow":"Open in new window","exitMaximize":"Exit maximize ({{modKey}}M)","maximize":"Maximize ({{modKey}}M)","pageLoadFailed":"Page load failed","clickToWake":"Click to wake","sleeping":"Sleeping","loadingPage":"Loading...","loadFailed":"Load failed"},"database":{"connectionFailed":"Connection failed","connected":"Connected","connecting":"Connecting...","refreshTableList":"Refresh table list","filterTable":"T Tables","filterView":"V Views","noTables":"No tables","tabStructure":"Structure","tabData":"Data","tabSql":"SQL","filterActive":"Filter: {{count}} cols","clearAllFilters":"Clear all filters","deleteNRows":"Delete {{count}} rows","confirmDeleteRows":"Confirm delete?","copyCsvSelected":"Copy selected rows as CSV","copyCsvAll":"Export all as CSV","copyJsonSelected":"Copy selected rows as JSON","copyJsonAll":"Export all as JSON","copyCSV":"Copy CSV","CSV":"CSV","copyJSON":"Copy JSON","JSON":"JSON","selectTable":"Select a table","selectTableToView":"Select a table to view structure","selectTableForData":"Select a table to view data","columns":"Columns","colName":"Name","colType":"Type","colNullable":"Nullable","colDefault":"Default","primaryKey":"Primary Key","foreignKeys":"Foreign Keys","indexes":"Indexes","enable":"Enable","commaValues":"Comma-separated values","likePattern":"%pattern%","valuePlaceholder":"Value","apply":"Apply","clearFilter":"Clear","addRow":"+ Add Row","totalRows":"{{count}} rows","rowsAffected":"{{command}} — {{count}} rows affected ({{duration}}ms)","queryRows":"{{count}} rows ({{duration}}ms)","resultTruncated":"[Results truncated to 1000 rows]","sqlPlaceholder":"Enter SQL... ({{modKey}}Enter to execute)","executing":"Executing...","execute":"▶ Execute","deleteRowsFailed":"{{count}} rows failed to delete","inputParams":"Input Parameters","resultLabel":"Result"},"mysql":{"connectionFailed":"Connection failed","connected":"Connected","connecting":"Connecting...","refreshTableList":"Refresh table list","filterTable":"T Tables","filterView":"V Views","noTables":"No tables","tabStructure":"Structure","tabData":"Data","tabSql":"SQL","filterActive":"Filter: {{count}} cols","clearAllFilters":"Clear all filters","deleteNRows":"Delete {{count}} rows","confirmDeleteRows":"Confirm delete?","copyCsvSelected":"Copy selected rows as CSV","copyCsvAll":"Export all as CSV","copyJsonSelected":"Copy selected rows as JSON","copyJsonAll":"Export all as JSON","copyCSV":"Copy CSV","CSV":"CSV","copyJSON":"Copy JSON","JSON":"JSON","selectTable":"Select a table","selectTableToView":"Select a table to view structure","selectTableForData":"Select a table to view data","columns":"Columns","colName":"Name","colType":"Type","colNullable":"Nullable","colDefault":"Default","primaryKey":"Primary Key","foreignKeys":"Foreign Keys","indexes":"Indexes","enable":"Enable","commaValues":"Comma-separated values","likePattern":"%pattern%","valuePlaceholder":"Value","apply":"Apply","clearFilter":"Clear","addRow":"+ Add Row","totalRows":"{{count}} rows","rowsAffected":"{{command}} — {{count}} rows affected ({{duration}}ms)","queryRows":"{{count}} rows ({{duration}}ms)","resultTruncated":"[Results truncated to 1000 rows]","sqlPlaceholder":"Enter SQL... ({{modKey}}Enter to execute)","executing":"Executing...","execute":"▶ Execute","deleteRowsFailed":"{{count}} rows failed to delete"},"redis":{"neverExpires":"Never expires","expired":"Expired","loadFailed":"Load failed","deleteFailed":"Delete failed","saveFailed":"Save failed","scanPlaceholder":"SCAN pattern...","scanSearch":"Search (SCAN)","noKeys":"No keys","loadMore":"Load more...","tabData":"Data","tabInfo":"Info","tabCli":"CLI","selectKey":"Select a key","keyNotExist":"Key does not exist","unsupportedType":"Unsupported type: {{type}}","nItems":"{{total}} items","showingN":"showing {{count}}","nMembers":"{{total}} members","nEntries":"{{total}} entries","cliHint":"Enter Redis commands, e.g. PING, GET key, KEYS *","cliPlaceholder":"Enter command..."},"git":{"switchBranch":"Switch branch","searchBranch":"Search branches...","noBranches":"No branches available","noMatchingBranches":"No matching branches","localBranches":"Local Branches","remoteBranches":"Remote Branches","branchNotFound":"Branch not found","selectBranch":"Select branch...","currentBranch":"Current","notGitRepo":"Current directory is not a Git repository","cannotGetBranches":"Cannot get branch info","getBranchesFailed":"Failed to get branch info","discardAllConfirm":"Discard changes in {{count}} workspace files? This cannot be undone.","worktree":{"title":"Git Worktree","count":"{{count}} worktrees","selectBranch":"Select branch","addWorktree":"+ Add Worktree","confirmDelete":"Confirm Delete","confirmDeleteMsg":"Delete this worktree?","path":"Path:","branch":"Branch:","locked":"Locked","unlock":"Unlock","lock":"Lock","searchBranch":"Search branches...","noBranches":"No available branches"}},"comments":{"addComment":"Add Comment","lineRange":"Line {{start}}-{{end}}","inputPlaceholder":"Enter comment...","newComment":"New comment {{range}}","commentPlaceholder":"Enter comment... ({{modKey}}Enter to submit, Esc to cancel)","nComments":"{{count}} comments","allComments":"All Comments","copyAllComments":"Copy all comments","noComments":"No comments yet","clearAll":"Clear all","totalComments":"{{count}} comments total","aiReply":"AI Reply","noContent":"(no content)","linesCount":"({{count}} lines)","codeRef":"Here are my annotated comments and references:","note":"Note: {{content}}","submitting":"Submitting...","enterSubmit":"Enter to submit \xb7 Shift+Enter for new line","submitComment":"Submit Comment","askAI":"Ask AI","inputQuestion":"Enter your question...","aiGenerating":"Generating, please wait...","enterSend":"Enter to send \xb7 Shift+Enter for new line","sendToAI":"Send to AI","aiResponding":"AI is responding..."},"fileContextMenu":{"createFile":"New File","copyFile":"Copy File","copyFolder":"Copy Folder","pasteHere":"Paste Here","deleteFile":"Delete File","deleteFolder":"Delete Folder","copyRelativePath":"Copy Relative Path","copyAbsolutePath":"Copy Absolute Path","copyRelativeDirPath":"Copy Relative Dir Path","copyAbsoluteDirPath":"Copy Absolute Dir Path","copyFileName":"Copy File Name","copyFolderName":"Copy Folder Name"},"settings":{"title":"Settings","theme":"Theme","themeLight":"Light","themeDark":"Dark","themeSystem":"System","browserExtension":"Browser Extension","extensionInstalled":"Cockpit Bridge installed","extensionNotInstalled":"Cockpit Bridge not installed","extensionDescription":"After installing the Chrome extension, link navigation in iframes will be intercepted: new tab links create new bubbles, page navigation updates the current bubble.","installSteps":"Installation steps:","step1":"1. Open Chrome and navigate to","step2":"2. Enable \\"Developer mode\\" in the top-right corner","step3":"3. Click \\"Load unpacked\\"","step4mac":"4. Press <kbd>Cmd+Shift+G</kbd> → paste the path below → Enter","copyExtensionPath":"Copy extension directory path","reloadExtension":"Reload extension","about":"About","language":"Language","languageAuto":"System","switchDark":"Switch to dark","switchLight":"Switch to light"},"editor":{"placeholder":"Write something... Type / for commands","noteTitle":"{{name}} - Notes","noteUntitled":"Notes","saving":"Saving...","conflictReloaded":"This note was changed elsewhere. Loaded the latest version; your recent unsaved edits were discarded.","linkPlaceholder":"Enter URL...","confirmLink":"Confirm","removeLink":"Remove link","heading1":"Heading 1","heading2":"Heading 2","heading3":"Heading 3","bold":"Bold","italic":"Italic","strikethrough":"Strikethrough","inlineCode":"Inline code","link":"Link","bulletList":"Bullet list","orderedList":"Ordered list","taskList":"Task list","blockquote":"Blockquote","codeBlock":"Code block","table":"Table","horizontalRule":"Horizontal rule","insertRowAbove":"Insert row above","insertRowBelow":"Insert row below","insertColumnLeft":"Insert column left","insertColumnRight":"Insert column right","deleteRow":"Delete row","deleteColumn":"Delete column","deleteTable":"Delete table","deleteCodeBlock":"Delete code block","toc":"TOC","expandToc":"Expand TOC","collapseToc":"Collapse TOC"},"slashCommands":{"heading1":"Heading 1","heading1Desc":"Large heading","heading2":"Heading 2","heading2Desc":"Medium heading","heading3":"Heading 3","heading3Desc":"Small heading","bulletList":"Bullet List","bulletListDesc":"Bulleted list","orderedList":"Ordered List","orderedListDesc":"Numbered list","taskList":"Task List","taskListDesc":"Checkable task list","blockquote":"Blockquote","blockquoteDesc":"Quote block","codeBlock":"Code Block","codeBlockDesc":"Code snippet","table":"Table","tableDesc":"Insert 3\xd73 table","horizontalRule":"Divider","horizontalRuleDesc":"Horizontal divider","link":"Link","linkDesc":"Insert hyperlink"},"commands":{"qa":"Enter requirements clarification mode","fx":"Enter bug evidence-chain analysis mode","ex":"Enter structured analysis & discussion mode","go":"Enter landing mode: MVP staged implementation","cg":"Enter CodeGraph exploration mode","plan":"Enable plan mode \xb7 /plan <task> to plan it \xb7 /plan off to disable"},"review":{"reviewManagement":"Review Management","allReviews":"All Reviews","noOpenReviews":"No open reviews","viewComments":"View comments","nComments":"{{count}} comments","nDocs":"{{count}} docs","nReviews":"{{count}} reviews","docList":"Document List","allReviewsList":"All Reviews","expandList":"Expand list","collapseList":"Collapse list","closeReview":"Close review","reopenReview":"Reopen","deleteReview":"Delete review","noOpenDocs":"No open documents","noReviews":"No reviews","sharing":"Sharing","notShared":"Not shared","closeSharing":"Disable sharing","enableSharing":"Enable sharing","view":"View","setNickname":"Set your nickname","nicknameHint":"Other reviewers will see this name","nicknamePlaceholder":"Enter nickname","skipForNow":"Skip for now","identitySettings":"Identity Settings","reviewNickname":"Review Nickname","random":"Random","selectTextToComment":"Select text to add comment","selectTextHint":"Select text on the left to add a comment","prevComment":"Previous","nextComment":"Next","commentsCount":"{{count}} comments","commentsNavCount":"{{current}}/{{total}} comments","allCommentsTitle":"All Comments","commentsCountBrief":"{{count}}","closedCount":"{{count}} closed","copyAllComments":"Copy all comments","noComments":"No comments yet","closedComments":"Closed ({{count}})","closedLabel":"Closed","moreReplies":"+{{count}} replies","copyComment":"Copy comment","reopen":"Reopen","closeComment":"Close comment","editComment":"Edit comment","deleteComment":"Delete comment","edited":"(edited)","editReply":"Edit reply","deleteReply":"Delete reply","reply":"Reply","replyPlaceholder":"Add a reply...","selectedText":"Selected text","addCommentPlaceholder":"Add a comment...","enterSubmitHint":"Enter to submit, Shift+Enter for new line","commentBtn":"Comment","reviewNotExist":"Review does not exist or has been deleted","loadFailed":"Load failed","networkError":"Network error","reviewNotFound":"Review not found","checkLink":"Please check the link","updatedAt":"Updated {{date}}","active":"Active","closed":"Closed","viewAllComments":"View all comments","viewCommentBtn":"View Comments","copyLink":"Copy Link","reviewSummary":"Review Comments Summary — {{title}}","totalNComments":"{{count}} comments total","quoteRef":"Quote: \\"{{text}}\\"","commentAuthor":"Comment ({{author}}): {{content}}","replyAuthor":" ↳ {{author}}: {{content}}"},"markdown":{"copied":"✓ Copied","copy":"Copy"},"imagePreview":{"previewImage":"Preview image","deleteImage":"Delete image","copyImage":"Copy image","copiedImage":"Image copied"},"tokenStats":{"title":"Claude Code Token Stats","activeHours":"Active Hours Distribution","hourSessions":"{{h}}:00 — {{count}} sessions","messages":"Messages","toolCalls":"Tool Calls","activityTrend":"Activity Trend","byModel":"By Model","tokenUsage":"Token Usage","equivalentCost":"Equivalent Cost","modelCostDetail":"Model Cost Details","model":"Model","share":"Share","total":"Total","totalSessions":"Total Sessions","totalMessages":"Total Messages","equivalentApiCost":"Equivalent API Cost","longestSession":"Longest Session","firstUse":"First Use","notFound":"~/.claude/stats-cache.json not found","day":"Day","week":"Week","month":"Month"},"toolCall":{"inputParams":"Input Parameters","resultLabel":"Result","inputParamsTitle":"View input parameters","resultTitle":"View result","input":"Input","result":"Result","foldedLines":"... ({{count}} lines)"},"fileEditor":{"unsavedConfirm":"You have unsaved changes. Close anyway?","discardChanges":"Discard changes","continueEditing":"Continue editing","externallyModified":"File was modified externally. Saving will overwrite external changes.","useDiskVersion":"Use disk version","forceOverwrite":"Force overwrite"},"quickFileOpen":{"placeholder":"Type file name to open...","noMatch":"No matching files","recent":"Recent","selectHint":"Select","openHint":"Open","closeHint":"Close"},"envManager":{"title":"Environment Variables","tabScope":"Current Tab Only","globalScope":"Global Environment Variables","varNamePlaceholder":"Variable name (e.g. NODE_ENV)","varValuePlaceholder":"Value (e.g. production)","valuePlaceholder":"Value","noVars":"No environment variables yet. Add one to get started."},"aliasManager":{"title":"Command Aliases","description":"Set shortcut aliases for common commands (global)","aliasPlaceholder":"Alias (e.g. ll)","commandPlaceholder":"Full command (e.g. ls -la)","fullCommandPlaceholder":"Full command","usage":"Usage tip:","usageDesc":"Type an alias to execute the corresponding full command","noAliases":"No command aliases yet. Add one to get started."},"diffViewer":{"fileChanges":"File Changes ({{count}})","toggleFileTree":"Toggle file tree","selectFileToView":"Select a file to view changes","sideBySide":"Side by side","unified":"Unified","viewSplit":"Split","viewUnified":"Unified","previewFile":"Preview file","copiedAll":"Full text copied","compact":"Compact","full":"Full","gap":{"hidden":"{{count}} lines hidden","more":"\xb7\xb7\xb7 more +{{count}} \xb7\xb7\xb7","expandUp":"Expand {{count}} lines up","expandDown":"Expand {{count}} lines down"},"loadingSnapshots":"Loading snapshots…","noChanges":"No file changes detected in this turn","notViewable":"Binary or oversized file — diff not viewable","externalChange":"Concurrent change from another session/process","reconstructed":"reconstructed","reconstructedHint":"Rebuilt from tool-call parameters — not a disk snapshot","truncated":"Too many files — list truncated","imageBefore":"Before","imageAfter":"After","imageAdded":"Added","imageDeleted":"Deleted","imageLoadFailed":"Failed to load image","imageUnavailable":"Image not present in either revision"},"commitDetail":{"title":"Commit Details","hash":"Hash:","author":"Author:","date":"Date:","files":"Files:","nChanges":"{{count}} changes","loadingFiles":"Loading files...","noFileChanges":"No file changes","loadingDiff":"Loading diff...","selectFileToView":"Select a file to view diff"},"askQuestion":{"title":"Questions","nQuestions":"{{count}} questions","checkedN":"{{count}} checked","copyChecked":"Copy {{count}} checked Q&A","copyAll":"Copy all Q&A","sendChecked":"Send {{count}} checked Q&A to AI","sendAll":"Send all Q&A to AI","sendNoChat":"No active chat session","checkToCopy":"Check to copy","custom":"Custom","customPlaceholder":"Enter custom answer...","notSelected":"(not selected)"},"tabBar":{"closeTab":"Close tab","closeAll":"Close all tabs","newTab":"New tab"},"tabManagerTopBar":{"copyPageUrl":"Copy page URL","copyDirPath":"Copy directory path","refreshProject":"Refresh project","openInVSCode":"Open in VS Code","openInCursor":"Open in Cursor","aliasesGlobal":"Command Aliases (Global)","tokenStats":"Token Stats","openSurething":"Open Surething"},"hoverTooltip":{"findReferences":"Find References","search":"Search"},"todoViewer":{"title":"Task List","progress":"{{completed}} / {{total}} done"},"userMessages":{"title":"User Messages","noMessages":"No user messages"},"shortIdBadge":{"clickToDisconnect":"Click to disconnect","clickToRegister":"Click to register and copy CLI command","setTitle":"Name this bubble (so /cc can find it later)","setTitlePlaceholder":"set title","editTitle":"Edit title","titleSet":"Title: {{title}}","dialogTitle":"Name this bubble","dialogPlaceholder":"e.g. alloydb proxy, staging admin"},"api":{"pathForbidden":"Operation not allowed on this path","deleteForbidden":"Delete not allowed on this path","notAFolder":"Target is not a folder","imageTooLarge":"Image too large to preview","cannotPreviewBinary":"Cannot preview binary file","fileTooLarge":"File too large to preview (over 10MB)","fileModifiedExternally":"File was modified externally","pickFolderPrompt":"Select project folder"},"confirm":{"title":"Notice","ok":"OK","cancel":"Cancel"},"floatingToolbar":{"addComment":"Add Comment","sendToAI":"Send to AI","search":"Search"},"quickReply":{"optionA":"A","optionB":"B","optionC":"C","optionD":"D","allRecommended":"Rest recommended","thisOne":"This one","notThis":"Not this","why":"Why?","elaborate":"Say more","example":"Give an example","start":"Do it","continue":"Continue","ok":"OK","done":"Done","edit":"Edit quick replies","editTitle":"Edit quick replies","editHint":"One line per row; separate phrases with commas. Each phrase is sent to the chat exactly as written.","editPlaceholder":"This one, Not this\\nWhy?, Say more","restoreDefault":"Restore defaults","save":"Save","cancel":"Cancel","customizedFor":"Customizing the {{lang}} phrases — the other language is unaffected.","langEn":"English","langZh":"Chinese","saveFailed":"Failed to save quick replies"},"searchResults":{"title":"Search Results","nMatches":"({{count}} matches)","searching":"Searching...","noResults":"No matches","scopeSelected":"Selected","scopeAll":"All"},"references":{"title":"References","searching":"Searching...","notFound":"No references found"},"gitFileTree":{"noFiles":"No files"},"deps":{"action":"Dependencies","none":"none","symbolMessage":"Analyse the dependencies of {{name}} ({{path}}:{{lines}}).\\n\\nCallers: {{callers}}\\nCalls: {{callees}}\\nExternal: {{externals}}\\n\\nExplain which modules it is coupled to, and which of those dependencies could be narrowed."},"explain":{"action":"Explain","fileMessage":"Explain {{path}}","symbolMessage":"Explain {{name}} ({{path}}:{{lines}})","selectionMessage":"Explain","commitFileMessage":"Explain what git commit {{hash}} changed in {{path}}","compareFileMessage":"Explain the git changes to {{path}} in {{base}}..HEAD","stagedFileMessage":"Explain the git staged changes to {{path}}","unstagedFileMessage":"Explain the git working tree changes to {{path}}"},"reviewUtils":{"adjectives":["Happy","Brave","Quiet","Bright","Gentle","Agile","Free","Clear","Flying","Relaxed","Lively","Wise","Calm","Alert","Composed","Steady","Cheerful","Warm","Bold","Poised"],"nouns":["Panda","Dolphin","Crane","Snow Leopard","Skylark","Squirrel","Flying Fish","Deer","Bluebird","Silver Fox","Owl","Dragonfly","Firefly","Sea Turtle","Butterfly","Monkey","Red-crowned Crane","Antelope","Swallow","Penguin"]}}'),i=JSON.parse('{"common":{"save":"保存","cancel":"取消","delete":"删除","close":"关闭","minimize":"最小化","copy":"复制","edit":"编辑","file":"文件","codeMap":"代码地图","diff":"Diff","confirm":"确认","loading":"加载中...","search":"搜索","refresh":"刷新","retry":"重试","submit":"提交","copied":"已复制","saved":"已保存","failed":"失败","noMatch":"无匹配","noData":"无数据","done":"完成","justNow":"刚刚","minutesAgo":"{{count}}分钟前","hoursAgo":"{{count}}小时前","daysAgo":"{{count}}天前","monthsAgo":"{{count}}个月前","yearsAgo":"{{count}}年前","saveFailed":"保存失败","copyFailed":"复制失败","deleteFailed":"删除失败","operationFailed":"操作失败","copiedPath":"已复制路径","copyPath":"复制路径","openInConsole":"在 Console 气泡打开","copyAbsPath":"复制绝对路径","loadMore":"加载更多","noResult":"无匹配结果","selected":"已选择","selectAll":"全选","hint":"提示","confirmBtn":"确定","cancelBtn":"取消","preview":"预览","readable":"可读","previous":"上一个","next":"下一个","all":"全部","input":"输入","result":"结果","line":"行","lines":"行","running":"运行中","connecting":"连接中","connected":"已连接","connectionFailed":"连接失败","builtin":"内置","global":"全局","project":"项目","current":"当前","code":"代码"},"htmlApps":{"title":"HTML 应用","addTooltip":"添加到 HTML 面板","added":"已添加到 HTML 面板","alreadyAdded":"已添加过","addFailed":"添加失败","add":"添加","adding":"添加中...","addHtmlApp":"添加 HTML 应用","searchPlaceholder":"搜索 HTML 应用...","pathLabel":".html 文件的绝对路径","invalid":"无效","builtin":"内置","noDescription":"无描述","emptyNoApps":"还没有自定义 HTML 应用。","emptyCreatePrefix":"在聊天里使用","emptyCreateSuffix":"创建新应用。","addExisting":"添加已有 HTML 文件","viewDocs":"查看文档","emptyNoMatch":"没有匹配的 HTML 应用。"},"skills":{"addTooltip":"添加到 Skills 面板","added":"已添加到 Skills 面板","alreadyAdded":"已添加过","addFailed":"添加失败","title":"Skills","searchPlaceholder":"搜索 skills...","clearSearch":"清除","addSkill":"添加 Skill","emptyNoSkills":"还没有 skill。","emptyIntroPrefix":"在聊天里使用","emptyIntroSuffix":"把可复用经验整理成 SKILL.md。","emptyNoMatch":"没有匹配的 skill。","viewDocs":"查看文档","pathLabel":"SKILL.md 的绝对路径","pathPlaceholder":"/Users/you/.../skills/foo/SKILL.md","add":"添加","adding":"添加中...","invalid":"无效","copyPath":"复制路径","noDescription":"无描述","previewTitle":"Skill 预览","source":"源码","cannotRead":"无法读取文件。"},"toast":{"savedSuccess":"已保存","saveFailed":"保存失败","copiedName":"已复制: {{name}}","copyFailed":"复制失败","deleteFailed":"删除失败","operationFailed":"操作失败","staged":"已暂存","stageFailed":"暂存失败","unstaged":"已取消暂存","unstageFailed":"取消暂存失败","stagedNFiles":"已暂存 {{count}} 个文件","unstagedNFiles":"已取消暂存 {{count}} 个文件","discardFailed":"放弃变更失败","discardedNFiles":"已放弃 {{count}} 个文件的变更","deletedFile":"已删除文件","discardedChanges":"已放弃变更","pastedFile":"已粘贴: {{name}}","pasteFailed":"粘贴失败","noFileToPaste":"没有可粘贴的文件","createdFile":"已创建文件: {{name}}","createFailed":"创建失败","movedToTrash":"已移动到回收站: {{name}}","copiedPageUrl":"已复制页面地址","copiedDirPath":"已复制目录路径","switchedToBranch":"已切换到 {{branch}}","switchBranchFailed":"切换分支失败","loadBranchFailed":"加载分支列表失败","copiedCommand":"已复制: {{command}}","copiedMessage":"已复制消息","forkFailed":"分叉会话失败","excerptFailed":"摘录本轮失败","copiedUrl":"已复制网址","copiedOutput":"已复制输出","copiedCmd":"已复制命令","copiedComment":"已复制评论","copiedAllComments":"已复制全部评论","copiedFileContent":"已复制文件内容","copiedQA":"已复制 {{count}} 个问答","copiedAllQA":"已复制所有问答","sentQA":"已发送给 AI","readFileFailed":"读取文件失败","fileOutsideProject":"文件在当前项目之外,仅支持预览 Markdown、CSV 和图片","reviewCreated":"评审已创建,链接已复制","reviewUpdated":"评审已更新,链接已复制","reviewCreateFailed":"创建评审失败","sharingClosed":"已关闭分享","sharingCloseFailed":"关闭分享失败","linkCopied":"链接已复制","addCommentFailed":"添加评论失败","deleteCommentFailed":"删除评论失败","editCommentFailed":"编辑评论失败","addReplyFailed":"添加回复失败","deleteReplyFailed":"删除回复失败","editReplyFailed":"编辑回复失败","disconnected":"已断开: {{id}}","pluginReloading":"插件重载中...","worktreeCreateSuccess":"Worktree 创建成功: {{name}}","worktreeCreateFailed":"创建 worktree 失败","worktreeLoadFailed":"加载 worktree 列表失败","worktreeDeleted":"Worktree 已删除","worktreeDeleteFailed":"删除 worktree 失败","worktreeLocked":"已锁定","worktreeUnlocked":"已解锁"},"workspace":{"selectProject":"选择一个项目开始","searchProjectPath":"搜索项目路径...","loadingProjects":"加载项目中...","projectNotFound":"未找到项目","sessions":"{{count}} 会话","loadingSessions":"加载会话...","noSessions":"无会话记录","loadingText":"加载中...","openProject":"打开项目","expandSidebar":"展开侧边栏","collapseSidebar":"折叠侧边栏","notes":"笔记","skills":"技能","apps":"应用","settings":"设置","help":"帮助","updateAvailable":"新版本 v{{version}} 可用","copyUpgradeCommand":"复制 cockpit update","updateNow":"立即更新","updating":"正在更新…","updateComplete":"更新完成","updateFailed":"更新失败","updateCardPreparing":"正在准备更新…","updateCardInstalling":"正在下载并安装","updateCardRepairing":"正在修复原生依赖","updateCardUpToDate":"已是最新版本 v{{version}}","updateCardCopyFix":"复制修复命令","updateCardFixCopied":"已复制修复命令","updateCardRollingBack":"安装失败,正在回滚","updateCardRestarting":"正在重启 Cockpit…","updateCardDone":"已更新到 v{{version}}","updateCardElapsed":"已用 {{seconds}} 秒","updateCardBaseline":"上次约 {{seconds}} 秒","updateCardNoLiveStatus":"暂时读不到实时状态,更新仍在进行","updateCardRolledBack":"已回滚到原版本,Cockpit 可正常使用。","updateCardManualHint":"可在终端手动重试:","updateCardLogHint":"日志:{{path}}","updateRestartNote":"Cockpit 将在后台重启。","viewChangelog":"查看变更日志","serverRestarted":"Cockpit 已在后台更新。","reloadNow":"刷新","upgradeCommandCopied":"已复制 `cockpit update`","projectNotes":"项目笔记","closeProject":"关闭项目"},"mobile":{"useDesktop":"桌面版","messagePlaceholder":"发消息…","send":"发送","stop":"停止","enableNotifications":"开启通知","disableNotifications":"关闭通知","notifyError":"无法开启通知"},"sessions":{"recentSessions":"最近会话","favorites":"收藏会话","noFavorites":"暂无收藏会话,在 Tab 栏点击星标可添加","addFavorite":"收藏此会话","removeFavorite":"取消收藏","runningCount":"{{count}} 运行中","unreadCount":"{{count}} 未读","noSessions":"暂无会话记录","running":"运行中","done":"完成","editTitle":"编辑标题","projectSessions":"项目会话","browseAllSessions":"浏览所有会话","sessionList":"会话列表","search":"搜索","searchSessions":"搜索会话...","searchRecentSessions":"搜索最近会话","loadSessionsFailed":"加载会话失败","loadingSessions":"加载会话中...","noMatchingSessions":"未找到匹配的会话","noSessionsYet":"暂无会话","projectList":"项目列表","openFolder":"打开文件夹","selectingFolder":"选择中...","loadingHistory":"加载历史消息..."},"scheduledTasks":{"title":"定时任务","aboutToTrigger":"即将触发","secondsLater":"{{count}}秒后","minutesLater":"{{count}}分钟后","hoursMinutesLater":"{{h}}小时{{m}}分后","hoursLater":"{{h}}小时后","onceType":"一次性 ({{minutes}}分钟)","everyNMinutes":"每{{minutes}}分钟","completed":"已完成","paused":"已暂停","activeCount":"{{running}} 个活跃","pausedCount":"{{paused}} 个暂停","noScheduledTasks":"暂无定时任务,在聊天输入栏点击时钟按钮创建","lastResult":"上次","runNow":"立即运行","resume":"恢复","pause":"暂停","completedCount":"已完成 ({{count}})","success":"成功","failure":"失败","createTask":"创建定时任务","editTask":"编辑定时任务","sendMessage":"发送消息","messagePlaceholder":"输入要发送的消息...","taskFile":"任务文件","taskFilePlaceholder":"/Users/you/project/tasks/daily-report.md","taskFileHint":"填写绝对路径。触发时会让 agent 先读取该文件,再按其中描述执行——文件内容改动下次触发即生效。","taskFilePromptHeader":"请先读取以下任务文件,再据此执行:","type":"类型","once":"一次性","interval":"周期","quickSelect":"快捷选择","customCron":"自定义 Cron 表达式","customMinutes":"自定义分钟数","cronPlaceholder":"例: 0 9 * * 1-5 (工作日9点)","cronFormat":"格式:分 时 日 月 星期(如 0 9 * * 1-5)","minutesPlaceholder":"分钟数","limitTimeRange":"限制执行时段","to":"至","saveBtn":"保存 ({{modKey}}↩)","createBtn":"创建 ({{modKey}}↩)","5minLater":"5 分钟后","15minLater":"15 分钟后","30minLater":"30 分钟后","1hourLater":"1 小时后","every15min":"每 15 分钟","every30min":"每 30 分钟","every1hour":"每 1 小时","every2hours":"每 2 小时","daily9am":"每天 09:00","daily6pm":"每天 18:00","weeklyMon9am":"每周一 09:00","monthly1st9am":"每月 1 号 09:00"},"cron":{"everyNMinutes":"每 {{n}} 分钟","everyNHours":"每 {{n}} 小时整点","everyMinute":"每分钟","everyHourAtMin":"每小时第 {{m}} 分","hourlyEveryMin":"{{h}} 点每分钟","daily":"每天 {{time}}","weekdays":"工作日","weekends":"周末","dowSun":"日","dowMon":"一","dowTue":"二","dowWed":"三","dowThu":"四","dowFri":"五","dowSat":"六","monthPrefix":"月","dayOfMonth":"号","dayRange":"{{a}}号到{{b}}号","weekdayPrefix":"周","weekdayRange":"周{{a}}到周{{b}}"},"blockViewer":{"empty":{"body":"在左侧文件树选择一个文件,查看它的代码地图。","hint":"或按 ⌘K 搜索。"},"fileMode":{"loading":"加载中…","notFound":"该文件未索引(不支持的语言或超出文件上限)。"},"buildProgress":{"listing":"正在扫描文件…","contexts":"正在读取项目配置…","parsing":"正在解析文件","resolving":"正在解析引用关系…","edges":"正在构建调用图…","done":"即将完成…"},"search":{"tooltip":"搜索 (⌘K)","hint":"开始输入以搜索","noResults":"未找到匹配","files":"文件","symbols":"符号"},"viewerToggle":{"toBlock":"显示代码地图","toCode":"返回代码视图"},"toc":{"title":"本文件","empty":"未检测到函数。","notIndexed":"该文件未被项目图收录(扩展未支持 / 不在 git 跟踪集 / 超出文件上限)。"},"history":{"title":"历史","empty":"点击左右两侧的 pin 开始追踪调用链。","clear":"清空历史"},"refresh":"重新构建项目图","retry":"重试"},"blockDiffViewer":{"loading":"正在生成代码地图…","unsupported":"该文件类型暂不支持代码地图 diff","unsupportedHint":"切回常规 diff 视图查看。","error":"代码地图 diff 失败:{{message}}","noBlockChanges":"代码地图无变化(仅格式或空白)。","noBefore":"(新增)","noAfter":"(已删除)","kind":{"added":"新增","deleted":"删除","modified":"修改"}},"fileBrowser":{"directoryTree":"目录树","searchTab":"搜索","recentTab":"最近","changesTab":"变更","historyTab":"历史","searchFiles":"搜索文件...","clear":"清除","exactMatchOn":"全词匹配(已开启)","exactMatchOff":"全词匹配(已关闭)","refreshTree":"刷新目录树","collapseAll":"折叠所有目录","searchFileContent":"搜索文件内容...","caseSensitive":"区分大小写","wholeWord":"完整词","regex":"正则","fileTypes":"文件类型 (ts,tsx)","compareMode":"对比","compareModeOff":"关闭分支对比","compareModeOn":"与选定分支对比","createFile":"新建文件","createFileIn":"新建文件 (在 {{path}}/)","fileName":"文件名...","noRecentFiles":"暂无最近浏览的文件","stagingArea":"暂存区 ({{count}})","changesSummary_one":"{{count}} 个变更","changesSummary_other":"{{count}} 个变更","noChanges":"工作区无变更","refreshChanges":"刷新变更列表","unstageAll":"全部取消","noStagedFiles":"无暂存的文件","unstageNFiles":"取消暂存 {{count}} 个文件","unstageFile":"取消暂存","workspace":"工作区 ({{count}})","discardAll":"放弃所有","stageAll":"全部暂存","noUnstagedChanges":"无未暂存的变更","discardNFiles":"放弃 {{count}} 个文件的变更","stageNFiles":"暂存 {{count}} 个文件","discardChanges":"放弃变更","stageFile":"暂存文件","loadingDiff":"加载对比文件中...","noDiffFiles":"无差异文件","nFilesChanged":"{{count}} 个文件变更(vs {{branch}})","loadingCommits":"加载提交记录中...","noCommits":"无提交记录","allLoaded":"已加载全部 {{count}} 条记录","locateInTree":"在目录树中定位","unsaved":"未保存","saveBeforeSwitch":"当前文件有未保存的修改,是否保存后切换?","saveAndSwitch":"保存并切换","closeEdit":"关闭编辑 (ESC)","closeBtn":"关闭","copyFileContent":"复制文件内容","toggleJsonReadable":"切换 JSON 可读模式","previewMarkdown":"预览 Markdown 渲染效果","exitPreview":"退出预览","viewBlame":"查看每行代码的修改记录","viewDiff":"查看相对 HEAD 的改动","exitDiff":"退出 Diff","diffLoadFailed":"加载差异失败","editFile":"编辑文件","backToPreview":"返回预览","cannotPreview":"无法预览此文件","selectFileToPreview":"选择文件以预览","staged":"已暂存","unstaged":"未暂存","selectFileToViewDiff":"选择文件查看差异","loadingDiffContent":"加载差异中...","clickCompareToLoad":"点击「对比」加载分支差异","selectCommitToView":"选择提交查看详情","confirmDelete":"确认删除","confirmDeleteMessage":"确定要将 <file>{{name}}</file> 移动到回收站吗?","nFilesNMatches":"{{files}} 个文件,{{matches}} 处匹配","resultsTruncated":"结果已截断","noContentSearchResults":"无匹配结果","enterKeywordToSearch":"输入关键词搜索文件内容","searchMinChars":"搜索内容至少需要 2 个字符"},"csv":{"table":"表格","raw":"原始内容","empty":"空表格","summary":"{{rows}} 行 \xb7 {{cols}} 列","summaryFiltered":"匹配 {{rows}} / {{total}} 行 \xb7 {{cols}} 列","loadMore":"加载更多(已显示 {{shown}} / {{total}})","filterPlaceholder":"筛选内容…","filterColumn":"筛选列","clearFilter":"清除筛选","allColumns":"全部列","noMatch":"没有匹配的行","sortHint":"点击排序(升序 / 降序 / 取消)"},"codeViewer":{"fileModifiedExternally":"文件已被外部修改,保存将覆盖外部更改","useDiskVersion":"使用磁盘版本","forceOverwrite":"强制覆盖","searchPlaceholder":"搜索...","caseSensitive":"区分大小写","wholeWordMatch":"全字匹配","unsavedConfirm":"有未保存的修改,确定关闭?","discardChanges":"放弃修改","continueEditing":"继续编辑","unsavedExitConfirm":"有未保存的修改,确定退出编辑模式?","clickToViewDetails":"点击查看详情","clickToViewCommit":"点击查看 commit 详情","nComments":"{{count}} 条评论","searchChat":"搜索聊天内容...","prevShiftEnter":"上一个 (Shift+Enter)","nextEnter":"下一个 (Enter)","closeEsc":"关闭 (Esc)"},"chat":{"startConversation":"开始对话吧","loadMoreHistory":"加载更多...","scrollUpForMore":"↑ 向上滚动加载更多历史","jumpToStart":"跳转到开始","jumpToLatest":"跳转到最新","copyMessage":"复制消息","copyImage":"复制图片","copiedImage":"已复制图片","forkSession":"从此处分叉会话","excerptTurn":"摘录本轮到新会话","imageN":"图片 {{index}}","imagePreview":"图片预览","toolCalls":"{{count}} 个工具调用","collapse":"▲ 收起","expand":"▼ 展开","subagent":"子代理","subagentEmpty":"未找到子代理消息记录","subagentViewTitle":"查看子代理执行过程","workflowRun":"运行详情","workflowViewTitle":"查看工作流运行详情","workflowEmpty":"未找到工作流运行记录","workflowAgents":"个代理","workflowViewAgent":"查看","workflowUngrouped":"未分组","viewQuestions":"查看提问","viewAllFileChanges":"查看所有文件变更","requestFailed":"请求失败","cannotReadStream":"无法读取响应流","errorRetry":"发生错误,请重试","placeholder":"输入消息,Enter 发送(Shift+Enter 换行,可粘贴图片;行首 /(主会话)或 @(子代理)唤起命令,支持多行多命令)","placeholderDisabled":"生成中... 可继续输入 (ESC 取消;卡住太久可取消后重发「继续」)","imageSizeLimit":"图片大小超过限制(最大 5MB),当前大小: {{size}}MB","viewGitChanges":"查看 Git 变更","viewAllComments":"查看所有评论","userMessages":"用户消息列表","projectNotes":"项目笔记","scheduledTasks":"定时任务","quickPrompts":"快捷 Prompt","globalPrompts":"全局 Prompt","projectPrompts":"项目 Prompt","noQuickPrompts":"暂无快捷 Prompt","addQuickPrompt":"新增快捷 Prompt","quickPromptPlaceholder":"输入一句话 Prompt,Enter 保存,Esc 取消","context":"上下文","output":"输出","copiedCommandTooltip":"已复制!","copyCommandTooltip":"复制命令: {{command}}","executedCommand":"执行了 `{{command}}`{{exitInfo}},输出:\\n```\\n{{output}}\\n```","executedCommandFailed":"执行 `{{command}}` 失败:{{error}}","executionMode":"执行模式","checkBalance":"查询余额","balanceFailed":"查询失败,请检查 API Key","balanceNeedsKey":"请先配置 DeepSeek API Key","balanceUnavailable":"账户当前不可用","balanceEmpty":"接口未返回余额","openUsagePage":"打开 DeepSeek 用量控制台","checkQuota":"查询额度","quotaFailed":"额度查询失败,请检查 API Key","quotaNeedsKey":"请先设置 API Key","quotaEmpty":"未返回额度信息","quotaResetAt":"{{time}} 重置","openProviderConsole":"打开服务商控制台","planMode":"计划模式","planModeDesc":"只读\xb7先出计划不改代码","planModeOn":"已开启计划模式——只读;发一个任务即可拿到计划","planModeOff":"已关闭计划模式","planModeHint":"计划模式:只读探索、产出计划但不改文件。取消勾选后重发才会实现。","noHistory":"独立任务","noHistoryDesc":"不发送历史","noHistoryHint":"独立任务:每条消息单独发给模型,不带之前的对话。上方的会话记录照常保留。","planTitle":"计划(待你确认)","approvePlan":"批准并执行","planApproveHint":"本环境无审批弹窗,点此退出计划模式并执行","approvePlanPrompt":"已批准,按上述计划开始执行。"},"console":{"enterCommandOrUrl":"输入命令或网址开始使用","emptyIntro":"在下方输入框输入以下内容,即可创建对应气泡:","bubbleCommand":"命令","bubbleInteractive":"交互终端","bubbleBrowser":"浏览器","bubbleBrowserNoteIframe":"部分网站会拦截 iframe 嵌入,请在「设置 → 浏览器插件」安装 Cockpit Bridge 后再打开。","bubbleBrowserNoteCookie":"已登录的网站若首次显示未登录,多刷新几次即可恢复。","bubbleDatabase":"数据库","bubbleNotebook":"笔记本","loadingMore":"加载中...","loadMoreHistory":"加载更多历史","quickCommands":"快捷命令","singleColumn":"单列布局","dualColumn":"双列布局","envVars":"环境变量","launchShell":"启动交互终端","htmlApps":"HTML 应用","inputPlaceholder":"输入命令或网址并按 Enter... (↑↓ 历史, Tab 补全)","scopeProject":"项目","scopeGlobal":"全局","tabSwitchEscClose":"Tab 切换 \xb7 Esc 关闭","copyOutput":"复制输出","copyCommand":"复制命令","rerun":"重新运行","deleteRecord":"删除记录","searchPlaceholder":"搜索...","searchMode":"搜索","filterMode":"过滤","prevShiftEnter":"上一个 (Shift+Enter)","nextEnter":"下一个 (Enter)","loadingTerminal":"加载终端...","clickToInput":"点击终端区域输入","stdinPlaceholder":"stdin 输入...","runningText":"运行中...","exitCode":"退出代码: {{code}}","totalLines":"共 {{count}} 行","globalCommands":"全局命令","projectCommands":"项目命令","noCustomCommands":"暂无自定义命令","namePlaceholder":"名称","commandPlaceholder":"命令","restoreTooltip":"还原 ({{modKey}}M / ESC)","screenshotting":"截图中...","outputFileDeleted":"[输出文件已删除]"},"browser":{"blankPage":"空白页","copyUrl":"复制网址","openInNewWindow":"在新窗口打开","exitMaximize":"退出最大化 ({{modKey}}M)","maximize":"最大化 ({{modKey}}M)","pageLoadFailed":"页面加载失败","clickToWake":"点击唤醒","sleeping":"已休眠","loadingPage":"加载中...","loadFailed":"加载失败"},"database":{"connectionFailed":"连接失败","connected":"已连接","connecting":"连接中...","refreshTableList":"刷新表列表","filterTable":"T 表","filterView":"V 视图","noTables":"无表","tabStructure":"结构","tabData":"数据","tabSql":"SQL","filterActive":"筛选: {{count}}列","clearAllFilters":"清除所有筛选","deleteNRows":"删除 {{count}} 行","confirmDeleteRows":"确认删除?","copyCsvSelected":"复制选中行为 CSV","copyCsvAll":"导出全表 CSV","copyJsonSelected":"复制选中行为 JSON","copyJsonAll":"导出全表 JSON","copyCSV":"复制 CSV","CSV":"CSV","copyJSON":"复制 JSON","JSON":"JSON","selectTable":"选择左侧表格","selectTableToView":"选择表以查看结构","selectTableForData":"选择表以查看数据","columns":"列","colName":"名称","colType":"类型","colNullable":"可空","colDefault":"默认值","primaryKey":"主键","foreignKeys":"外键","indexes":"索引","enable":"启用","commaValues":"逗号分隔多值","likePattern":"%pattern%","valuePlaceholder":"值","apply":"应用","clearFilter":"清除","addRow":"+ 新增行","totalRows":"{{count}} 行","rowsAffected":"{{command}} — {{count}} 行受影响 ({{duration}}ms)","queryRows":"{{count}} 行 ({{duration}}ms)","resultTruncated":"[结果已截断至1000行]","sqlPlaceholder":"输入 SQL... ({{modKey}}Enter 执行)","executing":"执行中...","execute":"▶ 执行","deleteRowsFailed":"{{count}} 行删除失败","inputParams":"输入参数","resultLabel":"结果"},"mysql":{"connectionFailed":"连接失败","connected":"已连接","connecting":"连接中...","refreshTableList":"刷新表列表","filterTable":"T 表","filterView":"V 视图","noTables":"无表","tabStructure":"结构","tabData":"数据","tabSql":"SQL","filterActive":"筛选: {{count}}列","clearAllFilters":"清除所有筛选","deleteNRows":"删除 {{count}} 行","confirmDeleteRows":"确认删除?","copyCsvSelected":"复制选中行为 CSV","copyCsvAll":"导出全表 CSV","copyJsonSelected":"复制选中行为 JSON","copyJsonAll":"导出全表 JSON","copyCSV":"复制 CSV","CSV":"CSV","copyJSON":"复制 JSON","JSON":"JSON","selectTable":"选择左侧表格","selectTableToView":"选择表以查看结构","selectTableForData":"选择表以查看数据","columns":"列","colName":"名称","colType":"类型","colNullable":"可空","colDefault":"默认值","primaryKey":"主键","foreignKeys":"外键","indexes":"索引","enable":"启用","commaValues":"逗号分隔多值","likePattern":"%pattern%","valuePlaceholder":"值","apply":"应用","clearFilter":"清除","addRow":"+ 新增行","totalRows":"{{count}} 行","rowsAffected":"{{command}} — {{count}} 行受影响 ({{duration}}ms)","queryRows":"{{count}} 行 ({{duration}}ms)","resultTruncated":"[结果已截断至1000行]","sqlPlaceholder":"输入 SQL... ({{modKey}}Enter 执行)","executing":"执行中...","execute":"▶ 执行","deleteRowsFailed":"{{count}} 行删除失败"},"redis":{"neverExpires":"永不过期","expired":"已过期","loadFailed":"加载失败","deleteFailed":"删除失败","saveFailed":"保存失败","scanPlaceholder":"SCAN 模式...","scanSearch":"搜索 (SCAN)","noKeys":"无 key","loadMore":"加载更多...","tabData":"数据","tabInfo":"信息","tabCli":"CLI","selectKey":"选择左侧 Key","keyNotExist":"Key 不存在","unsupportedType":"不支持的类型: {{type}}","nItems":"{{total}} items","showingN":"显示 {{count}}","nMembers":"{{total}} members","nEntries":"{{total}} entries","cliHint":"输入 Redis 命令,如 PING, GET key, KEYS *","cliPlaceholder":"输入命令..."},"git":{"switchBranch":"切换分支","searchBranch":"搜索分支...","noBranches":"无可切换分支","noMatchingBranches":"无匹配分支","localBranches":"本地分支","remoteBranches":"远程分支","branchNotFound":"未找到分支","selectBranch":"选择分支...","currentBranch":"当前","notGitRepo":"当前目录不是 Git 仓库","cannotGetBranches":"无法获取分支信息","getBranchesFailed":"获取分支信息失败","discardAllConfirm":"确定要放弃工作区的 {{count}} 个文件的变更吗?此操作不可恢复。","worktree":{"title":"Git Worktree","count":"{{count}} 个 worktree","selectBranch":"选择分支","addWorktree":"+ 添加 Worktree","confirmDelete":"确认删除","confirmDeleteMsg":"确定要删除 worktree 吗?","path":"路径:","branch":"分支:","locked":"已锁定","unlock":"解锁","lock":"锁定","searchBranch":"搜索分支...","noBranches":"无可用分支"}},"comments":{"addComment":"添加评论","lineRange":"行 {{start}}-{{end}}","inputPlaceholder":"输入评论...","newComment":"新评论 {{range}}","commentPlaceholder":"输入评论... ({{modKey}}Enter 提交, Esc 取消)","nComments":"{{count}} 条评论","allComments":"所有评论","copyAllComments":"复制全部评论","noComments":"暂无评论","clearAll":"清空所有","totalComments":"共 {{count}} 条评论","aiReply":"AI 回复","noContent":"(无内容)","linesCount":"({{count}} 行)","codeRef":"以下是我标注的评论和引用:","note":"备注: {{content}}","submitting":"提交中...","enterSubmit":"Enter 提交 \xb7 Shift+Enter 换行","submitComment":"提交评论","askAI":"提问 AI","inputQuestion":"输入你的问题...","aiGenerating":"正在生成中,请稍候...","enterSend":"Enter 发送 \xb7 Shift+Enter 换行","sendToAI":"发送 AI","aiResponding":"AI 正在响应中..."},"fileContextMenu":{"createFile":"新建文件","copyFile":"复制文件","copyFolder":"复制文件夹","pasteHere":"粘贴到此处","deleteFile":"删除文件","deleteFolder":"删除文件夹","copyRelativePath":"复制相对路径","copyAbsolutePath":"复制绝对路径","copyRelativeDirPath":"复制相对文件夹路径","copyAbsoluteDirPath":"复制绝对文件夹路径","copyFileName":"复制文件名","copyFolderName":"复制文件夹名"},"settings":{"title":"设置","theme":"主题","themeLight":"浅色","themeDark":"深色","themeSystem":"跟随系统","browserExtension":"浏览器插件","extensionInstalled":"Cockpit Bridge 已安装","extensionNotInstalled":"Cockpit Bridge 未安装","extensionDescription":"安装 Chrome 插件后,iframe 内的链接跳转将被拦截:新标签链接创建新气泡,页面内导航更新当前气泡。","installSteps":"安装步骤:","step1":"1. 打开 Chrome 地址栏输入","step2":"2. 开启右上角「开发者模式」","step3":"3. 点击「加载已解压的扩展程序」","step4mac":"4. 按 <kbd>Cmd+Shift+G</kbd> → 粘贴下方路径 → 回车","copyExtensionPath":"复制插件目录路径","reloadExtension":"重载插件","about":"关于","language":"语言","languageAuto":"跟随系统","switchDark":"切换暗色","switchLight":"切换亮色"},"editor":{"placeholder":"写点什么... 输入 / 打开快捷命令","noteTitle":"{{name}} - 笔记","noteUntitled":"笔记","saving":"保存中...","conflictReloaded":"笔记已被其他地方修改,已加载最新版本,刚才未保存的编辑已丢弃","linkPlaceholder":"输入链接地址...","confirmLink":"确认","removeLink":"移除链接","heading1":"标题 1","heading2":"标题 2","heading3":"标题 3","bold":"粗体","italic":"斜体","strikethrough":"删除线","inlineCode":"行内代码","link":"链接","bulletList":"无序列表","orderedList":"有序列表","taskList":"待办列表","blockquote":"引用","codeBlock":"代码块","table":"表格","horizontalRule":"分割线","insertRowAbove":"在上方插入行","insertRowBelow":"在下方插入行","insertColumnLeft":"在左侧插入列","insertColumnRight":"在右侧插入列","deleteRow":"删除当前行","deleteColumn":"删除当前列","deleteTable":"删除表格","deleteCodeBlock":"删除代码块","toc":"目录","expandToc":"展开目录","collapseToc":"收起目录"},"slashCommands":{"heading1":"标题 1","heading1Desc":"大标题","heading2":"标题 2","heading2Desc":"中标题","heading3":"标题 3","heading3Desc":"小标题","bulletList":"无序列表","bulletListDesc":"项目符号列表","orderedList":"有序列表","orderedListDesc":"编号列表","taskList":"待办列表","taskListDesc":"可勾选的任务列表","blockquote":"引用","blockquoteDesc":"引用块","codeBlock":"代码块","codeBlockDesc":"代码片段","table":"表格","tableDesc":"插入 3\xd73 表格","horizontalRule":"分割线","horizontalRuleDesc":"水平分割线","link":"链接","linkDesc":"插入超链接"},"commands":{"qa":"进入需求澄清讨论模式","fx":"进入 bug 证据链分析模式","ex":"进入结构化分析讨论模式","go":"进入连续落地(MVP)模式","cg":"进入 CodeGraph 探索模式","plan":"开启计划模式 \xb7 /plan <任务> 直接规划该任务 \xb7 /plan off 关闭"},"review":{"reviewManagement":"评审管理","allReviews":"所有评审","noOpenReviews":"暂无开放评审","viewComments":"查看评论","nComments":"{{count}} 条评论","nDocs":"{{count}} 文档","nReviews":"{{count}} 评审","docList":"文档列表","allReviewsList":"所有评审","expandList":"展开列表","collapseList":"折叠列表","closeReview":"关闭评审","reopenReview":"重新开放","deleteReview":"删除评审","noOpenDocs":"暂无开放文档","noReviews":"暂无评审","sharing":"分享中","notShared":"未分享","closeSharing":"关闭分享","enableSharing":"开启分享评审","view":"查看","setNickname":"设置你的昵称","nicknameHint":"其他评审人将看到这个名字","nicknamePlaceholder":"输入昵称","skipForNow":"下次再说","identitySettings":"身份设置","reviewNickname":"评审昵称","random":"随机","selectTextToComment":"选中左侧文本添加评论","selectTextHint":"选中左侧文本即可添加评论","prevComment":"上一条","nextComment":"下一条","commentsCount":"{{count}} 条评论","commentsNavCount":"{{current}}/{{total}} 条评论","allCommentsTitle":"全部评论","commentsCountBrief":"{{count}} 条","closedCount":"{{count}} 条已关闭","copyAllComments":"复制全部评论","noComments":"暂无评论","closedComments":"已关闭 ({{count}})","closedLabel":"已关闭","moreReplies":"+{{count}} 条回复","copyComment":"复制评论","reopen":"重开","closeComment":"关闭评论","editComment":"编辑评论","deleteComment":"删除评论","edited":"(已编辑)","editReply":"编辑回复","deleteReply":"删除回复","reply":"回复","replyPlaceholder":"添加回复...","selectedText":"选中文本","addCommentPlaceholder":"添加评论...","enterSubmitHint":"Enter 提交,Shift+Enter 换行","commentBtn":"评论","reviewNotExist":"评审不存在或已被删除","loadFailed":"加载失败","networkError":"网络错误","reviewNotFound":"评审不存在","checkLink":"请检查链接是否正确","updatedAt":"更新于 {{date}}","active":"开放中","closed":"已关闭","viewAllComments":"查看全部评论","viewCommentBtn":"查看评论","copyLink":"复制链接","reviewSummary":"评审评论汇总 — {{title}}","totalNComments":"共 {{count}} 条评论","quoteRef":"引用: \\"{{text}}\\"","commentAuthor":"评论 ({{author}}): {{content}}","replyAuthor":" ↳ {{author}}: {{content}}"},"markdown":{"copied":"✓ 已复制","copy":"复制"},"imagePreview":{"previewImage":"预览图片","deleteImage":"删除图片","copyImage":"复制图片","copiedImage":"已复制图片"},"tokenStats":{"title":"Claude Code Token 统计","activeHours":"活跃时段分布","hourSessions":"{{h}}:00 — {{count}} 次会话","messages":"消息","toolCalls":"工具调用","activityTrend":"活动趋势","byModel":"按模型","tokenUsage":"Token 用量","equivalentCost":"等效费用","modelCostDetail":"模型费用明细","model":"模型","share":"占比","total":"合计","totalSessions":"总会话","totalMessages":"总消息","equivalentApiCost":"等效 API 费用","longestSession":"最长会话","firstUse":"首次使用","notFound":"未找到 ~/.claude/stats-cache.json","day":"日","week":"周","month":"月"},"toolCall":{"inputParams":"输入参数","resultLabel":"结果","inputParamsTitle":"查看输入参数","resultTitle":"查看结果","input":"输入","result":"结果","foldedLines":"... ({{count}} 行)"},"fileEditor":{"unsavedConfirm":"有未保存的修改,确定关闭?","discardChanges":"放弃修改","continueEditing":"继续编辑","externallyModified":"文件已被外部修改,保存将覆盖外部更改","useDiskVersion":"使用磁盘版本","forceOverwrite":"强制覆盖"},"quickFileOpen":{"placeholder":"输入文件名快速打开...","noMatch":"没有匹配的文件","recent":"最近","selectHint":"选择","openHint":"打开","closeHint":"关闭"},"envManager":{"title":"环境变量管理","tabScope":"当前 Tab 专用","globalScope":"全局环境变量","varNamePlaceholder":"变量名(如 NODE_ENV)","varValuePlaceholder":"值(如 production)","valuePlaceholder":"值","noVars":"还没有环境变量,添加一个试试"},"aliasManager":{"title":"命令别名管理","description":"为常用命令设置快捷别名(全局生效)","aliasPlaceholder":"别名(如 ll)","commandPlaceholder":"完整命令(如 ls -la)","fullCommandPlaceholder":"完整命令","usage":"使用提示:","usageDesc":"输入别名即可执行对应的完整命令","noAliases":"还没有命令别名,添加一个试试"},"diffViewer":{"fileChanges":"文件变更 ({{count}})","toggleFileTree":"切换文件目录","selectFileToView":"选择左侧文件查看变更","sideBySide":"并列对比","unified":"统一对比","viewSplit":"双栏","viewUnified":"单栏","previewFile":"预览文件","copiedAll":"已复制全文","compact":"精简","full":"全文","gap":{"hidden":"已隐藏 {{count}} 行","more":"\xb7\xb7\xb7 更多 +{{count}} \xb7\xb7\xb7","expandUp":"向上展开 {{count}} 行","expandDown":"向下展开 {{count}} 行"},"loadingSnapshots":"正在加载快照…","noChanges":"本轮未检测到文件变更","notViewable":"二进制或超大文件,无法展示 diff","externalChange":"同期其他会话/外部进程的变更","reconstructed":"参数重建","reconstructedHint":"由工具调用参数重建,非磁盘快照","truncated":"文件过多,仅显示部分","imageBefore":"变更前","imageAfter":"变更后","imageAdded":"新增","imageDeleted":"已删除","imageLoadFailed":"图片加载失败","imageUnavailable":"该版本无此图片"},"commitDetail":{"title":"提交详情","hash":"哈希:","author":"作者:","date":"日期:","files":"文件:","nChanges":"{{count}} 个变更","loadingFiles":"加载文件中...","noFileChanges":"无文件变更","loadingDiff":"加载差异中...","selectFileToView":"选择文件查看差异"},"askQuestion":{"title":"提问","nQuestions":"{{count}} 个问题","checkedN":"已勾选 {{count}}","copyChecked":"复制勾选的 {{count}} 个问答","copyAll":"复制所有问答","sendChecked":"发送勾选的 {{count}} 个问答给 AI","sendAll":"发送所有问答给 AI","sendNoChat":"没有可用的聊天会话","checkToCopy":"勾选以复制","custom":"自定义","customPlaceholder":"输入自定义回答...","notSelected":"(未选择)"},"tabBar":{"closeTab":"关闭标签","closeAll":"关闭所有标签","newTab":"新建标签"},"tabManagerTopBar":{"copyPageUrl":"复制页面地址","copyDirPath":"复制目录路径","refreshProject":"刷新当前项目","openInVSCode":"在 VS Code 中打开","openInCursor":"在 Cursor 中打开","aliasesGlobal":"命令别名(全局)","tokenStats":"Token 统计","openSurething":"打开 Surething"},"hoverTooltip":{"findReferences":"查找引用","search":"搜索"},"todoViewer":{"title":"任务列表","progress":"{{completed}} / {{total}} 完成"},"userMessages":{"title":"用户消息列表","noMessages":"暂无用户消息"},"shortIdBadge":{"clickToDisconnect":"点击断开连接","clickToRegister":"点击注册并复制 CLI 命令","setTitle":"给这个气泡命名(便于 /cc 通过 connection list 找到它)","setTitlePlaceholder":"设置标题","editTitle":"编辑标题","titleSet":"标题:{{title}}","dialogTitle":"给气泡命名","dialogPlaceholder":"例如:alloydb 代理、预发管理后台"},"api":{"pathForbidden":"不允许操作此路径","deleteForbidden":"不允许删除此路径","notAFolder":"目标不是文件夹","imageTooLarge":"图片文件过大,无法预览","cannotPreviewBinary":"无法预览二进制文件","fileTooLarge":"文件过大,无法预览(超过 10MB)","fileModifiedExternally":"文件已被外部修改","pickFolderPrompt":"选择项目文件夹"},"confirm":{"title":"提示","ok":"确定","cancel":"取消"},"floatingToolbar":{"addComment":"添加评论","sendToAI":"发送 AI","search":"搜索"},"quickReply":{"optionA":"A","optionB":"B","optionC":"C","optionD":"D","allRecommended":"其他按推荐","thisOne":"就这个","notThis":"不要这样","why":"为什么","elaborate":"展开说","example":"举个例子","start":"开始做","continue":"继续","ok":"OK","done":"做完了","edit":"编辑快捷短语","editTitle":"编辑快捷短语","editHint":"一行对应面板的一行,行内用逗号分隔。每个短语会原样发送到对话。","editPlaceholder":"就这个,不要这样\\n为什么,展开说","restoreDefault":"恢复默认","save":"保存","cancel":"取消","customizedFor":"当前编辑的是{{lang}}短语,另一种语言不受影响。","langEn":"英文","langZh":"中文","saveFailed":"保存快捷短语失败"},"searchResults":{"title":"搜索结果","nMatches":"({{count}} 处匹配)","searching":"搜索中...","noResults":"无匹配结果","scopeSelected":"选中","scopeAll":"全部"},"references":{"title":"引用","searching":"搜索中...","notFound":"未找到引用"},"gitFileTree":{"noFiles":"无文件"},"deps":{"action":"依赖关系","none":"无","symbolMessage":"分析 {{name}} ({{path}}:{{lines}}) 的依赖关系。\\n\\n调用者:{{callers}}\\n调用了:{{callees}}\\n外部依赖:{{externals}}\\n\\n请说明它耦合在哪些模块上,以及哪些依赖是可以收敛掉的。"},"explain":{"action":"解释一下","fileMessage":"解释一下 {{path}}","symbolMessage":"解释一下 {{name}} ({{path}}:{{lines}})","selectionMessage":"解释一下","commitFileMessage":"解释一下 git commit {{hash}} 对 {{path}} 的改动","compareFileMessage":"解释一下 git {{base}}..HEAD 中 {{path}} 的改动","stagedFileMessage":"解释一下 git 暂存区中 {{path}} 的改动","unstagedFileMessage":"解释一下 git 工作区中 {{path}} 的改动"},"reviewUtils":{"adjectives":["快乐","勇敢","安静","明亮","温柔","灵巧","自由","清澈","飞翔","悠闲","活泼","聪慧","淡定","机敏","从容","坚定","爽朗","和煦","奔放","沉稳"],"nouns":["熊猫","海豚","白鹤","雪豹","云雀","松鼠","飞鱼","梅花鹿","青鸟","银狐","猫头鹰","蜻蜓","萤火虫","海龟","蝴蝶","金丝猴","丹顶鹤","羚羊","燕子","企鹅"]}}');n.Ay.isInitialized||n.Ay.init({resources:{en:{translation:a},zh:{translation:i}},lng:"en",fallbackLng:"en",interpolation:{escapeValue:!1}});let r=n.Ay},79968:(e,t,o)=>{o.d(t,{ShareReviewToggle:()=>d});var n=o(95155),a=o(12115),i=o(79114),r=o(34075),s=o(86957),l=o(90420);function d({content:e,sourceFile:t}){let o,c,u,p,h,{t:m}=(0,i.Bd)(),[g,f]=(0,a.useState)(null),[w,y]=(0,a.useState)(!0),[v,b]=(0,a.useState)(!1);(0,a.useEffect)(()=>{if(!t)return void y(!1);let e=!1;return s.t4.runPromiseExit((0,l.Y_)()).then(o=>{if(!e){if("Success"===o._tag){let e=(o.value.reviews??[]).find(e=>e.sourceFile===t);f(e?{id:e.id,active:e.active,updatedAt:e.updatedAt}:null)}y(!1)}}),()=>{e=!0}},[t]);let C=g?.active===!0,k=(0,a.useCallback)(async()=>{b(!0);let o=t.split("/").pop()||t,n=await s.t4.runPromiseExit((0,l.bx)({title:o,content:e,sourceFile:t}));if("Success"!==n._tag||!n.value.review){(0,r.oR)(m("toast.reviewCreateFailed"),"error"),b(!1);return}let a=n.value.review;f({id:a.id,active:!0,updatedAt:a.updatedAt||a.createdAt});let i=await s.t4.runPromiseExit((0,l._c)()),d="Success"===i._tag&&i.value.shareBase?`${i.value.shareBase}/review/${a.id}`:`${window.location.origin}/review/${a.id}`;try{await navigator.clipboard.writeText(d)}catch{}(0,r.oR)(a.existing?m("toast.reviewUpdated"):m("toast.reviewCreated"),"success"),b(!1)},[e,t,m]),S=(0,a.useCallback)(async()=>{g&&(b(!0),"Success"===(await s.t4.runPromiseExit((0,l.Gm)(g.id,{active:!1})))._tag?(f(e=>e?{...e,active:!1}:null),(0,r.oR)(m("toast.sharingClosed"),"success")):(0,r.oR)(m("toast.sharingCloseFailed"),"error"),b(!1))},[g,m]),x=(0,a.useCallback)(()=>{v||(C?S():k())},[v,C,k,S]),T=(0,a.useCallback)(()=>{g&&window.open(`${window.location.origin}/review/${g.id}`,"_blank")},[g]);return w?null:(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("button",{onClick:x,disabled:v,className:`relative inline-flex h-4 w-7 items-center rounded-full transition-colors ${v?"opacity-50 cursor-wait":"cursor-pointer"} ${C?"bg-green-500":"bg-muted-foreground/30"}`,title:C?m("review.closeSharing"):m("review.enableSharing"),children:(0,n.jsx)("span",{className:`inline-block h-3 w-3 rounded-full bg-white transition-transform ${C?"translate-x-3.5":"translate-x-0.5"}`})}),(0,n.jsx)("span",{className:`text-[11px] ${C?"text-green-600 dark:text-green-400":"text-muted-foreground"}`,children:C?m("review.sharing"):m("review.notShared")}),C&&g&&g.updatedAt&&(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("span",{className:"text-[10px] text-muted-foreground",children:(c=String((o=new Date(g.updatedAt)).getMonth()+1).padStart(2,"0"),u=String(o.getDate()).padStart(2,"0"),p=String(o.getHours()).padStart(2,"0"),h=String(o.getMinutes()).padStart(2,"0"),`${c}-${u} ${p}:${h}`)}),(0,n.jsx)("button",{onClick:T,className:"text-[11px] text-brand hover:underline",children:m("review.view")})]})]})}},82680:(e,t,o)=>{o.d(t,{m_:()=>i,uV:()=>a});var n=o(50584);class a extends n.rN("AppError"){}n.rN("DBError"),n.rN("WSError"),n.rN("FSError"),n.rN("AgentError"),n.rN("ValidationError");class i extends n.rN("NotFoundError"){}n.rN("PermissionError")},86957:(e,t,o)=>{o.d(t,{t4:()=>O});var n=o(59257),a=o(74565),i=o(49433),r=o(93404),s=o(22484),l=o(41463);let d=n.Um(s.j9,s.dl((e=>{switch((e??"").toLowerCase()){case"all":return r.u8;case"trace":return r.Cn;case"debug":return r.y;case"info":default:return r.R2;case"warning":case"warn":return r.N5;case"error":return r.$D;case"fatal":return r.Lj;case"none":return r.NV}})(l.env.COCKPIT_LOG_LEVEL)));var c=o(80905),u=o(98953);let p=globalThis,h=p.__cockpitSpanRing??={buffer:[],index:new Map},m=e=>{let t="abcdef0123456789",o="";for(let n=0;n<e;n++)o+=t.charAt(Math.floor(Math.random()*t.length));return o};class g{constructor(e,t,o,n,a,i){this.name=e,this.parent=t,this.context=o,this.startTime=a,this.kind=i,this._tag="Span",this.sampled=!0,this.attributes=new Map,this.events=[],this.traceId=c.Ru(t)?t.value.traceId:m(32),this.spanId=m(16),this.status={_tag:"Started",startTime:a},this.links=Array.from(n),function(e){if(h.buffer.push(e),h.index.set(e.spanId,h.buffer.length-1),h.buffer.length>500){h.buffer.shift(),h.index.clear();for(let e=0;e<h.buffer.length;e++)h.index.set(h.buffer[e].spanId,e)}}(function(e,t,o,n,a,i){return{traceId:t,spanId:e,parentSpanId:o,name:n,kind:a,startTimeNs:i.toString(),endTimeNs:null,durationMs:null,attributes:{},events:[],status:"started"}}(this.spanId,this.traceId,function(e){return c.Ru(e)?e.value.spanId:null}(t),e,i,a))}end(e,t){this.status={_tag:"Ended",endTime:e,exit:t,startTime:this.status.startTime},function(e,t,o){let n=h.index.get(e);if(void 0===n)return;let a=h.buffer[n];if(!a)return;let i=Number(t-BigInt(a.startTimeNs))/1e6;h.buffer[n]={...a,endTimeNs:t.toString(),durationMs:Math.round(100*i)/100,status:"Success"===o._tag?"ok":"error",errorMessage:"Failure"===o._tag?function(e){if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}(o.cause):void 0}}(this.spanId,e,"Success"===t._tag?{_tag:"Success"}:{_tag:"Failure",cause:t.cause})}attribute(e,t){this.attributes.set(e,t),function(e,t,o){let n=h.index.get(e);if(void 0===n)return;let a=h.buffer[n];a&&(h.buffer[n]={...a,attributes:{...a.attributes,[t]:o}})}(this.spanId,e,t)}event(e,t,o){this.events.push([e,t,o??{}]),function(e,t,o,n){let a=h.index.get(e);if(void 0===a)return;let i=h.buffer[a];i&&(h.buffer[a]={...i,events:[...i.events,{name:t,timeNs:o.toString(),attributes:n}]})}(this.spanId,e,t,o)}addLinks(e){this.links.push(...e)}}let f=u.L8({span:(e,t,o,n,a,i)=>new g(e,t,o,n,a,i),context:e=>e()}),w=n.Py(u.sh,f);n.Ie;var y=o(63400),v=o(41463);let b=y.eu("dev","prod")("COCKPIT_ENV").pipe(y.IQ("prod")),C=y.Yj("COCKPIT_HOST").pipe(y.IQ("127.0.0.1")),k=y.nd("COCKPIT_PORT").pipe(y.NW(()=>y.nd("PORT")),y.IQ(3457)),S=y.uK(y.Yj("COCKPIT_OPEN_PROJECT")).pipe(y.Tj(e=>"Some"===e._tag?e.value:void 0)),x=y.zM("COCKPIT_NO_OPEN").pipe(y.IQ(!1)),T=y.Yj("COCKPIT_LOG_LEVEL").pipe(y.IQ("info")),E=y.nd("COCKPIT_SNAPSHOT_KEEP_DAYS").pipe(y.IQ(7)),A=y.nd("COCKPIT_SNAPSHOT_REPO_TTL_DAYS").pipe(y.IQ(30)),N=y.nd("COCKPIT_SNAPSHOT_MAX_FILE_KB").pipe(y.IQ(2048)),F=y.nd("COCKPIT_SESSION_KEEP_DAYS").pipe(y.IQ(30));i.gen(function*(){let e=yield*b,t=yield*C,o=yield*k,n=yield*S,a=yield*x,r=yield*T,s=yield*E,l=yield*A,d=yield*N,c=yield*F,u=yield*i.sync(()=>{let e=void 0!==v?v.env:void 0,t=e?.HOME||e?.USERPROFILE||".",o=e?.COCKPIT_HOME;return o?o.replace(/^~(?=$|\/)/,t):t+"/.cockpit"});return{env:e,host:t,port:3457===o&&"dev"===e?3456:o,cockpitDir:u,openProject:n,openBrowser:!a,logLevel:r,logFile:u+"/logs/cockpit.log",snapshotKeepDays:s,snapshotRepoTtlDays:l,snapshotMaxFileKb:d,sessionKeepDays:c}}).pipe(i.orDie);let P=n.Ie;var L=o(38147),R=o(23363),D=o(88292);let M=n.P1(D.d,i.gen(function*(){let e=yield*L.dT();return yield*i.acquireRelease(i.sync(()=>{let t=t=>{i.runFork(L.mk(e,t))};return window.addEventListener("message",t),t}),e=>i.sync(()=>{window.removeEventListener("message",e)})),D.d.of({publish:(e,t)=>i.sync(()=>{let o={type:e.legacyType,topic:e.id,msg:t,..."object"==typeof t&&null!==t?t:{}};window.parent.postMessage(o,"*")}),subscribe:t=>R.qdp(e).pipe(R.pbD(e=>{var o;return o=e.data,!!o&&"object"==typeof o&&(o.topic===t.id||o.type===t.legacyType)}),R.TjK(e=>((e,t)=>{if(e.topic===t.id)return e.msg;let{type:o,...n}=e;return n})(e.data,t)))})})),I=n.Um(d,w,P),B=n.Um(I,M),O=a.L8(B);i.void},88292:(e,t,o)=>{o.d(t,{R:()=>a,d:()=>i});var n=o(50995);let a=(e,t)=>({id:e,legacyType:t??e.replace(/-/g,"_").toUpperCase()}),i=n.Io("@cockpit/IframeBus")},90420:(e,t,o)=>{o.d(t,{BL:()=>f,Gm:()=>h,JK:()=>u,Wr:()=>m,Y8:()=>v,Y_:()=>c,_c:()=>w,bx:()=>p,dU:()=>y,i7:()=>S,jw:()=>b,mu:()=>C,vy:()=>k,z1:()=>g});var n=o(49433),a=o(82680);let i=(e,t)=>n.tryPromise({try:async()=>{let o=await fetch(e,t);if(!o.ok)throw Error(`HTTP ${o.status}`);return await o.json()},catch:o=>new a.uV({message:`${t?.method??"GET"} ${e} failed`,cause:o})}),r=(e,t)=>i(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),s=(e,t)=>i(e,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),l=(e,t)=>i(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),d=e=>i(e,{method:"DELETE"}),c=()=>i("/api/review"),u=e=>{let t;return t=`/api/review/${encodeURIComponent(e)}`,n.tryPromise({try:async()=>{let e=await fetch(t);if(404===e.status)throw Object.assign(Error("not found"),{__404__:!0});if(!e.ok)throw Error(`HTTP ${e.status}`);return await e.json()},catch:e=>e?.__404__?new a.m_({resource:"review",id:t}):new a.uV({message:`GET ${t} failed`,cause:e})})},p=e=>r("/api/review",e),h=(e,t)=>l(`/api/review/${encodeURIComponent(e)}`,t),m=e=>d(`/api/review/${encodeURIComponent(e)}`),g=e=>l("/api/review/order",{order:e}),f=()=>i("/api/review/users"),w=()=>i("/api/review/share-info"),y=(e,t)=>r(`/api/review/${encodeURIComponent(e)}/comments`,t),v=(e,t)=>s(`/api/review/${encodeURIComponent(e)}/comments`,t),b=(e,t)=>d(`/api/review/${encodeURIComponent(e)}/comments?commentId=${encodeURIComponent(t)}`),C=(e,t)=>r(`/api/review/${encodeURIComponent(e)}/replies`,t),k=(e,t)=>s(`/api/review/${encodeURIComponent(e)}/replies`,t),S=(e,t,o)=>d(`/api/review/${encodeURIComponent(e)}/replies?commentId=${encodeURIComponent(t)}&replyId=${encodeURIComponent(o)}`)},94287:(e,t,o)=>{o.d(t,{m:()=>i});var n=o(95155),a=o(12115);function i({content:e,children:t,className:o}){if(o)return(0,n.jsx)("div",{"data-tooltip":e,className:o,children:t});let r=a.Children.toArray(t);if(1===r.length&&(0,a.isValidElement)(r[0])){let t=r[0];return(0,a.cloneElement)(t,{"data-tooltip":e})}return(0,n.jsx)("div",{"data-tooltip":e,style:{display:"contents"},children:t})}},97251:(e,t,o)=>{o.d(t,{W:()=>i});var n=o(48250);let a=new Set(["p","h1","h2","h3","h4","h5","h6","li","blockquote","pre","table","tr","hr","div","ul","ol"]);function i(){return e=>{(0,n.YR)(e,"element",e=>{if(a.has(e.tagName)&&e.position&&(e.properties||(e.properties={}),e.properties["data-source-start"]=e.position.start.line,e.properties["data-source-end"]=e.position.end.line,"pre"===e.tagName)){let t=e.children?.find(e=>"element"===e.type&&"code"===e.tagName);t&&(t.properties||(t.properties={}),t.properties["data-source-start"]=e.position.start.line,t.properties["data-source-end"]=e.position.end.line)}})}}}}]);