dsh-runnpu 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4CZL4IT4.mjs +4 -0
- package/dist/{chunk-XMZG2NP7.mjs → chunk-GJSGPQNW.mjs} +1 -1
- package/dist/chunk-KQBXZKCA.mjs +4 -0
- package/dist/chunk-MGSEPBNR.mjs +6 -0
- package/dist/{chunk-YPL4VUYF.mjs → chunk-ZA65VWZ4.mjs} +1 -1
- package/dist/chunk-ZVARRQYA.mjs +1 -0
- package/dist/compute-node.mjs +1 -1
- package/dist/compute-tools.mjs +20 -20
- package/dist/connectors.mjs +2 -2
- package/dist/pins.mjs +1 -1
- package/dist/training-node.mjs +2 -2
- package/dist/training-tools.mjs +16 -16
- package/lib/client.js +20 -20
- package/package.json +1 -1
- package/dist/chunk-JUBIWGKW.mjs +0 -4
- package/dist/chunk-KQOFBYGE.mjs +0 -9
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{randomUUID as K}from"node:crypto";import{readFile as k,writeFile as m,mkdir as g,chmod as R,readdir as P,rename as U,rm as _}from"node:fs/promises";import{existsSync as w}from"node:fs";import{homedir as C}from"node:os";import{join as s,resolve as A}from"node:path";var L=".train",x={apiHost:"https://api.swanlab.cn",webHost:"https://swanlab.cn"},S={runnpuToken:"RUNNPU_TOKEN",swanlabApiKey:"SWANLAB_API_KEY"},I;function N(){let e=I??(process.env.DSH_HOME||s(C(),".dsh"));return s(e,"runnpu-modes")}async function f(e){try{return JSON.parse(await k(e,"utf8"))}catch{return}}async function v(e,n,r){await g(s(e,".."),{recursive:!0}),await m(e,`${JSON.stringify(n,void 0,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:r}),r!==void 0&&await R(e,r)}function l(e){return s(A(e),L)}async function J(e){if(!e)return{config:void 0,secrets:void 0,dir:void 0};let n=l(e);return{dir:n,config:await f(s(n,"config.json")),secrets:await f(s(n,"secrets.json"))}}async function D(e){let n=l(e);await g(s(n,"runs"),{recursive:!0});let r=s(n,".gitignore");return w(r)||await m(r,`secrets.json
|
|
3
|
+
`,"utf8"),n}async function V(e,n){let r=await D(e),i={...await f(s(r,"config.json"))??{},...n,updatedAt:new Date().toISOString()};return await v(s(r,"config.json"),i),i}async function T(e,n){let r=await D(e),t=s(r,"secrets.json"),o={...await f(t)??{}};for(let[a,c]of Object.entries(n))c===void 0||c===""?delete o[a]:o[a]=c;return await v(t,o,384),Object.keys(o)}async function h(e,n,r){let t=r?.[n];if(typeof t=="string"&&t!=="")return{value:t,source:"project"};if(e)try{let o=await e.resolve(n);if(o?.value)return{value:o.value,source:`credentials:${o.source}`}}catch{}let i=process.env[n];if(i)return{value:i,source:"env"}}async function Y(e,n,r,t){if(t.scope==="project"){if(!t.cwd)throw new Error("project scope needs a workspace");return await T(t.cwd,{[n]:r}),"project"}if(!e)throw new Error("credential provider unavailable; use project scope");return await e.set(n,r),"credentials"}async function E(e,n,r){let{config:t,secrets:i,dir:o}=await J(r),a=await f(s(N(),"connections.json"))??{},c=t?.runnpu?.server||a.runnpu?.server||n?.runnpu?.server||process.env.RUNNPU_SERVER||"",p=await h(e,S.runnpuToken,i),u=t?.swanlab?.mode||a.swanlab?.mode||"cloud",d=u==="cloud",j=t?.swanlab?.apiHost||a.swanlab?.apiHost||(d?x.apiHost:""),O=t?.swanlab?.webHost||a.swanlab?.webHost||(d?x.webHost:""),b=await h(e,S.swanlabApiKey,i);return{workspace:r??void 0,trainDir:o,runnpu:{server:c,configured:!!(c&&p),tokenSource:p?.source,token:p?.value},swanlab:{mode:u,apiHost:j,webHost:O,configured:!!(j&&b),apiKeySource:b?.source,apiKey:b?.value}}}async function Q(e,n,r){let t=await E(e,n,r);return{workspace:t.workspace,trainDir:t.trainDir,runnpu:{server:t.runnpu.server,configured:t.runnpu.configured,tokenSource:t.runnpu.tokenSource},swanlab:{mode:t.swanlab.mode,apiHost:t.swanlab.apiHost,webHost:t.swanlab.webHost,configured:t.swanlab.configured,apiKeySource:t.swanlab.apiKeySource}}}async function X(e,n,r){return await E(e,n,r)}async function Z(e){let n=s(N(),"connections.json"),t={...await f(n)??{},...e};return await v(n,t),t}async function ee(e){if(!e)return[];let n=s(l(e),"runs"),r;try{r=await P(n)}catch{return[]}let t=[];for(let i of r.filter(o=>o.endsWith(".json")).sort().reverse()){let o=await f(s(n,i));o&&t.push(o)}return t}function $(e){return`${String(e).padStart(4,"0")}.json`}var H=Object.freeze(["swanlabRun","status","endedAt","swanlabUpload"]),y=new Map;function F(e,n){let r=A(e),i=(y.get(r)??Promise.resolve()).then(n),o=i.catch(()=>{});return y.set(r,o),o.then(()=>{y.get(r)===o&&y.delete(r)}),i}async function M(e,n){await g(s(e,".."),{recursive:!0});let r=`${e}.${K().slice(0,8)}.tmp`;await m(r,`${JSON.stringify(n,void 0,2)}
|
|
4
|
+
`,"utf8");try{await U(r,e)}catch(t){throw await _(r,{force:!0}),t}}async function ne(e,n,r){return await F(e,async()=>{let t=s(l(e),"runs",$(n)),i=r??{},o=Object.keys(i).filter(u=>!H.includes(u)),a=await f(t);if(!a)return{path:t,run:void 0,changed:[],ignored:o};let c={...a},p=[];for(let u of H){if(!(u in i))continue;let d=i[u];d===void 0||d===a[u]||(c[u]=d,p.push(u))}return p.length===0?{path:t,run:a,changed:p,ignored:o}:(await M(t,c),{path:t,run:c,changed:p,ignored:o})})}async function te(e){if(e)return await f(s(l(e),"metrics.json"))}async function re(e){if(!e)return!1;if(w(l(e))||w(s(e,"train.py")))return!0;for(let n of["requirements.txt","pyproject.toml"])try{let r=await k(s(e,n),"utf8");if(/\b(torch|transformers|deepspeed|swanlab|accelerate|ultralytics)\b/i.test(r))return!0}catch{}for(let n of["configs","config"])if(w(s(e,n,"accelerate.yaml"))||w(s(e,n,"deepspeed.json")))return!0;return!1}export{x as a,S as b,N as c,l as d,J as e,D as f,V as g,T as h,Y as i,Q as j,X as k,Z as l,ee as m,ne as n,te as o,re as p};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as $,e as v}from"./chunk-JLZMOSQC.mjs";import{c as R}from"./chunk-JUBIWGKW.mjs";import{readFile as ne,writeFile as ie,mkdir as oe,rename as ae,rm as ue}from"node:fs/promises";import{join as D}from"node:path";import{randomUUID as G}from"node:crypto";var S=["line","area","bar","table"],y={projects:{items:{label:"\u9879\u76EE",at:t=>t?.items},usage:{label:"\u9879\u76EE \xD7 \u8D44\u6E90\u6C60 \u7528\u91CF",at:t=>A(t,"usage",K)},storage:{label:"\u9879\u76EE \xD7 \u5B58\u50A8\u6C60 \u7528\u91CF",at:t=>A(t,"storage",W)},queues:{label:"\u9879\u76EE\u961F\u5217\u51C6\u5165",at:t=>A(t,"queues",z)}},workloads:{items:{label:"\u8D1F\u8F7D",at:t=>t?.items}},nodes:{items:{label:"\u8282\u70B9",at:t=>t?.items}},cluster:{items:{label:"\u96C6\u7FA4\u7EC4\u4EF6",at:t=>t?.items}},overview:{projects:{label:"\u9879\u76EE\u914D\u989D\u4E0E\u7528\u91CF",at:t=>t?.projects},idle:{label:"\u95F2\u7F6E\u5360\u7528",at:t=>t?.idle},queued:{label:"\u6392\u961F\u8D1F\u8F7D",at:t=>t?.queued},nodes:{label:"\u8282\u70B9",at:t=>t?.nodes}}},F=Object.fromEntries(Object.entries(y).map(([t,e])=>[t,Object.entries(e).map(([r,s])=>({key:r,label:s.label}))]));function A(t,e,r){let s=[];for(let n of t?.items??[])for(let a of n?.cluster?.[e]??[])s.push({project:n.slug,project_name:n.name,...r(a)});return s}function K(t){let e=t?.guaranteed??0,r=t?.used??0;return{pool:t?.pool,device_type:t?.device_type,guaranteed:e,used:r,over_guarantee:r-e}}function W(t){let e=t?.limit_gib??0,r=t?.remaining_gib,s=typeof r=="number"&&e>0?e-r:void 0;return{pool:t?.pool,limit_gib:t?.limit_gib,persistent_gib:t?.persistent_gib,runtime_gib:t?.runtime_gib,remaining_gib:r,used_gib:s,used_pct:s===void 0||e<=0?void 0:Math.round(s/e*1e3)/10}}function z(t){return{queue:t?.name,pool:t?.pool,admitted:t?.admitted,reason:t?.reason}}function Q(t,e,r){if(t==="overview"&&e==="idle"){let s=r?.workload;return{workload:typeof s=="string"?s:`${s?.project??"?"}/${s?.name??"?"}`,type:typeof s=="object"?s?.display_type:void 0,idle_cards:r?.idle_cards,idle_hours:r?.idle_seconds===void 0?void 0:Math.round(r.idle_seconds/3600*10)/10,source:r?.source}}return r}var I={"workloads/items":["project","name","status","xpu_count","pods_ready","pods_total","pool"],"overview/queued":["project","name","xpu_count","pool","created_at"],"overview/projects":["slug","quota_cards","used_cards","running","queued"],"overview/idle":["workload","idle_cards","idle_hours","source"],"overview/nodes":["name","status","cards_total","cards_allocated","cards_free"],"nodes/items":["name","status","pool","cards_total","cards_allocated","cards_free","avg_util"],"projects/items":["slug","name","member_count","created_at"],"projects/usage":["project","pool","guaranteed","used","over_guarantee"],"projects/storage":["project","pool","limit_gib","used_gib","used_pct","remaining_gib"],"projects/queues":["project","queue","pool","admitted","reason"],"cluster/items":["name","status","ready","total","version"]},H={"overview/projects":{dimension:"slug",measures:["quota_cards","used_cards"]},"overview/idle":{dimension:"workload",measures:["idle_cards"]},"overview/queued":{dimension:"name",measures:["xpu_count"]},"overview/nodes":{dimension:"name",measures:["cards_allocated","cards_free"]},"workloads/items":{dimension:"name",measures:["xpu_count"]},"nodes/items":{dimension:"name",measures:["cards_allocated","cards_free"]},"projects/items":{dimension:"slug",measures:["member_count"]},"projects/usage":{dimension:"project",measures:["guaranteed","used"]},"projects/storage":{dimension:"project",measures:["used_gib","remaining_gib"]},"projects/queues":{dimension:"project",measures:[]},"cluster/items":{dimension:"name",measures:["ready","total"]}},B={project:"\u9879\u76EE",project_name:"\u9879\u76EE\u540D",slug:"\u9879\u76EE",name:"\u540D\u79F0",workload:"\u8D1F\u8F7D",status:"\u72B6\u6001",phase:"\u9636\u6BB5",pool:"\u8D44\u6E90\u6C60",type:"\u7C7B\u578B",display_type:"\u7C7B\u578B",xpu_count:"\u5361\u6570",quota_cards:"\u914D\u989D(\u5361)",used_cards:"\u5DF2\u7528(\u5361)",running:"\u8FD0\u884C",queued:"\u6392\u961F",idle_cards:"\u95F2\u7F6E(\u5361)",idle_hours:"\u95F2\u7F6E(\u5C0F\u65F6)",source:"\u5224\u5B9A\u6765\u6E90",pods_ready:"\u5C31\u7EEA Pod",pods_total:"\u603B Pod",member_count:"\u6210\u5458\u6570",cards_total:"\u603B\u5361",cards_allocated:"\u5DF2\u5206\u914D",cards_free:"\u7A7A\u95F2",cards_healthy:"\u5065\u5EB7",cards_allocatable:"\u53EF\u5206\u914D",avg_util:"\u5E73\u5747\u5229\u7528\u7387",cpu_cores:"CPU \u6838",ready:"\u5C31\u7EEA",total:"\u603B\u6570",version:"\u7248\u672C",arch:"\u67B6\u6784",os:"\u7CFB\u7EDF",guaranteed:"\u4FDD\u5E95(\u5361)",used:"\u5B9E\u9645\u7528(\u5361)",over_guarantee:"\u8D85\u51FA\u4FDD\u5E95",limit_gib:"\u914D\u989D(GiB)",used_gib:"\u5DF2\u7528(GiB)",used_pct:"\u5DF2\u7528\u6BD4\u4F8B",remaining_gib:"\u5269\u4F59(GiB)",persistent_gib:"\u6301\u4E45(GiB)",runtime_gib:"\u8FD0\u884C\u65F6(GiB)",queue:"\u961F\u5217",admitted:"\u5DF2\u51C6\u5165",reason:"\u539F\u56E0",created_at:"\u521B\u5EFA\u65F6\u95F4",admitted_at:"\u51C6\u5165\u65F6\u95F4",started_at:"\u5F00\u59CB\u65F6\u95F4",last_activity_at:"\u6700\u8FD1\u6D3B\u52A8",updated_at:"\u66F4\u65B0\u65F6\u95F4",internal_ip:"\u5185\u7F51 IP",owner_name:"\u6240\u6709\u8005",image:"\u955C\u50CF",device_type:"\u8BBE\u5907\u578B\u53F7",chip_model:"\u82AF\u7247"},J=t=>t===null||["string","number","boolean"].includes(typeof t);function X(t,e){if(e==null||e==="")return{text:"\u2014",align:"right"};if(typeof e=="boolean")return{text:e?"\u662F":"\u5426",align:"center"};if(typeof e=="number")return t.endsWith("_bytes")?{text:Y(e),align:"right"}:t.endsWith("_pct")||t==="avg_util"?{text:`${Number(e.toPrecision(3))}%`,align:"right"}:{text:String(Number(e.toPrecision(6))),align:"right"};if(t.endsWith("_at")&&/^\d{4}-\d{2}-\d{2}T/.test(e)){let r=new Date(e);if(Number.isFinite(r.getTime())){let s=n=>String(n).padStart(2,"0");return{text:`${s(r.getMonth()+1)}-${s(r.getDate())} ${s(r.getHours())}:${s(r.getMinutes())}`,align:"right"}}}return{text:String(e),align:"left"}}function Y(t){let e=["B","KiB","MiB","GiB","TiB"],r=t,s=0;for(;Math.abs(r)>=1024&&s<e.length-1;)r/=1024,s+=1;return`${Number(r.toPrecision(3))} ${e[s]}`}function T(t,e,r){let s=y[t];if(!s)return;let n=r&&s[r]?r:Object.keys(s)[0],a=s[n]?.at(e);if(Array.isArray(a))return{source:n,rows:a.map(i=>Q(t,n,i))}}function Z(t){let e=[];for(let r of t.slice(0,20))for(let[s,n]of Object.entries(r??{}))J(n)&&!e.includes(s)&&e.push(s);return e}function ee(t,e,r,s){let n=new Set(r),a=Array.isArray(s)?s:[],i=a.filter(c=>!n.has(c)),o=a.filter(c=>n.has(c));if(o.length>0)return{columns:o,dropped:i};let u=I[`${t}/${e}`];if(u){let c=u.filter(m=>n.has(m));if(c.length>0)return{columns:c,dropped:i}}return{columns:r.slice(0,8),dropped:i}}var M=50,N=t=>Number.isFinite(t)?Math.max(1,Math.min(200,t)):M;function te(t,e,r){if(!e)return t;let s=r===!1?1:-1;return[...t].sort((n,a)=>{let i=n?.[e],o=a?.[e];return typeof i=="number"&&typeof o=="number"?(i-o)*s:String(i??"").localeCompare(String(o??""))*s})}function re(t,e,r={}){let s=S.includes(r.kind)?r.kind:"line";if(s==="line"||s==="area"){let d=v(e,{query:t,group:r.group,series:r.series});return{kind:s,series:d.series,group:d.group,note:d.note}}let n=T(t,e,r.source);if(!n){let d=Object.keys(y).join(" / ");return{kind:s,columns:[],rows:[],note:`${t} \u6CA1\u6709\u53EF\u5217\u8868\u5316\u7684\u6570\u636E\uFF08\u652F\u6301\uFF1A${d}\uFF09`}}let{source:a,rows:i}=n;if(i.length===0)return{kind:s,source:a,columns:[],rows:[],note:"\u8FD9\u6B21\u67E5\u8BE2\u6CA1\u6709\u8FD4\u56DE\u4EFB\u4F55\u884C"};let o=N(r.limit),u=te(i,r.sort,r.desc),c=u.slice(0,o),m=u.length>c.length?u.length-c.length:0,f=[];m>0&&f.push(`\u53EA\u663E\u793A\u524D ${c.length} \u884C\uFF0C\u53E6\u6709 ${m} \u884C\u672A\u663E\u793A`);let h=Z(i);if(r.sort&&!h.includes(r.sort)&&f.push(`\u6CA1\u6709 ${r.sort} \u8FD9\u4E00\u5217\uFF0C\u6392\u5E8F\u6CA1\u6709\u751F\u6548\uFF08\u53EF\u7528\uFF1A${h.join(" / ")}\uFF09`),s==="bar"){let d=h.filter(l=>i.slice(0,20).some(w=>typeof w?.[l]=="number")),g=r.dimension&&h.includes(r.dimension)?r.dimension:["slug","name","workload","project"].find(l=>h.includes(l))??h[0],p=Array.isArray(r.measures)?r.measures:[],k=p.filter(l=>d.includes(l)),O=p.filter(l=>!d.includes(l)),j=k.length>0?k.slice(0,5):d.slice(0,2);return j.length===0?{kind:s,source:a,categories:[],series:[],note:"\u8FD9\u7EC4\u6570\u636E\u91CC\u6CA1\u6709\u53EF\u7528\u4F5C\u67F1\u9AD8\u7684\u6570\u503C\u5217"}:(O.length>0&&f.push(`\u6CA1\u6709 ${O.join("/")} \u8FD9\u4E9B\u6570\u503C\u5217\uFF0C\u753B\u7684\u662F ${j.join("/")}\uFF08\u53EF\u7528\uFF1A${d.join(" / ")}\uFF09`),{kind:s,source:a,categories:c.map(l=>String(l?.[g]??"\u2014")),series:j.map(l=>({key:l,name:B[l]??l,data:c.map(w=>typeof w?.[l]=="number"?w[l]:null)})),dimension:g,note:f.length>0?f.join("\uFF1B"):void 0})}let{columns:b,dropped:E}=ee(t,a,h,r.columns);return E.length>0&&f.push(`\u6CA1\u6709 ${E.join("/")} \u8FD9\u4E9B\u5217\uFF0C\u663E\u793A\u7684\u662F ${b.join("/")}\uFF08\u53EF\u7528\uFF1A${h.join(" / ")}\uFF09`),{kind:"table",source:a,columns:b.map(d=>({key:d,label:B[d]??d})),rows:c.map(d=>b.map(g=>{let p=X(g,d?.[g]);return{text:p.text,align:p.align}})),total:i.length,note:f.length>0?f.join("\uFF1B"):void 0}}function se(t){return{kind:"line",...t?.view??{}}}function _(t,e={}){let r=S.includes(e.kind)?e.kind:"line";if(U(r))return{kind:r};let s=y[t],n={kind:r};s&&(n.source=e.source&&s[e.source]?e.source:Object.keys(s)[0]);let a=r==="bar"?H[`${t}/${n.source}`]:void 0,i=e.dimension??a?.dimension;i!==void 0&&(n.dimension=i),e.sort!==void 0&&(n.sort=e.sort);let o=N(e.limit);o!==M&&(n.limit=o),e.desc===!1&&(n.desc=!1);let u=r==="table"?I[`${t}/${n.source}`]:void 0,c=Array.isArray(e.columns)&&e.columns.length>0?e.columns:u;Array.isArray(c)&&c.length>0&&(n.columns=[...c]);let m=Array.isArray(e.measures)&&e.measures.length>0?e.measures:a?.measures;return Array.isArray(m)&&m.length>0&&(n.measures=[...m]),n}var U=t=>t===void 0||t==="line"||t==="area";var L=["1h","6h","24h","7d"],P=16,ce=["kind","source","dimension","sort","desc","limit"];function C(t){if(t?.range===void 0)return t??{};let{range:e,...r}=t;return r}function x(t){let e=Object.entries(t.params??{}).filter(([o])=>o!=="range").filter(([,o])=>o!==void 0).sort(([o],[u])=>o<u?-1:o>u?1:0).map(([o,u])=>`${o}=${String(u)}`).join("&"),r=Array.isArray(t.series)&&t.series.length>0?[...t.series].sort().join(","):"",s=_(t.query,t.view),n=ce.filter(o=>s[o]!==void 0).map(o=>`${o}=${String(s[o])}`).join(","),a=Array.isArray(s.columns)?s.columns.join("+"):"",i=Array.isArray(s.measures)?s.measures.join("+"):"";return`${t.query}?${e}#${r}@${n}|${a}|${i}`}function q(t,e){let r=Object.entries({...t.params??{},range:e}).filter(([s])=>s!=="group").filter(([,s])=>s!==void 0).sort(([s],[n])=>s<n?-1:s>n?1:0).map(([s,n])=>`${s}=${String(n)}`).join("&");return`${t.query}?${r}`}var V=class{#n;#e=[];#s=new Map;#t;#o=new Set;#r="24h";#a=0;#m=Promise.resolve();constructor(e=D(R(),"pins.json")){this.#n=e,this.#t=this.#f()}#u(e){let r=this.#m.then(e);return this.#m=r.catch(()=>{}),r}async#f(){try{let e=JSON.parse(await ne(this.#n,"utf8"));L.includes(e?.range)&&(this.#r=e.range);let r=Array.isArray(e?.pins)?e.pins:[],s=new Set,n=!1;this.#e=r.map(a=>{let i=a;i.params?.range!==void 0&&(n=!0,i={...i,params:C(i.params)});let o=_(i.query,i.view);return JSON.stringify(o)!==JSON.stringify(i.view)&&(n=!0,i={...i,view:o}),i}).filter(a=>{let i=x(a);return s.has(i)?(n=!0,!1):(s.add(i),!0)}),(n||this.#e.length!==r.length)&&await this.#i()}catch{this.#e=[]}}async#i(){await oe(D(this.#n,".."),{recursive:!0});let e=`${JSON.stringify({range:this.#r,pins:this.#e},void 0,2)}
|
|
1
|
+
import{a as $,e as v}from"./chunk-JLZMOSQC.mjs";import{c as R}from"./chunk-4CZL4IT4.mjs";import{readFile as ne,writeFile as ie,mkdir as oe,rename as ae,rm as ue}from"node:fs/promises";import{join as D}from"node:path";import{randomUUID as G}from"node:crypto";var S=["line","area","bar","table"],y={projects:{items:{label:"\u9879\u76EE",at:t=>t?.items},usage:{label:"\u9879\u76EE \xD7 \u8D44\u6E90\u6C60 \u7528\u91CF",at:t=>A(t,"usage",K)},storage:{label:"\u9879\u76EE \xD7 \u5B58\u50A8\u6C60 \u7528\u91CF",at:t=>A(t,"storage",W)},queues:{label:"\u9879\u76EE\u961F\u5217\u51C6\u5165",at:t=>A(t,"queues",z)}},workloads:{items:{label:"\u8D1F\u8F7D",at:t=>t?.items}},nodes:{items:{label:"\u8282\u70B9",at:t=>t?.items}},cluster:{items:{label:"\u96C6\u7FA4\u7EC4\u4EF6",at:t=>t?.items}},overview:{projects:{label:"\u9879\u76EE\u914D\u989D\u4E0E\u7528\u91CF",at:t=>t?.projects},idle:{label:"\u95F2\u7F6E\u5360\u7528",at:t=>t?.idle},queued:{label:"\u6392\u961F\u8D1F\u8F7D",at:t=>t?.queued},nodes:{label:"\u8282\u70B9",at:t=>t?.nodes}}},F=Object.fromEntries(Object.entries(y).map(([t,e])=>[t,Object.entries(e).map(([r,s])=>({key:r,label:s.label}))]));function A(t,e,r){let s=[];for(let n of t?.items??[])for(let a of n?.cluster?.[e]??[])s.push({project:n.slug,project_name:n.name,...r(a)});return s}function K(t){let e=t?.guaranteed??0,r=t?.used??0;return{pool:t?.pool,device_type:t?.device_type,guaranteed:e,used:r,over_guarantee:r-e}}function W(t){let e=t?.limit_gib??0,r=t?.remaining_gib,s=typeof r=="number"&&e>0?e-r:void 0;return{pool:t?.pool,limit_gib:t?.limit_gib,persistent_gib:t?.persistent_gib,runtime_gib:t?.runtime_gib,remaining_gib:r,used_gib:s,used_pct:s===void 0||e<=0?void 0:Math.round(s/e*1e3)/10}}function z(t){return{queue:t?.name,pool:t?.pool,admitted:t?.admitted,reason:t?.reason}}function Q(t,e,r){if(t==="overview"&&e==="idle"){let s=r?.workload;return{workload:typeof s=="string"?s:`${s?.project??"?"}/${s?.name??"?"}`,type:typeof s=="object"?s?.display_type:void 0,idle_cards:r?.idle_cards,idle_hours:r?.idle_seconds===void 0?void 0:Math.round(r.idle_seconds/3600*10)/10,source:r?.source}}return r}var I={"workloads/items":["project","name","status","xpu_count","pods_ready","pods_total","pool"],"overview/queued":["project","name","xpu_count","pool","created_at"],"overview/projects":["slug","quota_cards","used_cards","running","queued"],"overview/idle":["workload","idle_cards","idle_hours","source"],"overview/nodes":["name","status","cards_total","cards_allocated","cards_free"],"nodes/items":["name","status","pool","cards_total","cards_allocated","cards_free","avg_util"],"projects/items":["slug","name","member_count","created_at"],"projects/usage":["project","pool","guaranteed","used","over_guarantee"],"projects/storage":["project","pool","limit_gib","used_gib","used_pct","remaining_gib"],"projects/queues":["project","queue","pool","admitted","reason"],"cluster/items":["name","status","ready","total","version"]},H={"overview/projects":{dimension:"slug",measures:["quota_cards","used_cards"]},"overview/idle":{dimension:"workload",measures:["idle_cards"]},"overview/queued":{dimension:"name",measures:["xpu_count"]},"overview/nodes":{dimension:"name",measures:["cards_allocated","cards_free"]},"workloads/items":{dimension:"name",measures:["xpu_count"]},"nodes/items":{dimension:"name",measures:["cards_allocated","cards_free"]},"projects/items":{dimension:"slug",measures:["member_count"]},"projects/usage":{dimension:"project",measures:["guaranteed","used"]},"projects/storage":{dimension:"project",measures:["used_gib","remaining_gib"]},"projects/queues":{dimension:"project",measures:[]},"cluster/items":{dimension:"name",measures:["ready","total"]}},B={project:"\u9879\u76EE",project_name:"\u9879\u76EE\u540D",slug:"\u9879\u76EE",name:"\u540D\u79F0",workload:"\u8D1F\u8F7D",status:"\u72B6\u6001",phase:"\u9636\u6BB5",pool:"\u8D44\u6E90\u6C60",type:"\u7C7B\u578B",display_type:"\u7C7B\u578B",xpu_count:"\u5361\u6570",quota_cards:"\u914D\u989D(\u5361)",used_cards:"\u5DF2\u7528(\u5361)",running:"\u8FD0\u884C",queued:"\u6392\u961F",idle_cards:"\u95F2\u7F6E(\u5361)",idle_hours:"\u95F2\u7F6E(\u5C0F\u65F6)",source:"\u5224\u5B9A\u6765\u6E90",pods_ready:"\u5C31\u7EEA Pod",pods_total:"\u603B Pod",member_count:"\u6210\u5458\u6570",cards_total:"\u603B\u5361",cards_allocated:"\u5DF2\u5206\u914D",cards_free:"\u7A7A\u95F2",cards_healthy:"\u5065\u5EB7",cards_allocatable:"\u53EF\u5206\u914D",avg_util:"\u5E73\u5747\u5229\u7528\u7387",cpu_cores:"CPU \u6838",ready:"\u5C31\u7EEA",total:"\u603B\u6570",version:"\u7248\u672C",arch:"\u67B6\u6784",os:"\u7CFB\u7EDF",guaranteed:"\u4FDD\u5E95(\u5361)",used:"\u5B9E\u9645\u7528(\u5361)",over_guarantee:"\u8D85\u51FA\u4FDD\u5E95",limit_gib:"\u914D\u989D(GiB)",used_gib:"\u5DF2\u7528(GiB)",used_pct:"\u5DF2\u7528\u6BD4\u4F8B",remaining_gib:"\u5269\u4F59(GiB)",persistent_gib:"\u6301\u4E45(GiB)",runtime_gib:"\u8FD0\u884C\u65F6(GiB)",queue:"\u961F\u5217",admitted:"\u5DF2\u51C6\u5165",reason:"\u539F\u56E0",created_at:"\u521B\u5EFA\u65F6\u95F4",admitted_at:"\u51C6\u5165\u65F6\u95F4",started_at:"\u5F00\u59CB\u65F6\u95F4",last_activity_at:"\u6700\u8FD1\u6D3B\u52A8",updated_at:"\u66F4\u65B0\u65F6\u95F4",internal_ip:"\u5185\u7F51 IP",owner_name:"\u6240\u6709\u8005",image:"\u955C\u50CF",device_type:"\u8BBE\u5907\u578B\u53F7",chip_model:"\u82AF\u7247"},J=t=>t===null||["string","number","boolean"].includes(typeof t);function X(t,e){if(e==null||e==="")return{text:"\u2014",align:"right"};if(typeof e=="boolean")return{text:e?"\u662F":"\u5426",align:"center"};if(typeof e=="number")return t.endsWith("_bytes")?{text:Y(e),align:"right"}:t.endsWith("_pct")||t==="avg_util"?{text:`${Number(e.toPrecision(3))}%`,align:"right"}:{text:String(Number(e.toPrecision(6))),align:"right"};if(t.endsWith("_at")&&/^\d{4}-\d{2}-\d{2}T/.test(e)){let r=new Date(e);if(Number.isFinite(r.getTime())){let s=n=>String(n).padStart(2,"0");return{text:`${s(r.getMonth()+1)}-${s(r.getDate())} ${s(r.getHours())}:${s(r.getMinutes())}`,align:"right"}}}return{text:String(e),align:"left"}}function Y(t){let e=["B","KiB","MiB","GiB","TiB"],r=t,s=0;for(;Math.abs(r)>=1024&&s<e.length-1;)r/=1024,s+=1;return`${Number(r.toPrecision(3))} ${e[s]}`}function T(t,e,r){let s=y[t];if(!s)return;let n=r&&s[r]?r:Object.keys(s)[0],a=s[n]?.at(e);if(Array.isArray(a))return{source:n,rows:a.map(i=>Q(t,n,i))}}function Z(t){let e=[];for(let r of t.slice(0,20))for(let[s,n]of Object.entries(r??{}))J(n)&&!e.includes(s)&&e.push(s);return e}function ee(t,e,r,s){let n=new Set(r),a=Array.isArray(s)?s:[],i=a.filter(c=>!n.has(c)),o=a.filter(c=>n.has(c));if(o.length>0)return{columns:o,dropped:i};let u=I[`${t}/${e}`];if(u){let c=u.filter(m=>n.has(m));if(c.length>0)return{columns:c,dropped:i}}return{columns:r.slice(0,8),dropped:i}}var M=50,N=t=>Number.isFinite(t)?Math.max(1,Math.min(200,t)):M;function te(t,e,r){if(!e)return t;let s=r===!1?1:-1;return[...t].sort((n,a)=>{let i=n?.[e],o=a?.[e];return typeof i=="number"&&typeof o=="number"?(i-o)*s:String(i??"").localeCompare(String(o??""))*s})}function re(t,e,r={}){let s=S.includes(r.kind)?r.kind:"line";if(s==="line"||s==="area"){let d=v(e,{query:t,group:r.group,series:r.series});return{kind:s,series:d.series,group:d.group,note:d.note}}let n=T(t,e,r.source);if(!n){let d=Object.keys(y).join(" / ");return{kind:s,columns:[],rows:[],note:`${t} \u6CA1\u6709\u53EF\u5217\u8868\u5316\u7684\u6570\u636E\uFF08\u652F\u6301\uFF1A${d}\uFF09`}}let{source:a,rows:i}=n;if(i.length===0)return{kind:s,source:a,columns:[],rows:[],note:"\u8FD9\u6B21\u67E5\u8BE2\u6CA1\u6709\u8FD4\u56DE\u4EFB\u4F55\u884C"};let o=N(r.limit),u=te(i,r.sort,r.desc),c=u.slice(0,o),m=u.length>c.length?u.length-c.length:0,f=[];m>0&&f.push(`\u53EA\u663E\u793A\u524D ${c.length} \u884C\uFF0C\u53E6\u6709 ${m} \u884C\u672A\u663E\u793A`);let h=Z(i);if(r.sort&&!h.includes(r.sort)&&f.push(`\u6CA1\u6709 ${r.sort} \u8FD9\u4E00\u5217\uFF0C\u6392\u5E8F\u6CA1\u6709\u751F\u6548\uFF08\u53EF\u7528\uFF1A${h.join(" / ")}\uFF09`),s==="bar"){let d=h.filter(l=>i.slice(0,20).some(w=>typeof w?.[l]=="number")),g=r.dimension&&h.includes(r.dimension)?r.dimension:["slug","name","workload","project"].find(l=>h.includes(l))??h[0],p=Array.isArray(r.measures)?r.measures:[],k=p.filter(l=>d.includes(l)),O=p.filter(l=>!d.includes(l)),j=k.length>0?k.slice(0,5):d.slice(0,2);return j.length===0?{kind:s,source:a,categories:[],series:[],note:"\u8FD9\u7EC4\u6570\u636E\u91CC\u6CA1\u6709\u53EF\u7528\u4F5C\u67F1\u9AD8\u7684\u6570\u503C\u5217"}:(O.length>0&&f.push(`\u6CA1\u6709 ${O.join("/")} \u8FD9\u4E9B\u6570\u503C\u5217\uFF0C\u753B\u7684\u662F ${j.join("/")}\uFF08\u53EF\u7528\uFF1A${d.join(" / ")}\uFF09`),{kind:s,source:a,categories:c.map(l=>String(l?.[g]??"\u2014")),series:j.map(l=>({key:l,name:B[l]??l,data:c.map(w=>typeof w?.[l]=="number"?w[l]:null)})),dimension:g,note:f.length>0?f.join("\uFF1B"):void 0})}let{columns:b,dropped:E}=ee(t,a,h,r.columns);return E.length>0&&f.push(`\u6CA1\u6709 ${E.join("/")} \u8FD9\u4E9B\u5217\uFF0C\u663E\u793A\u7684\u662F ${b.join("/")}\uFF08\u53EF\u7528\uFF1A${h.join(" / ")}\uFF09`),{kind:"table",source:a,columns:b.map(d=>({key:d,label:B[d]??d})),rows:c.map(d=>b.map(g=>{let p=X(g,d?.[g]);return{text:p.text,align:p.align}})),total:i.length,note:f.length>0?f.join("\uFF1B"):void 0}}function se(t){return{kind:"line",...t?.view??{}}}function _(t,e={}){let r=S.includes(e.kind)?e.kind:"line";if(U(r))return{kind:r};let s=y[t],n={kind:r};s&&(n.source=e.source&&s[e.source]?e.source:Object.keys(s)[0]);let a=r==="bar"?H[`${t}/${n.source}`]:void 0,i=e.dimension??a?.dimension;i!==void 0&&(n.dimension=i),e.sort!==void 0&&(n.sort=e.sort);let o=N(e.limit);o!==M&&(n.limit=o),e.desc===!1&&(n.desc=!1);let u=r==="table"?I[`${t}/${n.source}`]:void 0,c=Array.isArray(e.columns)&&e.columns.length>0?e.columns:u;Array.isArray(c)&&c.length>0&&(n.columns=[...c]);let m=Array.isArray(e.measures)&&e.measures.length>0?e.measures:a?.measures;return Array.isArray(m)&&m.length>0&&(n.measures=[...m]),n}var U=t=>t===void 0||t==="line"||t==="area";var L=["1h","6h","24h","7d"],P=16,ce=["kind","source","dimension","sort","desc","limit"];function C(t){if(t?.range===void 0)return t??{};let{range:e,...r}=t;return r}function x(t){let e=Object.entries(t.params??{}).filter(([o])=>o!=="range").filter(([,o])=>o!==void 0).sort(([o],[u])=>o<u?-1:o>u?1:0).map(([o,u])=>`${o}=${String(u)}`).join("&"),r=Array.isArray(t.series)&&t.series.length>0?[...t.series].sort().join(","):"",s=_(t.query,t.view),n=ce.filter(o=>s[o]!==void 0).map(o=>`${o}=${String(s[o])}`).join(","),a=Array.isArray(s.columns)?s.columns.join("+"):"",i=Array.isArray(s.measures)?s.measures.join("+"):"";return`${t.query}?${e}#${r}@${n}|${a}|${i}`}function q(t,e){let r=Object.entries({...t.params??{},range:e}).filter(([s])=>s!=="group").filter(([,s])=>s!==void 0).sort(([s],[n])=>s<n?-1:s>n?1:0).map(([s,n])=>`${s}=${String(n)}`).join("&");return`${t.query}?${r}`}var V=class{#n;#e=[];#s=new Map;#t;#o=new Set;#r="24h";#a=0;#m=Promise.resolve();constructor(e=D(R(),"pins.json")){this.#n=e,this.#t=this.#f()}#u(e){let r=this.#m.then(e);return this.#m=r.catch(()=>{}),r}async#f(){try{let e=JSON.parse(await ne(this.#n,"utf8"));L.includes(e?.range)&&(this.#r=e.range);let r=Array.isArray(e?.pins)?e.pins:[],s=new Set,n=!1;this.#e=r.map(a=>{let i=a;i.params?.range!==void 0&&(n=!0,i={...i,params:C(i.params)});let o=_(i.query,i.view);return JSON.stringify(o)!==JSON.stringify(i.view)&&(n=!0,i={...i,view:o}),i}).filter(a=>{let i=x(a);return s.has(i)?(n=!0,!1):(s.add(i),!0)}),(n||this.#e.length!==r.length)&&await this.#i()}catch{this.#e=[]}}async#i(){await oe(D(this.#n,".."),{recursive:!0});let e=`${JSON.stringify({range:this.#r,pins:this.#e},void 0,2)}
|
|
2
2
|
`,r=`${this.#n}.${G().slice(0,8)}.tmp`;await ie(r,e,"utf8");try{await ae(r,this.#n)}catch(s){throw await ue(r,{force:!0}),s}}async ready(){return await this.#t,this}async list(){return await this.#t,this.#e.map(e=>({...e,latest:this.#s.get(e.id)}))}async range(){return await this.#t,this.#r}async setRange(e,r,s){if(await this.#t,!L.includes(e))throw new Error(`\u4E0D\u652F\u6301\u7684\u65F6\u95F4\u8303\u56F4\uFF1A${e}`);if(!await this.#u(async()=>e===this.#r?!1:(this.#r=e,this.#s.clear(),this.#a+=1,await this.#i(),!0)))return{range:e,results:[]};let a=await this.refreshAll(r,s);return this.#l(),{range:e,results:a}}async findEquivalent(e){await this.#t;let r=x(e);return this.#e.find(s=>x(s)===r)}async add(e,r){return await this.#t,this.#u(async()=>{let s=C(e.params),n=await this.findEquivalent({...e,params:s});if(n!==void 0)return{pin:n,created:!1};if(this.#e.length>=P){let i=new Error(`\u56FA\u5B9A\u56FE\u8868\u5DF2\u8FBE\u4E0A\u9650\uFF08${P} \u5F20\uFF09\uFF0C\u5148\u53D6\u6D88\u56FA\u5B9A\u4E00\u5F20\u518D\u9489\u65B0\u7684`);throw i.code="pin_limit",i.status=409,i}let a={id:G(),title:e.title||"\u672A\u547D\u540D\u56FE\u8868",query:e.query,params:s,series:e.series,view:_(e.query,e.view),workspace:e.workspace,provenance:{source:"runnpu",createdAt:new Date().toISOString(),...r}};return this.#e=[...this.#e,a],await this.#i(),this.#l(),{pin:a,created:!0}})}async remove(e){return await this.#t,this.#u(async()=>{let r=this.#e.length;return this.#e=this.#e.filter(s=>s.id!==e),this.#s.delete(e),this.#e.length===r?!1:(await this.#i(),this.#l(),!0)})}async refresh(e,r,s){let n=await this.#c(e,r,s);return n===void 0?{id:e.id,at:Date.now(),ok:!1,stale:!0,error:"\u65F6\u95F4\u8303\u56F4\u521A\u521A\u5207\u6362\uFF0C\u8FD9\u6B21\u53D6\u6570\u5DF2\u4F5C\u5E9F\uFF0C\u7A0D\u540E\u4F1A\u6309\u65B0\u7A97\u53E3\u91CD\u65B0\u53D6\u6570"}:this.#d(e,n)}async#c(e,r,s){let n=this.#a,a=$.includes(e.query)?{...e.params,range:this.#r}:{...e.params},i;try{i={ok:!0,data:await r.query(e.workspace,e.query,a,s)}}catch(o){i={ok:!1,error:o.message,code:o.code}}return n===this.#a?i:void 0}#d(e,r){let s={id:e.id,at:Date.now(),...r};return this.#s.set(e.id,s),s}async refreshAll(e,r){await this.#t;let s=new Map;for(let a of this.#e){let i=q(a,this.#r),o=s.get(i);o?o.push(a):s.set(i,[a])}return(await Promise.all([...s.values()].map(async a=>{let i=await this.#c(a[0],e,r);return i===void 0?[]:a.map(o=>this.#d(o,i))}))).flat()}async requestCount(){return await this.#t,new Set(this.#e.map(e=>q(e,this.#r))).size}async refreshMissing(e,r){await this.#t;let s=this.#e.filter(i=>this.#s.get(i.id)===void 0);if(s.length===0)return[];let n=new Map;for(let i of s){let o=q(i,this.#r),u=n.get(o);u?u.push(i):n.set(o,[i])}return(await Promise.all([...n.values()].map(async i=>{let o=await this.#c(i[0],e,r);return o===void 0?[]:i.map(u=>this.#d(u,o))}))).flat()}latestOf(e){return this.#s.get(e)}onChange(e){return this.#o.add(e),()=>this.#o.delete(e)}#l(){for(let e of[...this.#o])try{e()}catch{}}};export{S as a,F as b,T as c,re as d,se as e,_ as f,U as g,L as h,P as i,x as j,V as k};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{e as o}from"./chunk-MGSEPBNR.mjs";var h=Object.freeze({compute:Object.freeze({id:"compute",name:"\u7B97\u529B\u7BA1\u7406",description:"\u96C6\u7FA4\u72B6\u6001\u3001\u5360\u5361\u3001\u914D\u989D\u4E0E\u5F02\u5E38\uFF1B\u56FE\u8868\u53EF\u56FA\u5B9A\u5230\u53F3\u680F\u5E76\u81EA\u52A8\u5237\u65B0\u3002",needsWorkspace:!1,apiPath:"/runnpu-api",refreshMs:3e4,openers:Object.freeze(["\u73B0\u5728\u96C6\u7FA4\u6574\u4F53\u662F\u4EC0\u4E48\u72B6\u51B5\uFF1F\u6709\u6CA1\u6709\u5F02\u5E38\uFF1F","\u8C01\u5360\u4E86\u6700\u591A\u7684\u5361\uFF1F\u6709\u6CA1\u6709\u5360\u7740\u4E0D\u7528\u7684\uFF1F","\u5404\u9879\u76EE\u7684\u914D\u989D\u7528\u4E86\u591A\u5C11\uFF1F\u8FD8\u591F\u4E0D\u591F\u5206\uFF1F","\u5E2E\u6211\u62C9\u8D77\u4E00\u4E2A\u5F00\u53D1\u73AF\u5883","\u628A\u95F2\u7F6E\u8D85\u8FC7 2 \u5C0F\u65F6\u7684\u8D1F\u8F7D\u5217\u51FA\u6765\uFF0C\u6211\u51B3\u5B9A\u505C\u54EA\u4E9B","\u518D\u6765 3 \u4E2A\u4EBA\u505A\u5FAE\u8C03\uFF0C\u73B0\u5728\u7684\u5361\u591F\u4E0D\u591F\uFF1F"])}),training:Object.freeze({id:"training",name:"\u8BAD\u7EC3",description:"\u628A\u5DE5\u4F5C\u76EE\u5F55\u91CC\u7684\u8BAD\u7EC3\u5DE5\u7A0B\u90E8\u7F72\u5230\u96C6\u7FA4\uFF0CSwanLab \u8BB0\u5F55\uFF0C\u5173\u952E\u6307\u6807\u5E38\u9A7B\u8F93\u5165\u6846\u4E0A\u65B9\u3002",needsWorkspace:!0,apiPath:"/training-api",refreshMs:15e3,openers:Object.freeze(["\u770B\u4E00\u4E0B\u8FD9\u4E2A\u76EE\u5F55\u91CC\u7684\u8BAD\u7EC3\u5DE5\u7A0B\uFF0C\u5173\u952E\u6307\u6807\u5E94\u8BE5\u76EF\u54EA\u51E0\u4E2A\uFF1F","\u8FD9\u6B21\u8BAD\u7EC3\u8981\u7528\u4EC0\u4E48\u914D\u7F6E\uFF1F\u5148\u8BF4\u65B9\u6848\uFF0C\u6211\u786E\u8BA4\u540E\u518D\u63D0\u4EA4\u3002","\u524D\u51E0\u6B21\u8BAD\u7EC3\u90FD\u8BD5\u4E86\u4EC0\u4E48\uFF1F\u4E0B\u4E00\u6B65\u5EFA\u8BAE\u600E\u4E48\u8C03\uFF1F"])})});function b(i,a,t){try{i.write(`event: ${a}
|
|
2
|
+
data: ${JSON.stringify(t)}
|
|
3
|
+
|
|
4
|
+
`)}catch{}}function w({refresh:i,intervalMs:a}){let t=new o;async function c(){await i()}function f(e,s,r){if(e.method!=="GET"){s.writeHead(405,{allow:"GET"}).end();return}if(t.subscribe(e,s),r?.onClose&&e.on("close",r.onClose),!!r?.seed)try{r.seed((p,d)=>b(s,p,d))}catch{}}let n;function u(){if(n)return;let e=!1;n=setInterval(()=>{t.size!==0&&(e||(e=!0,c().catch(()=>{}).finally(()=>{e=!1})))},a)}function l(){n&&clearInterval(n),n=void 0,t.closeAll()}return{hub:t,handler:f,start:u,stop:l}}export{h as a,w as b};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{randomBytes as p,timingSafeEqual as g}from"node:crypto";function h(n,t,e){let r=JSON.stringify(e);n.writeHead(t,{"content-type":"application/json; charset=utf-8","cache-control":"no-store","content-length":Buffer.byteLength(r)}),n.end(r)}function s(n,t,e,r,o){h(n,t,{error:e,status:t,message:r,details:o})}async function w(n,t=256*1024){let e=[],r=0;for await(let o of n){if(r+=o.length,r>t)throw Object.assign(new Error(`request body exceeds ${t} bytes`),{status:413,code:"body_too_large"});e.push(o)}if(r!==0)try{return JSON.parse(Buffer.concat(e).toString("utf8"))}catch(o){throw Object.assign(new Error(`request body is not valid JSON: ${o.message}`),{status:400,code:"bad_json"})}}function l(n){let t=n.headers.origin;if(!t)return!0;try{let e=new URL(t);return e.hostname==="127.0.0.1"||e.hostname==="localhost"||e.hostname==="[::1]"}catch{return!1}}function N(n){return async(t,e)=>{try{let r=new URL(t.url??"/","http://127.0.0.1"),o=n[t.method??"GET"];if(!o){e.writeHead(405,{allow:Object.keys(n).join(", ")}).end();return}if(t.method!=="GET"&&t.method!=="HEAD"&&!l(t)){s(e,403,"forbidden_origin","cross-origin request refused");return}await o(t,e,r)}catch(r){if(e.headersSent){e.end();return}s(e,r?.status&&Number.isInteger(r.status)?r.status:500,r?.code??"internal_error",String(r?.message??r),r?.details)}}}var a=class{#e=new Set;subscribe(t,e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache, no-transform",connection:"keep-alive"}),e.write(`: connected
|
|
2
|
+
|
|
3
|
+
`);let r={res:e};this.#e.add(r);let o=()=>{this.#e.delete(r);try{e.end()}catch{}};return t.on("close",o),o}publish(t,e){let r=`event: ${t}
|
|
4
|
+
data: ${JSON.stringify(e)}
|
|
5
|
+
|
|
6
|
+
`;for(let o of this.#e)try{o.res.write(r)}catch{this.#e.delete(o)}}closeAll(){for(let t of this.#e)try{t.res.end()}catch{}this.#e.clear()}get size(){return this.#e.size}};var f=p(32).toString("base64url"),y="x-runnpu-nonce",b="nonce",c=0,i;function O(n){let t=n.get("webServer");t&&n.effect(()=>(c+=1,c===1&&(i=t.tapIndex(e=>e.replace("</head>",`<script>globalThis.__RUNNPU_NONCE__=${JSON.stringify(f)}</script></head>`))),()=>{c-=1,!(c>0)&&(i?.(),i=void 0)}),"runnpu: index nonce injection")}function u(n){if(typeof n!="string"||n.length===0)return!1;let t=Buffer.from(n,"utf8"),e=Buffer.from(f,"utf8");return t.byteLength===e.byteLength&&g(t,e)}function m(n,t){let e=n.headers?.[y];if(u(Array.isArray(e)?e[0]:e))return!0;let r=t??new URL(n.url??"/","http://127.0.0.1");return u(r.searchParams.get(b)??"")}function d(n){return(t,e)=>{if(!m(t)){s(e,401,"unauthenticated","\u7F3A\u5C11\u6216\u65E0\u6548\u7684\u63D2\u4EF6\u8BF7\u6C42\u4EE4\u724C");return}return n(t,e)}}function j(n,t){let e={};for(let[r,o]of Object.entries(t))Object.defineProperty(e,r,{enumerable:!0,get:()=>n.get(o)});return e}function $(n,t,e){let r=n.get("webServer");for(let o of t)n.effect(()=>r.register({kind:"exact",path:o.path,handler:d(o.handler)}),`${e}: ${o.path}`)}function J(n,t,e){n.effect(()=>(t.start(),()=>t.stop()),`${e}: live refresh`)}export{h as a,s as b,w as c,N as d,a as e,O as f,j as g,$ as h,J as i};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as y}from"./chunk-
|
|
1
|
+
import{c as y}from"./chunk-4CZL4IT4.mjs";function g(e){if(!e)return;let s=new Date(e).getTime();return Number.isFinite(s)?Math.max(0,Math.round((Date.now()-s)/1e3)):void 0}var l=e=>Math.round(e/3600*10)/10;function w(e){return typeof e=="string"?e:e?`${e.project??"?"}/${e.name??"?"}`:"\u672A\u77E5\u8D1F\u8F7D"}function F(e){let s=e?.kpi??{},r=(e?.projects??[]).map(n=>({slug:n.slug,name:n.name,quotaCards:n.quota_cards??0,usedCards:n.used_cards??0,running:n.running??0,queued:n.queued??0,idleHeld:Math.max(0,(n.used_cards??0)-(n.running??0))})),a=(e?.idle??[]).map(n=>({workload:w(n.workload),type:typeof n.workload=="object"?n.workload?.display_type:void 0,idleCards:n.idle_cards??0,idleHours:n.idle_seconds===void 0?void 0:l(n.idle_seconds),source:n.source}));return{cards:{total:s.cards_total??0,allocated:s.cards_allocated??0,available:s.cards_available??0,idleAllocated:s.cards_idle_allocated??0},workloads:{running:s.workloads_running??0,queued:s.workloads_queued??0,failed:s.workloads_failed??0},nodes:{ready:s.nodes_ready??0,total:s.nodes_total??0},projects:r.sort((n,d)=>d.usedCards-n.usedCards||d.idleHeld-n.idleHeld),idle:a.sort((n,d)=>d.idleCards-n.idleCards||(d.idleHours??0)-(n.idleHours??0)),metricsAvailable:e?.metrics?.available!==!1}}function N(e,s,r={}){let a=r.idleHours??2,n=r.queuedHours??1,d=r.notReadyMinutes??5,c=r.terminatingHours??.5,u=[];e?.metrics?.available===!1&&u.push({severity:"warn",kind:"metrics-source-down",subject:"\u6307\u6807\u6E90",detail:`\u6307\u6807\u6E90\u672A\u63A5\u5165\uFF08${e.metrics.reason??"\u539F\u56E0\u672A\u7ED9\u51FA"}\uFF09\u3002\u5229\u7528\u7387\u7C7B\u5224\u65AD\u6B64\u65F6\u5168\u90E8\u4E0D\u53EF\u4FE1\u2014\u2014\u5B83\u4EEC\u7F3A\u6570\u636E\uFF0C\u4E0D\u662F\u4E3A\u96F6\u3002`});for(let t of e?.idle??[]){let o=t.idle_seconds===void 0?void 0:l(t.idle_seconds);o!==void 0&&o<a||u.push({severity:(t.idle_cards??0)>=2?"high":"warn",kind:"idle-allocation",subject:w(t.workload),detail:`\u5360\u7740 ${t.idle_cards??"?"} \u5F20\u5361\u4F46\u95F2\u7F6E`+(o===void 0?"":` ${o} \u5C0F\u65F6`)+`\uFF08\u5224\u5B9A\u6765\u6E90\uFF1A${t.source??"\u5E73\u53F0"}\uFF09\u3002\u786E\u8BA4\u65E0\u4EBA\u4F7F\u7528\u540E\u53EF\u4EE5\u505C\u6B62\u4EE5\u91CA\u653E\u914D\u989D\u3002`})}for(let t of e?.queued??[]){let o=g(t.created_at);o===void 0||o<n*3600||u.push({severity:"warn",kind:"queued-too-long",subject:`${t.project}/${t.name}`,detail:`\u5DF2\u6392\u961F ${l(o)} \u5C0F\u65F6\uFF08${t.xpu_count??"?"} \u5361\uFF0C\u6C60 ${t.pool??"\u672A\u6307\u5B9A"}\uFF09\u3002\u5148\u770B\u9879\u76EE\u914D\u989D\uFF0C\u518D\u770B\u96C6\u7FA4\u662F\u5426\u771F\u7684\u6CA1\u6709\u7A7A\u95F2\u5361\u3002`})}for(let t of s?.items??[]){let o=`${t.project}/${t.name}`,_=t.pods_ready??0,f=t.pods_total??0,m=g(t.admitted_at??t.started_at??t.created_at);if((t.status==="admitted"||t.status==="running")&&f>0&&_<f&&m!==void 0&&m>=d*60&&u.push({severity:"high",kind:"not-ready",subject:o,detail:`\u72B6\u6001 ${t.status} \u4F46\u53EA\u6709 ${_}/${f} \u4E2A Pod \u5C31\u7EEA\uFF0C\u5360\u7740 ${t.xpu_count??"?"} \u5F20\u5361\u3002\u5148\u770B events \u4E0E logs\uFF1B\u5D29\u6E83\u5FAA\u73AF\u4F1A\u4E00\u76F4\u5360\u7740\u914D\u989D\u5374\u4E0D\u4EA7\u51FA\u7B97\u529B\u3002`}),t.status==="failed"&&u.push({severity:"warn",kind:"failed",subject:o,detail:"\u8D1F\u8F7D\u5DF2\u5931\u8D25\u3002\u786E\u8BA4\u539F\u56E0\u540E\u5220\u9664\uFF0C\u5426\u5219\u5B83\u4F1A\u4E00\u76F4\u7559\u5728\u5217\u8868\u91CC\u5E72\u6270\u5224\u65AD\u3002"}),t.phase==="terminating"||t.status==="terminating"){let p=g(t.last_activity_at??t.created_at);p!==void 0&&p>=c*3600&&u.push({severity:"warn",kind:"stuck-terminating",subject:o,detail:`\u5904\u4E8E Terminating \u5DF2 ${l(p)} \u5C0F\u65F6\u3002\u8FD9\u662F\u5DF2\u77E5\u7684\u4E0A\u6E38\u884C\u4E3A\u2014\u2014\u4E0D\u8981\u53CD\u590D\u5220\u9664\u3001\u4E0D\u8981\u7528 --force \u5FAA\u73AF\uFF0C\u7B49\u5F85\u6216\u8BA9\u8FD0\u7EF4\u4ECB\u5165\u3002`})}}let i={high:0,warn:1};return u.sort((t,o)=>(i[t.severity]??9)-(i[o.severity]??9))}import{appendFile as b,mkdir as O,open as R,rename as T,stat as j}from"node:fs/promises";import{dirname as q,join as S}from"node:path";function H(){return S(y(),"operations.jsonl")}var E=256*1024,L=5*1024*1024;async function A(e,s=E){let r;try{r=await R(e,"r")}catch{return[]}try{let{size:a}=await r.stat(),n=Math.max(0,a-s),d=a-n;if(d<=0)return[];let c=Buffer.allocUnsafe(d),{bytesRead:u}=await r.read(c,0,d,n),i=c.subarray(0,u).toString("utf8");if(n>0){let t=i.indexOf(`
|
|
2
2
|
`);i=t===-1?"":i.slice(t+1)}return i.split(`
|
|
3
3
|
`).filter(t=>t.trim()!=="")}catch{return[]}finally{await r.close().catch(()=>{})}}async function C(e,s,r=L){await O(q(e),{recursive:!0});try{let{size:a}=await j(e);a>=r&&await T(e,`${e}.1`)}catch{}await b(e,`${s}
|
|
4
4
|
`,"utf8")}async function V(e){let s=JSON.stringify({at:new Date().toISOString(),...e});try{await C(H(),s)}catch{}}async function D(e=50){let s=await A(H()),r=[];for(let a=s.length-1;a>=0&&r.length<e;a-=1)try{r.push(JSON.parse(s[a]))}catch{}return r}async function P(e,s=10*6e4){let r=Date.now()-s;return(await D(200)).find(n=>n.action==="delete"&&n.target===e&&n.outcome==="executed"&&new Date(n.at).getTime()>=r)}var M="delete|stop|start|create",x=new RegExp(String.raw`(?:^|[\s;&|(){}\`])(?:[^\s;&|(){}]*[/\\])?runnpu\s+workload\s+(${M})\b`,"gi"),v=/^[A-Za-z0-9][\w.-]*\/[\w.-]+$/,$=new RegExp(String.raw`(?:^|[\s;&|(){}\`])(?:[^\s;&|(){}]*[/\\])?runnpu\s+project\s+quota\s+set\b`,"gi"),I=[["project","project"],["name","name"],["type","type"],["from-template","template"],["image","image"],["xpu","xpu"],["nodes","nodes"],["replicas","replicas"]],U=120;function h(e){let s=e.at(0);return(s==='"'||s==="'")&&e.at(-1)===s?e.slice(1,-1):e}function B(e,s){let r=new RegExp(String.raw`--${s}(?:=|\s+)("[^"]*"|'[^']*'|[^\s;&|]+)`,"i").exec(e);if(!r)return;let a=h(r[1]).trim();return a===""?void 0:a.slice(0,U)}function k(e){let s=e.search(/[;&|\n]/),r=(s===-1?e:e.slice(0,s)).trim();if(r!=="")for(let a of r.split(/\s+/)){let n=h(a);if(v.test(n))return n}}function Y(e){if(typeof e!="string"||e==="")return{};$.lastIndex=0;let s=$.exec(e);if(s){let i=h(e.slice(s.index+s[0].length).trim().split(/\s+/)[0]??""),t=i!==""&&!i.startsWith("-")&&!i.includes("=")?i:void 0;return{deny:"\u4E0D\u8981\u5728 shell \u91CC\u6539\u914D\u989D\uFF1A\u8BF7\u6539\u7528 cluster_quota_set \u5DE5\u5177\uFF08\u53C2\u6570 project + pools/storage\uFF0C\u53EA\u5199\u8981\u53D8\u7684\u5B57\u6BB5\uFF09\u3002\u533A\u522B\u4E0D\u662F\u987A\u624B\u4E0E\u5426\u2014\u2014CLI \u7684 quota set \u662F\u6574\u4EFD\u66FF\u6362\uFF0C\u6F0F\u4E00\u4E2A\u6C60\u5C31\u6E05\u6389\u4E00\u4E2A\u6C60\uFF0C\u800C\u4E14\u6CA1\u6709\u5BA1\u6279\uFF1A\u5DE5\u5177\u4F1A\u5148\u8BFB\u5F53\u524D\u503C\u3001\u751F\u6210 diff \u9001\u8FDB harness \u5BA1\u6279\u5F39\u7A97\uFF0C\u7528\u6237\u6279\u51C6\u7684\u5C31\u662F\u968F\u540E\u6267\u884C\u7684\u90A3\u4EFD\u53D8\u66F4\uFF0C\u5E76\u4E14\u65E0\u8BBA\u6279\u4E0D\u6279\u90FD\u5199\u8FDB\u64CD\u4F5C\u65E5\u5FD7\u3002\u53EA\u8BFB\u7684 quota get \u4E0D\u53D7\u5F71\u54CD\uFF0C\u7167\u5E38\u6267\u884C\u3002",record:{action:"quota_set",outcome:"rejected",...t===void 0?{}:{target:t},error:"shell \u8DEF\u5F84\u88AB guard \u62E6\u622A\uFF0C\u672A\u6267\u884C\uFF1B\u5E94\u6539\u7528 cluster_quota_set"}}}x.lastIndex=0;let r=[...e.matchAll(x)];if(r.length===0)return{};let a=r.find(i=>i[1].toLowerCase()!=="create");if(a){let i=a[1].toLowerCase(),t=k(e.slice(a.index+a[0].length));return{deny:`\u4E0D\u8981\u5728 shell \u91CC ${i} \u8D1F\u8F7D${t?`\uFF08${t}\uFF09`:""}\uFF1A\u8BF7\u6539\u7528 cluster_workload_action \u5DE5\u5177\uFF08\u53C2\u6570 project / name / action / reason\uFF09\u3002\u533A\u522B\u4E0D\u662F\u987A\u624B\u4E0E\u5426\u2014\u2014\u5DE5\u5177\u4F1A\u628A delete \u9001\u8FDB harness \u7684\u5BA1\u6279\u5F39\u7A97\uFF0C\u7528\u6237\u6279\u51C6\u7684\u5C31\u662F\u968F\u540E\u771F\u6B63\u6267\u884C\u7684\u90A3\u4E2A\u7ED3\u6784\u5316\u52A8\u4F5C\uFF0C\u5E76\u4E14\u65E0\u8BBA\u6279\u4E0D\u6279\u90FD\u5199\u8FDB\u64CD\u4F5C\u65E5\u5FD7\uFF1Bshell \u547D\u4EE4\u4E24\u6837\u90FD\u7ED5\u8FC7\u4E86\u3002\u53EA\u8BFB\u5B50\u547D\u4EE4\uFF08list / logs / events / endpoints / get / exec \u2026\uFF09\u4E0D\u53D7\u5F71\u54CD\uFF0C\u7167\u5E38\u6267\u884C\u3002`,record:{action:i,outcome:"rejected",...t===void 0?{}:{target:t},error:"shell \u8DEF\u5F84\u88AB guard \u62E6\u622A\uFF0C\u672A\u6267\u884C\uFF1B\u5E94\u6539\u7528 cluster_workload_action"}}}let n=r[0],d=e.slice(n.index+n[0].length),c={};for(let[i,t]of I){let o=B(d,i);o!==void 0&&(c[t]=o)}let u=c.project&&c.name?`${c.project}/${c.name}`:c.name??k(d);return{record:{action:"create",outcome:"attempted",...u===void 0?{}:{target:u},...Object.keys(c).length===0?{}:{details:c}}}}export{F as a,N as b,A as c,C as d,V as e,D as f,P as g,Y as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=new Set(["type","properties","required","description"]);function a(t,e){let r=new Set(Array.isArray(e)?e:[]),o={};for(let[n,s]of Object.entries(t??{}))o[n]={...i(s),...r.has(n)?{required:!0}:{}};return o}function i(t){if(!t||typeof t!="object")return t;let{required:e,...r}=t,o={...r};return r.type==="object"&&r.properties&&typeof r.properties=="object"&&(o.properties=a(r.properties,e)),r.type==="array"&&r.items&&typeof r.items=="object"&&(o.items=i(r.items)),Array.isArray(r.oneOf)&&(o.oneOf=r.oneOf.map(n=>i(n))),o}function d(t){if(t?.type!=="object")throw new Error("tool parameters must have an object root");for(let e of Object.keys(t))if(!u.has(e))throw new Error(`dsh tool parameters cannot carry "${e}" on the root`);return a(t.properties??{},t.required)}function f(t,e){let r=e("approval");return{callId:t?.callId,cwd:t?.agent?.session?.header?.cwd,sessionId:t?.agent?.session?.id,signal:t?.signal,approve:r?o=>r.request({agent:t?.agent,toolName:o.toolName,callId:t?.callId,reason:o.reason,signal:t?.signal}):void 0}}function m(t,e){return{name:t.name,description:t.description,parameters:d(t.parameters),output:{schema:i(t.result),render:(r,o)=>t.content(r,o),...t.display?{presentationMeta:(r,o)=>t.display?.(r,o)}:{}},...t.timeoutMs===void 0?{}:{timeoutMs:t.timeoutMs},execute:(r,o)=>t.run(r,f(o,e))}}function l(t){return e=>t({name:e?.name,arguments:e?.arguments,cwd:e?.agent?.session?.header?.cwd,sessionId:e?.agent?.session?.id})}function c(t){if(!t||typeof t.name!="string"||t.name==="")throw new Error("toolSpec: name is required");let e=`toolSpec(${t.name})`;if(typeof t.description!="string")throw new Error(`${e}: description is required`);if(t.parameters?.type!=="object")throw new Error(`${e}: parameters must be a JSON Schema with an object root`);if(!t.result||typeof t.result!="object")throw new Error(`${e}: result schema is required`);if(typeof t.run!="function")throw new Error(`${e}: run is required`);if(typeof t.content!="function")throw new Error(`${e}: content is required`);if(t.display!==void 0&&typeof t.display!="function")throw new Error(`${e}: display must be a function`);if(t.timeoutMs!==void 0&&(!Number.isFinite(t.timeoutMs)||t.timeoutMs<=0))throw new Error(`${e}: timeoutMs must be a positive finite number`);return Object.freeze(t)}function w(t,e,r){let o=t?.[e];if(o==null){let n=new Error(`${r} \u672A\u6302\u8F7D\uFF1A\u5BBF\u4E3B\u6CA1\u6709\u63D0\u4F9B ${String(e)}`);throw Object.assign(n,{code:"dependency_missing",status:503}),n}return o}export{c as a,w as b,m as c,l as d};
|
package/dist/compute-node.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as E,b as G}from"./chunk-KQBXZKCA.mjs";import{b as N,e as $,f as j,g as F}from"./chunk-ZA65VWZ4.mjs";import{a as o,b as P,c as S,d as m,f as L,g as C,h as D,i as R}from"./chunk-MGSEPBNR.mjs";import{k as U}from"./chunk-GJSGPQNW.mjs";import"./chunk-JLZMOSQC.mjs";import{b as T,h as A}from"./chunk-4CZL4IT4.mjs";import"./chunk-JZXLCA2E.mjs";function I(p={}){let h=new Map;return{set(l,c){if(l){for(h.delete(l),h.set(l,c);h.size>200;){let b=h.keys().next().value;if(b===void 0)break;h.delete(b)}p.onChange?.(l,c)}},get:l=>h.get(l)??[]}}var K={apiPath:E.compute.apiPath,refreshMs:E.compute.refreshMs};function W(p,h){let l={...K,...h??{}},c=l.apiPath,b=G({refresh:()=>Promise.all([x(),B()]),intervalMs:l.refreshMs}),v=b.hub,k=I({onChange:(n,e)=>v.publish("followups",{sessionId:n,questions:e})}),i=new U,u=()=>{let n=p.runnpu;if(!n)throw Object.assign(new Error("RunNPU \u8FDE\u63A5\u5668\u672A\u6302\u8F7D"),{code:"connector_missing",status:503});return n};async function z(n){try{let e=await u().identity?.(n);return e?{operator:e}:{}}catch{return{}}}async function x(n){let e=await i.refreshAll(u(),n);return e.length>0&&v.publish("pins",e),e}async function B(n){try{let e=await u().query(void 0,"workloads",{limit:50},n);v.publish("workloads",{items:e?.items??[],at:Date.now()})}catch{}}let _=Promise.resolve(),J=()=>{_=_.then(async()=>{await i.refreshMissing(u()),v.publish("list",await i.list())}).catch(()=>{})},M=[],f=(n,e,t)=>{M.push({path:e,handler:t})};f("exact",`${c}/state`,m({async GET(n,e,t){let a=t.searchParams.get("cwd")||void 0,r=u(),[s,d,w,y]=await Promise.all([r.describe(a),r.health(a),i.list(),i.range()]);o(e,200,{connection:s,health:d,queries:r.queries,pins:w,range:y,refreshMs:l.refreshMs})}})),f("exact",`${c}/login`,m({async POST(n,e){let t=await S(n),a=String(t?.server??"").trim(),r=String(t?.email??"").trim(),s=String(t?.password??"");if(!a||!r||!s){P(e,422,"validation_failed","\u767B\u5F55\u5730\u5740\u3001\u8D26\u53F7\u3001\u5BC6\u7801\u90FD\u4E0D\u80FD\u4E3A\u7A7A");return}let d=await u().login({server:a,email:r,password:s,scope:t?.scope==="project"?"project":"global",cwd:t?.cwd||void 0}),w=await u().health(t?.cwd||void 0);v.publish("health",w),o(e,200,{stored:d.stored,identity:d.identity,health:w})}})),f("exact",`${c}/logout`,m({async POST(n,e){let a=(await S(n))?.cwd||void 0,r=u(),s=p.credentials;s&&await s.unset(T.runnpuToken),a&&await A(a,{[T.runnpuToken]:void 0});let[d,w]=await Promise.all([r.describe(a),r.health(a)]),y=d?.runnpu?.tokenSource;v.publish("health",w),o(e,200,{health:w,residual:y,reason:y?y==="env"?"\u8FDB\u7A0B\u73AF\u5883\u4ECD\u6709 RUNNPU_TOKEN\uFF0C\u672C\u6B21\u767B\u51FA\u672A\u5B8C\u5168\u751F\u6548\uFF1A\u8BE5\u53D8\u91CF\u7531\u542F\u52A8\u670D\u52A1\u7684\u8FDB\u7A0B\u6301\u6709\uFF0C\u53EA\u80FD\u5728\u5916\u90E8\u6E05\u9664\u540E\u91CD\u542F\u3002":`${y} \u5C42\u4ECD\u80FD\u89E3\u6790\u51FA RUNNPU_TOKEN\uFF0C\u672C\u6B21\u767B\u51FA\u672A\u5B8C\u5168\u751F\u6548\u3002`:void 0})}})),f("exact",`${c}/followups`,m({GET(n,e,t){let a=t.searchParams.get("sessionId")??"";o(e,200,{sessionId:a,questions:k.get(a)??[]})}})),f("exact",`${c}/query`,m({async GET(n,e,t){let a=t.searchParams.get("id");if(!a){P(e,422,"validation_failed","query id \u7F3A\u5931");return}let r={};for(let[d,w]of t.searchParams)d!=="id"&&d!=="cwd"&&(r[d]=w);let s=await u().query(t.searchParams.get("cwd")||void 0,a,r);o(e,200,{id:a,params:r,at:Date.now(),data:s})}})),f("exact",`${c}/anomalies`,m({async GET(n,e,t){let a=t.searchParams.get("cwd")||void 0,r=u(),[s,d]=await Promise.all([r.query(a,"overview",{}),r.query(a,"workloads",{limit:100})]);o(e,200,{findings:N(s,d)})}})),f("exact",`${c}/workloads`,m({async GET(n,e,t){let a=t.searchParams.get("cwd")||void 0;o(e,200,await u().query(a,"workloads",{limit:50}))}})),f("exact",`${c}/workloads/action`,m({async POST(n,e){let t=await S(n),{project:a,name:r,action:s}=t??{};if(!a||!r||!["stop","start","delete"].includes(s)){P(e,422,"validation_failed","\u9700\u8981 project\u3001name \u548C\u5408\u6CD5\u7684 action");return}let d=`${a}/${r}`,w={action:s,target:d,via:"panel",reason:t?.reason??"\u4ECE\u7B97\u529B\u9762\u677F\u64CD\u4F5C"},y=z(t?.cwd||void 0);if(s==="delete"){let g=await F(d);if(g){await $({...w,...await y,outcome:"skipped",error:`\u5DF2\u4E8E ${g.at} \u5220\u9664`}),o(e,200,{outcome:"skipped",detail:`${d} \u5DF2\u7ECF\u5220\u8FC7\u4E86\uFF08${g.at}\uFF09\u3002\u8D1F\u8F7D\u53EF\u80FD\u957F\u65F6\u95F4\u505C\u7559\u5728 Terminating\uFF0C\u8BF7\u7B49\u5F85\uFF0C\u4E0D\u8981\u53CD\u590D\u5220\u3002`});return}}try{let g=await u().act(t?.cwd||void 0,s,a,r);await $({...w,...await y,outcome:"executed"}),o(e,200,{outcome:"executed",status:g?.status})}catch(g){await $({...w,...await y,outcome:"failed",error:g.message}),P(e,g.status??500,g.code??"action_failed",g.message)}}})),f("exact",`${c}/operations`,m({async GET(n,e){o(e,200,{operations:await j(30)})}})),f("exact",`${c}/pins`,m({async GET(n,e){o(e,200,{pins:await i.list(),range:await i.range()})},async POST(n,e){let t=await S(n);if(!t?.query){P(e,422,"validation_failed","pin \u5FC5\u987B\u5E26 query");return}if(t.params!==void 0&&(typeof t.params!="object"||t.params===null||Array.isArray(t.params))){P(e,422,"validation_failed","params \u5FC5\u987B\u662F\u5BF9\u8C61");return}let{pin:a,created:r}=await i.add({title:t.title,query:String(t.query),params:t.params,series:Array.isArray(t.series)?t.series:void 0,view:t.view&&typeof t.view=="object"?t.view:void 0,workspace:t.cwd||void 0},{sessionId:t.sessionId,question:t.question,note:t.note});if(!r){o(e,200,{pin:{...a,latest:i.latestOf(a.id)},duplicate:!0});return}let s=await i.refresh(a,u());o(e,201,{pin:{...a,latest:s},duplicate:!1})},async DELETE(n,e,t){let a=t.searchParams.get("id"),r=await i.remove(a);r&&v.publish("unpinned",{id:a}),o(e,200,{id:a,removed:r})}})),f("exact",`${c}/range`,m({async POST(n,e){let t=await S(n),a=await i.setRange(String(t?.range??""),u());v.publish("list",await i.list()),o(e,200,{range:a.range})}})),f("exact",`${c}/pins/refresh`,m({async POST(n,e){o(e,200,{results:await x()})}})),f("exact",`${c}/events`,(n,e)=>{b.handler(n,e,{seed(t){i.list().then(async a=>{let r=a.map(s=>s.latest).filter(Boolean);r.length>0&&t("pins",r),r.length<a.length&&(await i.refreshMissing(u()),v.publish("list",await i.list()))}).catch(()=>{})}})});let q;return{routes:M,pins:i,followups:k,start(){q||(q=i.onChange(J),b.start())},stop(){q?.(),q=void 0,b.stop()}}}var O="runnpu-compute-node",oe=["webServer"];function ce(p,h){L(p);let l=W(C(p,{runnpu:"runnpu",credentials:"credentials"}),h);p.effect(()=>p.provide("runnpuPins",l.pins),`${O}: pin store`),p.effect(()=>p.provide("runnpuFollowups",l.followups),`${O}: follow-up store`),D(p,l.routes,O),R(p,l,O)}export{ce as apply,oe as inject,O as name};
|
package/dist/compute-tools.mjs
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import{k as
|
|
2
|
-
`);return`\u5171 ${r.total} \u884C\uFF0C\u5217\uFF1A${
|
|
3
|
-
${
|
|
4
|
-
\u2026\uFF08\u5176\u4F59 ${r.total-5} \u884C\u53EA\u5728\u754C\u9762\u4E0A\uFF0C\u4E0D\u5728\u8FD9\u91CC\uFF09`:"")}if(r.kind==="bar"){if(r.categories.length===0)return"\u6CA1\u6709\u6570\u636E";let
|
|
1
|
+
import{k as C}from"./chunk-YKASEMP3.mjs";import{a as _,b as P,c as O,d as H,e as w,g as T,h as N}from"./chunk-ZA65VWZ4.mjs";import{a as b,b as f,c as B,d as M}from"./chunk-ZVARRQYA.mjs";import{g as W}from"./chunk-MGSEPBNR.mjs";import{a as y}from"./chunk-XQPU3AJN.mjs";import{b as k,d as U,g as $}from"./chunk-GJSGPQNW.mjs";import{a as v,d as L,f as I}from"./chunk-JLZMOSQC.mjs";import{c as R}from"./chunk-4CZL4IT4.mjs";import"./chunk-JZXLCA2E.mjs";import{defineTool as se}from"@deepseek-ai/dsh-tools";import{join as X}from"node:path";function G(){return X(R(),"reports.jsonl")}var Z=1024*1024,A=r=>`${r.kind}:${r.subject}`;function j(r,p){if(!(typeof p!="number"||typeof r!="number"))return r-p}function Q(r,p,u){let l=_(r),m=P(r,p),t=new Map((u?.findings??[]).map(n=>[A(n),n])),e=new Map(m.map(n=>[A(n),n])),o=[...t.values()].filter(n=>!e.has(A(n))),s=m.filter(n=>!t.has(A(n))),d=m.filter(n=>t.has(A(n))),c=new Map((u?.projects??[]).map(n=>[n.slug,n])),i={usedCards:0,idleHeld:0},a=l.projects.map(n=>{let q=u?c.get(n.slug)??i:void 0;return{...n,usedDelta:j(n.usedCards,q?.usedCards),idleHeldDelta:j(n.idleHeld,q?.idleHeld)}}),h=a.filter(n=>u?n.usedDelta!==0||n.idleHeldDelta!==0:n.usedCards>0);return{at:new Date().toISOString(),since:u?.at,cards:{...l.cards,allocatedDelta:j(l.cards.allocated,u?.cards?.allocated),idleAllocatedDelta:j(l.cards.idleAllocated,u?.cards?.idleAllocated)},workloads:{...l.workloads,runningDelta:j(l.workloads.running,u?.workloads?.running),queuedDelta:j(l.workloads.queued,u?.workloads?.queued),failedDelta:j(l.workloads.failed,u?.workloads?.failed)},metricsAvailable:l.metricsAvailable,projects:h,allProjects:a,findings:m,changes:{appeared:s,ongoing:d,resolved:o},quiet:u!==void 0&&s.length===0&&o.length===0&&h.length===0}}async function V(){let r=await O(G(),Z);for(let p=r.length-1;p>=0;p-=1)try{return JSON.parse(r[p])}catch{}}async function z(r){let p={at:r.at,cards:r.cards,workloads:r.workloads,projects:(r.allProjects??r.projects).map(u=>({slug:u.slug,usedCards:u.usedCards,idleHeld:u.idleHeld})),findings:r.findings};try{await H(G(),JSON.stringify(p))}catch{}}var ee=4;function F(r){return{limit:200,...r.project===void 0?{}:{project:r.project},...r.status===void 0?{}:{status:r.status}}}function J(r,p){if($(p)){if(!v.includes(r.query))throw new Error(`${r.query} \u6CA1\u6709\u65F6\u95F4\u8F74\uFF0C\u753B\u4E0D\u4E86 ${p}\u3002\u8981\u4E48\u6362 view: "table" / "bar"\uFF0C\u8981\u4E48\u6362\u4E00\u4E2A\u65F6\u5E8F\u67E5\u8BE2\uFF08${v.join(" / ")}\uFF09`);if(r.query==="node.metrics"&&!r.node)throw new Error("node.metrics \u9700\u8981 `node`\uFF08\u8282\u70B9\u540D\uFF09");if(r.query==="workload.metrics"&&(!r.project||!r.name))throw new Error("workload.metrics \u9700\u8981 `project` \u4E0E `name`");return}if(!k[r.query])throw new Error(`${r.query} \u4E0D\u662F\u5217\u8868\u67E5\u8BE2\uFF0C\u505A\u4E0D\u4E86 ${p}\u3002\u53EF\u5217\u8868\u5316\u7684\u662F\uFF1A${Object.keys(k).join(" / ")}`)}function S(r){return{kind:r.view??"line",source:r.source,columns:r.columns,dimension:r.dimension,measures:r.measures,sort:r.sort,desc:r.desc,limit:r.limit}}function te(r){if(r.kind==="table"){if(r.rows.length===0)return"\u6CA1\u6709\u6570\u636E\u884C";let p=r.columns.map(l=>l.label).join(" | "),u=r.rows.slice(0,5).map(l=>l.map(m=>m.text).join(" | ")).join(`
|
|
2
|
+
`);return`\u5171 ${r.total} \u884C\uFF0C\u5217\uFF1A${p}
|
|
3
|
+
${u}`+(r.total>5?`
|
|
4
|
+
\u2026\uFF08\u5176\u4F59 ${r.total-5} \u884C\u53EA\u5728\u754C\u9762\u4E0A\uFF0C\u4E0D\u5728\u8FD9\u91CC\uFF09`:"")}if(r.kind==="bar"){if(r.categories.length===0)return"\u6CA1\u6709\u6570\u636E";let p=r.categories.slice(0,5).map((u,l)=>`${u}\uFF1A${r.series.map(m=>`${m.name} ${m.data[l]??"\u2014"}`).join("\uFF0C")}`).join("\uFF1B");return`\u6309 ${r.dimension} \u5206\u7EC4\uFF0C\u524D\u51E0\u9879\uFF1A${p}`}return`\u6700\u65B0\u503C\uFF1A${re(r.series??[])||"\u65E0\u6570\u636E"}`}function re(r){return r.map(p=>{let u=I(p);if(u===void 0)return`${p.name}\uFF1A\u65E0\u6570\u636E`;let l=Number(Number(u).toPrecision(4));return`${p.name}\uFF1A${l}${p.unit?` ${p.unit}`:""}`}).join("\uFF1B")}var oe=["delete"],D="\u5BA1\u6279\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u7834\u574F\u6027\u64CD\u4F5C\u4E00\u5F8B\u62D2\u7EDD\u6267\u884C",Y="rejected",ne=new Set(["bash","pwsh"]);async function E(r,p){try{let l=await r.runnpu?.identity?.(p);return l?{operator:l}:{}}catch{return{}}}async function ie(r,p,u){await w({...u,via:"shell",sessionId:p?.sessionId,...await E(r,p?.cwd)})}function K(r,p={}){let u=new Set(Array.isArray(p?.requireApproval)?p.requireApproval:oe),l=[],m=[];return m.push(t=>{if(!ne.has(t?.name))return;let e=(t.arguments??{}).command;if(typeof e!="string")return;let o=N(e);return o.record&&ie(r,t,o.record).catch(()=>{}),o.deny}),l.push(b({name:"cluster_chart",description:'Render a cluster query as a VIEW in the conversation \u2014 a line chart, a bar chart, or a TABLE \u2014 with a Pin button that sends it to the right column, where it keeps refreshing itself. Choose the kind by the shape of the question, not by habit: "how did it CHANGE" is a line (utilization over the day, queue depth, storage growth); "who has the MOST" is a bar (cards per project, free cards per node); "which ones, with their numbers" is a table (quota vs used per project, what is queued, node inventory). A table is a first-class answer here, not a fallback \u2014 it is the right shape for a list, and pasting the same list as prose is worse for the reader and cannot be pinned. Write your reply about what the view SHOWS (trend, outlier, what to do), not by restating its values. A metric source that is not wired up reports as unavailable, never as zero: say so rather than showing a flat line as if it meant idle.',parameters:{type:"object",properties:{title:{type:"string",description:'Human title, e.g. "\u8FD1 24 \u5C0F\u65F6 NPU \u7B97\u529B\u5229\u7528\u7387" or "\u5404\u9879\u76EE\u914D\u989D\u4E0E\u5360\u7528". Becomes the pinned card\u2019s title.'},query:{type:"string",enum:[...v,...Object.keys(k)],description:"TIME SERIES (view line/area): overview.trends = whole cluster; node.metrics = one node (needs `node`); workload.metrics = one workload (needs `project` and `name`). LISTS (view bar/table): overview = the dashboard lists (source: projects | idle | queued | nodes); projects = the project dimension (source: items | usage | storage | queues \u2014 per project PER POOL); workloads / nodes / cluster = that endpoint\u2019s own list."},view:{type:"string",enum:["line","area","bar","table"],description:"How to render it. Default line. bar and table need a LIST query; line and area need a time-series query."},source:{type:"string",description:'Which list inside the payload, for the queries that hold several. overview: projects | idle | queued | nodes. projects: items (the plain project list) | usage | storage | queues \u2014 the last three are the PROJECT DIMENSION the platform keeps nested, one row per project PER POOL: `usage` carries guaranteed vs used cards and a signed `over_guarantee` (positive = borrowing preemptible capacity, negative = paying for idle guarantee); `storage` carries limit/used/used_pct per storage pool; `queues` carries admission and its reason. Sort `usage` by over_guarantee to answer "who is over and who is wasting" in one view. workloads / nodes / cluster have exactly one list; omit it there.'},group:{type:"string",description:"line/area only. Which group to plot; the vocabulary depends on the query. overview.trends: utilization | allocation | storage | workloads. node.metrics: cpu | memory | net | disk. workload.metrics: npu_util | npu_hbm | cpu | mem | net. A group that does not exist falls back to the first one and the result says so, so guessing is cheap."},columns:{type:"array",items:{type:"string"},description:"table only. Column keys in the order you want them. Omit for a curated default per list \u2014 that default is usually right, so name columns only when the question is about something it leaves out."},dimension:{type:"string",description:'bar only. The key whose values become the bars, e.g. "slug" or "name". Defaults to the obvious identifier.'},measures:{type:"array",items:{type:"string"},description:'bar only. Numeric keys to draw as bar height, e.g. ["quota_cards","used_cards"]. At most five.'},sort:{type:"string",description:"bar/table. Sort rows by this key, descending. Sorting by the number the question is about is almost always what you want."},desc:{type:"boolean",description:"bar/table. Set false for ascending order."},limit:{type:"integer",description:"bar/table. Rows to show, default 50. A bar chart is unreadable past about 15."},node:{type:"string",description:'node.metrics: the node name, e.g. "910b1".'},project:{type:"string",description:'workload.metrics: project slug. ALSO a real server-side filter for the workloads list \u2014 pass it for "just this project\u2019s workloads" rather than fetching everything and describing a subset.'},status:{type:"string",description:'workloads list only: narrow to one status server-side, e.g. "running" / "admitted" / "failed".'},name:{type:"string",description:"workload.metrics: workload name."},range:{type:"string",enum:["1h","6h","24h","7d"],description:"line/area only. Time window for THIS chart. Default 24h. (A pinned chart follows the panel\u2019s own window instead.)"},series:{type:"array",items:{type:"string"},description:"line/area only. Series keys to narrow to. Omit for every series in the group (capped at five)."}},required:["title","query"]},result:{type:"object",additionalProperties:!1,properties:{title:{type:"string"},query:{type:"string"},kind:{type:"string"},params:{type:"object",additionalProperties:!0,properties:{}},summary:{type:"string"},note:{type:"string"},view:{type:"object",additionalProperties:!0,properties:{kind:{type:"string"}},required:["kind"]},groupsAvailable:{type:"array",items:{type:"string"}},sourcesAvailable:{type:"array",items:{type:"string"}}},required:["title","query","kind","params","summary","view","groupsAvailable","sourcesAvailable"]},content:(t,e)=>[{type:"text",text:`\u5DF2\u5728\u5BF9\u8BDD\u4E2D\u663E\u793A${e.kind==="table"?"\u8868\u683C":"\u56FE\u8868"}\u300C${e.title}\u300D\uFF0C\u7528\u6237\u5DF2\u7ECF\u770B\u5230\u4E86\uFF08\u4ED6\u4EEC\u53EF\u4EE5\u70B9\u300C\u56FA\u5B9A\u5230\u53F3\u680F\u300D\uFF09\u3002**\u4E0D\u8981\u628A\u5B83\u518D\u6284\u4E00\u904D\u5230\u56DE\u590D\u91CC** \u2014\u2014 \u4E0B\u9762\u8FD9\u51E0\u884C\u662F\u7ED9\u4F60\u5224\u65AD\u7528\u7684\uFF0C\u4E0D\u662F\u7ED9\u4F60\u8F6C\u8FF0\u7684\uFF1B\u4F60\u7684\u56DE\u590D\u5E94\u8BE5\u8BF4\u8FD9\u5F20\u89C6\u56FE\u610F\u5473\u7740\u4EC0\u4E48\u3002
|
|
5
5
|
`+e.summary+(e.note?`
|
|
6
6
|
\u6CE8\u610F\uFF1A${e.note}`:"")+(e.groupsAvailable.length>1?`
|
|
7
7
|
\u8FD9\u4E2A\u67E5\u8BE2\u8FD8\u80FD\u753B\uFF1A${e.groupsAvailable.join(" / ")}`:"")+(e.sourcesAvailable.length>1?`
|
|
8
|
-
\u8FD9\u4E2A\u67E5\u8BE2\u8FD8\u6709\u8FD9\u4E9B\u5217\u8868\uFF1A${e.sourcesAvailable.join(" / ")}`:"")}],
|
|
8
|
+
\u8FD9\u4E2A\u67E5\u8BE2\u8FD8\u6709\u8FD9\u4E9B\u5217\u8868\uFF1A${e.sourcesAvailable.join(" / ")}`:"")}],display:(t,e)=>y({card:"runnpu-chart",title:e.title,query:e.query,params:e.params,note:e.note,view:e.view,spec:{...S(t),group:t.group,series:t.series}}),timeoutMs:6e4,async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=e.cwd,d=t.view??"line";J(t,d);let c=$(d)?{range:t.range??"24h",...t.group===void 0?{}:{group:t.group},...t.node===void 0?{}:{node:t.node},...t.project===void 0?{}:{project:t.project},...t.name===void 0?{}:{name:t.name}}:F(t),i=await o.query(s,t.query,c,e.signal),a=S(t),h=U(t.query,i,a);return y({title:t.title,query:t.query,kind:h.kind,params:{...c,...h.group===void 0?{}:{group:h.group}},summary:te(h),note:h.note,view:h,groupsAvailable:$(d)?L(t.query,i):[],sourcesAvailable:$(d)?[]:(k[t.query]??[]).map(n=>n.key)})}})),l.push(b({name:"cluster_pin",description:'Pin a chart to the right column, where it refreshes itself and keeps showing current data. Pin when the user says to, or when a chart answers a question they will clearly ask again \u2014 a pinned chart is worth more than a number in the transcript. ALWAYS pass `question`: the pin records why it exists, and a chart nobody can explain three weeks later is clutter. Pinning a view that is already pinned is refused and reported, so it is safe to call. The column holds at most 16 pins; a full column REFUSES rather than evicting \u2014 list what is there with cluster_pins and let the user choose what to give up. A pin stores the QUERY and the VIEW \u2014 the time window is a live control on the panel that the user sets for all pinned charts at once, so never pin "the same chart at another range": tell them to change the range instead. Tables and bar charts pin exactly like line charts do, and a quota table that refreshes itself in the corner is usually worth more than the same numbers said once in a reply.',parameters:{type:"object",properties:{title:{type:"string",description:'Card title. Do NOT put a time window in it ("\u8FD1 1 \u5C0F\u65F6 \u2026"): the window is a live control the user changes for the whole column, so a baked-in window makes the card lie the moment they change it. Name what it shows \u2014 "NPU \u7B97\u529B\u5229\u7528\u7387", "\u5361\u5206\u914D".'},query:{type:"string",enum:[...v,...Object.keys(k)],description:"The query to replay on every refresh. Same vocabulary as cluster_chart."},view:{type:"string",enum:["line","area","bar","table"],description:"How the pinned card renders. Default line. Pass the same value you passed to cluster_chart."},source:{type:"string",description:"bar/table: which list inside the payload. overview: projects | idle | queued | nodes. projects: items | usage | storage | queues (per project per pool). Pass the same value you passed to cluster_chart."},columns:{type:"array",items:{type:"string"},description:"table: column keys, in order. Omit for the curated default."},dimension:{type:"string",description:"bar: the key whose values become the bars."},measures:{type:"array",items:{type:"string"},description:"bar: numeric keys drawn as bar height."},sort:{type:"string",description:"bar/table: sort rows by this key, descending."},desc:{type:"boolean",description:"bar/table: set false for ascending."},limit:{type:"integer",description:"bar/table: rows to show, default 50."},group:{type:"string",description:"line/area: which group to plot; vocabulary depends on the query (see cluster_chart)."},node:{type:"string",description:"node.metrics: the node name."},project:{type:"string",description:"workload.metrics: project slug. Also filters a workloads list view \u2014 pass the same value you passed to cluster_chart."},status:{type:"string",description:'workloads list view: narrow to one status, e.g. "running".'},name:{type:"string",description:"workload.metrics: workload name."},series:{type:"array",items:{type:"string"},description:"line/area: series keys to narrow to."},question:{type:"string",description:"What the user was asking when this chart mattered. Shown under the card as its provenance."},note:{type:"string",description:"Anything else worth remembering about this chart \u2014 caveats, the reading you gave."}},required:["title","query","question"]},result:{type:"object",additionalProperties:!1,properties:{id:{type:"string"},title:{type:"string"},refreshed:{type:"boolean"},duplicate:{type:"boolean"},error:{type:"string"}},required:["id","title","refreshed","duplicate"]},content:(t,e)=>[{type:"text",text:e.duplicate?`\u53F3\u680F\u5DF2\u7ECF\u6709\u540C\u6837\u7684\u89C6\u56FE\u4E86\uFF08\u300C${e.title}\u300D\uFF09\uFF0C\u6CA1\u6709\u91CD\u590D\u56FA\u5B9A\u3002\u6362\u5206\u7EC4\u3001\u6362\u89C6\u56FE\u7C7B\u578B\u90FD\u662F\u53E6\u4E00\u5F20\u5361\uFF1B\u6362\u65F6\u95F4\u8303\u56F4\u4E0D\u7528\u91CD\u65B0\u56FA\u5B9A\u2014\u2014\u53F3\u680F\u9876\u90E8\u6709\u65F6\u95F4\u8303\u56F4\u9009\u62E9\u5668\uFF0C\u7528\u6237\u81EA\u5DF1\u9009\uFF0C\u6240\u6709\u56FA\u5B9A\u56FE\u8868\u4E00\u8D77\u8DDF\u7740\u53D8\u3002`:e.refreshed?`\u5DF2\u56FA\u5B9A\u5230\u53F3\u680F\uFF1A\u300C${e.title}\u300D\uFF0C\u4E4B\u540E\u4F1A\u81EA\u52A8\u5237\u65B0\u4E3A\u6700\u65B0\u6570\u636E\u3002`:`\u5DF2\u56FA\u5B9A\u300C${e.title}\u300D\uFF0C\u4F46\u9996\u6B21\u53D6\u6570\u5931\u8D25\uFF1A${e.error}`}],async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=f(r,"pins","\u56FE\u8868\u56FA\u5B9A\u533A");J(t,t.view??"line");let d;try{d=await s.add({title:t.title,query:t.query,params:$(t.view)?{...t.group===void 0?{}:{group:t.group},...t.node===void 0?{}:{node:t.node},...t.project===void 0?{}:{project:t.project},...t.name===void 0?{}:{name:t.name}}:F(t),series:t.series,view:S(t),workspace:e.cwd},{sessionId:e.sessionId,question:t.question,note:t.note})}catch(h){throw h.code==="pin_limit"?new Error(`${h.message}\u3002\u7528 cluster_pins \u5217\u51FA\u73B0\u6709\u56FE\u8868\uFF0C\u95EE\u7528\u6237\u60F3\u8BA9\u51FA\u54EA\u4E00\u5F20\uFF0C\u7ECF\u4ED6\u4EEC\u540C\u610F\u540E cluster_unpin\uFF0C\u518D\u91CD\u65B0\u56FA\u5B9A\u3002\u4E0D\u8981\u81EA\u4F5C\u4E3B\u5F20\u79FB\u9664\u3002`):h}let{pin:c,created:i}=d;if(!i)return y({id:c.id,title:c.title,refreshed:!0,duplicate:!0});let a=await s.refresh(c,o,e.signal);return y({id:c.id,title:c.title,refreshed:!!a.ok,duplicate:!1,error:a.ok?void 0:a.error})}})),l.push(b({name:"cluster_pins",description:`List what is currently pinned in the right column, with each pin's query and the question it came from. Read it before pinning something new, and when the user refers to "that chart" without saying which.`,parameters:{type:"object",properties:{}},result:{type:"object",additionalProperties:!1,properties:{range:{type:"string"},pins:{type:"array",items:{type:"object",additionalProperties:!1,properties:{id:{type:"string"},title:{type:"string"},query:{type:"string"},group:{type:"string"},question:{type:"string"},createdAt:{type:"string"},healthy:{type:"boolean"}},required:["id","title","query","healthy"]}}},required:["range","pins"]},content:(t,e)=>[{type:"text",text:e.pins.length===0?"\u53F3\u680F\u8FD8\u6CA1\u6709\u56FA\u5B9A\u4EFB\u4F55\u56FE\u8868\u3002":`\u53F3\u680F\u56FA\u5B9A\u4E86 ${e.pins.length} \u5F20\u56FE\u8868\uFF0C\u5F53\u524D\u65F6\u95F4\u8303\u56F4 ${e.range}\uFF1A
|
|
9
9
|
`+e.pins.map(o=>`- ${o.title}\uFF08${o.query} / ${o.group??"\u9ED8\u8BA4\u5206\u7EC4"}\uFF09${o.healthy?"":"\uFF08\u6700\u8FD1\u4E00\u6B21\u5237\u65B0\u5931\u8D25\uFF09"}`).join(`
|
|
10
|
-
`)}]
|
|
11
|
-
`),
|
|
10
|
+
`)}],async run(){let t=f(r,"pins","\u56FE\u8868\u56FA\u5B9A\u533A"),e=await t.list();return y({range:await t.range(),pins:e.map(o=>({id:o.id,title:o.title,query:o.query,group:o.params?.group,question:o.provenance?.question,createdAt:o.provenance?.createdAt,healthy:o.latest===void 0?!0:!!o.latest.ok}))})}})),l.push(b({name:"cluster_usage",description:`Who is holding the cards: headline capacity, per-project attribution (quota vs held vs actually running), and the platform's own list of idle allocations. Use this for "\u914D\u989D\u7528\u4E86\u591A\u5C11 / \u8C01\u5360\u4E86\u6700\u591A\u7684\u5361 / \u6709\u6CA1\u6709\u95F2\u7F6E" instead of assembling it from several CLI calls \u2014 the numbers are computed here, not by you, so they do not need checking. The gap between a project's held cards and its running cards is what starts most reclamation conversations. Quota is in CARDS; a null metric means the source is not wired up, not zero.`,parameters:{type:"object",properties:{}},result:{type:"object",additionalProperties:!0,properties:{}},content:(t,e)=>{let o=e.projects.slice(0,6).map(d=>`- ${d.slug}\uFF1A\u6301\u6709 ${d.usedCards} / \u914D\u989D ${d.quotaCards} \u5361\uFF0C\u8FD0\u884C ${d.running}${d.queued?`\uFF0C\u6392\u961F ${d.queued}`:""}${d.idleHeld?`\uFF0C\u5176\u4E2D ${d.idleHeld} \u5F20\u672A\u5728\u8DD1`:""}`).join(`
|
|
11
|
+
`),s=e.idle.slice(0,6).map(d=>`- ${d.workload}\uFF1A${d.idleCards} \u5361\u95F2\u7F6E${d.idleHours===void 0?"":` ${d.idleHours} \u5C0F\u65F6`}`).join(`
|
|
12
12
|
`);return[{type:"text",text:`\u5361\uFF1A${e.cards.allocated}/${e.cards.total} \u5DF2\u5206\u914D\uFF0C${e.cards.available} \u7A7A\u95F2\uFF0C\u5176\u4E2D ${e.cards.idleAllocated} \u5F20\u5DF2\u5206\u914D\u4F46\u95F2\u7F6E\u3002
|
|
13
13
|
\u8D1F\u8F7D\uFF1A\u8FD0\u884C ${e.workloads.running}\uFF0C\u6392\u961F ${e.workloads.queued}\uFF0C\u5931\u8D25 ${e.workloads.failed}\u3002
|
|
14
14
|
\u8282\u70B9\uFF1A${e.nodes.ready}/${e.nodes.total} \u5C31\u7EEA\u3002
|
|
15
15
|
|
|
16
16
|
\u6309\u9879\u76EE\uFF1A
|
|
17
|
-
${o}`+(
|
|
17
|
+
${o}`+(s?`
|
|
18
18
|
|
|
19
19
|
\u95F2\u7F6E\u5360\u7528\uFF1A
|
|
20
|
-
${
|
|
20
|
+
${s}`:"")+(e.metricsAvailable?"":`
|
|
21
21
|
|
|
22
|
-
\u6CE8\u610F\uFF1A\u6307\u6807\u6E90\u672A\u63A5\u5165\uFF0C\u5229\u7528\u7387\u7C7B\u5224\u65AD\u6B64\u65F6\u4E0D\u53EF\u4FE1\u3002`)}]}
|
|
22
|
+
\u6CE8\u610F\uFF1A\u6307\u6807\u6E90\u672A\u63A5\u5165\uFF0C\u5229\u7528\u7387\u7C7B\u5224\u65AD\u6B64\u65F6\u4E0D\u53EF\u4FE1\u3002`)}]},async run(t,e){let s=await f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668").query(e.cwd,"overview",{},e.signal);return y(_(s))}})),l.push(b({name:"cluster_anomalies",description:'Everything that looks wrong right now, by deterministic rules: idle allocations, workloads queued too long, admitted-but-not-ready (how a crash loop looks from here), failed workloads, and anything stuck terminating. Call it when the user asks what is wrong, and at the start of any "\u96C6\u7FA4\u600E\u4E48\u6837" answer \u2014 it is cheap and it catches the things nobody thinks to ask about. Each finding carries the evidence it fired on, so say what the evidence is rather than just repeating the verdict.',parameters:{type:"object",properties:{idleHours:{type:"number",description:"How long an allocation must be idle to report it. Default 2."},queuedHours:{type:"number",description:"How long a workload must wait to report it. Default 1."},notReadyMinutes:{type:"number",description:"Grace period after admission before an admitted-but-not-ready workload counts as a crash loop. Default 5. Lower it only when hunting a suspected crash loop \u2014 pulling an image and starting a container legitimately takes minutes, so a small value reports every normal launch."},terminatingHours:{type:"number",description:"How long a workload must sit in Terminating before it counts as stuck. Default 0.5. Anything shorter is the ordinary delete path still finishing, not a problem."}}},result:{type:"object",additionalProperties:!0,properties:{}},content:(t,e)=>[{type:"text",text:e.findings.length===0?"\u6309\u5F53\u524D\u89C4\u5219\u6CA1\u6709\u53D1\u73B0\u5F02\u5E38\u3002":`\u53D1\u73B0 ${e.findings.length} \u9879\uFF1A
|
|
23
23
|
`+e.findings.map(o=>`- [${o.severity==="high"?"\u91CD\u8981":"\u6CE8\u610F"}] ${o.subject}\uFF1A${o.detail}`).join(`
|
|
24
|
-
`)}]
|
|
24
|
+
`)}],async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=e.cwd,[d,c]=await Promise.all([o.query(s,"overview",{},e.signal),o.query(s,"workloads",{limit:100},e.signal)]);return y({findings:P(d,c,{idleHours:t.idleHours,queuedHours:t.queuedHours,notReadyMinutes:t.notReadyMinutes,terminatingHours:t.terminatingHours})})}})),l.push(b({name:"cluster_workload_action",description:'Stop, start, or delete one workload. This is the ONLY way you should perform these actions \u2014 not `runnpu workload stop/start/delete` through the shell. The difference is not convenience: every call is written to the operation log whether it went ahead or not, which is what later answers "who stopped this and why", and a delete additionally asks the user through an approval prompt so what they approve is the exact structured action that then runs. A shell command asks in prose and executes something the user never saw. Explain what you are about to do BEFORE calling, in your own words, including which workload and why \u2014 stop and start go ahead without a prompt, so your sentence is the only warning the user gets.',parameters:{type:"object",properties:{project:{type:"string",description:"Project slug owning the workload."},name:{type:"string",description:"Workload name."},action:{type:"string",enum:["stop","start","delete"],description:"stop suspends it and frees its cards; start resumes a stopped one; delete removes it permanently. Prefer stop when the user only wants the cards back."},reason:{type:"string",description:"Why this is being done, in one line. Shown in the approval prompt and kept in the operation log."}},required:["project","name","action","reason"]},result:{type:"object",additionalProperties:!1,properties:{target:{type:"string"},action:{type:"string"},outcome:{type:"string",enum:["executed","rejected","failed","skipped"]},detail:{type:"string"},status:{type:"string"}},required:["target","action","outcome"]},content:(t,e)=>[{type:"text",text:e.outcome==="executed"?`\u5DF2\u5BF9 ${e.target} \u6267\u884C ${e.action}${e.status?`\uFF0C\u5F53\u524D\u72B6\u6001 ${e.status}`:""}\u3002`:e.outcome==="rejected"?e.detail===Y?`\u7528\u6237\u6CA1\u6709\u6279\u51C6\u5BF9 ${e.target} \u7684 ${e.action}\uFF0C\u672A\u6267\u884C\u3002\u4E0D\u8981\u6362\u4E2A\u8BF4\u6CD5\u518D\u95EE\u4E00\u6B21\u3002`:e.detail===D?`\u6CA1\u6709\u5BF9 ${e.target} \u6267\u884C ${e.action}\uFF1A\u5BA1\u6279\u901A\u9053\u4E0D\u53EF\u7528\uFF08\u5BA1\u6279\u670D\u52A1\u672A\u6302\u8F7D\uFF09\uFF0C\u7834\u574F\u6027\u64CD\u4F5C\u6309\u62D2\u7EDD\u5904\u7406\u3002**\u8FD9\u4E0D\u662F\u7528\u6237\u7684\u62D2\u7EDD** \u2014\u2014 \u4ED6\u4EEC\u6839\u672C\u6CA1\u6709\u6536\u5230\u8FC7\u5F39\u7A97\uFF0C\u4E0D\u8981\u5411\u4ED6\u4EEC\u590D\u8FF0\u4E00\u4E2A\u6CA1\u53D1\u751F\u8FC7\u7684\u5426\u51B3\u3002\u5982\u5B9E\u8BF4\u660E\u662F\u8FD0\u884C\u73AF\u5883\u6CA1\u6709\u63A5\u4E0A\u5BA1\u6279\u901A\u9053\uFF0C\u8BF7\u4ED6\u4EEC\u68C0\u67E5\u6240\u7528\u5BBF\u4E3B\uFF08dsh \u6216 RunNPU \u754C\u9762\uFF09\u7684\u5B89\u88C5\u4E0E\u914D\u7F6E\u540E\u91CD\u542F\u3002`:`\u6CA1\u6709\u5BF9 ${e.target} \u6267\u884C ${e.action}\uFF1A\u5BA1\u6279\u8BF7\u6C42\u6CA1\u6709\u62FF\u5230\u653E\u884C\u7ED3\u679C\uFF08${e.detail}\uFF09\uFF0C\u6309\u62D2\u7EDD\u5904\u7406\u3002**\u8FD9\u4E0D\u662F\u7528\u6237\u70B9\u4E86\u62D2\u7EDD** \u2014\u2014 \u8BF7\u6C42\u53EF\u80FD\u88AB\u53D6\u6D88\u3001\u4E2D\u65AD\uFF0C\u6216\u5BA1\u6279\u901A\u9053\u5F53\u65F6\u4E0D\u53EF\u7528\u3002\u5982\u5B9E\u8BF4\u660E\u53D1\u751F\u4E86\u4EC0\u4E48\u518D\u8BA9\u7528\u6237\u51B3\u5B9A\u8981\u4E0D\u8981\u91CD\u6765\uFF0C\u4E0D\u8981\u6362\u4E2A\u8BF4\u6CD5\u628A\u540C\u4E00\u4E2A\u64CD\u4F5C\u518D\u63D0\u4E00\u6B21\u3002`:e.outcome==="skipped"?`\u672A\u6267\u884C\uFF1A${e.detail}`:`\u5BF9 ${e.target} \u6267\u884C ${e.action} \u5931\u8D25\uFF1A${e.detail}`}],timeoutMs:12e4,async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=`${t.project}/${t.name}`,d=e.sessionId,c={action:t.action,target:s,via:"agent",sessionId:d,reason:t.reason},i=E(r,e.cwd);if(t.action==="delete"){let a=await T(s);if(a){let h=`${s} \u5728 ${a.at} \u5DF2\u7ECF\u5220\u8FC7\u4E86\u3002\u5220\u9664\u662F\u5E42\u7B49\u7684\uFF0C\u518D\u5220\u4E00\u6B21\u540C\u6837\u8FD4\u56DE\u6210\u529F\u4F46\u4EC0\u4E48\u90FD\u4E0D\u4F1A\u53D1\u751F\uFF1B\u8D1F\u8F7D\u53EF\u80FD\u505C\u7559\u5728 Terminating \u6570\u5206\u949F\u4E43\u81F3\u66F4\u4E45\uFF08\u4E0A\u6E38\u5DF2\u77E5\u95EE\u9898\uFF09\u3002\u7B49\u5F85\u6216\u8BA9\u8FD0\u7EF4\u4ECB\u5165\uFF0C\u4E0D\u8981\u53CD\u590D\u5220\u3002`;return await w({...c,...await i,outcome:"skipped",error:h}),y({target:s,action:t.action,outcome:"skipped",detail:h})}}if(u.has(t.action)){if(!e.approve){let h=D;return await w({...c,...await i,outcome:"rejected",error:h}),y({target:s,action:t.action,outcome:"rejected",detail:h})}let a=await e.approve({toolName:"cluster_workload_action",reason:`${t.action} ${s}\uFF1A${t.reason}`});if(a!=="allowed-once")return await w({...c,...await i,outcome:"rejected",error:a}),y({target:s,action:t.action,outcome:"rejected",detail:a})}try{let a=await o.act(e.cwd,t.action,t.project,t.name,e.signal);return await w({...c,...await i,outcome:"executed"}),y({target:s,action:t.action,outcome:"executed",status:typeof a?.status=="string"?a.status:void 0})}catch(a){return await w({...c,...await i,outcome:"failed",error:a.message}),y({target:s,action:t.action,outcome:"failed",detail:a.message})}}})),l.push(b({name:"cluster_quota_set",description:'Change a project\'s quota: guaranteed / borrowable cards per compute pool, and the size cap per storage pool. Use this instead of `runnpu project quota set`, which REPLACES the whole quota block \u2014 with the CLI, changing one pool means reading the quota, retyping every other pool by hand, and living with whatever a slip drops; a pool left out is a pool set to nothing. This tool reads the current quota, applies only the fields you name, and leaves everything else exactly as it was, in one write. Name ONLY what changes. What the user approves is a DIFF ("\u4FDD\u5E95 2 \u2192 4 \u5361"), so say the same diff in your own words before you call \u2014 agreeing to a change is only possible if the change is what was shown. Quota is in CARDS. Removing a pool is not offered on purpose: to take capacity away, keep the pool and set its numbers to 0 (the platform refuses a quota that empties the pools while the cluster still holds a QuotaGrant, because deleting that object fails every new workload in the project). Editing quota needs the system-level `projects:quota` permission \u2014 a 403 here is a permission fact to report, not something to retry.',parameters:{type:"object",properties:{project:{type:"string",description:'Project slug, e.g. "main". The same identifier used everywhere else in this mode.'},pools:{type:"array",description:"Compute pools to change, one entry per pool, and ONLY the pools that change \u2014 every pool you leave out keeps its current numbers. A pool name that does not exist in the quota yet is ADDED. Pool names come from `cluster_chart` (query `projects`, source `usage`) or `runnpu cluster get`.",items:{type:"object",additionalProperties:!1,properties:{pool:{type:"string",description:'Accelerator pool name, e.g. "ascend910b4".'},guaranteed:{type:"integer",description:"Guaranteed cards (Kueue nominalQuota): capacity this project always gets. Omit to leave unchanged."},limit:{type:"integer",description:"Extra cards this project may BORROW on top of the guarantee (Kueue borrowingLimit \u2014 an increment, not a total). Borrowed capacity is preemptible. 0 means no borrowing."},lending_limit:{type:"integer",description:"Cap on how much of the guarantee may be lent OUT to other projects. Omit to leave unchanged."}},required:["pool"]}},storage:{type:"array",description:"Storage pools to change. Same rule: only what changes, everything else survives untouched.",items:{type:"object",additionalProperties:!1,properties:{pool:{type:"string",description:'Storage pool name, e.g. "shared-cephfs".'},limit_gib:{type:"integer",description:"Size cap in GiB. 0 means nothing is allocated from this pool."},alert_pct:{type:"integer",description:"Usage percentage that raises an alert. Platform default is 80."}},required:["pool"]}},reason:{type:"string",description:"Why, in one line. Shown in the approval prompt beside the diff and kept in the operation log."}},required:["project","reason"]},result:{type:"object",additionalProperties:!1,properties:{project:{type:"string"},outcome:{type:"string",enum:["executed","rejected","failed","skipped"]},changes:{type:"array",items:{type:"string"}},detail:{type:"string"}},required:["project","outcome","changes"]},content:(t,e)=>[{type:"text",text:e.outcome==="executed"?`\u5DF2\u66F4\u65B0 ${e.project} \u7684\u914D\u989D\uFF1A
|
|
25
25
|
${e.changes.map(o=>`- ${o}`).join(`
|
|
26
|
-
`)}`:e.outcome==="skipped"?`\u6CA1\u6709\u6539\u52A8\uFF1A${e.detail}`:e.outcome==="rejected"?e.detail===
|
|
27
|
-
\uFF08\u914D\u989D\u662F\u6574\u4F53\u5199\u5165\u7684\uFF1A\u8FD9\u6B21\u8981\u4E48\u5168\u90E8\u751F\u6548\u3001\u8981\u4E48\u5168\u90FD\u6CA1\u751F\u6548\uFF0C\u4E0D\u4F1A\u53EA\u6539\u4E86\u4E00\u534A\u3002\u5982\u679C\u5E73\u53F0\u8BF4 DB \u5DF2\u66F4\u65B0\u800C\u96C6\u7FA4\u672A\u66F4\u65B0\uFF0C\u90A3\u662F\u7269\u5316\u88AB\u62E6\u4E0B\uFF0C\u9700\u8981\u8FD0\u7EF4\u4ECB\u5165\u3002\uFF09`}]
|
|
26
|
+
`)}`:e.outcome==="skipped"?`\u6CA1\u6709\u6539\u52A8\uFF1A${e.detail}`:e.outcome==="rejected"?e.detail===Y?`\u7528\u6237\u6CA1\u6709\u6279\u51C6\u8FD9\u6B21 ${e.project} \u7684\u914D\u989D\u4FEE\u6539\uFF0C\u672A\u6267\u884C\u3002\u4E0D\u8981\u6362\u4E2A\u8BF4\u6CD5\u518D\u95EE\u4E00\u6B21\u3002`:e.detail===D?`\u6CA1\u6709\u4FEE\u6539 ${e.project} \u7684\u914D\u989D\uFF1A\u5BA1\u6279\u901A\u9053\u4E0D\u53EF\u7528\uFF08\u5BA1\u6279\u670D\u52A1\u672A\u6302\u8F7D\uFF09\uFF0C\u6309\u62D2\u7EDD\u5904\u7406\u3002**\u8FD9\u4E0D\u662F\u7528\u6237\u7684\u62D2\u7EDD** \u2014\u2014 \u4ED6\u4EEC\u6839\u672C\u6CA1\u6709\u6536\u5230\u8FC7\u5F39\u7A97\u3002\u5982\u5B9E\u8BF4\u660E\u662F\u8FD0\u884C\u73AF\u5883\u6CA1\u6709\u63A5\u4E0A\u5BA1\u6279\u901A\u9053\uFF0C\u8BF7\u4ED6\u4EEC\u68C0\u67E5\u6240\u7528\u5BBF\u4E3B\uFF08dsh \u6216 RunNPU \u754C\u9762\uFF09\u7684\u5B89\u88C5\u4E0E\u914D\u7F6E\u540E\u91CD\u542F\u3002`:`\u6CA1\u6709\u4FEE\u6539 ${e.project} \u7684\u914D\u989D\uFF1A\u5BA1\u6279\u8BF7\u6C42\u6CA1\u6709\u62FF\u5230\u653E\u884C\u7ED3\u679C\uFF08${e.detail}\uFF09\uFF0C\u6309\u62D2\u7EDD\u5904\u7406\u3002**\u8FD9\u4E0D\u662F\u7528\u6237\u70B9\u4E86\u62D2\u7EDD** \u2014\u2014 \u8BF7\u6C42\u53EF\u80FD\u88AB\u53D6\u6D88\u3001\u4E2D\u65AD\uFF0C\u6216\u5BA1\u6279\u901A\u9053\u5F53\u65F6\u4E0D\u53EF\u7528\u3002\u5982\u5B9E\u8BF4\u660E\u53D1\u751F\u4E86\u4EC0\u4E48\u518D\u8BA9\u7528\u6237\u51B3\u5B9A\u8981\u4E0D\u8981\u91CD\u6765\u3002`:`\u4FEE\u6539 ${e.project} \u7684\u914D\u989D\u5931\u8D25\uFF1A${e.detail}
|
|
27
|
+
\uFF08\u914D\u989D\u662F\u6574\u4F53\u5199\u5165\u7684\uFF1A\u8FD9\u6B21\u8981\u4E48\u5168\u90E8\u751F\u6548\u3001\u8981\u4E48\u5168\u90FD\u6CA1\u751F\u6548\uFF0C\u4E0D\u4F1A\u53EA\u6539\u4E86\u4E00\u534A\u3002\u5982\u679C\u5E73\u53F0\u8BF4 DB \u5DF2\u66F4\u65B0\u800C\u96C6\u7FA4\u672A\u66F4\u65B0\uFF0C\u90A3\u662F\u7269\u5316\u88AB\u62E6\u4E0B\uFF0C\u9700\u8981\u8FD0\u7EF4\u4ECB\u5165\u3002\uFF09`}],timeoutMs:12e4,async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=e.cwd,d=e.sessionId,c=E(r,s),i={action:"quota_set",target:t.project,via:"agent",sessionId:d,reason:t.reason};if((t.pools?.length??0)===0&&(t.storage?.length??0)===0)throw new Error("\u81F3\u5C11\u8981\u7ED9\u51FA\u4E00\u4E2A\u8981\u6539\u7684\u6C60\uFF1Apools\uFF08\u7B97\u529B\u6C60\uFF09\u6216 storage\uFF08\u5B58\u50A8\u6C60\uFF09");let a=await o.projectBySlug(s,t.project,e.signal),{next:h,lines:n}=C(a.quota,{pools:t.pools,storage:t.storage});if(n.length===0){let g=`${t.project} \u7684\u914D\u989D\u5DF2\u7ECF\u662F\u8FD9\u4E9B\u503C\u4E86\uFF0C\u6CA1\u6709\u53EF\u5199\u7684\u6539\u52A8\u3002`;return await w({...i,...await c,outcome:"skipped",error:g}),y({project:t.project,outcome:"skipped",changes:[],detail:g})}if(!e.approve){let g=D;return await w({...i,...await c,outcome:"rejected",error:g}),y({project:t.project,outcome:"rejected",changes:n,detail:g})}let q=await e.approve({toolName:"cluster_quota_set",reason:`\u4FEE\u6539 ${t.project} \u7684\u914D\u989D\uFF1A${n.join("\uFF1B")}\uFF08${t.reason}\uFF09`});if(q!=="allowed-once")return await w({...i,...await c,outcome:"rejected",error:q}),y({project:t.project,outcome:"rejected",changes:n,detail:q});try{return await o.setQuota(s,a.id,h,e.signal),await w({...i,...await c,outcome:"executed",details:{changes:n.join("\uFF1B")}}),y({project:t.project,outcome:"executed",changes:n})}catch(g){let x=g.code==="foreign_instance"?`${g.message}\uFF08\u96C6\u7FA4\u91CC\u7684 QuotaGrant / \u547D\u540D\u7A7A\u95F4\u5E26\u7740\u53E6\u4E00\u4E2A\u63A7\u5236\u9762\u677F\u5B9E\u4F8B\u7684\u6807\u8BB0\uFF0C\u672C\u5B9E\u4F8B\u4E0D\u5199\u4E5F\u4E0D\u5220\u3002\u8FD9\u9700\u8981\u8FD0\u7EF4\u5728\u5E73\u53F0\u4FA7\u5904\u7406\u5F52\u5C5E\uFF0C\u4E0D\u8981\u91CD\u8BD5\u3002\uFF09`:g.code==="empty_quota_grant_exists"?`${g.message}\uFF08\u8FD9\u6B21\u6539\u52A8\u628A\u7B97\u529B\u6C60\u6E05\u7A7A\u4E86\uFF0C\u800C\u96C6\u7FA4\u91CC\u5DF2\u7ECF\u6709 QuotaGrant\u3002\u5E73\u53F0\u4E0D\u4F1A\u9690\u5F0F\u5220\u9664\u5B83\u2014\u2014\u5220\u6389\u4F1A\u8BA9\u8BE5\u9879\u76EE\u5185\u6240\u6709\u65B0\u8D1F\u8F7D\u62A5 QuotaGrantNotFound\u3002\u8981\u64A4\u9500\u7B97\u529B\uFF0C\u8BF7\u4FDD\u7559\u6C60\u5E76\u628A\u4FDD\u5E95/\u4E0A\u9650\u8C03\u5230 0\uFF1B\u8981\u8FDE\u5BF9\u8C61\u4E00\u8D77\u6E05\u6389\uFF0C\u53EA\u80FD\u5220\u9664\u9879\u76EE\u3002\uFF09`:g.status===403?`${g.message}\uFF08\u4FEE\u6539\u914D\u989D\u9700\u8981\u7CFB\u7EDF\u7EA7 projects:quota \u6743\u9650\uFF0C\u5F53\u524D\u8EAB\u4EFD\u6CA1\u6709\u3002\u9879\u76EE\u7EA7 projects:update \u53EA\u591F\u6539\u540D\u5B57\u548C\u63CF\u8FF0\u3002\u8BF7\u8BA9\u5E73\u53F0\u7BA1\u7406\u5458\u64CD\u4F5C\uFF0C\u6216\u5148\u6388\u4E88\u6743\u9650\u3002\uFF09`:g.message;return await w({...i,...await c,outcome:"failed",error:x}),y({project:t.project,outcome:"failed",changes:n,detail:x})}}})),l.push(b({name:"cluster_report",description:'Produce the periodic cluster report: what CHANGED since the last report. This is not a status snapshot \u2014 `cluster_usage` and `cluster_anomalies` answer "how are things now". A report answers "what moved", which is the only thing worth delivering on a schedule: a digest that repeats the same three findings every morning gets skipped, including the morning a fourth one appears. Calling this ADVANCES the baseline, so the next report diffs against this moment; pass preview to look without consuming the delta. Lead your summary with what appeared and what resolved, and say plainly when nothing moved \u2014 `quiet` is a real and useful outcome, and one line is the right length for it.',parameters:{type:"object",properties:{preview:{type:"boolean",description:"Compute the report without saving it as the new baseline. Use when trying the report out, so the first real one still has a delta to show."}}},result:{type:"object",additionalProperties:!1,properties:{at:{type:"string"},since:{type:"string"},quiet:{type:"boolean"},saved:{type:"boolean"},metricsAvailable:{type:"boolean"},cards:{type:"object",additionalProperties:!1,properties:{total:{type:"integer"},allocated:{type:"integer"},available:{type:"integer"},idleAllocated:{type:"integer"},allocatedDelta:{type:"integer"},idleAllocatedDelta:{type:"integer"}},required:["total","allocated","available","idleAllocated"]},workloads:{type:"object",additionalProperties:!1,properties:{running:{type:"integer"},queued:{type:"integer"},failed:{type:"integer"},runningDelta:{type:"integer"},queuedDelta:{type:"integer"},failedDelta:{type:"integer"}},required:["running","queued","failed"]},appeared:{type:"array",items:{type:"object",additionalProperties:!1,properties:{severity:{type:"string"},kind:{type:"string"},subject:{type:"string"},detail:{type:"string"}},required:["severity","kind","subject","detail"]}},resolved:{type:"array",items:{type:"object",additionalProperties:!1,properties:{severity:{type:"string"},kind:{type:"string"},subject:{type:"string"},detail:{type:"string"}},required:["severity","kind","subject","detail"]}},ongoing:{type:"array",items:{type:"object",additionalProperties:!1,properties:{severity:{type:"string"},kind:{type:"string"},subject:{type:"string"},detail:{type:"string"}},required:["severity","kind","subject","detail"]}},projects:{type:"array",items:{type:"object",additionalProperties:!1,properties:{slug:{type:"string"},quotaCards:{type:"integer"},usedCards:{type:"integer"},running:{type:"integer"},idleHeld:{type:"integer"},usedDelta:{type:"integer"},idleHeldDelta:{type:"integer"}},required:["slug","quotaCards","usedCards","running","idleHeld"]}}},required:["at","quiet","saved","metricsAvailable","cards","workloads","appeared","resolved","ongoing","projects"]},content:(t,e)=>{let o=i=>i===void 0?"":i===0?"\uFF08\u6301\u5E73\uFF09":i>0?`\uFF08+${i}\uFF09`:`\uFF08${i}\uFF09`,s=(i,a)=>a.length===0?"":`
|
|
28
28
|
|
|
29
|
-
${
|
|
30
|
-
${a.map(
|
|
31
|
-
`)}`,
|
|
32
|
-
`);return[{type:"text",text:`${
|
|
29
|
+
${i}
|
|
30
|
+
${a.map(h=>`- ${h.subject}\uFF1A${h.detail}`).join(`
|
|
31
|
+
`)}`,d=e.since?`\u81EA ${e.since} \u4EE5\u6765`:"\u9996\u6B21\u62A5\u544A\uFF08\u5C1A\u65E0\u5BF9\u6BD4\u57FA\u7EBF\uFF09";if(e.quiet)return[{type:"text",text:`${d}\uFF1A\u65E0\u53D8\u5316\u3002\u5361 ${e.cards.allocated}/${e.cards.total} \u5DF2\u5206\u914D\uFF0C\u5176\u4E2D ${e.cards.idleAllocated} \u5F20\u95F2\u7F6E\uFF1B\u8D1F\u8F7D \u8FD0\u884C ${e.workloads.running}\u3001\u6392\u961F ${e.workloads.queued}\u3001\u5931\u8D25 ${e.workloads.failed}\u3002${e.ongoing.length} \u9879\u5F02\u5E38\u4ECD\u5728\u3002`}];let c=e.projects.slice(0,6).map(i=>`- ${i.slug}\uFF1A\u6301\u6709 ${i.usedCards}/${i.quotaCards} \u5361${o(i.usedDelta)}\uFF0C\u5176\u4E2D ${i.idleHeld} \u5F20\u672A\u5728\u8DD1${o(i.idleHeldDelta)}`).join(`
|
|
32
|
+
`);return[{type:"text",text:`${d}
|
|
33
33
|
\u5361\uFF1A\u5DF2\u5206\u914D ${e.cards.allocated}${o(e.cards.allocatedDelta)}\uFF0C\u95F2\u7F6E\u5206\u914D ${e.cards.idleAllocated}${o(e.cards.idleAllocatedDelta)}\uFF0C\u7A7A\u95F2 ${e.cards.available}\u3002
|
|
34
|
-
\u8D1F\u8F7D\uFF1A\u8FD0\u884C ${e.workloads.running}${o(e.workloads.runningDelta)}\uFF0C\u6392\u961F ${e.workloads.queued}${o(e.workloads.queuedDelta)}\uFF0C\u5931\u8D25 ${e.workloads.failed}${o(e.workloads.failedDelta)}\u3002`+
|
|
34
|
+
\u8D1F\u8F7D\uFF1A\u8FD0\u884C ${e.workloads.running}${o(e.workloads.runningDelta)}\uFF0C\u6392\u961F ${e.workloads.queued}${o(e.workloads.queuedDelta)}\uFF0C\u5931\u8D25 ${e.workloads.failed}${o(e.workloads.failedDelta)}\u3002`+s("\u65B0\u589E\u5F02\u5E38\uFF1A",e.appeared)+s("\u5DF2\u6D88\u5931\uFF1A",e.resolved)+s("\u4ECD\u5728\uFF1A",e.ongoing)+(c?`
|
|
35
35
|
|
|
36
36
|
\u9879\u76EE\u5360\u7528\u53D8\u5316\uFF1A
|
|
37
|
-
${
|
|
37
|
+
${c}`:"")+(e.metricsAvailable?"":`
|
|
38
38
|
|
|
39
39
|
\u6CE8\u610F\uFF1A\u6307\u6807\u6E90\u672A\u63A5\u5165\uFF0C\u5229\u7528\u7387\u7C7B\u5224\u65AD\u6B64\u65F6\u4E0D\u53EF\u4FE1\u3002`)+(e.saved?"":`
|
|
40
40
|
|
|
41
|
-
\uFF08\u9884\u89C8\uFF0C\u672A\u63A8\u8FDB\u57FA\u7EBF\uFF09`)}]}
|
|
41
|
+
\uFF08\u9884\u89C8\uFF0C\u672A\u63A8\u8FDB\u57FA\u7EBF\uFF09`)}]},async run(t,e){let o=f(r,"runnpu","RunNPU \u8FDE\u63A5\u5668"),s=e.cwd,[d,c,i]=await Promise.all([o.query(s,"overview",{},e.signal),o.query(s,"workloads",{limit:100},e.signal),V()]),a=Q(d,c,i),h=t.preview!==!0;return h&&await z(a),y({at:a.at,since:a.since,quiet:a.quiet,saved:h,metricsAvailable:a.metricsAvailable,cards:a.cards,workloads:a.workloads,appeared:a.changes.appeared,resolved:a.changes.resolved,ongoing:a.changes.ongoing,projects:a.projects.map(n=>({slug:n.slug,quotaCards:n.quotaCards,usedCards:n.usedCards,running:n.running,idleHeld:n.idleHeld,usedDelta:n.usedDelta,idleHeldDelta:n.idleHeldDelta}))})}})),l.push(b({name:"cluster_followups",description:'Offer the user 2\u20134 one-click follow-up questions, shown as buttons above the composer. Call this at the END of a turn, after you have answered \u2014 it replaces whatever was offered before. Propose what THIS answer actually raises: name the workload, node or project you just found something about ("\u770B test-project/svc-41hl \u7684\u65E5\u5FD7", "\u753B\u4E00\u4E0B 910b1 \u6700\u8FD1\u7684 CPU \u66F2\u7EBF"), or the obvious next decision ("\u8981\u4E0D\u8981\u5220\u6389\u91CD\u5EFA\uFF1F"). Do not offer generic questions the user could have asked before reading your answer, and do not offer something you already answered. Skip the call entirely when nothing genuinely follows \u2014 an empty row is better than four questions nobody wants, and the user can always type.',parameters:{type:"object",properties:{questions:{type:"array",items:{type:"string"},description:"The follow-ups, most useful first. At most four; each should read as a question the user would actually send."}},required:["questions"]},result:{type:"object",additionalProperties:!1,properties:{accepted:{type:"array",items:{type:"string"}},dropped:{type:"integer"}},required:["accepted","dropped"]},content:(t,e)=>[{type:"text",text:e.accepted.length===0?"\u6CA1\u6709\u63D0\u4F9B\u8FFD\u95EE\u5EFA\u8BAE\u3002":`\u5DF2\u5728\u8F93\u5165\u6846\u4E0A\u65B9\u7ED9\u51FA ${e.accepted.length} \u4E2A\u8FFD\u95EE\u5EFA\u8BAE\u3002`+(e.dropped>0?`\uFF08\u8D85\u8FC7 4 \u4E2A\u4E0A\u9650\uFF0C\u4E22\u5F03\u4E86 ${e.dropped} \u4E2A\uFF09`:"")}],async run(t,e){let o=f(r,"followups","\u8FFD\u95EE\u5EFA\u8BAE"),s=e.sessionId;if(!s)throw new Error("\u8FD9\u4E2A\u5DE5\u5177\u9700\u8981\u4E00\u4E2A\u4F1A\u8BDD");let d=t.questions.map(i=>String(i).trim()).filter(i=>i.length>0&&i.length<=60),c=d.slice(0,ee);return o.set(s,c),y({accepted:c,dropped:Math.max(0,d.length-c.length)})}})),l.push(b({name:"cluster_unpin",description:"Remove one pinned chart from the right column. Only on the user's say-so: the right column is theirs, and a chart you find redundant may be the one they check every morning. Get the id from cluster_pins.",parameters:{type:"object",properties:{id:{type:"string",description:"Pin id, from cluster_pins."}},required:["id"]},result:{type:"object",additionalProperties:!1,properties:{id:{type:"string"},removed:{type:"boolean"}},required:["id","removed"]},content:(t,e)=>[{type:"text",text:e.removed?"\u5DF2\u4ECE\u53F3\u680F\u79FB\u9664\u3002":"\u53F3\u680F\u91CC\u6CA1\u6709\u8FD9\u4E2A id \u5BF9\u5E94\u7684\u56FE\u8868\u3002"}],async run(t){let e=f(r,"pins","\u56FE\u8868\u56FA\u5B9A\u533A");return{id:t.id,removed:await e.remove(t.id)}}})),{tools:l,guards:m}}var ae="runnpu-compute-tools",Ae=["tools"];function _e(r,p){let u=W(r,{runnpu:"runnpu",pins:"runnpuPins",followups:"runnpuFollowups"}),{tools:l,guards:m}=K(u,p??{}),t=e=>r.get(e);for(let e of m)r.effect(()=>r.tools?.guard(M(e)),`${ae}: shell workload guard`);for(let e of l)r.tools?.register(se(B(e,t)))}export{_e as apply,Ae as inject,ae as name};
|