claw-dashboard 2.1.1 → 2.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/CHANGELOG.md +29 -1
- package/docs/API.md +1 -2
- package/index.js +31 -41
- package/package.json +22 -12
- package/src/auto-save.js +11 -5
- package/src/cli/export-snapshot.js +3 -1
- package/src/cli/import-snapshot.js +3 -1
- package/src/config.js +9 -15
- package/src/errors.js +0 -9
- package/src/security.js +6 -2
- package/src/snapshot.js +73 -26
- package/src/web-server.js +7 -10
- package/.c8rc.json +0 -38
- package/.dockerignore +0 -68
- package/.github/dependabot.yml +0 -45
- package/.github/pull_request_template.md +0 -39
- package/.github/workflows/ci.yml +0 -147
- package/.github/workflows/release.yml +0 -40
- package/.github/workflows/security.yml +0 -84
- package/.husky/pre-commit +0 -1
- package/.planning/codebase/ARCHITECTURE.md +0 -206
- package/.planning/codebase/INTEGRATIONS.md +0 -150
- package/.planning/codebase/STACK.md +0 -122
- package/.planning/codebase/STRUCTURE.md +0 -201
- package/CONTRIBUTING.md +0 -378
- package/Dockerfile +0 -54
- package/FEATURES.md +0 -307
- package/TODO.md +0 -28
- package/ai.openclaw.dashboard.plist +0 -35
- package/build-cjs.js +0 -127
- package/cjs-shim.js +0 -13
- package/dist/clawdash +0 -1729
- package/dist/clawdash.meta.json +0 -2236
- package/dist/widgets.cjs +0 -6511
- package/docker-compose.yml +0 -67
- package/esbuild.config.js +0 -158
- package/eslint.config.js +0 -56
- package/examples/plugins/README.md +0 -122
- package/examples/plugins/api-status/index.js +0 -294
- package/examples/plugins/api-status/plugin.json +0 -19
- package/examples/plugins/hello-world/index.js +0 -104
- package/examples/plugins/hello-world/plugin.json +0 -15
- package/examples/plugins/system-metrics-chart/index.js +0 -339
- package/examples/plugins/system-metrics-chart/plugin.json +0 -18
- package/examples/plugins/weather-widget/index.js +0 -136
- package/examples/plugins/weather-widget/plugin.json +0 -19
- package/index.cjs +0 -23005
- package/jest.config.js +0 -11
- package/scripts/release.js +0 -595
- package/src/database.js +0 -734
- package/tests/alerts.test.js +0 -437
- package/tests/auto-save.test.js +0 -529
- package/tests/cache.test.js +0 -317
- package/tests/cli.test.js +0 -351
- package/tests/command-palette.test.js +0 -320
- package/tests/config-processor.test.js +0 -452
- package/tests/config-validator.test.js +0 -710
- package/tests/config-watcher.test.js +0 -594
- package/tests/config.test.js +0 -755
- package/tests/database.test.js +0 -438
- package/tests/errors.test.js +0 -189
- package/tests/example-plugins.test.js +0 -624
- package/tests/integration.test.js +0 -1321
- package/tests/loading-states.test.js +0 -300
- package/tests/manifest-validation-on-load.test.js +0 -671
- package/tests/performance-monitor.test.js +0 -190
- package/tests/plugin-api-rate-limit.test.js +0 -302
- package/tests/plugin-errors.test.js +0 -311
- package/tests/plugin-lifecycle-e2e.test.js +0 -1036
- package/tests/plugin-reload.test.js +0 -764
- package/tests/rate-limiter.test.js +0 -539
- package/tests/removed-dependencies.test.js +0 -74
- package/tests/retry.test.js +0 -308
- package/tests/security.test.js +0 -411
- package/tests/settings-modal.test.js +0 -226
- package/tests/theme-selector.test.js +0 -57
- package/tests/utils.js +0 -242
- package/tests/utils.test.js +0 -317
- package/tests/validate-plugin-cli.test.js +0 -359
- package/tests/validation.test.js +0 -837
- package/tests/web-server.test.js +0 -646
- package/tests/widget-arrange-mode.test.js +0 -183
- package/tests/widget-config-hot-reload.test.js +0 -465
- package/tests/widget-dependency.test.js +0 -591
- package/tests/widget-error-boundary.test.js +0 -749
- package/tests/widget-error-isolation.test.js +0 -469
- package/tests/widget-integration.test.js +0 -1147
- package/tests/widget-refresh-intervals.test.js +0 -284
- package/tests/worker-pool.test.js +0 -522
package/dist/clawdash
DELETED
|
@@ -1,1729 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
|
-
/**
|
|
4
|
-
* claw-dashboard v1.10.0
|
|
5
|
-
* A beautiful console dashboard for monitoring OpenClaw instances
|
|
6
|
-
*
|
|
7
|
-
* License: MIT
|
|
8
|
-
* Repository: https://github.com/spleck/claw-dashboard
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
var ec=Object.create;var ki=Object.defineProperty;var tc=Object.getOwnPropertyDescriptor;var sc=Object.getOwnPropertyNames;var rc=Object.getPrototypeOf,ic=Object.prototype.hasOwnProperty;var Eo=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var Us=(r,e)=>()=>(r&&(e=r(r=0)),e);var nc=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),oc=(r,e)=>{for(var t in e)ki(r,t,{get:e[t],enumerable:!0})},ac=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of sc(e))!ic.call(r,i)&&i!==t&&ki(r,i,{get:()=>e[i],enumerable:!(s=tc(e,i))||s.enumerable});return r};var lc=(r,e,t)=>(t=r!=null?ec(rc(r)):{},ac(e||!r||!r.__esModule?ki(t,"default",{value:r,enumerable:!0}):t,r));import Ze from"os";import cc from"fs";import{fileURLToPath as hc}from"url";import{dirname as uc,join as dc}from"path";var fc,gc,pe,bo,pc,mc,ct,ws,yc,Rt,wc,Ec,bc,Xt,Sc,_t,xc,Tc,vc,Ic,fe,Ac,Rc,_c,ye,Cc,Lc,Ne,Sr,kc,Oc,Mc,Le,br,ce,Ct,w,te=Us(()=>{fc=hc(import.meta.url),gc=uc(fc),pe="unknown";try{pe=JSON.parse(cc.readFileSync(dc(gc,"../package.json"),"utf8")).version||"unknown"}catch{}bo={DEFAULT:2e3,ACTIVE:2e3,IDLE:1e4,OPTIONS:[1e3,2e3,5e3,1e4]},pc=300*1e3,mc={LENGTH:60,NETWORK_LENGTH:30},ct={DEFAULT_PORT:18789,TIMEOUT_MS:3e3,MAX_ENDPOINTS:10,DEFAULT_ENDPOINT_NAME:"local"},ws={name:"local",host:"localhost",port:18789,token:null,enabled:!0,type:"local"},yc={GAUGE_WIDTH:15,SPARKLINE_WIDTH:15,LOG_BOX_MIN_HEIGHT:10,DEFAULT_WIDTH:80,DEFAULT_HEIGHT:24},Rt={CPU:1e3,MEMORY:1e3,GPU:5e3,NETWORK:5e3,DISK:6e4,SYSTEM:36e5,CONTAINER:3e5,DEFAULT:2e3},wc={cpu:{ttl:Rt.CPU},memory:{ttl:Rt.MEMORY},gpu:{ttl:Rt.GPU},network:{ttl:Rt.NETWORK},disk:{ttl:Rt.DISK},system:{ttl:Rt.SYSTEM},container:{ttl:Rt.CONTAINER}},Ec={PATH:Ze.homedir()+"/.openclaw/dashboard-history.db",SAVE_INTERVAL_MS:3e4,CLEANUP_INTERVAL_MS:3600*1e3,DEFAULT_RETENTION_DAYS:30},bc={ENABLED:!0,ALGORITHM:"sha256",HEADER_NAME:"x-response-checksum",STRICT_MODE:!1,MAX_AGE_MS:3e5},Xt={DEFAULT_MAX_RETRIES:3,DEFAULT_INITIAL_DELAY:1e3,DEFAULT_MAX_DELAY:1e4,DEFAULT_BACKOFF_MULTIPLIER:2,TIMEOUT:3e4,INTERVAL:1e3,JITTER_FACTOR:.1,RETRYABLE_STATUSES:[408,429,500,502,503,504],RETRYABLE_ERRORS:["ECONNREFUSED","ETIMEDOUT","ENOTFOUND","EAI_AGAIN","ECONNRESET","EPIPE"]},Sc={maxRetries:Xt.DEFAULT_MAX_RETRIES,initialDelay:Xt.DEFAULT_INITIAL_DELAY,maxDelay:Xt.DEFAULT_MAX_DELAY,backoffMultiplier:Xt.DEFAULT_BACKOFF_MULTIPLIER,retryableStatuses:Xt.RETRYABLE_STATUSES,retryableErrors:Xt.RETRYABLE_ERRORS},_t={ENABLED:!0,DEFAULT_INTERVAL_MS:3e4,MIN_INTERVAL_MS:5e3,MAX_INTERVAL_MS:3e5,EXPONENTIAL_BACKOFF:!0,BACKOFF_MULTIPLIER:2,MAX_BACKOFF_INTERVAL_MS:3e5,RESET_AFTER_SUCCESS:!0,CONSECUTIVE_FAILURE_THRESHOLD:3},xc={CPU:{warning:70,critical:90},MEMORY:{warning:75,critical:90},DISK:{warning:80,critical:95}},Tc={ENABLED:!0,WINDOW_MS:6e4,MAX_ALERTS:5},vc=100,Ic={THRESHOLDS:{WARNING_MB:512,CRITICAL_MB:1024,EMERGENCY_MB:1536},TREND:{SAMPLE_COUNT:10,GROWTH_THRESHOLD_MB:50,TIME_WINDOW_MS:6e4},SUSTAINED:{DURATION_MS:12e4,CHECK_INTERVAL_MS:1e4},ACTIONS:{AUTO_CLEAR_HISTORY:!0,REQUEST_GC:!0}},fe={REFRESH_INTERVAL:{MIN:500,MAX:6e4},VALID_THEMES:["default","dark","high-contrast","ocean","auto"],VALID_SORT_MODES:["time","tokens","idle","name"],VALID_LOG_LEVELS:["all","error","warn","info","debug"],VALID_EXPORT_FORMATS:["json","csv"],VALID_ENDPOINT_TYPES:["local","remote","cloud"],ENDPOINT_NAME:{MIN_LENGTH:1,MAX_LENGTH:32,PATTERN:/^[a-zA-Z0-9_-]+$/},AUTO_RETRY:{INTERVAL_MS:{MIN:5e3,MAX:3e5},BACKOFF_MULTIPLIER:{MIN:1,MAX:10},MAX_BACKOFF_INTERVAL_MS:{MIN:1e4,MAX:6e5},CONSECUTIVE_FAILURE_THRESHOLD:{MIN:1,MAX:10}}},Ac={LAUNCHCTL:2e3,PS:2e3,SYSTEM_PROFILER:5e3,IOREG:3e3,POWERMETRICS:3e3,OPENCLAW_VERSION:3e3,OPENCLAW_LOGS:5e3,NVIDIA_SMI:3e3,LSPCI:3e3,RADEONTOP:3e3,POWERSHELL:5e3,WSL_SMI:5e3},Rc={ENABLED:!0,MAX_WORKERS:2,TASK_TIMEOUT:1e4,FALLBACK_ON_ERROR:!0},_c={QUEUE:{WARNING_SIZE:10,CRITICAL_SIZE:25,MAX_SIZE:50},UTILIZATION:{WARNING_PCT:75,CRITICAL_PCT:90},STRATEGIES:{ADAPTIVE_TIMEOUT:{ENABLED:!0,WARNING_MULTIPLIER:1.5,CRITICAL_MULTIPLIER:2},SHED_LOAD:{ENABLED:!0,SHED_NON_CRITICAL:!0},CIRCUIT_BREAKER:{ENABLED:!0,FAILURE_THRESHOLD:5,RESET_TIMEOUT_MS:3e4}},RECOVERY:{COOLDOWN_MS:5e3,MIN_NORMAL_OPERATIONS:5}},ye={DEFAULT_PORT:18790,HOST:"0.0.0.0",CORS_ORIGIN:"*",REQUEST_TIMEOUT:3e4,REFRESH_CACHE_MS:2e3,ENDPOINTS:{HEALTH:"/health",METRICS:"/metrics",SESSIONS:"/sessions",AGENTS:"/agents",LOGS:"/logs",STATUS:"/status"},RATE_LIMIT:{ENABLED:!0,WINDOW_MS:6e4,MAX_REQUESTS:100,TRUST_PROXY:!1},CORS:{ALLOWED_ORIGINS:"*",ALLOWED_METHODS:["GET","POST","OPTIONS"],ALLOWED_HEADERS:["Content-Type","Authorization"],CREDENTIALS:!1,MAX_AGE:86400},AUTH:{ENABLED:!1,HEADER_NAME:"Authorization",SCHEME:"Bearer",KEY_PREFIX:"cd_",KEY_LENGTH:32,KEY_PATTERN:/^cd_[a-zA-Z0-9]{32}$/,MAX_KEYS:10,KEY_NAME_MIN_LENGTH:1,KEY_NAME_MAX_LENGTH:64}},Cc={ENABLED:!0,AUTO_DISCOVER:!0,PRELOAD_PRIORITY:["cpu","memory","gpu"],LAZY_LOAD_DELAY:500,MAX_CONCURRENT_LOADS:3,FALLBACK_ON_ERROR:!0,CACHE_TTL:6e4,BUILTIN:{cpu:{priority:10,lazyLoad:!1},memory:{priority:20,lazyLoad:!1},gpu:{priority:30,lazyLoad:!1},network:{priority:40,lazyLoad:!0},disk:{priority:50,lazyLoad:!0},system:{priority:60,lazyLoad:!0},uptime:{priority:70,lazyLoad:!0},dataHealth:{priority:80,lazyLoad:!0}}},Lc={DEFAULT:null,CPU:1e3,MEMORY:1e3,GPU:5e3,NETWORK:1e3,DISK:3e4,SYSTEM:5e3,UPTIME:6e4,DATA_HEALTH:1e4},Ne={SMALL:"small",MEDIUM:"medium",LARGE:"large",WIDE:"wide"},Sr={[Ne.SMALL]:3,[Ne.MEDIUM]:5,[Ne.LARGE]:8,[Ne.WIDE]:5},kc={cpu:Ne.MEDIUM,mem:Ne.MEDIUM,gpu:Ne.MEDIUM,net:Ne.MEDIUM,disk:Ne.MEDIUM,sys:Ne.MEDIUM,uptime:Ne.MEDIUM,health:Ne.MEDIUM,gateway:Ne.MEDIUM},Oc={MIN_INTERVAL:500,MAX_INTERVAL:6e4,ALLOWED_CUSTOM_INTERVALS:[500,1e3,2e3,5e3,1e4,3e4,6e4]},Mc={WARNING:{SKIP_NON_CRITICAL:!1,EXTEND_INTERVAL_MULTIPLIER:1.5,PRIORITY_THRESHOLD:50},CRITICAL:{SKIP_NON_CRITICAL:!0,EXTEND_INTERVAL_MULTIPLIER:2,PRIORITY_THRESHOLD:30},CRITICAL_WIDGETS:["cpu","memory"],NON_CRITICAL_WIDGETS:["disk","system","uptime","dataHealth"]},Le={SETTINGS:Ze.homedir()+"/.openclaw/dashboard-settings.json",STATE:Ze.homedir()+"/.openclaw/dashboard-state.json",EXPORTS:Ze.homedir()+"/.openclaw/exports",OPENCLAW_CONFIG:Ze.homedir()+"/.openclaw/openclaw.json",LOG:Ze.homedir()+"/.openclaw/claw-dashboard.log",HOME_DIR:Ze.homedir(),OPENCLAW_DIR:Ze.homedir()+"/.openclaw",AGENTS_DIR:Ze.homedir()+"/.openclaw/agents",WIDGETS_DIR:Ze.homedir()+"/.openclaw/widgets",PLUGINS_DIR:Ze.homedir()+"/.openclaw/plugins"},br={ENABLED:!0,INTERVAL_MS:3e4,SAVE_ON_EXIT:!0,MAX_CONSECUTIVE_FAILURES:3,BACKUP_COUNT:3},ce={ENABLED:!1,DEFAULT_FORMAT:"json",DEFAULT_SCHEDULE:"0 * * * *",MIN_RETENTION_DAYS:0,MAX_RETENTION_DAYS:365,DEFAULT_RETENTION_DAYS:30,MAX_SCHEDULED_EXPORTS_PER_DAY:1440},Ct={refreshInterval:bo.DEFAULT,logLevelFilter:"all",sessionSortMode:"time",showWidget1:!0,showWidget2:!0,showWidget3:!0,showWidget4:!0,showWidget5:!0,showWidget6:!0,showWidget7:!0,showWidget8:!0,showWidget9:!0,showPerformanceMetrics:!1,theme:"auto",exportFormat:"json",exportDirectory:Le.EXPORTS,sessionSearchQuery:"",favorites:{},showFavoritesOnly:!1,pinnedWidgets:[],firstRun:!0,gatewayEndpoints:[{...ws}],activeGatewayEndpoint:"local",webInterface:{enabled:!1,port:ye.DEFAULT_PORT,host:ye.HOST,cors:!0,corsOrigins:ye.CORS.ALLOWED_ORIGINS,rateLimit:{enabled:ye.RATE_LIMIT.ENABLED,windowMs:ye.RATE_LIMIT.WINDOW_MS,maxRequests:ye.RATE_LIMIT.MAX_REQUESTS,trustProxy:ye.RATE_LIMIT.TRUST_PROXY},auth:{enabled:ye.AUTH.ENABLED,keys:[]}},widgetLoading:{enabled:!0,preloadPriority:["cpu","memory","gpu"],lazyLoadDelay:500,maxConcurrent:3,autoDiscover:!0},widgetSizes:{},plugins:{},autoRetry:{enabled:_t.ENABLED,intervalMs:_t.DEFAULT_INTERVAL_MS,exponentialBackoff:_t.EXPONENTIAL_BACKOFF,backoffMultiplier:_t.BACKOFF_MULTIPLIER,maxBackoffIntervalMs:_t.MAX_BACKOFF_INTERVAL_MS,resetAfterSuccess:_t.RESET_AFTER_SUCCESS,consecutiveFailureThreshold:_t.CONSECUTIVE_FAILURE_THRESHOLD},autoSave:{enabled:br.ENABLED,intervalMs:br.INTERVAL_MS,saveOnExit:br.SAVE_ON_EXIT},exportSchedule:{enabled:ce.ENABLED,format:ce.DEFAULT_FORMAT,schedule:ce.DEFAULT_SCHEDULE,retentionDays:ce.DEFAULT_RETENTION_DAYS,directory:null,includeMetrics:!0}},w={REFRESH_INTERVALS:bo,IDLE_THRESHOLD_MS:pc,HISTORY:mc,GATEWAY:ct,DEFAULT_GATEWAY_ENDPOINT:ws,CHECKSUM:bc,UI:yc,CACHE_TTL:Rt,CACHE_CONFIG:wc,DATABASE:Ec,RETRY:Xt,DEFAULT_RETRY_OPTIONS:Sc,AUTO_RETRY:_t,AUTO_SAVE:br,EXPORT_SCHEDULE:ce,ALERT_THRESHOLDS:xc,ALERT_RATE_LIMIT:Tc,MAX_ALERT_HISTORY:vc,MEMORY_PRESSURE:Ic,VALIDATION:fe,COMMAND_TIMEOUTS:Ac,PATHS:Le,DEFAULT_SETTINGS:Ct,WORKERS:Rc,WORKER_DEGRADATION:_c,WEB:ye,WIDGETS:Cc,WIDGET_REFRESH_INTERVALS:Lc,WIDGET_REFRESH_VALIDATION:Oc,WIDGET_DEGRADATION:Mc,WIDGET_SIZE_PRESETS:Ne,WIDGET_SIZES:Sr,WIDGET_DEFAULT_SIZES:kc,DASHBOARD_VERSION:pe}});import Bs from"fs";import Fe from"path";import Oi from"crypto";function Di(r){return!(!r||typeof r!="string"||r.includes("\0")||r.length===0||r.length>4096)}function Dc(r){try{let e=Bs.lstatSync(r);return!(!e.isFile()||e.isSymbolicLink())}catch{return!1}}function Jt(r){if(!Di(r))return console.error("Invalid file path provided for permission setting"),!1;if(!Dc(r))return console.error(`Cannot set permissions on non-file path: ${r}`),!1;try{return Bs.chmodSync(r,384),!0}catch(e){return console.error(`Failed to set permissions on ${r}: ${e.message}`),!1}}function Tr(r,e=null){return new Mi().validate(r,e)}function wt(r,e={}){let{allowedDirs:t=[],allowAbsolute:s=!1,mustExist:i=!1,expectedType:n=null}=e;if(!r||typeof r!="string")return{valid:!1,path:null,error:"Path must be a non-empty string"};if(r.includes("\0"))return{valid:!1,path:null,error:"Path contains null bytes"};if(Fe.isAbsolute(r)&&!s)return{valid:!1,path:null,error:"Absolute paths are not allowed"};if(Fe.normalize(r).startsWith(".."))return{valid:!1,path:null,error:"Path traversal detected"};if(r.includes("../")||r.includes("..\\"))return{valid:!1,path:null,error:"Path traversal detected"};let c=r.split(Fe.sep).filter(g=>g.length>0);for(let g of c)if(!(g==="."||g==="..")){if(!/^[a-zA-Z0-9._-]+$/.test(g))return{valid:!1,path:null,error:`Invalid characters in path component: ${g}`};if(g.startsWith(".")&&g!=="."&&g!==".."&&![".gitkeep",".gitignore",".npmignore"].includes(g))return{valid:!1,path:null,error:`Hidden files/directories are not allowed: ${g}`}}let d;try{if(t.length>0){let g=t[0];d=Fe.resolve(g,r)}else d=Fe.resolve(r)}catch(g){return{valid:!1,path:null,error:`Failed to resolve path: ${g.message}`}}if(t.length>0&&!t.some(p=>{let T=p.endsWith(Fe.sep)?p:p+Fe.sep;return(d.endsWith(Fe.sep)?d:d+Fe.sep).startsWith(T)}))return{valid:!1,path:null,error:"Path is outside allowed directories"};if(i)try{let g=Bs.statSync(d);if(n==="file"&&!g.isFile())return{valid:!1,path:null,error:"Path exists but is not a file"};if(n==="directory"&&!g.isDirectory())return{valid:!1,path:null,error:"Path exists but is not a directory"}}catch{return{valid:!1,path:null,error:`Path does not exist: ${d}`}}try{let g=Bs.realpathSync(d);if(t.length>0&&!t.map(b=>{try{return Bs.realpathSync(b)}catch{return b}}).some(b=>{let _=b.endsWith(Fe.sep)?b:b+Fe.sep;return(g.endsWith(Fe.sep)?g:g+Fe.sep).startsWith(_)}))return{valid:!1,path:null,error:"Path resolves outside allowed directories via symlink"}}catch(g){if(i)return{valid:!1,path:null,error:`Failed to resolve real path: ${g.message}`}}return{valid:!0,path:d,error:null}}function So(r){if(!r||typeof r!="string")return{valid:!1,error:"Plugin name must be a non-empty string"};let e=r.trim();return e.length===0?{valid:!1,error:"Plugin name cannot be empty"}:e.length>100?{valid:!1,error:"Plugin name too long (max 100 characters)"}:["node_modules","package.json","package-lock.json",".git",".hg",".svn"].includes(e.toLowerCase())?{valid:!1,error:`Plugin name '${e}' is reserved`}:/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(e)?{valid:!0,error:null}:{valid:!1,error:"Plugin name must contain only alphanumeric characters, hyphens, and underscores, and must start with alphanumeric"}}var Mi,xr,Es=Us(()=>{te();Mi=class{constructor(e={}){this.maxStringLength=e.maxStringLength||1e3,this.maxDepth=e.maxDepth||10,this.maxArrayLength=e.maxArrayLength||100,this.allowedTypes=e.allowedTypes||["string","number","boolean","object","array","null"],this.stripNullBytes=e.stripNullBytes!==!1,this.maxKeyLength=e.maxKeyLength||100}validate(e,t=null){if(e==null)return{};if(typeof e!="object")throw new Error("Widget config must be an object");return this._sanitizeValue(e,0,t)}_sanitizeValue(e,t,s){if(t>this.maxDepth)throw new Error(`Configuration exceeds maximum depth of ${this.maxDepth}`);if(e===null)return null;if(e===void 0)return;let i=Array.isArray(e)?"array":typeof e;if(!this.allowedTypes.includes(i))throw new Error(`Invalid type: ${i}`);return i==="string"?this._sanitizeString(e):i==="number"?this._sanitizeNumber(e):i==="boolean"?e:i==="array"?this._sanitizeArray(e,t,s):i==="object"?this._sanitizeObject(e,t,s):e}_sanitizeString(e){return typeof e!="string"?String(e):(this.stripNullBytes&&(e=e.replace(/\0/g,"")),e.length>this.maxStringLength&&(e=e.substring(0,this.maxStringLength)),e)}_sanitizeNumber(e){return typeof e!="number"?NaN:Number.isNaN(e)||!Number.isFinite(e)?0:e}_sanitizeArray(e,t,s){if(!Array.isArray(e))return[];e.length>this.maxArrayLength&&(e=e.slice(0,this.maxArrayLength));let i=s?.items;return e.map((n,a)=>{try{return this._sanitizeValue(n,t+1,i)}catch{return null}})}_sanitizeObject(e,t,s){if(typeof e!="object"||e===null||Array.isArray(e))return{};let i={},n=s?.properties||{},a=s?new Set(Object.keys(n)):null;for(let c of Object.keys(e))if(!(c.length>this.maxKeyLength)&&!(a&&!a.has(c)))try{let d=n?.[c];i[c]=this._sanitizeValue(e[c],t+1,d)}catch{let g=n?.[c]?.default;i[c]=g!==void 0?g:null}return i}};xr=class{constructor(e={}){this.keys=new Map,this.revokedKeys=new Set,this.failedAttempts=new Map,this.enabled=e.enabled??ye.AUTH.ENABLED,this.headerName=e.headerName??ye.AUTH.HEADER_NAME,this.scheme=e.scheme??ye.AUTH.SCHEME,this.keyPrefix=e.keyPrefix??ye.AUTH.KEY_PREFIX,this.keyLength=e.keyLength??ye.AUTH.KEY_LENGTH,this.maxKeys=e.maxKeys??ye.AUTH.MAX_KEYS,this.maxFailedAttempts=e.maxFailedAttempts??5,this.blockDurationMs=e.blockDurationMs??6e4;let t=this.keyPrefix.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");this.keyPattern=new RegExp(`^${t}[a-zA-Z0-9]{${this.keyLength}}$`)}generateKey(e){if(!e||typeof e!="string")throw new Error("API key name is required");if(e.length<ye.AUTH.KEY_NAME_MIN_LENGTH||e.length>ye.AUTH.KEY_NAME_MAX_LENGTH)throw new Error(`Key name must be between ${ye.AUTH.KEY_NAME_MIN_LENGTH} and ${ye.AUTH.KEY_NAME_MAX_LENGTH} characters`);if(this.keys.size>=this.maxKeys)throw new Error(`Maximum number of API keys (${this.maxKeys}) reached`);let s=Oi.randomBytes(Math.ceil(this.keyLength/2)).toString("hex").slice(0,this.keyLength),i=`${this.keyPrefix}${s}`,n={id:Oi.randomUUID(),name:e.trim(),createdAt:new Date().toISOString(),lastUsed:null,usageCount:0,keyHash:this._hashKey(i)};return this.keys.set(i,n),{key:i,id:n.id,name:n.name,createdAt:n.createdAt}}_hashKey(e){return Oi.createHash("sha256").update(e).digest("hex")}isValidKeyFormat(e){return!e||typeof e!="string"?!1:this.keyPattern.test(e)}isBlocked(e){if(!e)return{blocked:!1};let t=this.failedAttempts.get(e);if(!t)return{blocked:!1};let s=Date.now();return t.blockedUntil&&s<t.blockedUntil?{blocked:!0,retryAfter:Math.ceil((t.blockedUntil-s)/1e3)}:(t.blockedUntil&&s>=t.blockedUntil&&this.failedAttempts.delete(e),{blocked:!1})}_recordFailedAttempt(e){if(!e)return;let t=Date.now(),s=this.failedAttempts.get(e);s||(s={count:0,firstAttempt:t,blockedUntil:null}),s.count++,s.count>=this.maxFailedAttempts&&(s.blockedUntil=t+this.blockDurationMs),this.failedAttempts.set(e,s)}_clearFailedAttempts(e){e&&this.failedAttempts.delete(e)}extractKey(e){if(!e||typeof e!="object")return null;let t=this.headerName.toLowerCase(),s=Object.entries(e).find(([i])=>i.toLowerCase()===t)?.[1];if(!s)return null;if(this.scheme){let i=this.scheme.toLowerCase();if(s.toLowerCase().startsWith(`${i} `))return s.slice(this.scheme.length+1).trim()}return s}authenticate(e,t){if(!this.enabled)return{authenticated:!0};let s=this.isBlocked(t);if(s.blocked)return{authenticated:!1,error:`Too many failed attempts. Retry after ${s.retryAfter} seconds`,code:"AUTH_BLOCKED",retryAfter:s.retryAfter};let i=this.extractKey(e);if(!i)return this._recordFailedAttempt(t),{authenticated:!1,error:"Authentication required. Provide API key in header",code:"AUTH_REQUIRED"};if(!this.isValidKeyFormat(i))return this._recordFailedAttempt(t),{authenticated:!1,error:"Invalid API key format",code:"AUTH_INVALID_FORMAT"};let n=this.keys.get(i);return n?this.revokedKeys.has(n.keyHash)?(this._recordFailedAttempt(t),{authenticated:!1,error:"API key has been revoked",code:"AUTH_REVOKED"}):(this._clearFailedAttempts(t),n.lastUsed=new Date().toISOString(),n.usageCount++,{authenticated:!0,keyId:n.id,keyName:n.name}):(this._recordFailedAttempt(t),{authenticated:!1,error:"Invalid API key",code:"AUTH_INVALID_KEY"})}revokeKey(e){for(let[t,s]of this.keys.entries())if(s.id===e)return this.revokedKeys.add(s.keyHash),this.keys.delete(t),!0;return!1}listKeys(){return Array.from(this.keys.values()).map(e=>({id:e.id,name:e.name,createdAt:e.createdAt,lastUsed:e.lastUsed,usageCount:e.usageCount}))}getKeyCount(){return this.keys.size}isEnabled(){return this.enabled}enable(){this.enabled=!0}disable(){this.enabled=!1}clear(){this.keys.clear(),this.revokedKeys.clear(),this.failedAttempts.clear()}}});import Hs from"fs";import xo from"os";import{fileURLToPath as Nc}from"url";import{dirname as $c}from"path";function Wc(){let r=xo.homedir()+"/.openclaw";Hs.existsSync(r)||Hs.mkdirSync(r,{recursive:!0})}function $i(r){if(r==null)return String(r);let e=String(r);return e=e.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,""),e=e.replace(/\x1b\][^\x07]*\x07/g,""),e=e.replace(/\x1b[P][a-zA-Z0-9]/g,""),e=e.replace(/\x1b\[[0-9;]*[@-~]/g,""),e=e.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g,t=>t===" "?" ":t===`
|
|
12
|
-
`?"\\n":t==="\r"?"\\r":"\\x"+t.charCodeAt(0).toString(16).padStart(2,"0")),e=e.replace(/\r\n/g,"\\r\\n"),e=e.replace(/\n/g,"\\n"),e=e.replace(/\r/g,"\\r"),e}function Fc(r){return r.map(e=>{if(typeof e=="object")try{return $i(JSON.stringify(e))}catch{return $i(String(e))}return $i(e)})}function vr(r,e){let t=Uc(),i=Fc(e).join(" "),n=`${t} [${r}] ${i}
|
|
13
|
-
`;try{Wc();let a=!1;try{Hs.accessSync(Ni,Hs.constants.F_OK)}catch{a=!0}Hs.appendFileSync(Ni,n),a&&Jt(Ni)}catch(a){r==="ERROR"&&process.stderr.write(`[Log Error] Failed to write ERROR log: ${a.message}
|
|
14
|
-
`)}}function Uc(){let r=new Date,e=r.getFullYear(),t=String(r.getMonth()+1).padStart(2,"0"),s=String(r.getDate()).padStart(2,"0"),i=String(r.getHours()).padStart(2,"0"),n=String(r.getMinutes()).padStart(2,"0"),a=String(r.getSeconds()).padStart(2,"0");return`[${e}-${t}-${s} ${i}:${n}:${a}]`}var Pc,eg,Ni,Bc,u,Q=Us(()=>{Es();Pc=Nc(import.meta.url),eg=$c(Pc),Ni=xo.homedir()+"/.openclaw/claw-dashboard.log";Bc={error(...r){vr("ERROR",r)},warn(...r){vr("WARN",r)},info(...r){vr("INFO",r)},debug(...r){process.env.DEBUG&&vr("DEBUG",r)}},u=Bc});var Ye,qs,Fr,Ur,Br,Ys,Is,As=Us(()=>{Ye=class extends Error{constructor(e,t="DASHBOARD_ERROR",s={}){super(e),this.name="DashboardError",this.code=t,this.details=s,this.timestamp=new Date().toISOString(),Error.captureStackTrace(this,this.constructor)}toJSON(){return{name:this.name,message:this.message,code:this.code,details:this.details,timestamp:this.timestamp,stack:this.stack}}},qs=class extends Ye{constructor(e,t={}){super(e,"GATEWAY_ERROR",t),this.name="GatewayError"}},Fr=class extends Ye{constructor(e,t={}){super(e,"AUTH_ERROR",t),this.name="AuthError"}},Ur=class extends Ye{constructor(e,t={}){super(e,"NETWORK_ERROR",t),this.name="NetworkError"}},Br=class extends Ye{constructor(e,t={}){super(e,"TIMEOUT_ERROR",t),this.name="TimeoutError"}},Ys=class extends Ye{constructor(e,t={}){super(e,"WORKER_POOL_OVERLOAD",t),this.name="WorkerPoolOverloadError",this.degradationLevel=t.degradationLevel||"none",this.queueSize=t.queueSize||0,this.utilizationPercent=t.utilizationPercent||0}},Is=class extends Ye{constructor(e,t={}){super(e,"CHECKSUM_ERROR",t),this.name="ChecksumError"}}});var ta={};oc(ta,{CIRCUIT_STATES:()=>Dt,DEGRADATION_LEVELS:()=>Ae,DegradationLevel:()=>Oh,WorkerPool:()=>Hr,default:()=>Nt});import{Worker as Ah}from"worker_threads";import{fileURLToPath as Rh}from"url";import{dirname as _h,join as Ch}from"path";var Lh,kh,Ae,Dt,Oh,Hr,Mh,Nt,Yi=Us(()=>{Q();te();As();Lh=Rh(import.meta.url),kh=_h(Lh),Ae={NONE:"none",WARNING:"warning",CRITICAL:"critical"},Dt={CLOSED:"closed",OPEN:"open",HALF_OPEN:"half_open"},Oh={NONE:"none",WARNING:"warning",CRITICAL:"critical"},Hr=class{constructor(e={}){this.workerPath=e.workerPath||Ch(kh,"system-worker.js"),this.maxWorkers=e.maxWorkers||w.WORKERS?.MAX_WORKERS||2,this.taskTimeout=e.taskTimeout||w.WORKERS?.TASK_TIMEOUT||1e4,this.enableWorkers=e.enableWorkers??w.WORKERS?.ENABLED??!0,this.workers=[],this.taskQueue=[],this.taskId=0,this.pendingTasks=new Map,this.isShutdown=!1;let t=e.degradationConfig||w.WORKER_DEGRADATION||{};this.degradationConfig={queue:t.QUEUE||{WARNING_SIZE:10,CRITICAL_SIZE:25,MAX_SIZE:50},utilization:t.UTILIZATION||{WARNING_PCT:75,CRITICAL_PCT:90},strategies:t.STRATEGIES||{ADAPTIVE_TIMEOUT:{ENABLED:!0,WARNING_MULTIPLIER:1.5,CRITICAL_MULTIPLIER:2},SHED_LOAD:{ENABLED:!0,SHED_NON_CRITICAL:!0},CIRCUIT_BREAKER:{ENABLED:!0,FAILURE_THRESHOLD:5,RESET_TIMEOUT_MS:3e4}},recovery:t.RECOVERY||{COOLDOWN_MS:5e3,MIN_NORMAL_OPERATIONS:5}},this.degradationLevel=Ae.NONE,this.degradationSince=null,this.consecutiveFailures=0,this.circuitBreakerState=Dt.CLOSED,this.circuitBreakerOpenedAt=null,this.successfulOperations=0,this.overloadEvents=0,this.lastOverloadTime=null,this.totalRejected=0,this.totalShed=0,this.workersSupported=this.checkWorkerSupport(),this.enableWorkers&&this.workersSupported&&this.initializeWorkers()}checkWorkerSupport(){try{let[e]=process.versions.node.split(".").map(Number);return e<12?(u.info("Worker threads not available (Node.js < 12)"),!1):!0}catch(e){return u.info("Worker threads not supported in this environment:",e.message),!1}}initializeWorkers(){try{for(let e=0;e<this.maxWorkers;e++)this.createWorker(e);u.info(`Initialized ${this.maxWorkers} system information worker threads`)}catch(e){u.error("Failed to initialize workers:",e.message),this.workersSupported=!1,this.workers=[]}}createWorker(e){let t=new Ah(this.workerPath,{execArgv:["--experimental-vm-modules"],workerData:{__filename:this.workerPath}});return t.id=e,t.isReady=!1,t.isBusy=!1,t.on("message",s=>{this.handleWorkerMessage(t,s)}),t.on("error",s=>{u.error(`Worker ${e} error:`,s.message),this.restartWorker(e)}),t.on("exit",s=>{s!==0&&u.warn(`Worker ${e} exited with code ${s}`),this.removeWorker(e)}),this.workers.push(t),t}handleWorkerMessage(e,t){if(t.type==="ready"){e.isReady=!0,this.processQueue();return}if(t.id!==void 0){let s=this.pendingTasks.get(t.id);if(s){if(this.pendingTasks.delete(t.id),e.isBusy=!1,s.timeout&&clearTimeout(s.timeout),t.success)this.recordSuccess(),s.resolve(t.data);else{this.recordFailure();let i=new Error(t.error||"Worker task failed");t.stack&&(i.stack=t.stack),s.reject(i)}this.processQueue()}}}restartWorker(e){let t=this.workers.find(s=>s.id===e);t&&t.terminate().catch(()=>{}),setTimeout(()=>{this.isShutdown||this.createWorker(e)},100).unref()}removeWorker(e){let t=this.workers.findIndex(s=>s.id===e);t!==-1&&this.workers.splice(t,1)}checkOverload(){let e=this.taskQueue.length,t=this.workers.filter(c=>c.isBusy).length,s=this.workers.length>0?Math.round(t/this.workers.length*100):0;if(this.circuitBreakerState===Dt.OPEN)if(Date.now()-this.circuitBreakerOpenedAt>=this.degradationConfig.strategies.CIRCUIT_BREAKER.RESET_TIMEOUT_MS)this.circuitBreakerState=Dt.HALF_OPEN,u.info("Circuit breaker entering half-open state");else return{level:Ae.CRITICAL,queueSize:e,utilizationPercent:s,circuitOpen:!0,reason:"circuit_breaker"};let{WARNING_SIZE:i,CRITICAL_SIZE:n,MAX_SIZE:a}=this.degradationConfig.queue;return e>=a?{level:Ae.CRITICAL,queueSize:e,utilizationPercent:s,reason:"max_queue_size"}:e>=n||s>=this.degradationConfig.utilization.CRITICAL_PCT?{level:Ae.CRITICAL,queueSize:e,utilizationPercent:s,reason:e>=n?"queue_size":"utilization"}:e>=i||s>=this.degradationConfig.utilization.WARNING_PCT?{level:Ae.WARNING,queueSize:e,utilizationPercent:s,reason:e>=i?"queue_size":"utilization"}:{level:Ae.NONE,queueSize:e,utilizationPercent:s,reason:null}}getAdaptiveTimeout(){let e=this.taskTimeout;if(!this.degradationConfig.strategies.ADAPTIVE_TIMEOUT.ENABLED)return e;switch(this.degradationLevel){case Ae.CRITICAL:return e*this.degradationConfig.strategies.ADAPTIVE_TIMEOUT.CRITICAL_MULTIPLIER;case Ae.WARNING:return e*this.degradationConfig.strategies.ADAPTIVE_TIMEOUT.WARNING_MULTIPLIER;default:return e}}updateDegradationLevel(e){let t=this.degradationLevel,s=e.level;t!==s&&(this.degradationLevel=s,this.degradationSince=Date.now(),s===Ae.CRITICAL?(this.overloadEvents++,this.lastOverloadTime=Date.now(),u.warn(`Worker pool entering critical degradation: ${e.reason} (queue: ${e.queueSize}, utilization: ${e.utilizationPercent}%)`)):s===Ae.WARNING?u.warn(`Worker pool entering warning state: ${e.reason} (queue: ${e.queueSize}, utilization: ${e.utilizationPercent}%)`):t!==Ae.NONE&&u.info(`Worker pool returning to normal operation from ${t}`)),t!==s&&(this.successfulOperations=0)}recordSuccess(){if(this.consecutiveFailures=0,this.successfulOperations++,this.circuitBreakerState===Dt.HALF_OPEN&&(this.circuitBreakerState=Dt.CLOSED,this.circuitBreakerOpenedAt=null,u.info("Circuit breaker closed - service recovered")),this.degradationLevel!==Ae.NONE){let e=Date.now()-this.degradationSince>=this.degradationConfig.recovery.COOLDOWN_MS,t=this.successfulOperations>=this.degradationConfig.recovery.MIN_NORMAL_OPERATIONS;if(e&&t){let s=this.checkOverload();s.level===Ae.NONE&&this.updateDegradationLevel(s)}}}recordFailure(){this.consecutiveFailures++,this.successfulOperations=0;let e=this.degradationConfig.strategies.CIRCUIT_BREAKER.FAILURE_THRESHOLD;this.degradationConfig.strategies.CIRCUIT_BREAKER.ENABLED&&this.consecutiveFailures>=e&&this.circuitBreakerState===Dt.CLOSED&&(this.circuitBreakerState=Dt.OPEN,this.circuitBreakerOpenedAt=Date.now(),u.error(`Circuit breaker opened after ${this.consecutiveFailures} consecutive failures`))}shouldShedLoad(e={}){return e.critical||e.priority==="high"||!this.degradationConfig.strategies.SHED_LOAD.ENABLED?!1:!!(this.degradationLevel===Ae.CRITICAL&&this.degradationConfig.strategies.SHED_LOAD.SHED_NON_CRITICAL)}async execute(e,t={}){let s=this.checkOverload();if(this.updateDegradationLevel(s),s.level===Ae.CRITICAL&&s.reason==="max_queue_size")throw this.totalRejected++,new Ys("Worker pool queue at maximum capacity",{degradationLevel:this.degradationLevel,queueSize:s.queueSize,utilizationPercent:s.utilizationPercent});if(s.circuitOpen)throw this.totalRejected++,new Ys("Worker pool circuit breaker is open",{degradationLevel:this.degradationLevel,queueSize:s.queueSize,utilizationPercent:s.utilizationPercent});if(this.shouldShedLoad(t)){this.totalShed++,u.debug(`Shedding load for command: ${e}`);try{let i=await this.fallbackExecute(e,t);return this.recordSuccess(),i}catch(i){throw this.recordFailure(),i}}if(!this.workersSupported||!this.enableWorkers||this.workers.length===0)try{let i=await this.fallbackExecute(e,t);return this.recordSuccess(),i}catch(i){throw this.recordFailure(),i}return new Promise((i,n)=>{let a=++this.taskId,c=this.getAdaptiveTimeout(),d=setTimeout(()=>{this.pendingTasks.delete(a),this.recordFailure(),n(new Error(`Worker task timeout: ${e}`))},c).unref();this.pendingTasks.set(a,{id:a,command:e,options:t,resolve:i,reject:n,timeout:d,timestamp:Date.now()}),this.taskQueue.push({id:a,command:e,options:t}),this.processQueue()})}processQueue(){if(this.taskQueue.length===0)return;let e=this.workers.find(s=>s.isReady&&!s.isBusy);if(!e)return;let t=this.taskQueue.shift();t&&(e.isBusy=!0,e.postMessage({id:t.id,command:t.command,options:t.options}))}async fallbackExecute(e,t={}){try{let s=await import("systeminformation"),i=s.default||s;switch(e){case"currentLoad":return await i.currentLoad();case"mem":return await i.mem();case"graphics":return await i.graphics();case"networkStats":return await i.networkStats();case"fsSize":return await i.fsSize();case"systemData":{let[n,a,c]=await Promise.all([i.osInfo(),i.versions(),i.time()]);return{os:n,ver:a,time:c}}default:throw new Error(`Unknown command: ${e}`)}}catch(s){throw u.warn(`Fallback execution failed for ${e}:`,s.message),s}}getStatus(){let e=this.checkOverload();return{enabled:this.enableWorkers,supported:this.workersSupported,totalWorkers:this.workers.length,busyWorkers:this.workers.filter(t=>t.isBusy).length,readyWorkers:this.workers.filter(t=>t.isReady).length,pendingTasks:this.pendingTasks.size,queuedTasks:this.taskQueue.length,degradation:{level:this.degradationLevel,since:this.degradationSince,queueSize:e.queueSize,utilizationPercent:e.utilizationPercent,circuitBreakerState:this.circuitBreakerState,consecutiveFailures:this.consecutiveFailures,successfulOperations:this.successfulOperations,overloadEvents:this.overloadEvents,lastOverloadTime:this.lastOverloadTime,totalRejected:this.totalRejected,totalShed:this.totalShed}}}async shutdown(){this.isShutdown=!0;for(let[t,s]of this.pendingTasks)s.timeout&&clearTimeout(s.timeout),s.reject(new Error("Worker pool shutting down"));this.pendingTasks.clear(),this.taskQueue=[];let e=this.workers.map(t=>t.terminate().catch(()=>{}));await Promise.all(e),this.workers=[],u.info("Worker pool shut down")}},Mh=new Hr,Nt=Mh});var ra=nc((jr,is)=>{var Gr=void 0,Vr=function(r){return Gr||(Gr=new Promise(function(e,t){var s=typeof r<"u"?r:{},i=s.onAbort;s.onAbort=function(o){t(new Error(o)),i&&i(o)},s.postRun=s.postRun||[],s.postRun.push(function(){e(s)}),is=void 0;var n;n||=typeof s<"u"?s:{};var a=!!globalThis.window,c=!!globalThis.WorkerGlobalScope,d=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";n.onRuntimeInitialized=function(){function o(y,R){switch(typeof R){case"boolean":Ql(y,R?1:0);break;case"number":Kl(y,R);break;case"string":Xl(y,R,-1,-1);break;case"object":if(R===null)po(y);else if(R.length!=null){var N=pr(R.length);O.set(R,N),Jl(y,N,R.length,-1),Fs(N)}else Er(y,"Wrong API use : tried to return a value of an unknown type ("+R+").",-1);break;default:po(y)}}function l(y,R){for(var N=[],$=0;$<y;$+=1){var Y=ot(R+4*$,"i32"),J=Vl(Y);if(J===1||J===2)Y=Yl(Y);else if(J===3)Y=zl(Y);else if(J===4){J=Y,Y=jl(J),J=ql(J);for(var Je=new Uint8Array(Y),ze=0;ze<Y;ze+=1)Je[ze]=O[J+ze];Y=Je}else Y=null;N.push(Y)}return N}function h(y,R){this.Qa=y,this.db=R,this.Oa=1,this.lb=[]}function f(y,R){if(this.db=R,this.eb=gr(y),this.eb===null)throw Error("Unable to allocate memory for the SQL string");this.kb=this.eb,this.Za=this.qb=null}function m(y){if(this.filename="dbfile_"+(4294967295*Math.random()>>>0),y!=null){var R=this.filename,N="/",$=R;if(N&&(N=typeof N=="string"?N:yi(N),$=R?Ds(N+"/"+R):N),R=Fn(!0,!0),$=El($,R),y){if(typeof y=="string"){N=Array(y.length);for(var Y=0,J=y.length;Y<J;++Y)N[Y]=y.charCodeAt(Y);y=N}hr($,R|146),N=ys($,577),so(N,y,0,y.length,0),Ti(N),hr($,R)}}this.handleError(B(this.filename,x)),this.db=ot(x,"i32"),yo(this.db),this.fb={},this.Sa={}}var x=Yt(4),A=n.cwrap,B=A("sqlite3_open","number",["string","number"]),X=A("sqlite3_close_v2","number",["number"]),z=A("sqlite3_exec","number",["number","string","number","number","number"]),ie=A("sqlite3_changes","number",["number"]),Se=A("sqlite3_prepare_v2","number",["number","string","number","number","number"]),co=A("sqlite3_sql","string",["number"]),Rl=A("sqlite3_normalized_sql","string",["number"]),ho=A("sqlite3_prepare_v2","number",["number","number","number","number","number"]),_l=A("sqlite3_bind_text","number",["number","number","number","number","number"]),uo=A("sqlite3_bind_blob","number",["number","number","number","number","number"]),Cl=A("sqlite3_bind_double","number",["number","number","number"]),Ll=A("sqlite3_bind_int","number",["number","number","number"]),kl=A("sqlite3_bind_parameter_index","number",["number","string"]),Ol=A("sqlite3_step","number",["number"]),Ml=A("sqlite3_errmsg","string",["number"]),Dl=A("sqlite3_column_count","number",["number"]),Nl=A("sqlite3_data_count","number",["number"]),$l=A("sqlite3_column_double","number",["number","number"]),fo=A("sqlite3_column_text","string",["number","number"]),Pl=A("sqlite3_column_blob","number",["number","number"]),Wl=A("sqlite3_column_bytes","number",["number","number"]),Fl=A("sqlite3_column_type","number",["number","number"]),Ul=A("sqlite3_column_name","string",["number","number"]),Bl=A("sqlite3_reset","number",["number"]),Hl=A("sqlite3_clear_bindings","number",["number"]),Gl=A("sqlite3_finalize","number",["number"]),go=A("sqlite3_create_function_v2","number","number string number number number number number number number".split(" ")),Vl=A("sqlite3_value_type","number",["number"]),jl=A("sqlite3_value_bytes","number",["number"]),zl=A("sqlite3_value_text","string",["number"]),ql=A("sqlite3_value_blob","number",["number"]),Yl=A("sqlite3_value_double","number",["number"]),Kl=A("sqlite3_result_double","",["number","number"]),po=A("sqlite3_result_null","",["number"]),Xl=A("sqlite3_result_text","",["number","string","number","number"]),Jl=A("sqlite3_result_blob","",["number","number","number","number"]),Ql=A("sqlite3_result_int","",["number","number"]),Er=A("sqlite3_result_error","",["number","string","number"]),mo=A("sqlite3_aggregate_context","number",["number","number"]),yo=A("RegisterExtensionFunctions","number",["number"]),wo=A("sqlite3_update_hook","number",["number","number","number"]);h.prototype.bind=function(y){if(!this.Qa)throw"Statement closed";return this.reset(),Array.isArray(y)?this.Cb(y):y!=null&&typeof y=="object"?this.Db(y):!0},h.prototype.step=function(){if(!this.Qa)throw"Statement closed";this.Oa=1;var y=Ol(this.Qa);switch(y){case 100:return!0;case 101:return!1;default:throw this.db.handleError(y)}},h.prototype.wb=function(y){return y==null&&(y=this.Oa,this.Oa+=1),$l(this.Qa,y)},h.prototype.Gb=function(y){if(y==null&&(y=this.Oa,this.Oa+=1),y=fo(this.Qa,y),typeof BigInt!="function")throw Error("BigInt is not supported");return BigInt(y)},h.prototype.Hb=function(y){return y==null&&(y=this.Oa,this.Oa+=1),fo(this.Qa,y)},h.prototype.getBlob=function(y){y==null&&(y=this.Oa,this.Oa+=1);var R=Wl(this.Qa,y);y=Pl(this.Qa,y);for(var N=new Uint8Array(R),$=0;$<R;$+=1)N[$]=O[y+$];return N},h.prototype.get=function(y,R){R=R||{},y!=null&&this.bind(y)&&this.step(),y=[];for(var N=Nl(this.Qa),$=0;$<N;$+=1)switch(Fl(this.Qa,$)){case 1:var Y=R.useBigInt?this.Gb($):this.wb($);y.push(Y);break;case 2:y.push(this.wb($));break;case 3:y.push(this.Hb($));break;case 4:y.push(this.getBlob($));break;default:y.push(null)}return y},h.prototype.getColumnNames=function(){for(var y=[],R=Dl(this.Qa),N=0;N<R;N+=1)y.push(Ul(this.Qa,N));return y},h.prototype.getAsObject=function(y,R){y=this.get(y,R),R=this.getColumnNames();for(var N={},$=0;$<R.length;$+=1)N[R[$]]=y[$];return N},h.prototype.getSQL=function(){return co(this.Qa)},h.prototype.getNormalizedSQL=function(){return Rl(this.Qa)},h.prototype.run=function(y){return y!=null&&this.bind(y),this.step(),this.reset()},h.prototype.tb=function(y,R){R==null&&(R=this.Oa,this.Oa+=1),y=gr(y),this.lb.push(y),this.db.handleError(_l(this.Qa,R,y,-1,0))},h.prototype.Bb=function(y,R){R==null&&(R=this.Oa,this.Oa+=1);var N=pr(y.length);O.set(y,N),this.lb.push(N),this.db.handleError(uo(this.Qa,R,N,y.length,0))},h.prototype.sb=function(y,R){R==null&&(R=this.Oa,this.Oa+=1),this.db.handleError((y===(y|0)?Ll:Cl)(this.Qa,R,y))},h.prototype.Eb=function(y){y==null&&(y=this.Oa,this.Oa+=1),uo(this.Qa,y,0,0,0)},h.prototype.ub=function(y,R){switch(R==null&&(R=this.Oa,this.Oa+=1),typeof y){case"string":this.tb(y,R);return;case"number":this.sb(y,R);return;case"bigint":this.tb(y.toString(),R);return;case"boolean":this.sb(y+0,R);return;case"object":if(y===null){this.Eb(R);return}if(y.length!=null){this.Bb(y,R);return}}throw"Wrong API use : tried to bind a value of an unknown type ("+y+")."},h.prototype.Db=function(y){var R=this;return Object.keys(y).forEach(function(N){var $=kl(R.Qa,N);$!==0&&R.ub(y[N],$)}),!0},h.prototype.Cb=function(y){for(var R=0;R<y.length;R+=1)this.ub(y[R],R+1);return!0},h.prototype.reset=function(){return this.freemem(),Hl(this.Qa)===0&&Bl(this.Qa)===0},h.prototype.freemem=function(){for(var y;(y=this.lb.pop())!==void 0;)Fs(y)},h.prototype.free=function(){this.freemem();var y=Gl(this.Qa)===0;return delete this.db.fb[this.Qa],this.Qa=0,y},f.prototype.next=function(){if(this.eb===null)return{done:!0};if(this.Za!==null&&(this.Za.free(),this.Za=null),!this.db.db)throw this.nb(),Error("Database closed");var y=yr(),R=Yt(4);mt(x),mt(R);try{this.db.handleError(ho(this.db.db,this.kb,-1,x,R)),this.kb=ot(R,"i32");var N=ot(x,"i32");return N===0?(this.nb(),{done:!0}):(this.Za=new h(N,this.db),this.db.fb[N]=this.Za,{value:this.Za,done:!1})}catch($){throw this.qb=de(this.kb),this.nb(),$}finally{mr(y)}},f.prototype.nb=function(){Fs(this.eb),this.eb=null},f.prototype.getRemainingSQL=function(){return this.qb!==null?this.qb:de(this.kb)},typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"&&(f.prototype[Symbol.iterator]=function(){return this}),m.prototype.run=function(y,R){if(!this.db)throw"Database closed";if(R){y=this.prepare(y,R);try{y.step()}finally{y.free()}}else this.handleError(z(this.db,y,0,0,x));return this},m.prototype.exec=function(y,R,N){if(!this.db)throw"Database closed";var $=null,Y=null,J=null;try{J=Y=gr(y);var Je=Yt(4);for(y=[];ot(J,"i8")!==0;){mt(x),mt(Je),this.handleError(ho(this.db,J,-1,x,Je));var ze=ot(x,"i32");if(J=ot(Je,"i32"),ze!==0){var We=null;for($=new h(ze,this),R!=null&&$.bind(R);$.step();)We===null&&(We={columns:$.getColumnNames(),values:[]},y.push(We)),We.values.push($.get(null,N));$.free()}}return y}catch(Qe){throw $&&$.free(),Qe}finally{Y&&Fs(Y)}},m.prototype.each=function(y,R,N,$,Y){typeof R=="function"&&($=N,N=R,R=void 0),y=this.prepare(y,R);try{for(;y.step();)N(y.getAsObject(null,Y))}finally{y.free()}if(typeof $=="function")return $()},m.prototype.prepare=function(y,R){if(mt(x),this.handleError(Se(this.db,y,-1,x,0)),y=ot(x,"i32"),y===0)throw"Nothing to prepare";var N=new h(y,this);return R!=null&&N.bind(R),this.fb[y]=N},m.prototype.iterateStatements=function(y){return new f(y,this)},m.prototype.export=function(){Object.values(this.fb).forEach(function(R){R.free()}),Object.values(this.Sa).forEach(It),this.Sa={},this.handleError(X(this.db));var y=bl(this.filename);return this.handleError(B(this.filename,x)),this.db=ot(x,"i32"),yo(this.db),y},m.prototype.close=function(){this.db!==null&&(Object.values(this.fb).forEach(function(y){y.free()}),Object.values(this.Sa).forEach(It),this.Sa={},this.Ya&&(It(this.Ya),this.Ya=void 0),this.handleError(X(this.db)),Jn("/"+this.filename),this.db=null)},m.prototype.handleError=function(y){if(y===0)return null;throw y=Ml(this.db),Error(y)},m.prototype.getRowsModified=function(){return ie(this.db)},m.prototype.create_function=function(y,R){Object.prototype.hasOwnProperty.call(this.Sa,y)&&(It(this.Sa[y]),delete this.Sa[y]);var N=Ws(function($,Y,J){Y=l(Y,J);try{var Je=R.apply(null,Y)}catch(ze){Er($,ze,-1);return}o($,Je)},"viii");return this.Sa[y]=N,this.handleError(go(this.db,y,R.length,1,0,N,0,0,0)),this},m.prototype.create_aggregate=function(y,R){var N=R.init||function(){return null},$=R.finalize||function(We){return We},Y=R.step;if(!Y)throw"An aggregate function must have a step function in "+y;var J={};Object.hasOwnProperty.call(this.Sa,y)&&(It(this.Sa[y]),delete this.Sa[y]),R=y+"__finalize",Object.hasOwnProperty.call(this.Sa,R)&&(It(this.Sa[R]),delete this.Sa[R]);var Je=Ws(function(We,Qe,Li){var Kt=mo(We,1);Object.hasOwnProperty.call(J,Kt)||(J[Kt]=N()),Qe=l(Qe,Li),Qe=[J[Kt]].concat(Qe);try{J[Kt]=Y.apply(null,Qe)}catch(Zl){delete J[Kt],Er(We,Zl,-1)}},"viii"),ze=Ws(function(We){var Qe=mo(We,1);try{var Li=$(J[Qe])}catch(Kt){delete J[Qe],Er(We,Kt,-1);return}o(We,Li),delete J[Qe]},"vi");return this.Sa[y]=Je,this.Sa[R]=ze,this.handleError(go(this.db,y,Y.length-1,1,0,0,Je,ze,0)),this},m.prototype.updateHook=function(y){return this.Ya&&(wo(this.db,0,0),It(this.Ya),this.Ya=void 0),y?(this.Ya=Ws(function(R,N,$,Y,J){switch(N){case 18:R="insert";break;case 23:R="update";break;case 9:R="delete";break;default:throw"unknown operationCode in updateHook callback: "+N}if($=de($),Y=de(Y),J>Number.MAX_SAFE_INTEGER)throw"rowId too big to fit inside a Number";y(R,$,Y,Number(J))},"viiiij"),wo(this.db,this.Ya,0),this):this},n.Database=m};var g="./this.program",p=(o,l)=>{throw l},T=globalThis.document?.currentScript?.src;typeof __filename<"u"?T=__filename:c&&(T=self.location.href);var b="",_,v;if(d){var S=Eo("node:fs");b=__dirname+"/",v=o=>(o=D(o)?new URL(o):o,S.readFileSync(o)),_=async o=>(o=D(o)?new URL(o):o,S.readFileSync(o,void 0)),1<process.argv.length&&(g=process.argv[1].replace(/\\/g,"/")),process.argv.slice(2),typeof is<"u"&&(is.exports=n),p=(o,l)=>{throw process.exitCode=o,l}}else if(a||c){try{b=new URL(".",T).href}catch{}c&&(v=o=>{var l=new XMLHttpRequest;return l.open("GET",o,!1),l.responseType="arraybuffer",l.send(null),new Uint8Array(l.response)}),_=async o=>{if(D(o))return new Promise((h,f)=>{var m=new XMLHttpRequest;m.open("GET",o,!0),m.responseType="arraybuffer",m.onload=()=>{m.status==200||m.status==0&&m.response?h(m.response):f(m.status)},m.onerror=f,m.send(null)});var l=await fetch(o,{credentials:"same-origin"});if(l.ok)return l.arrayBuffer();throw Error(l.status+" : "+l.url)}}var M=console.log.bind(console),j=console.error.bind(console),k,F=!1,ee,D=o=>o.startsWith("file://"),O,I,G,W,U,oe,ae,K;function me(){var o=wr.buffer;O=new Int8Array(o),G=new Int16Array(o),I=new Uint8Array(o),new Uint16Array(o),W=new Int32Array(o),U=new Uint32Array(o),oe=new Float32Array(o),ae=new Float64Array(o),K=new BigInt64Array(o),new BigUint64Array(o)}function se(o){throw n.onAbort?.(o),o="Aborted("+o+")",j(o),F=!0,new WebAssembly.RuntimeError(o+". Build with -sASSERTIONS for more info.")}var ue;async function Me(o){if(!k)try{var l=await _(o);return new Uint8Array(l)}catch{}if(o==ue&&k)o=new Uint8Array(k);else if(v)o=v(o);else throw"both async and sync fetching of the wasm failed";return o}async function nt(o,l){try{var h=await Me(o);return await WebAssembly.instantiate(h,l)}catch(f){j(`failed to asynchronously prepare wasm: ${f}`),se(f)}}async function le(o){var l=ue;if(!k&&!D(l)&&!d)try{var h=fetch(l,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(h,o)}catch(f){j(`wasm streaming compile failed: ${f}`),j("falling back to ArrayBuffer instantiation")}return nt(l,o)}class _e{name="ExitStatus";constructor(l){this.message=`Program terminated with exit(${l})`,this.status=l}}var Ht=o=>{for(;0<o.length;)o.shift()(n)},Os=[],ir=[],pt=()=>{var o=n.preRun.shift();ir.push(o)},Ve=0,Gt=null;function ot(o,l="i8"){switch(l.endsWith("*")&&(l="*"),l){case"i1":return O[o];case"i8":return O[o];case"i16":return G[o>>1];case"i32":return W[o>>2];case"i64":return K[o>>3];case"float":return oe[o>>2];case"double":return ae[o>>3];case"*":return U[o>>2];default:se(`invalid type for getValue: ${l}`)}}var ds=!0;function mt(o){var l="i32";switch(l.endsWith("*")&&(l="*"),l){case"i1":O[o]=0;break;case"i8":O[o]=0;break;case"i16":G[o>>1]=0;break;case"i32":W[o>>2]=0;break;case"i64":K[o>>3]=BigInt(0);break;case"float":oe[o>>2]=0;break;case"double":ae[o>>3]=0;break;case"*":U[o>>2]=0;break;default:se(`invalid type for setValue: ${l}`)}}var nr=new TextDecoder,or=(o,l,h,f)=>{if(h=l+h,f)return h;for(;o[l]&&!(l>=h);)++l;return l},de=(o,l,h)=>o?nr.decode(I.subarray(o,or(I,o,l,h))):"",Ms=(o,l)=>{for(var h=0,f=o.length-1;0<=f;f--){var m=o[f];m==="."?o.splice(f,1):m===".."?(o.splice(f,1),h++):h&&(o.splice(f,1),h--)}if(l)for(;h;h--)o.unshift("..");return o},Ds=o=>{var l=o.charAt(0)==="/",h=o.slice(-1)==="/";return(o=Ms(o.split("/").filter(f=>!!f),!l).join("/"))||l||(o="."),o&&h&&(o+="/"),(l?"/":"")+o},yt=o=>{var l=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(o).slice(1);return o=l[0],l=l[1],!o&&!l?".":(l&&=l.slice(0,-1),o+l)},fs=o=>o&&o.match(/([^\/]+|\/)\/*$/)[1],Vt=()=>{if(d){var o=Eo("node:crypto");return l=>o.randomFillSync(l)}return l=>crypto.getRandomValues(l)},$n=o=>{($n=Vt())(o)},hl=(...o)=>{for(var l="",h=!1,f=o.length-1;-1<=f&&!h;f--){if(h=0<=f?o[f]:"/",typeof h!="string")throw new TypeError("Arguments to path.resolve must be strings");if(!h)return"";l=h+"/"+l,h=h.charAt(0)==="/"}return l=Ms(l.split("/").filter(m=>!!m),!h).join("/"),(h?"/":"")+l||"."},Ns=o=>{var l=or(o,0);return nr.decode(o.buffer?o.subarray(0,l):new Uint8Array(o.slice(0,l)))},pi=[],gs=o=>{for(var l=0,h=0;h<o.length;++h){var f=o.charCodeAt(h);127>=f?l++:2047>=f?l+=2:55296<=f&&57343>=f?(l+=4,++h):l+=3}return l},at=(o,l,h,f)=>{if(!(0<f))return 0;var m=h;f=h+f-1;for(var x=0;x<o.length;++x){var A=o.codePointAt(x);if(127>=A){if(h>=f)break;l[h++]=A}else if(2047>=A){if(h+1>=f)break;l[h++]=192|A>>6,l[h++]=128|A&63}else if(65535>=A){if(h+2>=f)break;l[h++]=224|A>>12,l[h++]=128|A>>6&63,l[h++]=128|A&63}else{if(h+3>=f)break;l[h++]=240|A>>18,l[h++]=128|A>>12&63,l[h++]=128|A>>6&63,l[h++]=128|A&63,x++}}return l[h]=0,h-m},Pn=[];function Wn(o,l){Pn[o]={input:[],output:[],cb:l},Si(o,ul)}var ul={open(o){var l=Pn[o.node.rdev];if(!l)throw new L(43);o.tty=l,o.seekable=!1},close(o){o.tty.cb.fsync(o.tty)},fsync(o){o.tty.cb.fsync(o.tty)},read(o,l,h,f){if(!o.tty||!o.tty.cb.xb)throw new L(60);for(var m=0,x=0;x<f;x++){try{var A=o.tty.cb.xb(o.tty)}catch{throw new L(29)}if(A===void 0&&m===0)throw new L(6);if(A==null)break;m++,l[h+x]=A}return m&&(o.node.atime=Date.now()),m},write(o,l,h,f){if(!o.tty||!o.tty.cb.rb)throw new L(60);try{for(var m=0;m<f;m++)o.tty.cb.rb(o.tty,l[h+m])}catch{throw new L(29)}return f&&(o.node.mtime=o.node.ctime=Date.now()),m}},dl={xb(){e:{if(!pi.length){var o=null;if(d){var l=Buffer.alloc(256),h=0,f=process.stdin.fd;try{h=S.readSync(f,l,0,256)}catch(m){if(m.toString().includes("EOF"))h=0;else throw m}0<h&&(o=l.slice(0,h).toString("utf-8"))}else globalThis.window?.prompt&&(o=window.prompt("Input: "),o!==null&&(o+=`
|
|
15
|
-
`));if(!o){o=null;break e}l=Array(gs(o)+1),o=at(o,l,0,l.length),l.length=o,pi=l}o=pi.shift()}return o},rb(o,l){l===null||l===10?(M(Ns(o.output)),o.output=[]):l!=0&&o.output.push(l)},fsync(o){0<o.output?.length&&(M(Ns(o.output)),o.output=[])},Tb(){return{Ob:25856,Qb:5,Nb:191,Pb:35387,Mb:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},Ub(){return 0},Vb(){return[24,80]}},fl={rb(o,l){l===null||l===10?(j(Ns(o.output)),o.output=[]):l!=0&&o.output.push(l)},fsync(o){0<o.output?.length&&(j(Ns(o.output)),o.output=[])}},V={Wa:null,Xa(){return V.createNode(null,"/",16895,0)},createNode(o,l,h,f){if((h&61440)===24576||(h&61440)===4096)throw new L(63);return V.Wa||(V.Wa={dir:{node:{Ta:V.La.Ta,Ua:V.La.Ua,lookup:V.La.lookup,hb:V.La.hb,rename:V.La.rename,unlink:V.La.unlink,rmdir:V.La.rmdir,readdir:V.La.readdir,symlink:V.La.symlink},stream:{Va:V.Ma.Va}},file:{node:{Ta:V.La.Ta,Ua:V.La.Ua},stream:{Va:V.Ma.Va,read:V.Ma.read,write:V.Ma.write,ib:V.Ma.ib,jb:V.Ma.jb}},link:{node:{Ta:V.La.Ta,Ua:V.La.Ua,readlink:V.La.readlink},stream:{}},vb:{node:{Ta:V.La.Ta,Ua:V.La.Ua},stream:wl}}),h=Vn(o,l,h,f),De(h.mode)?(h.La=V.Wa.dir.node,h.Ma=V.Wa.dir.stream,h.Na={}):(h.mode&61440)===32768?(h.La=V.Wa.file.node,h.Ma=V.Wa.file.stream,h.Ra=0,h.Na=null):(h.mode&61440)===40960?(h.La=V.Wa.link.node,h.Ma=V.Wa.link.stream):(h.mode&61440)===8192&&(h.La=V.Wa.vb.node,h.Ma=V.Wa.vb.stream),h.atime=h.mtime=h.ctime=Date.now(),o&&(o.Na[l]=h,o.atime=o.mtime=o.ctime=h.atime),h},Sb(o){return o.Na?o.Na.subarray?o.Na.subarray(0,o.Ra):new Uint8Array(o.Na):new Uint8Array(0)},La:{Ta(o){var l={};return l.dev=(o.mode&61440)===8192?o.id:1,l.ino=o.id,l.mode=o.mode,l.nlink=1,l.uid=0,l.gid=0,l.rdev=o.rdev,De(o.mode)?l.size=4096:(o.mode&61440)===32768?l.size=o.Ra:(o.mode&61440)===40960?l.size=o.link.length:l.size=0,l.atime=new Date(o.atime),l.mtime=new Date(o.mtime),l.ctime=new Date(o.ctime),l.blksize=4096,l.blocks=Math.ceil(l.size/l.blksize),l},Ua(o,l){for(var h of["mode","atime","mtime","ctime"])l[h]!=null&&(o[h]=l[h]);l.size!==void 0&&(l=l.size,o.Ra!=l&&(l==0?(o.Na=null,o.Ra=0):(h=o.Na,o.Na=new Uint8Array(l),h&&o.Na.set(h.subarray(0,Math.min(l,o.Ra))),o.Ra=l)))},lookup(){throw V.mb||(V.mb=new L(44),V.mb.stack="<generic error, no stack>"),V.mb},hb(o,l,h,f){return V.createNode(o,l,h,f)},rename(o,l,h){try{var f=jt(l,h)}catch{}if(f){if(De(o.mode))for(var m in f.Na)throw new L(55);Ei(f)}delete o.parent.Na[o.name],l.Na[h]=o,o.name=h,l.ctime=l.mtime=o.parent.ctime=o.parent.mtime=Date.now()},unlink(o,l){delete o.Na[l],o.ctime=o.mtime=Date.now()},rmdir(o,l){var h=jt(o,l),f;for(f in h.Na)throw new L(55);delete o.Na[l],o.ctime=o.mtime=Date.now()},readdir(o){return[".","..",...Object.keys(o.Na)]},symlink(o,l,h){return o=V.createNode(o,l,41471,0),o.link=h,o},readlink(o){if((o.mode&61440)!==40960)throw new L(28);return o.link}},Ma:{read(o,l,h,f,m){var x=o.node.Na;if(m>=o.node.Ra)return 0;if(o=Math.min(o.node.Ra-m,f),8<o&&x.subarray)l.set(x.subarray(m,m+o),h);else for(f=0;f<o;f++)l[h+f]=x[m+f];return o},write(o,l,h,f,m,x){if(l.buffer===O.buffer&&(x=!1),!f)return 0;if(o=o.node,o.mtime=o.ctime=Date.now(),l.subarray&&(!o.Na||o.Na.subarray)){if(x)return o.Na=l.subarray(h,h+f),o.Ra=f;if(o.Ra===0&&m===0)return o.Na=l.slice(h,h+f),o.Ra=f;if(m+f<=o.Ra)return o.Na.set(l.subarray(h,h+f),m),f}x=m+f;var A=o.Na?o.Na.length:0;if(A>=x||(x=Math.max(x,A*(1048576>A?2:1.125)>>>0),A!=0&&(x=Math.max(x,256)),A=o.Na,o.Na=new Uint8Array(x),0<o.Ra&&o.Na.set(A.subarray(0,o.Ra),0)),o.Na.subarray&&l.subarray)o.Na.set(l.subarray(h,h+f),m);else for(x=0;x<f;x++)o.Na[m+x]=l[h+x];return o.Ra=Math.max(o.Ra,m+f),f},Va(o,l,h){if(h===1?l+=o.position:h===2&&(o.node.mode&61440)===32768&&(l+=o.node.Ra),0>l)throw new L(28);return l},ib(o,l,h,f,m){if((o.node.mode&61440)!==32768)throw new L(43);if(o=o.node.Na,m&2||!o||o.buffer!==O.buffer){m=!0,f=65536*Math.ceil(l/65536);var x=ao(65536,f);if(x&&I.fill(0,x,x+f),f=x,!f)throw new L(48);o&&((0<h||h+l<o.length)&&(o.subarray?o=o.subarray(h,h+l):o=Array.prototype.slice.call(o,h,h+l)),O.set(o,f))}else m=!1,f=o.byteOffset;return{Kb:f,Ab:m}},jb(o,l,h,f){return V.Ma.write(o,l,0,f,h,!1),0}}},Fn=(o,l)=>{var h=0;return o&&(h|=365),l&&(h|=146),h},mi=null,Un={},ps=[],gl=1,Tt=null,Bn=!1,Hn=!0,Gn={},L=class{name="ErrnoError";constructor(o){this.Pa=o}},pl=class{gb={};node=null;get flags(){return this.gb.flags}set flags(o){this.gb.flags=o}get position(){return this.gb.position}set position(o){this.gb.position=o}},ml=class{La={};Ma={};ab=null;constructor(o,l,h,f){o||=this,this.parent=o,this.Xa=o.Xa,this.id=gl++,this.name=l,this.mode=h,this.rdev=f,this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&365)===365}set read(o){o?this.mode|=365:this.mode&=-366}get write(){return(this.mode&146)===146}set write(o){o?this.mode|=146:this.mode&=-147}};function je(o,l={}){if(!o)throw new L(44);l.ob??(l.ob=!0),o.charAt(0)==="/"||(o="//"+o);var h=0;e:for(;40>h;h++){o=o.split("/").filter(B=>!!B);for(var f=mi,m="/",x=0;x<o.length;x++){var A=x===o.length-1;if(A&&l.parent)break;if(o[x]!==".")if(o[x]==="..")if(m=yt(m),f===f.parent){o=m+"/"+o.slice(x+1).join("/"),h--;continue e}else f=f.parent;else{m=Ds(m+"/"+o[x]);try{f=jt(f,o[x])}catch(B){if(B?.Pa===44&&A&&l.Jb)return{path:m};throw B}if(!f.ab||A&&!l.ob||(f=f.ab.root),(f.mode&61440)===40960&&(!A||l.$a)){if(!f.La.readlink)throw new L(52);f=f.La.readlink(f),f.charAt(0)==="/"||(f=yt(m)+"/"+f),o=f+"/"+o.slice(x+1).join("/");continue e}}}return{path:m,node:f}}throw new L(32)}function yi(o){for(var l;;){if(o===o.parent)return o=o.Xa.zb,l?o[o.length-1]!=="/"?`${o}/${l}`:o+l:o;l=l?`${o.name}/${l}`:o.name,o=o.parent}}function wi(o,l){for(var h=0,f=0;f<l.length;f++)h=(h<<5)-h+l.charCodeAt(f)|0;return(o+h>>>0)%Tt.length}function Ei(o){var l=wi(o.parent.id,o.name);if(Tt[l]===o)Tt[l]=o.bb;else for(l=Tt[l];l;){if(l.bb===o){l.bb=o.bb;break}l=l.bb}}function jt(o,l){var h=De(o.mode)?(h=ms(o,"x"))?h:o.La.lookup?0:2:54;if(h)throw new L(h);for(h=Tt[wi(o.id,l)];h;h=h.bb){var f=h.name;if(h.parent.id===o.id&&f===l)return h}return o.La.lookup(o,l)}function Vn(o,l,h,f){return o=new ml(o,l,h,f),l=wi(o.parent.id,o.name),o.bb=Tt[l],Tt[l]=o}function De(o){return(o&61440)===16384}function jn(o){var l=["r","w","rw"][o&3];return o&512&&(l+="w"),l}function ms(o,l){if(Hn)return 0;if(!l.includes("r")||o.mode&292){if(l.includes("w")&&!(o.mode&146)||l.includes("x")&&!(o.mode&73))return 2}else return 2;return 0}function zn(o,l){if(!De(o.mode))return 54;try{return jt(o,l),20}catch{}return ms(o,"wx")}function qn(o,l,h){try{var f=jt(o,l)}catch(m){return m.Pa}if(o=ms(o,"wx"))return o;if(h){if(!De(f.mode))return 54;if(f===f.parent||yi(f)==="/")return 10}else if(De(f.mode))return 31;return 0}function ar(o){if(!o)throw new L(63);return o}function Ce(o){if(o=ps[o],!o)throw new L(8);return o}function Yn(o,l=-1){if(o=Object.assign(new pl,o),l==-1)e:{for(l=0;4096>=l;l++)if(!ps[l])break e;throw new L(33)}return o.fd=l,ps[l]=o}function yl(o,l=-1){return o=Yn(o,l),o.Ma?.Rb?.(o),o}function bi(o,l,h){var f=o?.Ma.Ua;o=f?o:l,f??=l.La.Ua,ar(f),f(o,h)}var wl={open(o){o.Ma=Un[o.node.rdev].Ma,o.Ma.open?.(o)},Va(){throw new L(70)}};function Si(o,l){Un[o]={Ma:l}}function Kn(o,l){var h=l==="/";if(h&&mi)throw new L(10);if(!h&&l){var f=je(l,{ob:!1});if(l=f.path,f=f.node,f.ab)throw new L(10);if(!De(f.mode))throw new L(54)}l={type:o,Wb:{},zb:l,Ib:[]},o=o.Xa(l),o.Xa=l,l.root=o,h?mi=o:f&&(f.ab=l,f.Xa&&f.Xa.Ib.push(l))}function lr(o,l,h){var f=je(o,{parent:!0}).node;if(o=fs(o),!o)throw new L(28);if(o==="."||o==="..")throw new L(20);var m=zn(f,o);if(m)throw new L(m);if(!f.La.hb)throw new L(63);return f.La.hb(f,o,l,h)}function El(o,l=438){return lr(o,l&4095|32768,0)}function lt(o,l=511){return lr(o,l&1023|16384,0)}function cr(o,l,h){typeof h>"u"&&(h=l,l=438),lr(o,l|8192,h)}function xi(o,l){if(!hl(o))throw new L(44);var h=je(l,{parent:!0}).node;if(!h)throw new L(44);l=fs(l);var f=zn(h,l);if(f)throw new L(f);if(!h.La.symlink)throw new L(63);h.La.symlink(h,l,o)}function Xn(o){var l=je(o,{parent:!0}).node;o=fs(o);var h=jt(l,o),f=qn(l,o,!0);if(f)throw new L(f);if(!l.La.rmdir)throw new L(63);if(h.ab)throw new L(10);l.La.rmdir(l,o),Ei(h)}function Jn(o){var l=je(o,{parent:!0}).node;if(!l)throw new L(44);o=fs(o);var h=jt(l,o),f=qn(l,o,!1);if(f)throw new L(f);if(!l.La.unlink)throw new L(63);if(h.ab)throw new L(10);l.La.unlink(l,o),Ei(h)}function $s(o,l){return o=je(o,{$a:!l}).node,ar(o.La.Ta)(o)}function Qn(o,l,h,f){bi(o,l,{mode:h&4095|l.mode&-4096,ctime:Date.now(),Fb:f})}function hr(o,l){o=typeof o=="string"?je(o,{$a:!0}).node:o,Qn(null,o,l)}function Zn(o,l,h){if(De(l.mode))throw new L(31);if((l.mode&61440)!==32768)throw new L(28);var f=ms(l,"w");if(f)throw new L(f);bi(o,l,{size:h,timestamp:Date.now()})}function ys(o,l,h=438){if(o==="")throw new L(44);if(typeof l=="string"){var f={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090}[l];if(typeof f>"u")throw Error(`Unknown file open mode: ${l}`);l=f}if(h=l&64?h&4095|32768:0,typeof o=="object")f=o;else{var m=o.endsWith("/");o=je(o,{$a:!(l&131072),Jb:!0}),f=o.node,o=o.path}var x=!1;if(l&64)if(f){if(l&128)throw new L(20)}else{if(m)throw new L(31);f=lr(o,h|511,0),x=!0}if(!f)throw new L(44);if((f.mode&61440)===8192&&(l&=-513),l&65536&&!De(f.mode))throw new L(54);if(!x&&(m=f?(f.mode&61440)===40960?32:De(f.mode)&&(jn(l)!=="r"||l&576)?31:ms(f,jn(l)):44))throw new L(m);return l&512&&!x&&(m=f,m=typeof m=="string"?je(m,{$a:!0}).node:m,Zn(null,m,0)),l&=-131713,m=Yn({node:f,path:yi(f),flags:l,seekable:!0,position:0,Ma:f.Ma,Lb:[],error:!1}),m.Ma.open&&m.Ma.open(m),x&&hr(f,h&511),!n.logReadFiles||l&1||o in Gn||(Gn[o]=1),m}function Ti(o){if(o.fd===null)throw new L(8);o.pb&&(o.pb=null);try{o.Ma.close&&o.Ma.close(o)}catch(l){throw l}finally{ps[o.fd]=null}o.fd=null}function eo(o,l,h){if(o.fd===null)throw new L(8);if(!o.seekable||!o.Ma.Va)throw new L(70);if(h!=0&&h!=1&&h!=2)throw new L(28);o.position=o.Ma.Va(o,l,h),o.Lb=[]}function to(o,l,h,f,m){if(0>f||0>m)throw new L(28);if(o.fd===null)throw new L(8);if((o.flags&2097155)===1)throw new L(8);if(De(o.node.mode))throw new L(31);if(!o.Ma.read)throw new L(28);var x=typeof m<"u";if(!x)m=o.position;else if(!o.seekable)throw new L(70);return l=o.Ma.read(o,l,h,f,m),x||(o.position+=l),l}function so(o,l,h,f,m){if(0>f||0>m)throw new L(28);if(o.fd===null)throw new L(8);if((o.flags&2097155)===0)throw new L(8);if(De(o.node.mode))throw new L(31);if(!o.Ma.write)throw new L(28);o.seekable&&o.flags&1024&&eo(o,0,2);var x=typeof m<"u";if(!x)m=o.position;else if(!o.seekable)throw new L(70);return l=o.Ma.write(o,l,h,f,m,void 0),x||(o.position+=l),l}function bl(o){var l=l||0,h="binary";h!=="utf8"&&h!=="binary"&&se(`Invalid encoding type "${h}"`),l=ys(o,l),o=$s(o).size;var f=new Uint8Array(o);return to(l,f,0,o,0),h==="utf8"&&(f=Ns(f)),Ti(l),f}function vt(o,l,h){o=Ds("/dev/"+o);var f=Fn(!!l,!!h);vt.yb??(vt.yb=64);var m=vt.yb++<<8|0;Si(m,{open(x){x.seekable=!1},close(){h?.buffer?.length&&h(10)},read(x,A,B,X){for(var z=0,ie=0;ie<X;ie++){try{var Se=l()}catch{throw new L(29)}if(Se===void 0&&z===0)throw new L(6);if(Se==null)break;z++,A[B+ie]=Se}return z&&(x.node.atime=Date.now()),z},write(x,A,B,X){for(var z=0;z<X;z++)try{h(A[B+z])}catch{throw new L(29)}return X&&(x.node.mtime=x.node.ctime=Date.now()),z}}),cr(o,f,m)}var re={};function zt(o,l,h){if(l.charAt(0)==="/")return l;if(o=o===-100?"/":Ce(o).path,l.length==0){if(!h)throw new L(44);return o}return o+"/"+l}function ur(o,l){U[o>>2]=l.dev,U[o+4>>2]=l.mode,U[o+8>>2]=l.nlink,U[o+12>>2]=l.uid,U[o+16>>2]=l.gid,U[o+20>>2]=l.rdev,K[o+24>>3]=BigInt(l.size),W[o+32>>2]=4096,W[o+36>>2]=l.blocks;var h=l.atime.getTime(),f=l.mtime.getTime(),m=l.ctime.getTime();return K[o+40>>3]=BigInt(Math.floor(h/1e3)),U[o+48>>2]=h%1e3*1e6,K[o+56>>3]=BigInt(Math.floor(f/1e3)),U[o+64>>2]=f%1e3*1e6,K[o+72>>3]=BigInt(Math.floor(m/1e3)),U[o+80>>2]=m%1e3*1e6,K[o+88>>3]=BigInt(l.ino),0}var dr=void 0,fr=()=>{var o=W[+dr>>2];return dr+=4,o},vi=0,Sl=[0,31,60,91,121,152,182,213,244,274,305,335],xl=[0,31,59,90,120,151,181,212,243,273,304,334],Ps={},ro=o=>{ee=o,ds||0<vi||(n.onExit?.(o),F=!0),p(o,new _e(o))},Tl=o=>{if(!F)try{o()}catch(l){l instanceof _e||l=="unwind"||p(1,l)}finally{if(!(ds||0<vi))try{ee=o=ee,ro(o)}catch(l){l instanceof _e||l=="unwind"||p(1,l)}}},Ii={},io=()=>{if(!Ai){var o={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:(globalThis.navigator?.language??"C").replace("-","_")+".UTF-8",_:g||"./this.program"},l;for(l in Ii)Ii[l]===void 0?delete o[l]:o[l]=Ii[l];var h=[];for(l in o)h.push(`${l}=${o[l]}`);Ai=h}return Ai},Ai,vl=(o,l,h,f)=>{var m={string:z=>{var ie=0;if(z!=null&&z!==0){ie=gs(z)+1;var Se=Yt(ie);at(z,I,Se,ie),ie=Se}return ie},array:z=>{var ie=Yt(z.length);return O.set(z,ie),ie}};o=n["_"+o];var x=[],A=0;if(f)for(var B=0;B<f.length;B++){var X=m[h[B]];X?(A===0&&(A=yr()),x[B]=X(f[B])):x[B]=f[B]}return h=o(...x),h=(function(z){return A!==0&&mr(A),l==="string"?de(z):l==="boolean"?!!z:z})(h)},gr=o=>{var l=gs(o)+1,h=pr(l);return h&&at(o,I,h,l),h},qt,Ri=[],It=o=>{qt.delete(At.get(o)),At.set(o,null),Ri.push(o)},no=o=>{let l=o.length;return[l%128|128,l>>7,...o]},Il={i:127,p:127,j:126,f:125,d:124,e:111},oo=o=>no(Array.from(o,l=>Il[l])),Ws=(o,l)=>{if(!qt){qt=new WeakMap;var h=At.length;if(qt)for(var f=0;f<0+h;f++){var m=At.get(f);m&&qt.set(m,f)}}if(h=qt.get(o)||0)return h;h=Ri.length?Ri.pop():At.grow(1);try{At.set(h,o)}catch(x){if(!(x instanceof TypeError))throw x;l=Uint8Array.of(0,97,115,109,1,0,0,0,1,...no([1,96,...oo(l.slice(1)),...oo(l[0]==="v"?"":l[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),l=new WebAssembly.Module(l),l=new WebAssembly.Instance(l,{e:{f:o}}).exports.f,At.set(h,l)}return qt.set(o,h),h};if(Tt=Array(4096),Kn(V,"/"),lt("/tmp"),lt("/home"),lt("/home/web_user"),(function(){lt("/dev"),Si(259,{read:()=>0,write:(f,m,x,A)=>A,Va:()=>0}),cr("/dev/null",259),Wn(1280,dl),Wn(1536,fl),cr("/dev/tty",1280),cr("/dev/tty1",1536);var o=new Uint8Array(1024),l=0,h=()=>(l===0&&($n(o),l=o.byteLength),o[--l]);vt("random",h),vt("urandom",h),lt("/dev/shm"),lt("/dev/shm/tmp")})(),(function(){lt("/proc");var o=lt("/proc/self");lt("/proc/self/fd"),Kn({Xa(){var l=Vn(o,"fd",16895,73);return l.Ma={Va:V.Ma.Va},l.La={lookup(h,f){h=+f;var m=Ce(h);return h={parent:null,Xa:{zb:"fake"},La:{readlink:()=>m.path},id:h+1},h.parent=h},readdir(){return Array.from(ps.entries()).filter(([,h])=>h).map(([h])=>h.toString())}},l}},"/proc/self/fd")})(),n.noExitRuntime&&(ds=n.noExitRuntime),n.print&&(M=n.print),n.printErr&&(j=n.printErr),n.wasmBinary&&(k=n.wasmBinary),n.thisProgram&&(g=n.thisProgram),n.preInit)for(typeof n.preInit=="function"&&(n.preInit=[n.preInit]);0<n.preInit.length;)n.preInit.shift()();n.stackSave=()=>yr(),n.stackRestore=o=>mr(o),n.stackAlloc=o=>Yt(o),n.cwrap=(o,l,h,f)=>{var m=!h||h.every(x=>x==="number"||x==="boolean");return l!=="string"&&m&&!f?n["_"+o]:(...x)=>vl(o,l,h,x)},n.addFunction=Ws,n.removeFunction=It,n.UTF8ToString=de,n.stringToNewUTF8=gr,n.writeArrayToMemory=(o,l)=>{O.set(o,l)};var pr,Fs,ao,lo,mr,Yt,yr,wr,At,Al={a:(o,l,h,f)=>se(`Assertion failed: ${de(o)}, at: `+[l?de(l):"unknown filename",h,f?de(f):"unknown function"]),i:function(o,l){try{return o=de(o),hr(o,l),0}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return-h.Pa}},L:function(o,l,h){try{if(l=de(l),l=zt(o,l),h&-8)return-28;var f=je(l,{$a:!0}).node;return f?(o="",h&4&&(o+="r"),h&2&&(o+="w"),h&1&&(o+="x"),o&&ms(f,o)?-2:0):-44}catch(m){if(typeof re>"u"||m.name!=="ErrnoError")throw m;return-m.Pa}},j:function(o,l){try{var h=Ce(o);return Qn(h,h.node,l,!1),0}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return-f.Pa}},h:function(o){try{var l=Ce(o);return bi(l,l.node,{timestamp:Date.now(),Fb:!1}),0}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return-h.Pa}},b:function(o,l,h){dr=h;try{var f=Ce(o);switch(l){case 0:var m=fr();if(0>m)break;for(;ps[m];)m++;return yl(f,m).fd;case 1:case 2:return 0;case 3:return f.flags;case 4:return m=fr(),f.flags|=m,0;case 12:return m=fr(),G[m+0>>1]=2,0;case 13:case 14:return 0}return-28}catch(x){if(typeof re>"u"||x.name!=="ErrnoError")throw x;return-x.Pa}},g:function(o,l){try{var h=Ce(o),f=h.node,m=h.Ma.Ta;o=m?h:f,m??=f.La.Ta,ar(m);var x=m(o);return ur(l,x)}catch(A){if(typeof re>"u"||A.name!=="ErrnoError")throw A;return-A.Pa}},H:function(o,l){l=-9007199254740992>l||9007199254740992<l?NaN:Number(l);try{if(isNaN(l))return-61;var h=Ce(o);if(0>l||(h.flags&2097155)===0)throw new L(28);return Zn(h,h.node,l),0}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return-f.Pa}},G:function(o,l){try{if(l===0)return-28;var h=gs("/")+1;return l<h?-68:(at("/",I,o,l),h)}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return-f.Pa}},K:function(o,l){try{return o=de(o),ur(l,$s(o,!0))}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return-h.Pa}},C:function(o,l,h){try{return l=de(l),l=zt(o,l),lt(l,h),0}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return-f.Pa}},J:function(o,l,h,f){try{l=de(l);var m=f&256;return l=zt(o,l,f&4096),ur(h,m?$s(l,!0):$s(l))}catch(x){if(typeof re>"u"||x.name!=="ErrnoError")throw x;return-x.Pa}},x:function(o,l,h,f){dr=f;try{l=de(l),l=zt(o,l);var m=f?fr():0;return ys(l,h,m).fd}catch(x){if(typeof re>"u"||x.name!=="ErrnoError")throw x;return-x.Pa}},v:function(o,l,h,f){try{if(l=de(l),l=zt(o,l),0>=f)return-28;var m=je(l).node;if(!m)throw new L(44);if(!m.La.readlink)throw new L(28);var x=m.La.readlink(m),A=Math.min(f,gs(x)),B=O[h+A];return at(x,I,h,f+1),O[h+A]=B,A}catch(X){if(typeof re>"u"||X.name!=="ErrnoError")throw X;return-X.Pa}},u:function(o){try{return o=de(o),Xn(o),0}catch(l){if(typeof re>"u"||l.name!=="ErrnoError")throw l;return-l.Pa}},f:function(o,l){try{return o=de(o),ur(l,$s(o))}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return-h.Pa}},r:function(o,l,h){try{if(l=de(l),l=zt(o,l),h)if(h===512)Xn(l);else return-28;else Jn(l);return 0}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return-f.Pa}},q:function(o,l,h){try{l=de(l),l=zt(o,l,!0);var f=Date.now(),m,x;if(h){var A=U[h>>2]+4294967296*W[h+4>>2],B=W[h+8>>2];B==1073741823?m=f:B==1073741822?m=null:m=1e3*A+B/1e6,h+=16,A=U[h>>2]+4294967296*W[h+4>>2],B=W[h+8>>2],B==1073741823?x=f:B==1073741822?x=null:x=1e3*A+B/1e6}else x=m=f;if((x??m)!==null){o=m;var X=je(l,{$a:!0}).node;ar(X.La.Ua)(X,{atime:o,mtime:x})}return 0}catch(z){if(typeof re>"u"||z.name!=="ErrnoError")throw z;return-z.Pa}},m:()=>se(""),l:()=>{ds=!1,vi=0},A:function(o,l){o=-9007199254740992>o||9007199254740992<o?NaN:Number(o),o=new Date(1e3*o),W[l>>2]=o.getSeconds(),W[l+4>>2]=o.getMinutes(),W[l+8>>2]=o.getHours(),W[l+12>>2]=o.getDate(),W[l+16>>2]=o.getMonth(),W[l+20>>2]=o.getFullYear()-1900,W[l+24>>2]=o.getDay();var h=o.getFullYear();W[l+28>>2]=(h%4!==0||h%100===0&&h%400!==0?xl:Sl)[o.getMonth()]+o.getDate()-1|0,W[l+36>>2]=-(60*o.getTimezoneOffset()),h=new Date(o.getFullYear(),6,1).getTimezoneOffset();var f=new Date(o.getFullYear(),0,1).getTimezoneOffset();W[l+32>>2]=(h!=f&&o.getTimezoneOffset()==Math.min(f,h))|0},y:function(o,l,h,f,m,x,A){m=-9007199254740992>m||9007199254740992<m?NaN:Number(m);try{var B=Ce(f);if((l&2)!==0&&(h&2)===0&&(B.flags&2097155)!==2)throw new L(2);if((B.flags&2097155)===1)throw new L(2);if(!B.Ma.ib)throw new L(43);if(!o)throw new L(28);var X=B.Ma.ib(B,o,m,l,h),z=X.Kb;return W[x>>2]=X.Ab,U[A>>2]=z,0}catch(ie){if(typeof re>"u"||ie.name!=="ErrnoError")throw ie;return-ie.Pa}},z:function(o,l,h,f,m,x){x=-9007199254740992>x||9007199254740992<x?NaN:Number(x);try{var A=Ce(m);if(h&2){if(h=x,(A.node.mode&61440)!==32768)throw new L(43);if(!(f&2)){var B=I.slice(o,o+l);A.Ma.jb&&A.Ma.jb(A,B,h,l,f)}}}catch(X){if(typeof re>"u"||X.name!=="ErrnoError")throw X;return-X.Pa}},n:(o,l)=>{if(Ps[o]&&(clearTimeout(Ps[o].id),delete Ps[o]),!l)return 0;var h=setTimeout(()=>{delete Ps[o],Tl(()=>lo(o,performance.now()))},l);return Ps[o]={id:h,Xb:l},0},B:(o,l,h,f)=>{var m=new Date().getFullYear(),x=new Date(m,0,1).getTimezoneOffset();m=new Date(m,6,1).getTimezoneOffset(),U[o>>2]=60*Math.max(x,m),W[l>>2]=+(x!=m),l=A=>{var B=Math.abs(A);return`UTC${0<=A?"-":"+"}${String(Math.floor(B/60)).padStart(2,"0")}${String(B%60).padStart(2,"0")}`},o=l(x),l=l(m),m<x?(at(o,I,h,17),at(l,I,f,17)):(at(o,I,f,17),at(l,I,h,17))},d:()=>Date.now(),s:()=>2147483648,c:()=>performance.now(),o:o=>{var l=I.length;if(o>>>=0,2147483648<o)return!1;for(var h=1;4>=h;h*=2){var f=l*(1+.2/h);f=Math.min(f,o+100663296);e:{f=(Math.min(2147483648,65536*Math.ceil(Math.max(o,f)/65536))-wr.buffer.byteLength+65535)/65536|0;try{wr.grow(f),me();var m=1;break e}catch{}m=void 0}if(m)return!0}return!1},E:(o,l)=>{var h=0,f=0,m;for(m of io()){var x=l+h;U[o+f>>2]=x,h+=at(m,I,x,1/0)+1,f+=4}return 0},F:(o,l)=>{var h=io();U[o>>2]=h.length,o=0;for(var f of h)o+=gs(f)+1;return U[l>>2]=o,0},e:function(o){try{var l=Ce(o);return Ti(l),0}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return h.Pa}},p:function(o,l){try{var h=Ce(o);return O[l]=h.tty?2:De(h.mode)?3:(h.mode&61440)===40960?7:4,G[l+2>>1]=0,K[l+8>>3]=BigInt(0),K[l+16>>3]=BigInt(0),0}catch(f){if(typeof re>"u"||f.name!=="ErrnoError")throw f;return f.Pa}},w:function(o,l,h,f){try{e:{var m=Ce(o);o=l;for(var x,A=l=0;A<h;A++){var B=U[o>>2],X=U[o+4>>2];o+=8;var z=to(m,O,B,X,x);if(0>z){var ie=-1;break e}if(l+=z,z<X)break;typeof x<"u"&&(x+=z)}ie=l}return U[f>>2]=ie,0}catch(Se){if(typeof re>"u"||Se.name!=="ErrnoError")throw Se;return Se.Pa}},D:function(o,l,h,f){l=-9007199254740992>l||9007199254740992<l?NaN:Number(l);try{if(isNaN(l))return 61;var m=Ce(o);return eo(m,l,h),K[f>>3]=BigInt(m.position),m.pb&&l===0&&h===0&&(m.pb=null),0}catch(x){if(typeof re>"u"||x.name!=="ErrnoError")throw x;return x.Pa}},I:function(o){try{var l=Ce(o);return l.Ma?.fsync?.(l)}catch(h){if(typeof re>"u"||h.name!=="ErrnoError")throw h;return h.Pa}},t:function(o,l,h,f){try{e:{var m=Ce(o);o=l;for(var x,A=l=0;A<h;A++){var B=U[o>>2],X=U[o+4>>2];o+=8;var z=so(m,O,B,X,x);if(0>z){var ie=-1;break e}if(l+=z,z<X)break;typeof x<"u"&&(x+=z)}ie=l}return U[f>>2]=ie,0}catch(Se){if(typeof re>"u"||Se.name!=="ErrnoError")throw Se;return Se.Pa}},k:ro};function _i(){function o(){if(n.calledRun=!0,!F){if(!n.noFSInit&&!Bn){var l,h;Bn=!0,l??=n.stdin,h??=n.stdout,f??=n.stderr,l?vt("stdin",l):xi("/dev/tty","/dev/stdin"),h?vt("stdout",null,h):xi("/dev/tty","/dev/stdout"),f?vt("stderr",null,f):xi("/dev/tty1","/dev/stderr"),ys("/dev/stdin",0),ys("/dev/stdout",1),ys("/dev/stderr",1)}if(Ci.N(),Hn=!1,n.onRuntimeInitialized?.(),n.postRun)for(typeof n.postRun=="function"&&(n.postRun=[n.postRun]);n.postRun.length;){var f=n.postRun.shift();Os.push(f)}Ht(Os)}}if(0<Ve)Gt=_i;else{if(n.preRun)for(typeof n.preRun=="function"&&(n.preRun=[n.preRun]);n.preRun.length;)pt();Ht(ir),0<Ve?Gt=_i:n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),o()},1)):o()}}var Ci;return(async function(){function o(h){return h=Ci=h.exports,n._sqlite3_free=h.P,n._sqlite3_value_text=h.Q,n._sqlite3_prepare_v2=h.R,n._sqlite3_step=h.S,n._sqlite3_reset=h.T,n._sqlite3_exec=h.U,n._sqlite3_finalize=h.V,n._sqlite3_column_name=h.W,n._sqlite3_column_text=h.X,n._sqlite3_column_type=h.Y,n._sqlite3_errmsg=h.Z,n._sqlite3_clear_bindings=h._,n._sqlite3_value_blob=h.$,n._sqlite3_value_bytes=h.aa,n._sqlite3_value_double=h.ba,n._sqlite3_value_int=h.ca,n._sqlite3_value_type=h.da,n._sqlite3_result_blob=h.ea,n._sqlite3_result_double=h.fa,n._sqlite3_result_error=h.ga,n._sqlite3_result_int=h.ha,n._sqlite3_result_int64=h.ia,n._sqlite3_result_null=h.ja,n._sqlite3_result_text=h.ka,n._sqlite3_aggregate_context=h.la,n._sqlite3_column_count=h.ma,n._sqlite3_data_count=h.na,n._sqlite3_column_blob=h.oa,n._sqlite3_column_bytes=h.pa,n._sqlite3_column_double=h.qa,n._sqlite3_bind_blob=h.ra,n._sqlite3_bind_double=h.sa,n._sqlite3_bind_int=h.ta,n._sqlite3_bind_text=h.ua,n._sqlite3_bind_parameter_index=h.va,n._sqlite3_sql=h.wa,n._sqlite3_normalized_sql=h.xa,n._sqlite3_changes=h.ya,n._sqlite3_close_v2=h.za,n._sqlite3_create_function_v2=h.Aa,n._sqlite3_update_hook=h.Ba,n._sqlite3_open=h.Ca,pr=n._malloc=h.Da,Fs=n._free=h.Ea,n._RegisterExtensionFunctions=h.Fa,ao=h.Ga,lo=h.Ha,mr=h.Ia,Yt=h.Ja,yr=h.Ka,wr=h.M,At=h.O,me(),Ve--,n.monitorRunDependencies?.(Ve),Ve==0&&Gt&&(h=Gt,Gt=null,h()),Ci}Ve++,n.monitorRunDependencies?.(Ve);var l={a:Al};return n.instantiateWasm?new Promise(h=>{n.instantiateWasm(l,(f,m)=>{h(o(f,m))})}):(ue??=n.locateFile?n.locateFile("sql-wasm.wasm",b):b+"sql-wasm.wasm",o((await le(l)).instance))})(),_i(),s}),Gr)};typeof jr=="object"&&typeof is=="object"?(is.exports=Vr,is.exports.default=Vr):typeof define=="function"&&define.amd?define([],function(){return Vr}):typeof jr=="object"&&(jr.Module=Vr)});import C from"blessed";import"blessed-contrib";import"systeminformation";import{exec as df}from"child_process";import{promisify as ff}from"util";import gf from"https";Q();import it from"os";import Bt from"fs";import{fileURLToPath as pf}from"url";import{dirname as mf,join as yf,resolve as rl}from"path";Q();import Qt from"fs";import{execSync as bs}from"child_process";import To from"os";var Pi=process.env.HOME+"/.openclaw/dashboard-settings.json",Ir="theme",Wi=new Set,Et=null;function Fi(){try{return bs('defaults read -g AppleInterfaceStyle 2>/dev/null || echo "Light"',{encoding:"utf8",timeout:1e3}).trim()==="Dark"?"dark":"light"}catch{return null}}function Ar(){try{let e=bs('gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null || echo "default"',{encoding:"utf8",timeout:1e3}).trim().replace(/'/g,"");if(e==="prefer-dark")return"dark";if(e==="prefer-light")return"light";let s=bs('gsettings get org.gnome.desktop.interface gtk-theme 2>/dev/null || echo ""',{encoding:"utf8",timeout:1e3}).trim().toLowerCase();return s.includes("dark")?"dark":s.includes("light")?"light":null}catch{return null}}function Hc(){let r=process.env.COLORFGBG;if(r){let e=r.split(";");if(e.length>=2){let t=parseInt(e[1],10);if(t>=0&&t<=7)return"dark";if(t>=8&&t<=15)return"light"}}return process.env.DARK_MODE==="1"||process.env.THEME==="dark"?"dark":process.env.THEME==="light"?"light":null}function Gc(){let r=null,e=To.platform();return e==="darwin"?r=Fi():e==="linux"&&(r=Ar()),r||(r=Hc()),r||(r=Yc()),r}function Vc(r){let e=To.platform();return e==="darwin"?jc(r):e==="linux"?zc(r):(u.debug("System theme watching not supported on this platform"),null)}function jc(r){let e=Fi(),t=setInterval(()=>{let s=Fi();s&&s!==e&&(u.info(`System theme changed: ${e} -> ${s}`),e=s,r(s))},2e3);return{stop:()=>{clearInterval(t),u.debug("macOS theme watcher stopped")}}}function zc(r){let e=process.env.DCONF_PROFILE?`/etc/dconf/db/${process.env.DCONF_PROFILE}`:`${process.env.HOME}/.config/dconf/user`,t=Ar(),s=null,i=null;if(Qt.existsSync(e))try{s=Qt.watch(e,n=>{if(n==="change"){let a=Ar();a&&a!==t&&(u.info(`System theme changed: ${t} -> ${a}`),t=a,r(a))}}),u.debug(`Linux theme watcher started via fs.watch on ${e}`)}catch(n){u.debug(`Failed to watch dconf file: ${n.message}, falling back to polling`),s=null}return s||(i=setInterval(()=>{let n=Ar();n&&n!==t&&(u.info(`System theme changed: ${t} -> ${n}`),t=n,r(n))},3e3)),{stop:()=>{s&&s.close(),i&&clearInterval(i),u.debug("Linux theme watcher stopped")}}}function Rr(r){return Wi.add(r),()=>Wi.delete(r)}function qc(r){Wi.forEach(e=>{try{e(r)}catch(t){u.debug(`Theme change listener error: ${t.message}`)}})}function Ui(){return Et&&(Et.stop(),Et=null),$e!=="auto"?null:(Et=Vc(r=>{Gs=r,qc("auto")}),Et&&u.info("Auto theme detection started - watching for system theme changes"),Et)}function vo(){Et&&(Et.stop(),Et=null,u.debug("Auto theme detection stopped"))}function Yc(){try{let r=process.env.TERM_PROGRAM||"",e=process.env.COLORTERM||"",t=process.env.TERM||"";if(r==="iTerm.app"||r==="vscode"){if(r==="iTerm.app")try{let c=bs(`osascript -e 'tell app "System Events" to tell process "iTerm2" to get value of attribute "AXBackgroundColor" of window 1'`,{encoding:"utf8",timeout:1e3});if(c&&c.trim()){let d=c.match(/\d+/g);if(d&&d.length>=3)return(parseInt(d[0])+parseInt(d[1])+parseInt(d[2]))/765<.5?"dark":"light"}}catch{}if(r==="vscode")return"dark"}if(["-light","light"].some(c=>t.toLowerCase().includes(c)||e.toLowerCase().includes(c)))return"light";if(["-256color","dark","truecolor"].some(c=>t.toLowerCase().includes(c))||r!=="")return"dark";if(process.env.TERM_SESSION_ID)try{let c=bs(`osascript -e 'tell app "iTerm2" to tell current session of current window to get background color'`,{encoding:"utf8",timeout:1e3});if(c){let d=c.match(/\d+/g);if(d&&d.length>=3)return(parseInt(d[0])+parseInt(d[1])+parseInt(d[2]))/765<.5?"dark":"light"}}catch{}if(r==="Apple_Terminal")try{let c=bs(`osascript -e 'tell app "Terminal" to get background color of window 1'`,{encoding:"utf8",timeout:1e3});if(c){let d=c.match(/\d+/g);if(d&&d.length>=3)return(parseInt(d[0])+parseInt(d[1])+parseInt(d[2]))/765<.5?"dark":"light"}}catch{}return"dark"}catch(r){return u.debug(`Background detection failed: ${r.message}`),"dark"}}var Ue={default:{name:"Default",colors:{border:{sessions:"blue",logs:"cyan",cpu:"cyan",memory:"magenta",gpu:"yellow",network:"brightCyan",disk:"green",system:"gray",uptime:"brightMagenta",gateway:"cyan",help:"brightCyan",settings:"brightCyan",modal:"brightBlue"},text:{primary:"white",secondary:"gray",bright:"brightWhite",header:"brightWhite"},status:{active:"green",idle:"yellow",stale:"gray",error:"red",warning:"yellow",success:"green"},gauge:{low:"green",medium:"yellow",high:"red",critical:"brightRed"},chart:{line:"cyan",fill:"blue",grid:"gray"},alert:{info:"cyan",warning:"yellow",error:"red",success:"green"},branding:{logo:"brightCyan",title:"brightWhite",clock:"brightCyan"},footer:{bg:"black",fg:"gray"}}},dark:{name:"Dark",colors:{border:{sessions:"cyan",logs:"blue",cpu:"green",memory:"magenta",gpu:"yellow",network:"cyan",disk:"green",system:"gray",uptime:"magenta",gateway:"cyan",help:"cyan",settings:"cyan",modal:"cyan"},text:{primary:"white",secondary:"black",bright:"brightWhite",header:"brightWhite"},status:{active:"green",idle:"yellow",stale:"black",error:"red",warning:"yellow",success:"green"},gauge:{low:"green",medium:"yellow",high:"red",critical:"brightRed"},chart:{line:"green",fill:"cyan",grid:"black"},alert:{info:"cyan",warning:"yellow",error:"red",success:"green"},branding:{logo:"green",title:"brightGreen",clock:"green"},footer:{bg:"black",fg:"green"}}},"high-contrast":{name:"High Contrast",colors:{border:{sessions:"brightWhite",logs:"brightWhite",cpu:"brightWhite",memory:"brightWhite",gpu:"brightWhite",network:"brightWhite",disk:"brightWhite",system:"brightWhite",uptime:"brightWhite",gateway:"brightWhite",help:"brightWhite",settings:"brightWhite",modal:"brightWhite"},text:{primary:"white",secondary:"brightWhite",bright:"brightWhite",header:"brightWhite"},status:{active:"brightGreen",idle:"brightYellow",stale:"brightWhite",error:"brightRed",warning:"brightYellow",success:"brightGreen"},gauge:{low:"brightGreen",medium:"brightYellow",high:"brightRed",critical:"brightRed"},chart:{line:"brightWhite",fill:"brightWhite",grid:"brightWhite"},alert:{info:"brightCyan",warning:"brightYellow",error:"brightRed",success:"brightGreen"},branding:{logo:"brightWhite",title:"brightWhite",clock:"brightWhite"},footer:{bg:"white",fg:"black"}}},ocean:{name:"Ocean",colors:{border:{sessions:"blue",logs:"cyan",cpu:"blue",memory:"cyan",gpu:"blue",network:"cyan",disk:"blue",system:"cyan",uptime:"blue",gateway:"cyan",help:"cyan",settings:"cyan",modal:"brightBlue"},text:{primary:"white",secondary:"blue",bright:"brightWhite",header:"brightCyan"},status:{active:"cyan",idle:"blue",stale:"gray",error:"red",warning:"yellow",success:"green"},gauge:{low:"cyan",medium:"blue",high:"yellow",critical:"red"},chart:{line:"cyan",fill:"blue",grid:"blue"},alert:{info:"cyan",warning:"yellow",error:"red",success:"green"},branding:{logo:"cyan",title:"brightCyan",clock:"cyan"},footer:{bg:"blue",fg:"cyan"}}},auto:{name:"Auto-detect",isAuto:!0,colors:null}},Gs=null;function _r(){return Gs||(Gs=Gc(),u.info(`Theme background detected: ${Gs}`)),Gs}function Kc(){return _r()==="light"?Ue.default:Ue.dark}var $e="default";function ke(){return $e==="auto"?Kc():Ue[$e]||Ue.default}function Cr(){return $e}function Vs(r){return r==="auto"?Ue.auto:Ue[r]||null}function Io(){return Object.keys(Ue)}function Ss(r){if(!Ue[r])return u.warn(`Theme '${r}' not found, keeping current theme`),!1;$e=r;let e=r==="auto"?`Auto-detect (${_r()})`:Ue[r].name;return u.info(`Theme changed to: ${e}`),!0}function Ao(){let r=Object.keys(Ue),t=(r.indexOf($e)+1)%r.length;$e=r[t];let s=$e==="auto"?`Auto-detect (${_r()})`:Ue[$e].name;return u.info(`Theme cycled to: ${s}`),$e}function Bi(){try{let r=Qt.readFileSync(Pi,"utf8"),e=JSON.parse(r);if(e[Ir]&&Ue[e[Ir]])if($e=e[Ir],$e==="auto"){let t=_r();u.info(`Loaded theme: Auto-detect (${t} background)`)}else u.info(`Loaded theme: ${Ue[$e].name}`)}catch{}}function Zt(){try{let r={};try{let t=Qt.readFileSync(Pi,"utf8");r=JSON.parse(t)}catch{}r[Ir]=$e;let e=process.env.HOME+"/.openclaw";Qt.existsSync(e)||Qt.mkdirSync(e,{recursive:!0}),Qt.writeFileSync(Pi,JSON.stringify(r,null,2))}catch(r){u.warn(`Failed to save theme: ${r.message}`)}}Q();te();import Ro from"process";var Lo={cpu:{warning:w.ALERT_THRESHOLDS.CPU.warning,critical:w.ALERT_THRESHOLDS.CPU.critical},memory:{warning:w.ALERT_THRESHOLDS.MEMORY.warning,critical:w.ALERT_THRESHOLDS.MEMORY.critical},disk:{warning:w.ALERT_THRESHOLDS.DISK.warning,critical:w.ALERT_THRESHOLDS.DISK.critical}},ne={INFO:"info",WARNING:"warning",CRITICAL:"critical",CLEARED:"cleared"},et={enabled:!1,soundType:"bell",warningEnabled:!0,criticalEnabled:!0},Lt=[],ve={...Lo},js=[],_o=w.MAX_ALERT_HISTORY,ug=w.ALERT_RATE_LIMIT,Ie={enabled:w.ALERT_RATE_LIMIT.ENABLED,windowMs:w.ALERT_RATE_LIMIT.WINDOW_MS,maxAlerts:w.ALERT_RATE_LIMIT.MAX_ALERTS},xs={};function ko(r){if(!Ie.enabled)return!1;let e=Date.now(),s=(xs[r]||[]).filter(i=>e-i<Ie.windowMs);return s.length>=Ie.maxAlerts?(u.debug(`[RATE LIMIT] Alert for ${r} suppressed - rate limit exceeded (${s.length}/${Ie.maxAlerts} in ${Ie.windowMs}ms)`),!0):(xs[r]=s,!1)}function Oo(r){Ie.enabled&&(xs[r]||(xs[r]=[]),xs[r].push(Date.now()))}function Vi(r){Ie={...Ie,...r},u.info(`Rate limiting updated: enabled=${Ie.enabled}, window=${Ie.windowMs}ms, max=${Ie.maxAlerts}`)}function Xc(){return{...Ie}}function Mo(){xs={},Ie={enabled:w.ALERT_RATE_LIMIT.ENABLED,windowMs:w.ALERT_RATE_LIMIT.WINDOW_MS,maxAlerts:w.ALERT_RATE_LIMIT.MAX_ALERTS}}function Hi(r,e,t,s){return{id:`${r}-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,type:r,level:e,value:t,threshold:s,timestamp:new Date().toISOString(),message:Jc(r,e,t,s),dismissed:!1}}function Jc(r,e,t,s){let i={cpu:"CPU usage",memory:"Memory usage",disk:"Disk usage"},n={info:"Information",warning:"Warning",critical:"Critical",cleared:"Resolved"};return e===ne.CLEARED?`${i[r]} normalized (${t}% - was above ${s}%)`:`${n[e]}: ${i[r]} at ${t}% (threshold: ${s}%)`}function Lr(r,e){if(!ve[r])return u.warn(`Unknown alert type: ${r}`),null;let{warning:t,critical:s}=ve[r],i=Lt.find(n=>n.type===r&&!n.dismissed);if(e>=s){if((!i||i.level!==ne.CRITICAL)&&Co.checkAndRecord(r,ne.CRITICAL).allowed){let a=Hi(r,ne.CRITICAL,e,s);return Gi(a),a}return i&&(i.value=e,i.timestamp=new Date().toISOString()),null}if(e>=t){if((!i||i.level===ne.CLEARED)&&Co.checkAndRecord(r,ne.WARNING).allowed){let a=Hi(r,ne.WARNING,e,t);return Gi(a),a}return i&&(i.value=e,i.timestamp=new Date().toISOString()),null}if(i){let n=Hi(r,ne.CLEARED,e,i.threshold);return No(i.id),Gi(n),n}return null}function Do(r){if(et.enabled&&!(r===ne.WARNING&&!et.warningEnabled)&&!(r===ne.CRITICAL&&!et.criticalEnabled))try{if(et.soundType==="bell")Ro.stdout.write("\x07");else if(et.soundType==="beep"){let e=r===ne.CRITICAL?3:1;Ro.stdout.write("\x07".repeat(e))}}catch(e){u.debug(`Failed to play sound: ${e.message}`)}}function Qc(r){et={...et,...r},u.info(`Sound notifications: enabled=${et.enabled}, type=${et.soundType}`)}function Zc(){return{...et}}function eh(r){et.enabled=r,u.info(`Sound notifications ${r?"enabled":"disabled"}`)}function Gi(r){Lt=Lt.filter(e=>e.type!==r.type||e.dismissed),Lt.push(r),js.push(r),js.length>_o&&(js=js.slice(-_o)),(r.level===ne.WARNING||r.level===ne.CRITICAL)&&Do(r.level),u.info(`[ALERT] ${r.message}`)}function No(r){let e=Lt.find(t=>t.id===r);e&&(e.dismissed=!0,e.timestamp=new Date().toISOString())}function $o(){return Lt.filter(r=>!r.dismissed)}function th(r){return Lt.filter(e=>e.level===r&&!e.dismissed)}function sh(){return[...js]}function rh(){Lt.forEach(r=>r.dismissed=!0)}function ih(r){r.cpu&&(ve.cpu={...ve.cpu,...r.cpu}),r.memory&&(ve.memory={...ve.memory,...r.memory}),r.disk&&(ve.disk={...ve.disk,...r.disk}),u.info(`Alert thresholds updated: CPU ${ve.cpu.warning}/${ve.cpu.critical}%, Memory ${ve.memory.warning}/${ve.memory.critical}%, Disk ${ve.disk.warning}/${ve.disk.critical}%`)}function nh(){return{...ve}}function oh(){ve={...Lo},u.info("Alert thresholds reset to defaults")}function ah(r){let e=[];if(r&&r.cpu!==void 0){let t=Lr("cpu",r.cpu);t&&e.push(t)}if(r&&r.memory!==void 0){let t=Lr("memory",r.memory);t&&e.push(t)}if(r&&r.disk!==void 0){let t=Lr("disk",r.disk);t&&e.push(t)}return e}function Po(r){let e=ke();return{[ne.INFO]:e.colors.alert?.info||"cyan",[ne.WARNING]:e.colors.alert?.warning||"yellow",[ne.CRITICAL]:e.colors.alert?.error||"red",[ne.CLEARED]:e.colors.alert?.success||"green"}[r]||"white"}function lh(r){let e=Po(r.level),t=ch(r.level);return`{${e}-fg}${t} ${r.message}{/}`}function ch(r){return{[ne.INFO]:"\u2139",[ne.WARNING]:"\u26A0",[ne.CRITICAL]:"\u2716",[ne.CLEARED]:"\u2713"}[r]||"\u2022"}function hh(){let r=$o();return{info:r.filter(e=>e.level===ne.INFO).length,warning:r.filter(e=>e.level===ne.WARNING).length,critical:r.filter(e=>e.level===ne.CRITICAL).length,total:r.length}}var kt=class{constructor(e={}){this.enabled=e.enabled??Ie.enabled,this.windowMs=e.windowMs??Ie.windowMs,this.maxAlerts=e.maxAlerts??Ie.maxAlerts,this.alwaysAllowCritical=e.alwaysAllowCritical??!0,this.timestamps={},Vi({enabled:this.enabled,windowMs:this.windowMs,maxAlerts:this.maxAlerts})}check(e,t="warning"){return this.enabled?this.alwaysAllowCritical&&t==="critical"?{allowed:!0,reason:"critical_always_allowed"}:ko(e)?{allowed:!1,reason:"rate_limit_exceeded"}:{allowed:!0,reason:"ok"}:{allowed:!0,reason:"rate_limiting_disabled"}}record(e,t="warning"){this.enabled&&(this._addTimestamp(e),Oo(e))}_addTimestamp(e){this.timestamps[e]||(this.timestamps[e]=[]),this.timestamps[e].push(Date.now())}getCount(e){let t=this.timestamps[e]||[],s=Date.now();return t.filter(n=>s-n<this.windowMs).length}getRetryAfter(e){let t=this.timestamps[e]||[];if(t.length===0)return 0;let s=Date.now(),i=t.filter(a=>s-a<this.windowMs);if(i.length<this.maxAlerts)return 0;let n=Math.min(...i);return Math.max(0,n+this.windowMs-s)}getStatus(){let e=Date.now(),t=Object.keys(this.timestamps),s={};for(let i of t){let n=this.timestamps[i].filter(a=>e-a<this.windowMs);s[i]={current:n.length,max:this.maxAlerts,retryAfter:n.length>=this.maxAlerts?this.getRetryAfter(i):0}}return{enabled:this.enabled,windowMs:this.windowMs,maxAlerts:this.maxAlerts,alwaysAllowCritical:this.alwaysAllowCritical,types:s}}configure(e){e.enabled!==void 0&&(this.enabled=e.enabled),e.windowMs!==void 0&&(this.windowMs=e.windowMs),e.maxAlerts!==void 0&&(this.maxAlerts=e.maxAlerts),e.alwaysAllowCritical!==void 0&&(this.alwaysAllowCritical=e.alwaysAllowCritical),Vi({enabled:this.enabled,windowMs:this.windowMs,maxAlerts:this.maxAlerts})}reset(){this.timestamps={},Mo()}checkAndRecord(e,t="warning"){let s=this.check(e,t);return s.allowed&&this.record(e,t),s}},Co=new kt({alwaysAllowCritical:!0}),uh=new kt,Ts={AlertLevel:ne,checkThreshold:Lr,checkAllMetrics:ah,dismissAlert:No,getActiveAlerts:$o,getAlertsByLevel:th,getAlertHistory:sh,getAlertCounts:hh,getAlertColor:Po,formatAlert:lh,setThresholds:ih,getThresholds:nh,resetThresholds:oh,clearAllAlerts:rh,setRateLimit:Vi,getRateLimit:Xc,resetRateLimit:Mo,shouldRateLimitAlert:ko,recordAlertTimestamp:Oo,RateLimiter:kt,defaultRateLimiter:uh,setSoundConfig:Qc,getSoundConfig:Zc,toggleSound:eh,playAlertSound:Do};Q();te();var mg=w.DEFAULT_RETRY_OPTIONS;te();Q();te();import ph from"os";import Wr from"fs";import{resolve as Bo,dirname as mh}from"path";Q();te();import es from"fs";import Pr from"path";import{fileURLToPath as fh}from"url";te();Q();import ht from"fs";import Wo from"os";import{join as Fo}from"path";var ji="1.0.0",Uo=["refreshInterval","logLevelFilter","sessionSortMode","showWidget1","showWidget2","showWidget3","showWidget4","showWidget5","showWidget6","showWidget7","showWidget8","showWidget9","showPerformanceMetrics","theme","exportFormat","exportDirectory","favorites","showFavoritesOnly","gatewayEndpoints","activeGatewayEndpoint","webInterface","widgetLoading","plugins","autoRetry"];function kr(r,e={}){let t={schemaVersion:ji,dashboardVersion:pe,createdAt:new Date().toISOString(),name:e.name||"Dashboard Snapshot",description:e.description||"",platform:{os:Wo.platform(),arch:Wo.arch(),nodeVersion:process.version},settings:{}};for(let s of Uo)s in r&&(t.settings[s]=r[s]);return t.metadata={widgetCount:["showWidget1","showWidget2","showWidget3","showWidget4","showWidget5","showWidget6","showWidget7","showWidget8","showWidget9"].filter(s=>t.settings[s]!==!1).length,pluginCount:Object.keys(t.settings.plugins||{}).length,endpointCount:(t.settings.gatewayEndpoints||[]).length},t}function dh(r){if(!r||typeof r!="object")return{valid:!1,error:"Invalid snapshot format"};let e=r.schemaVersion||"0.0.0",[t]=e.split("."),[s]=ji.split(".");if(parseInt(t)>parseInt(s))return{valid:!1,error:`Snapshot version ${e} is newer than supported (${ji})`};if(!r.settings||typeof r.settings!="object")return{valid:!1,error:"Missing or invalid settings in snapshot"};let i=[{key:"refreshInterval",type:"number",min:500,max:6e4},{key:"theme",type:"string",allowed:["auto","default","dark","high-contrast","ocean"]},{key:"logLevelFilter",type:"string",allowed:["all","debug","info","warn","error"]}];for(let n of i){let a=r.settings[n.key];if(a!==void 0){if(n.type&&typeof a!==n.type)return{valid:!1,error:`Invalid type for ${n.key}: expected ${n.type}`};if(n.min!==void 0&&a<n.min)return{valid:!1,error:`${n.key} must be at least ${n.min}`};if(n.max!==void 0&&a>n.max)return{valid:!1,error:`${n.key} must be at most ${n.max}`};if(n.allowed&&!n.allowed.includes(a))return{valid:!1,error:`${n.key} must be one of: ${n.allowed.join(", ")}`}}}for(let n=1;n<=9;n++){let a=`showWidget${n}`,c=r.settings[a];if(c!==void 0&&typeof c!="boolean")return{valid:!1,error:`${a} must be a boolean`}}return{valid:!0}}function Or(r,e){let t={...r};for(let s of Uo)s in e&&(typeof e[s]=="object"&&e[s]!==null?t[s]=JSON.parse(JSON.stringify(e[s])):t[s]=e[s]);return t}function Mr(r,e){try{let t=e.substring(0,e.lastIndexOf("/"));t&&!ht.existsSync(t)&&ht.mkdirSync(t,{recursive:!0}),ht.writeFileSync(e,JSON.stringify(r,null,2));try{ht.chmodSync(e,384)}catch(s){u.warn(`Could not set permissions on snapshot: ${s.message}`)}return{success:!0,path:e}}catch(t){return{success:!1,error:t.message}}}function Dr(r){try{if(!ht.existsSync(r))return{success:!1,error:`File not found: ${r}`};let e=ht.readFileSync(r,"utf8"),t=JSON.parse(e),s=dh(t);return s.valid?{success:!0,snapshot:t}:{success:!1,error:s.error}}catch(e){return e instanceof SyntaxError?{success:!1,error:"Invalid JSON format"}:{success:!1,error:e.message}}}function Nr(r){let e=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19);return`claw-snapshot-${r?r.replace(/[^a-zA-Z0-9-_]/g,"_"):"dashboard"}-${e}.json`}function bt(){return Fo(Le.OPENCLAW_DIR,"snapshots")}function $r(){let r=bt();if(!ht.existsSync(r))return[];try{return ht.readdirSync(r).filter(t=>t.endsWith(".json")).map(t=>{let s=Fo(r,t);try{let i=ht.readFileSync(s,"utf8"),n=JSON.parse(i),a=ht.statSync(s);return{filename:t,path:s,name:n.name||"Unnamed",description:n.description||"",createdAt:n.createdAt||a.mtime.toISOString(),dashboardVersion:n.dashboardVersion||"unknown",schemaVersion:n.schemaVersion||"unknown",metadata:n.metadata||{}}}catch{return null}}).filter(Boolean).sort((t,s)=>new Date(s.createdAt)-new Date(t.createdAt))}catch(e){return u.warn(`Failed to list snapshots: ${e.message}`),[]}}function zs(r){if(!r)return"Invalid snapshot";let e=[`Name: ${r.name||"Unnamed"}`,`Created: ${r.createdAt?new Date(r.createdAt).toLocaleString():"Unknown"}`];if(r.description&&e.push(`Description: ${r.description}`),r.metadata){let{widgetCount:t,pluginCount:s,endpointCount:i}=r.metadata;e.push(`Widgets: ${t}, Plugins: ${s}, Endpoints: ${i}`)}if(r.settings){let t=r.settings.theme||"auto",s=r.settings.refreshInterval||2e3;e.push(`Theme: ${t}, Refresh: ${s}ms`)}return e.join(`
|
|
16
|
-
`)}var gh=fh(import.meta.url),$g=Pr.dirname(gh),ut={enabled:!1,format:"json",directory:null,filename:null,schedule:"0 * * * *",includeMetrics:!0,compressOlder:!1,retentionDays:30},ts=class{static parse(e){let t=e.trim().split(/\s+/);if(t.length!==5)throw new Error(`Invalid cron expression: expected 5 fields, got ${t.length}`);let[s,i,n,a,c]=t;return{minute:this._parseField(s,0,59),hour:this._parseField(i,0,23),dayOfMonth:this._parseField(n,1,31),month:this._parseField(a,1,12),dayOfWeek:this._parseField(c,0,6)}}static _parseField(e,t,s){let i=new Set,n=e.split(",");for(let a of n){let[c,d]=a.split("/"),g=d?parseInt(d,10):1;if(c==="*")for(let p=t;p<=s;p+=g)i.add(p);else if(c.includes("-")){let[p,T]=c.split("-"),b=parseInt(p,10),_=parseInt(T,10);if(isNaN(b)||isNaN(_)||b<t||_>s||b>_)throw new Error(`Invalid range: ${c}`);for(let v=b;v<=_;v+=g)i.add(v)}else{let p=parseInt(c,10);if(isNaN(p)||p<t||p>s)throw new Error(`Invalid value: ${c}`);i.add(p)}}return i}static matches(e,t){let s=e.getMinutes(),i=e.getHours(),n=e.getDate(),a=e.getMonth()+1,c=e.getDay();return t.minute.has(s)&&t.hour.has(i)&&t.dayOfMonth.has(n)&&t.month.has(a)&&t.dayOfWeek.has(c)}static nextExecution(e,t){let s=this.parse(t),i=new Date(e);i.setSeconds(0,0),i.setMinutes(i.getMinutes()+1);let n=366*24*60;for(let a=0;a<n;a++){if(this.matches(i,s))return i;i.setMinutes(i.getMinutes()+1)}throw new Error("Could not find next execution time within 1 year")}},ss=class r{constructor(e={}){this.config={...ut,...e},this.enabled=this.config.enabled,this.timer=null,this.lastExport=null,this.nextExport=null,this.exportCount=0,this.failedCount=0,this.getMetricsCallback=null,this.exportDir=this.config.directory||bt()}setMetricsCallback(e){if(typeof e!="function")throw new Error("Metrics callback must be a function");this.getMetricsCallback=e}configure(e){let t=r.validateConfig(e);this.config={...this.config,...t},this.enabled=this.config.enabled,this.exportDir=this.config.directory||bt(),this.enabled&&this.timer&&(this.stop(),this.start()),u.info(`Export scheduler configured: ${this.enabled?"enabled":"disabled"}`)}start(){if(!this.enabled){u.debug("Export scheduler not enabled, skipping start");return}try{this.nextExport=ts.nextExecution(new Date,this.config.schedule);let e=this.nextExport.getTime()-Date.now();u.info(`Export scheduler started, next export in ${this._formatDelay(e)}`),this.timer=setTimeout(()=>this._onExportTime(),e)}catch(e){u.error(`Failed to start export scheduler: ${e.message}`),this.enabled=!1}}stop(){this.timer&&(clearTimeout(this.timer),this.timer=null,u.debug("Export scheduler stopped"))}async triggerExport(){return this._performExport("manual")}async _onExportTime(){try{let e=await this._performExport("scheduled");e.success?(this.lastExport=new Date,this.exportCount++,u.info(`Scheduled export completed: ${e.path}`)):(this.failedCount++,u.error(`Scheduled export failed: ${e.error}`))}catch(e){this.failedCount++,u.error(`Export scheduler error: ${e.message}`)}if(this.enabled){this.nextExport=ts.nextExecution(new Date,this.config.schedule);let e=this.nextExport.getTime()-Date.now();this.timer=setTimeout(()=>this._onExportTime(),e),u.debug(`Next export scheduled for ${this.nextExport.toISOString()}`)}}async _performExport(e){try{es.existsSync(this.exportDir)||es.mkdirSync(this.exportDir,{recursive:!0});let t=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),s=this.config.filename?`${this.config.filename}-${t}.${this.config.format}`:`claw-export-${t}.${this.config.format}`,i=Pr.join(this.exportDir,s),n=await this._getExportData(e),a=this.config.format==="csv"?this._convertToCSV(n):JSON.stringify(n,null,2);es.writeFileSync(i,a);try{es.chmodSync(i,384)}catch(c){u.warn(`Could not set permissions on export: ${c.message}`)}return this.config.retentionDays>0&&this._cleanupOldExports(),{success:!0,path:i,data:n}}catch(t){return{success:!1,error:t.message}}}async _getExportData(e){let t={schemaVersion:"1.0.0",dashboardVersion:pe,exportedAt:new Date().toISOString(),trigger:e,format:this.config.format,schedule:this.config.schedule,metrics:null};if(this.config.includeMetrics&&typeof this.getMetricsCallback=="function")try{t.metrics=await this.getMetricsCallback()}catch(s){u.warn(`Failed to collect metrics for export: ${s.message}`),t.metrics={error:"Failed to collect metrics"}}return t}_convertToCSV(e){let t=[];if(t.push(`# Claw Dashboard Export - ${e.exportedAt}`),t.push(`# Format: ${e.format}`),t.push(`# Schedule: ${e.schedule}`),t.push(""),e.metrics){let s=e.metrics,i=e.exportedAt,n=["timestamp"],a=[i];s.cpu!==void 0&&(n.push("cpu_percent"),a.push(s.cpu)),s.memory!==void 0&&(n.push("memory_percent"),a.push(s.memory)),s.disk!==void 0&&(n.push("disk_percent"),a.push(s.disk)),s.network!==void 0&&(s.network.rx!==void 0&&(n.push("network_rx_bytes"),a.push(s.network.rx)),s.network.tx!==void 0&&(n.push("network_tx_bytes"),a.push(s.network.tx))),t.push(n.join(",")),t.push(a.join(","))}return t.join(`
|
|
17
|
-
`)}_cleanupOldExports(){try{let e=Date.now()-this.config.retentionDays*24*60*60*1e3,t=es.readdirSync(this.exportDir).filter(s=>s.startsWith("claw-export-")).map(s=>({name:s,path:Pr.join(this.exportDir,s),mtime:es.statSync(Pr.join(this.exportDir,s)).mtimeMs}));for(let s of t)s.mtime<e&&(es.unlinkSync(s.path),u.debug(`Cleaned up old export: ${s.name}`))}catch(e){u.warn(`Failed to cleanup old exports: ${e.message}`)}}_formatDelay(e){let t=Math.floor(e/6e4),s=Math.floor(t/60),i=Math.floor(s/24);return i>0?`${i}d ${s%24}h`:s>0?`${s}h ${t%60}m`:`${t}m`}getStatus(){return{enabled:this.enabled,schedule:this.config.schedule,format:this.config.format,exportDir:this.exportDir,lastExport:this.lastExport?.toISOString(),nextExport:this.nextExport?.toISOString(),exportCount:this.exportCount,failedCount:this.failedCount,retentionDays:this.config.retentionDays}}static validateConfig(e){let t={},s=[];if(e.enabled!==void 0&&(t.enabled=!!e.enabled),e.format!==void 0&&(["json","csv"].includes(e.format)?t.format=e.format:s.push(`Invalid format: ${e.format}`)),e.schedule!==void 0)try{ts.parse(e.schedule),t.schedule=e.schedule}catch{s.push(`Invalid cron expression: ${e.schedule}`)}if(e.directory!==void 0&&(e.directory===null||typeof e.directory=="string"?t.directory=e.directory:s.push("Directory must be a string or null")),e.retentionDays!==void 0){let i=Number(e.retentionDays);!isNaN(i)&&i>=0&&i<=365?t.retentionDays=i:s.push("retentionDays must be 0-365")}return e.includeMetrics!==void 0&&(t.includeMetrics=!!e.includeMetrics),s.length>0&&u.warn(`Export scheduler config validation warnings: ${s.join("; ")}`),t}},vs={everyMinute:"* * * * *",every5Minutes:"*/5 * * * *",every10Minutes:"*/10 * * * *",every15Minutes:"*/15 * * * *",every30Minutes:"*/30 * * * *",hourly:"0 * * * *",every6Hours:"0 */6 * * *",every12Hours:"0 */12 * * *",daily:"0 0 * * *",weekly:"0 0 * * 0",monthly:"0 0 1 * *"};var Ho=w.VALIDATION.VALID_THEMES,Go=w.VALIDATION.VALID_SORT_MODES,Vo=w.VALIDATION.VALID_LOG_LEVELS,jo=w.VALIDATION.VALID_EXPORT_FORMATS,qe={refreshInterval:{min:w.VALIDATION.REFRESH_INTERVAL.MIN,max:w.VALIDATION.REFRESH_INTERVAL.MAX,type:"number"},logLevelFilter:{type:"string",values:Vo},sessionSortMode:{type:"string",values:Go},theme:{type:"string",values:Ho},exportFormat:{type:"string",values:jo},exportDirectory:{type:"string",required:!1}};function qi(r,e=!1){if(!r||typeof r!="string")return{valid:!1,error:"Path must be a non-empty string"};if(r.includes(".."))return{valid:!1,error:"Path traversal not allowed"};let t=r.startsWith("~")?Bo(ph.homedir(),r.slice(1)):Bo(r);if(e&&!Wr.existsSync(t))return{valid:!1,error:`Path does not exist: ${t}`};let s=mh(t);if(!Wr.existsSync(s)&&!Wr.existsSync(t))try{if(!Wr.existsSync(s))return{valid:!0,resolvedPath:t,warning:"Parent directory will be created"}}catch{return{valid:!1,error:"Cannot determine if path is writable"}}return{valid:!0,resolvedPath:t}}function zo(r){if(r==null)return{valid:!0,value:w.REFRESH_INTERVALS.DEFAULT};let e=Number(r);return isNaN(e)?{valid:!1,error:"Refresh interval must be a number"}:e<qe.refreshInterval.min||e>qe.refreshInterval.max?{valid:!1,error:`Refresh interval must be between ${qe.refreshInterval.min}ms and ${qe.refreshInterval.max}ms`}:{valid:!0,value:e}}function qo(r){if(!r)return{valid:!0,value:"all"};if(typeof r!="string")return{valid:!1,error:"Log level must be a string"};let e=r.toLowerCase();return qe.logLevelFilter.values.includes(e)?{valid:!0,value:e}:{valid:!1,error:`Invalid log level. Must be one of: ${qe.logLevelFilter.values.join(", ")}`}}function Yo(r){if(!r)return{valid:!0,value:"time"};if(typeof r!="string")return{valid:!1,error:"Sort mode must be a string"};let e=r.toLowerCase();return qe.sessionSortMode.values.includes(e)?{valid:!0,value:e}:{valid:!1,error:`Invalid sort mode. Must be one of: ${qe.sessionSortMode.values.join(", ")}`}}function Ko(r){if(!r)return{valid:!0,value:"default"};if(typeof r!="string")return{valid:!1,error:"Theme must be a string"};let e=r.toLowerCase();return qe.theme.values.includes(e)?{valid:!0,value:e}:{valid:!1,error:`Invalid theme. Must be one of: ${qe.theme.values.join(", ")}`}}function Xo(r){if(!r)return{valid:!0,value:"json"};if(typeof r!="string")return{valid:!1,error:"Export format must be a string"};let e=r.toLowerCase();return qe.exportFormat.values.includes(e)?{valid:!0,value:e}:{valid:!1,error:`Invalid export format. Must be one of: ${qe.exportFormat.values.join(", ")}`}}function Jo(r){return r?typeof r!="string"?{valid:!1,error:"Export directory must be a string"}:qi(r,!1):{valid:!0,value:w.PATHS.EXPORTS}}function yh(r,e="setting"){return r==null?{valid:!0,value:!0}:typeof r!="boolean"?r==="true"||r==="1"||r==="yes"?{valid:!0,value:!0}:r==="false"||r==="0"||r==="no"?{valid:!0,value:!1}:{valid:!1,error:`${e} must be a boolean`}:{valid:!0,value:!!r}}function Ot(r){return yh(r,"Widget visibility")}function wh(r){if(!r)return{valid:!0,value:[]};if(!Array.isArray(r))return{valid:!1,error:"pinnedWidgets must be an array"};let e=["cpu","mem","gpu","net","disk","sys","uptime","health","gateway"],t=[];for(let s of r)typeof s=="string"&&e.includes(s)&&t.push(s);return t.length>4?{valid:!0,value:t.slice(0,4),warning:"Maximum 4 widgets can be pinned, truncating to first 4"}:{valid:!0,value:t}}function Eh(r){if(!r)return{valid:!0,value:[]};if(!Array.isArray(r))return{valid:!1,error:"widgetOrder must be an array"};let e=["cpu","mem","gpu","net","disk","sys","uptime","health","gateway"],t=[],s=new Set;for(let i of r)typeof i=="string"&&e.includes(i)&&!s.has(i)&&(t.push(i),s.add(i));return{valid:!0,value:t}}function bh(r){if(!r||typeof r!="object")return{valid:!0,value:{}};let e=["small","medium","large","wide"],t=["cpu","mem","gpu","net","disk","sys","uptime","health","gateway"],s={valid:!0,value:{}};for(let[i,n]of Object.entries(r))t.includes(i)&&e.includes(n)&&(s.value[i]=n);return s}function Sh(r){if(!r||typeof r!="object")return{valid:!1,error:"Alert thresholds must be an object"};let e={valid:!0,value:{}},t=["cpu","memory","disk"];for(let s of t)if(r[s]){let i=r[s];if(typeof i!="object")return{valid:!1,error:`Alert threshold for ${s} must be an object`};if(e.value[s]={},i.warning!==void 0){let n=Number(i.warning);if(isNaN(n)||n<0||n>100)return{valid:!1,error:`${s} warning threshold must be 0-100`};e.value[s].warning=n}else e.value[s].warning=s==="disk"?80:70;if(i.critical!==void 0){let n=Number(i.critical);if(isNaN(n)||n<0||n>100)return{valid:!1,error:`${s} critical threshold must be 0-100`};e.value[s].critical=n}else e.value[s].critical=s==="disk"?95:90;if(e.value[s].critical<e.value[s].warning)return{valid:!1,error:`${s} critical threshold must be >= warning threshold`}}return e}function Qo(r){if(!r||typeof r!="object")return{valid:!0,value:{enabled:w.AUTO_RETRY.ENABLED,intervalMs:w.AUTO_RETRY.DEFAULT_INTERVAL_MS,exponentialBackoff:w.AUTO_RETRY.EXPONENTIAL_BACKOFF,backoffMultiplier:w.AUTO_RETRY.BACKOFF_MULTIPLIER,maxBackoffIntervalMs:w.AUTO_RETRY.MAX_BACKOFF_INTERVAL_MS,resetAfterSuccess:w.AUTO_RETRY.RESET_AFTER_SUCCESS,consecutiveFailureThreshold:w.AUTO_RETRY.CONSECUTIVE_FAILURE_THRESHOLD}};let e={},t=w.VALIDATION.AUTO_RETRY;e.enabled=r.enabled!==!1;let s=Number(r.intervalMs);r.intervalMs!==void 0&&!isNaN(s)&&s>=t.INTERVAL_MS.MIN&&s<=t.INTERVAL_MS.MAX?e.intervalMs=s:e.intervalMs=w.AUTO_RETRY.DEFAULT_INTERVAL_MS,e.exponentialBackoff=r.exponentialBackoff!==!1;let i=Number(r.backoffMultiplier);r.backoffMultiplier!==void 0&&!isNaN(i)&&i>=t.BACKOFF_MULTIPLIER.MIN&&i<=t.BACKOFF_MULTIPLIER.MAX?e.backoffMultiplier=i:e.backoffMultiplier=w.AUTO_RETRY.BACKOFF_MULTIPLIER;let n=Number(r.maxBackoffIntervalMs);r.maxBackoffIntervalMs!==void 0&&!isNaN(n)&&n>=t.MAX_BACKOFF_INTERVAL_MS.MIN&&n<=t.MAX_BACKOFF_INTERVAL_MS.MAX?e.maxBackoffIntervalMs=n:e.maxBackoffIntervalMs=w.AUTO_RETRY.MAX_BACKOFF_INTERVAL_MS,e.resetAfterSuccess=r.resetAfterSuccess!==!1;let a=Number(r.consecutiveFailureThreshold);return r.consecutiveFailureThreshold!==void 0&&!isNaN(a)&&a>=t.CONSECUTIVE_FAILURE_THRESHOLD.MIN&&a<=t.CONSECUTIVE_FAILURE_THRESHOLD.MAX?e.consecutiveFailureThreshold=a:e.consecutiveFailureThreshold=w.AUTO_RETRY.CONSECUTIVE_FAILURE_THRESHOLD,{valid:!0,value:e}}function Zo(r){if(!r||typeof r!="object")return{valid:!0,value:{enabled:w.AUTO_SAVE.ENABLED,intervalMs:w.AUTO_SAVE.INTERVAL_MS,saveOnExit:w.AUTO_SAVE.SAVE_ON_EXIT}};let e={};e.enabled=r.enabled!==!1;let t=Number(r.intervalMs);return!isNaN(t)&&t>=5e3&&t<=3e5?e.intervalMs=t:e.intervalMs=w.AUTO_SAVE.INTERVAL_MS,e.saveOnExit=r.saveOnExit!==!1,{valid:!0,value:e}}function zi(r){if(!r||typeof r!="object")return{valid:!0,value:{enabled:ce.ENABLED,format:ce.DEFAULT_FORMAT,schedule:ce.DEFAULT_SCHEDULE,retentionDays:ce.DEFAULT_RETENTION_DAYS,directory:null,includeMetrics:!0}};let e={},t=[];if(e.enabled=!!r.enabled,r.format!==void 0?["json","csv"].includes(r.format)?e.format=r.format:(t.push(`Invalid format: ${r.format}`),e.format=ce.DEFAULT_FORMAT):e.format=ce.DEFAULT_FORMAT,r.schedule!==void 0)try{ts.parse(r.schedule),e.schedule=r.schedule}catch{t.push(`Invalid cron expression: ${r.schedule}`),e.schedule=ce.DEFAULT_SCHEDULE}else e.schedule=ce.DEFAULT_SCHEDULE;if(r.retentionDays!==void 0){let s=Number(r.retentionDays);!isNaN(s)&&s>=ce.MIN_RETENTION_DAYS&&s<=ce.MAX_RETENTION_DAYS?e.retentionDays=s:(t.push(`retentionDays must be ${ce.MIN_RETENTION_DAYS}-${ce.MAX_RETENTION_DAYS}`),e.retentionDays=ce.DEFAULT_RETENTION_DAYS)}else e.retentionDays=ce.DEFAULT_RETENTION_DAYS;if(r.directory!==void 0&&r.directory!==null)if(typeof r.directory=="string"){let s=qi(r.directory,!1);s.valid?e.directory=s.resolvedPath:(t.push(`Invalid directory: ${s.error}`),e.directory=null)}else t.push("directory must be a string or null"),e.directory=null;else e.directory=null;return e.includeMetrics=r.includeMetrics!==!1,t.length>0&&u.warn(`Export schedule validation warnings: ${t.join("; ")}`),{valid:!0,value:e}}function xh(r){if(!r||typeof r!="object")return u.warn("Settings must be an object, using defaults"),ea();let e={},t=[],s={refreshInterval:zo,logLevelFilter:qo,sessionSortMode:Yo,theme:Ko,exportFormat:Xo,exportDirectory:Jo,showWidget1:Ot,showWidget2:Ot,showWidget3:Ot,showWidget4:Ot,showWidget5:Ot,showWidget6:Ot,showWidget7:Ot,pinnedWidgets:wh,widgetOrder:Eh,widgetSizes:bh,exportSchedule:zi};for(let[c,d]of Object.entries(s)){let g=d(r[c]);g.valid?e[c]=g.value:(t.push(`${c}: ${g.error}`),e[c]=Th(c))}let i=Qo(r.autoRetry);i.valid||t.push(`autoRetry: ${i.error}`),e.autoRetry=i.value;let n=Zo(r.autoSave);n.valid||t.push(`autoSave: ${n.error}`),e.autoSave=n.value;let a=zi(r.exportSchedule);return a.valid||t.push(`exportSchedule: ${a.error}`),e.exportSchedule=a.value,t.length>0&&u.warn(`Settings validation errors: ${t.join("; ")}`),{valid:!0,value:e}}function Th(r){return{refreshInterval:w.REFRESH_INTERVALS.DEFAULT,logLevelFilter:"all",sessionSortMode:"time",theme:"default",exportFormat:"json",exportDirectory:w.PATHS.EXPORTS,autoRetry:{enabled:w.AUTO_RETRY.ENABLED,intervalMs:w.AUTO_RETRY.DEFAULT_INTERVAL_MS,exponentialBackoff:w.AUTO_RETRY.EXPONENTIAL_BACKOFF,backoffMultiplier:w.AUTO_RETRY.BACKOFF_MULTIPLIER,maxBackoffIntervalMs:w.AUTO_RETRY.MAX_BACKOFF_INTERVAL_MS,resetAfterSuccess:w.AUTO_RETRY.RESET_AFTER_SUCCESS,consecutiveFailureThreshold:w.AUTO_RETRY.CONSECUTIVE_FAILURE_THRESHOLD},showWidget1:!0,showWidget2:!0,showWidget3:!0,showWidget4:!0,showWidget5:!0,showWidget6:!0,showWidget7:!0,pinnedWidgets:[],widgetOrder:[],exportSchedule:{enabled:ce.ENABLED,format:ce.DEFAULT_FORMAT,schedule:ce.DEFAULT_SCHEDULE,retentionDays:ce.DEFAULT_RETENTION_DAYS,directory:null,includeMetrics:!0}}[r]}function ea(){return{refreshInterval:w.REFRESH_INTERVALS.DEFAULT,versionCheckInterval:432e5,lastVersionCheck:0,logLevelFilter:"all",sessionSortMode:"time",theme:"default",exportFormat:"json",exportDirectory:w.PATHS.EXPORTS,showWidget1:!0,showWidget2:!0,showWidget3:!0,showWidget4:!0,showWidget5:!0,showWidget6:!0,showWidget7:!0,showWidget8:!0,showPerformanceMetrics:!1,sessionSearchQuery:"",favorites:{},showFavoritesOnly:!1,pinnedWidgets:[],widgetOrder:[],widgetSizes:{cpu:"medium",mem:"medium",gpu:"medium",net:"medium",disk:"medium",sys:"medium",uptime:"medium",health:"medium",gateway:"medium"},firstRun:!0,gatewayEndpoints:[{name:"local",host:"localhost",port:18789,token:null,enabled:!0,type:"local"}],activeGatewayEndpoint:"local",webInterface:{enabled:!1,port:w.WEB.DEFAULT_PORT,host:w.WEB.HOST,cors:!0}}}function vh(r){if(!r||typeof r!="object")return{valid:!1,error:"Endpoint must be an object"};if(!r.name||typeof r.name!="string"||r.name.length===0)return{valid:!1,error:"Endpoint name is required and must be a non-empty string"};if(r.name.length>w.VALIDATION.ENDPOINT_NAME.MAX_LENGTH)return{valid:!1,error:`Endpoint name must be at most ${w.VALIDATION.ENDPOINT_NAME.MAX_LENGTH} characters`};if(!w.VALIDATION.ENDPOINT_NAME.PATTERN.test(r.name))return{valid:!1,error:"Endpoint name must contain only alphanumeric characters, underscores, and hyphens"};if(!r.host||typeof r.host!="string"||r.host.length===0)return{valid:!1,error:"Endpoint host is required and must be a non-empty string"};let e=Number(r.port);return isNaN(e)||e<1||e>65535?{valid:!1,error:"Endpoint port must be a valid port number (1-65535)"}:r.type!==void 0&&!w.VALIDATION.VALID_ENDPOINT_TYPES.includes(r.type)?{valid:!1,error:`Endpoint type must be one of: ${w.VALIDATION.VALID_ENDPOINT_TYPES.join(", ")}`}:r.enabled!==void 0&&typeof r.enabled!="boolean"?{valid:!1,error:"Endpoint enabled must be a boolean"}:r.token!==void 0&&r.token!==null&&typeof r.token!="string"?{valid:!1,error:"Endpoint token must be a string or null"}:{valid:!0,value:{name:r.name,host:r.host,port:e,token:r.token||null,enabled:r.enabled!==!1,type:r.type||"local"}}}function Ih(r,e){switch(e){case"number":return typeof r=="number"&&!isNaN(r);case"string":return typeof r=="string";case"boolean":return typeof r=="boolean";case"object":return typeof r=="object"&&r!==null;default:return!1}}var Mt={validateSettings:xh,validateRefreshInterval:zo,validateLogLevelFilter:qo,validateSessionSortMode:Yo,validateTheme:Ko,validateExportFormat:Xo,validateExportDirectory:Jo,validateWidgetVisibility:Ot,validateAlertThresholds:Sh,validateAutoRetry:Qo,validateAutoSave:Zo,validateExportSchedule:zi,validatePath:qi,validateType:Ih,validateGatewayEndpoint:vh,getDefaultSettings:ea,VALID_THEMES:Ho,VALID_SORT_MODES:Go,VALID_LOG_LEVELS:Vo,VALID_EXPORT_FORMATS:jo};te();Q();var Ki=null;async function Dh(){if(!w.WORKERS?.ENABLED)return null;if(!Ki)try{let{default:r}=await Promise.resolve().then(()=>(Yi(),ta));Ki=r}catch(r){return u.debug("Worker pool not available:",r.message),null}return Ki}var Rs=new Map;function sa(r){let e=Rs.get(r);return e?Date.now()>e.expiresAt?(Rs.delete(r),null):e.value:null}function Xi(r,e,t){let s=w.CACHE_CONFIG[r]||{ttl:w.CACHE_TTL.DEFAULT},i=t||s.ttl;Rs.set(r,{value:e,expiresAt:Date.now()+i,createdAt:Date.now()})}async function rs(r,e,t){let s=sa(r);if(s!==null)return s;let i=await e();return Xi(r,i,t),i}async function _s(r,e){let t=await Dh();if(t)try{return await t.execute(r)}catch(s){u.debug(`Worker execution failed for ${r}, using fallback: ${s.message}`)}return e()}async function Nh(){return rs("cpu",async()=>{try{let e=_s("currentLoad",async()=>await(await import("systeminformation")).currentLoad()),t=new Promise((s,i)=>setTimeout(()=>i(new Error("CPU data timeout")),2e3));return await Promise.race([e,t])}catch(r){throw u.warn(`systeminformation.currentLoad() failed: ${r.message}`),r}})}async function $h(){return rs("memory",async()=>{try{let e=_s("mem",async()=>await(await import("systeminformation")).mem()),t=new Promise((s,i)=>setTimeout(()=>i(new Error("Memory data timeout")),2e3));return await Promise.race([e,t])}catch(r){throw u.warn(`systeminformation.mem() failed: ${r.message}`),r}})}async function Ph(){return rs("gpu",async()=>{try{return await _s("graphics",async()=>await(await import("systeminformation")).graphics())}catch(r){throw u.warn(`systeminformation.graphics() failed: ${r.message}`),r}})}async function Wh(){return rs("network",async()=>{try{let e=_s("networkStats",async()=>await(await import("systeminformation")).networkStats()),t=new Promise((s,i)=>setTimeout(()=>i(new Error("Network stats timeout")),2e3));return await Promise.race([e,t])}catch(r){return u.warn(`Network data fetch failed or timed out: ${r.message}`),[]}})}async function Fh(){return rs("disk",async()=>{try{return await _s("fsSize",async()=>await(await import("systeminformation")).fsSize())}catch(r){throw u.warn(`systeminformation.fsSize() failed: ${r.message}`),r}})}async function Uh(){return rs("system",async()=>{try{let r=await import("os"),e={os:{platform:r.platform(),distro:r.type(),release:r.release(),arch:r.arch()},ver:{node:process.version},time:{uptime:r.uptime()}};return _s("systemData",async()=>{let t=await import("systeminformation"),[s,i,n]=await Promise.all([t.osInfo(),t.versions(),t.time()]);return{os:s,ver:i,time:n}}).then(t=>{Xi("system",t)}).catch(()=>{}),e}catch(r){throw u.warn(`System data fetch failed: ${r.message}`),r}})}function Bh(r){Rs.delete(r)}function Hh(){Rs.clear()}function Gh(){let r=Date.now(),e={};for(let[t,s]of Rs){let i=Math.max(0,s.expiresAt-r);e[t]={cached:!0,age:r-s.createdAt,ttlRemaining:i,configTtl:w.CACHE_CONFIG[t]?.ttl||w.CACHE_TTL.DEFAULT}}return e}function Vh(r,e){let t=null,s=null;return function(...i){s=i,t&&clearTimeout(t),t=setTimeout(()=>{r.apply(this,s),t=null},e)}}function jh(r,e){let t=0,s=null;return function(...i){let n=Date.now(),a=e-(n-t);a<=0?(s&&(clearTimeout(s),s=null),t=n,r.apply(this,i)):s||(s=setTimeout(()=>{t=Date.now(),s=null,r.apply(this,i)},a))}}var xe={get:sa,set:Xi,getOrFetch:rs,getCpuData:Nh,getMemoryData:$h,getGpuData:Ph,getNetworkData:Wh,getDiskData:Fh,getSystemData:Uh,invalidate:Bh,clear:Hh,getStatus:Gh,debounce:Vh,throttle:jh,CACHE_CONFIG:w.CACHE_CONFIG};var na=lc(ra(),1);import Ks from"fs";Q();te();import oa from"path";import{fileURLToPath as zh}from"url";var qh=zh(import.meta.url),cp=oa.dirname(qh),Xs=w.DATABASE.PATH,H=null,ia=null,zr=null,qr=null;async function Yh(){try{ia=await(0,na.default)();let r=null;try{Ks.existsSync(Xs)&&(r=Ks.readFileSync(Xs),u.info("Loaded existing database from "+Xs))}catch(e){u.warn("Could not load existing database: "+e.message)}return H=new ia.Database(r),Kh(),zr=setInterval(Ji,w.DATABASE.SAVE_INTERVAL_MS).unref(),qr=setInterval(fa,w.DATABASE.CLEANUP_INTERVAL_MS).unref(),u.info("Database initialized successfully"),!0}catch(r){return u.error("Failed to initialize database: "+r.message),!1}}function Kh(){H.run(`
|
|
18
|
-
CREATE TABLE IF NOT EXISTS session_snapshots (
|
|
19
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20
|
-
session_id TEXT NOT NULL,
|
|
21
|
-
agent TEXT,
|
|
22
|
-
channel TEXT,
|
|
23
|
-
model TEXT,
|
|
24
|
-
tokens INTEGER DEFAULT 0,
|
|
25
|
-
status TEXT,
|
|
26
|
-
created_at INTEGER NOT NULL,
|
|
27
|
-
updated_at INTEGER NOT NULL
|
|
28
|
-
)
|
|
29
|
-
`),H.run(`
|
|
30
|
-
CREATE INDEX IF NOT EXISTS idx_session_snapshots_created
|
|
31
|
-
ON session_snapshots(created_at)
|
|
32
|
-
`),H.run(`
|
|
33
|
-
CREATE INDEX IF NOT EXISTS idx_session_snapshots_session_id
|
|
34
|
-
ON session_snapshots(session_id)
|
|
35
|
-
`),H.run(`
|
|
36
|
-
CREATE TABLE IF NOT EXISTS cpu_metrics (
|
|
37
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38
|
-
timestamp INTEGER NOT NULL,
|
|
39
|
-
cpu_count INTEGER,
|
|
40
|
-
load_avg_1 REAL,
|
|
41
|
-
load_avg_5 REAL,
|
|
42
|
-
load_avg_15 REAL,
|
|
43
|
-
cpu_usage_user REAL,
|
|
44
|
-
cpu_usage_system REAL,
|
|
45
|
-
cpu_usage_idle REAL,
|
|
46
|
-
cpu_usage_irq REAL,
|
|
47
|
-
cpu_usage_soft_irq REAL,
|
|
48
|
-
cpu_usage_stolen REAL
|
|
49
|
-
)
|
|
50
|
-
`),H.run(`
|
|
51
|
-
CREATE INDEX IF NOT EXISTS idx_cpu_metrics_timestamp
|
|
52
|
-
ON cpu_metrics(timestamp)
|
|
53
|
-
`),H.run(`
|
|
54
|
-
CREATE TABLE IF NOT EXISTS memory_metrics (
|
|
55
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
56
|
-
timestamp INTEGER NOT NULL,
|
|
57
|
-
total_bytes INTEGER,
|
|
58
|
-
used_bytes INTEGER,
|
|
59
|
-
free_bytes INTEGER,
|
|
60
|
-
available_bytes INTEGER,
|
|
61
|
-
used_percent REAL,
|
|
62
|
-
swap_total_bytes INTEGER,
|
|
63
|
-
swap_used_bytes INTEGER,
|
|
64
|
-
swap_free_bytes INTEGER,
|
|
65
|
-
swap_used_percent REAL
|
|
66
|
-
)
|
|
67
|
-
`),H.run(`
|
|
68
|
-
CREATE INDEX IF NOT EXISTS idx_memory_metrics_timestamp
|
|
69
|
-
ON memory_metrics(timestamp)
|
|
70
|
-
`),H.run(`
|
|
71
|
-
CREATE TABLE IF NOT EXISTS network_metrics (
|
|
72
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
73
|
-
timestamp INTEGER NOT NULL,
|
|
74
|
-
interface_name TEXT,
|
|
75
|
-
rx_bytes INTEGER,
|
|
76
|
-
tx_bytes INTEGER,
|
|
77
|
-
rx_sec REAL,
|
|
78
|
-
tx_sec REAL,
|
|
79
|
-
ms REAL
|
|
80
|
-
)
|
|
81
|
-
`),H.run(`
|
|
82
|
-
CREATE INDEX IF NOT EXISTS idx_network_metrics_timestamp
|
|
83
|
-
ON network_metrics(timestamp)
|
|
84
|
-
`),u.debug("Database tables created")}function Ji(){if(H)try{let r=H.export(),e=Buffer.from(r),t=oa.dirname(Xs);Ks.existsSync(t)||Ks.mkdirSync(t,{recursive:!0}),Ks.writeFileSync(Xs,e),u.debug("Database saved to disk")}catch(r){u.error("Failed to save database: "+r.message)}}function aa(r){if(!(!H||!r))try{let e=Date.now(),t=r.sessionId||r.key||null,s=r.agent||ru(r.key)||"unknown",i=r.deliveryContext?.channel||r.origin?.channel||r.origin?.surface||"unknown",n=r.model||r.llmModel||"unknown",a=r.totalTokens||r.tokens||0,c=r.status||(r.systemRunning?"running":"idle"),d=H.exec("SELECT id FROM session_snapshots WHERE session_id = ? ORDER BY created_at DESC LIMIT 1",[t]);d.length>0&&d[0].values.length>0?H.run(`UPDATE session_snapshots
|
|
85
|
-
SET agent = ?, channel = ?, model = ?, tokens = ?, status = ?, updated_at = ?
|
|
86
|
-
WHERE session_id = ?`,[s,i,n,a,c,e,t]):H.run(`INSERT INTO session_snapshots (session_id, agent, channel, model, tokens, status, created_at, updated_at)
|
|
87
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[t,s,i,n,a,c,e,e]),u.debug("Stored session snapshot: "+t)}catch(e){u.error("Failed to store session snapshot: "+e.message)}}function la(r){if(!(!H||!r))try{let e=Date.now(),t=r.cpus||[r];for(let s of t)H.run(`INSERT INTO cpu_metrics (
|
|
88
|
-
timestamp, cpu_count, load_avg_1, load_avg_5, load_avg_15,
|
|
89
|
-
cpu_usage_user, cpu_usage_system, cpu_usage_idle,
|
|
90
|
-
cpu_usage_irq, cpu_usage_soft_irq, cpu_usage_stolen
|
|
91
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[e,s.cpuCount||s.cpu_count||t.length||1,s.loadAvg1||s.load_avg_1||s.loadavg?.[0]||0,s.loadAvg5||s.load_avg_5||s.loadavg?.[1]||0,s.loadAvg15||s.load_avg_15||s.loadavg?.[2]||0,s.cpuUsageUser||s.cpu_usage_user||s.cpuUsage?.[0]||0,s.cpuUsageSystem||s.cpu_usage_system||s.cpuUsage?.[1]||0,s.cpuUsageIdle||s.cpu_usage_idle||s.cpuUsage?.[2]||100,s.cpuUsageIrq||s.cpu_usage_irq||s.cpuUsage?.[3]||0,s.cpuUsageSoftIrq||s.cpu_usage_soft_irq||s.cpuUsage?.[4]||0,s.cpuUsageStolen||s.cpu_usage_stolen||s.cpuUsage?.[5]||0]);u.debug("Stored CPU metrics")}catch(e){u.error("Failed to store CPU metrics: "+e.message)}}function ca(r){if(!(!H||!r))try{let e=Date.now();H.run(`INSERT INTO memory_metrics (
|
|
92
|
-
timestamp, total_bytes, used_bytes, free_bytes, available_bytes,
|
|
93
|
-
used_percent, swap_total_bytes, swap_used_bytes, swap_free_bytes, swap_used_percent
|
|
94
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[e,r.totalBytes||r.total_bytes||0,r.usedBytes||r.used_bytes||0,r.freeBytes||r.free_bytes||0,r.availableBytes||r.available_bytes||0,r.usedPercent||r.used_percent||0,r.swapTotalBytes||r.swap_total_bytes||0,r.swapUsedBytes||r.swap_used_bytes||0,r.swapFreeBytes||r.swap_free_bytes||0,r.swapUsedPercent||r.swap_used_percent||0]),u.debug("Stored memory metrics")}catch(e){u.error("Failed to store memory metrics: "+e.message)}}function ha(r){if(!(!H||!r))try{let e=Date.now(),t=Array.isArray(r)?r:[r];for(let s of t)H.run(`INSERT INTO network_metrics (
|
|
95
|
-
timestamp, interface_name, rx_bytes, tx_bytes, rx_sec, tx_sec, ms
|
|
96
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?)`,[e,s.interfaceName||s.interface_name||"unknown",s.rxBytes||s.rx_bytes||0,s.txBytes||s.tx_bytes||0,s.rxSec||s.rx_sec||0,s.txSec||s.tx_sec||0,s.ms||0]);u.debug("Stored network metrics")}catch(e){u.error("Failed to store network metrics: "+e.message)}}function Xh(){return ua(24)}function Jh(){return da(7)}function ua(r=24){if(!H)return[];try{let e=Date.now()-r*60*60*1e3,t=H.exec(`SELECT session_id, agent, channel, model, tokens, status, created_at, updated_at
|
|
97
|
-
FROM session_snapshots
|
|
98
|
-
WHERE created_at >= ?
|
|
99
|
-
ORDER BY created_at DESC`,[e]);return t.length===0?[]:t[0].values.map(s=>({sessionId:s[0],agent:s[1],channel:s[2],model:s[3],tokens:s[4],status:s[5],createdAt:s[6],updatedAt:s[7]}))}catch(e){return u.error("Failed to get sessions by hours: "+e.message),[]}}function da(r=7){if(!H)return[];try{let e=Date.now()-r*24*60*60*1e3,t=H.exec(`SELECT session_id, agent, channel, model, tokens, status, created_at, updated_at
|
|
100
|
-
FROM session_snapshots
|
|
101
|
-
WHERE created_at >= ?
|
|
102
|
-
ORDER BY created_at DESC`,[e]);return t.length===0?[]:t[0].values.map(s=>({sessionId:s[0],agent:s[1],channel:s[2],model:s[3],tokens:s[4],status:s[5],createdAt:s[6],updatedAt:s[7]}))}catch(e){return u.error("Failed to get sessions by days: "+e.message),[]}}function Qh(r=24){if(!H)return[];try{let e=Date.now()-r*60*60*1e3,t=H.exec(`SELECT timestamp, cpu_count, load_avg_1, load_avg_5, load_avg_15,
|
|
103
|
-
cpu_usage_user, cpu_usage_system, cpu_usage_idle
|
|
104
|
-
FROM cpu_metrics
|
|
105
|
-
WHERE timestamp >= ?
|
|
106
|
-
ORDER BY timestamp ASC`,[e]);return t.length===0?[]:t[0].values.map(s=>({timestamp:s[0],cpuCount:s[1],loadAvg1:s[2],loadAvg5:s[3],loadAvg15:s[4],cpuUsageUser:s[5],cpuUsageSystem:s[6],cpuUsageIdle:s[7]}))}catch(e){return u.error("Failed to get CPU metrics history: "+e.message),[]}}function Zh(r=24){if(!H)return[];try{let e=Date.now()-r*60*60*1e3,t=H.exec(`SELECT timestamp, total_bytes, used_bytes, free_bytes, available_bytes, used_percent
|
|
107
|
-
FROM memory_metrics
|
|
108
|
-
WHERE timestamp >= ?
|
|
109
|
-
ORDER BY timestamp ASC`,[e]);return t.length===0?[]:t[0].values.map(s=>({timestamp:s[0],totalBytes:s[1],usedBytes:s[2],freeBytes:s[3],availableBytes:s[4],usedPercent:s[5]}))}catch(e){return u.error("Failed to get memory metrics history: "+e.message),[]}}function eu(r=24){if(!H)return[];try{let e=Date.now()-r*60*60*1e3,t=H.exec(`SELECT timestamp, interface_name, rx_bytes, tx_bytes, rx_sec, tx_sec
|
|
110
|
-
FROM network_metrics
|
|
111
|
-
WHERE timestamp >= ?
|
|
112
|
-
ORDER BY timestamp ASC`,[e]);return t.length===0?[]:t[0].values.map(s=>({timestamp:s[0],interfaceName:s[1],rxBytes:s[2],txBytes:s[3],rxSec:s[4],txSec:s[5]}))}catch(e){return u.error("Failed to get network metrics history: "+e.message),[]}}function tu(r=24){if(!H)return null;try{let e=Date.now()-r*60*60*1e3,t=H.exec(`SELECT
|
|
113
|
-
AVG(cpu_usage_user) as avg_user,
|
|
114
|
-
MAX(cpu_usage_user) as max_user,
|
|
115
|
-
AVG(load_avg_1) as avg_load
|
|
116
|
-
FROM cpu_metrics
|
|
117
|
-
WHERE timestamp >= ?`,[e]),s=H.exec(`SELECT
|
|
118
|
-
AVG(used_percent) as avg_used,
|
|
119
|
-
MAX(used_percent) as max_used,
|
|
120
|
-
AVG(available_bytes) as avg_available
|
|
121
|
-
FROM memory_metrics
|
|
122
|
-
WHERE timestamp >= ?`,[e]),i=H.exec(`SELECT COUNT(DISTINCT session_id) as session_count
|
|
123
|
-
FROM session_snapshots
|
|
124
|
-
WHERE created_at >= ?`,[e]),n=H.exec(`SELECT SUM(tokens) as total_tokens
|
|
125
|
-
FROM session_snapshots
|
|
126
|
-
WHERE created_at >= ?`,[e]);return{cpu:t.length>0&&t[0].values.length>0?{avgUser:t[0].values[0][0]||0,maxUser:t[0].values[0][1]||0,avgLoad:t[0].values[0][2]||0}:null,memory:s.length>0&&s[0].values.length>0?{avgUsed:s[0].values[0][0]||0,maxUsed:s[0].values[0][1]||0,avgAvailable:s[0].values[0][2]||0}:null,sessions:i.length>0&&i[0].values.length>0?{count:i[0].values[0][0]||0}:{count:0},tokens:n.length>0&&n[0].values.length>0?{total:n[0].values[0][0]||0}:{total:0}}}catch(e){return u.error("Failed to get metrics summary: "+e.message),null}}function fa(r=30){if(H){try{let e=Date.now()-r*24*60*60*1e3;H.run("DELETE FROM session_snapshots WHERE created_at < ?",[e]),H.run("DELETE FROM cpu_metrics WHERE timestamp < ?",[e]),H.run("DELETE FROM memory_metrics WHERE timestamp < ?",[e]),H.run("DELETE FROM network_metrics WHERE timestamp < ?",[e]),u.info("Cleaned up data older than "+r+" days")}catch(e){u.error("Failed to cleanup old data: "+e.message)}try{Ji()}catch(e){u.error("Failed to save database after cleanup: "+e.message)}}}function su(r){if(r){if(r.cpu){let e=Array.isArray(r.cpu)?{cpus:r.cpu}:r.cpu;la(e)}if(r.memory&&ca(r.memory),r.network&&ha(r.network),r.sessions&&r.sessions.length>0)for(let e of r.sessions)aa(e)}}function ru(r){if(!r)return"unknown";let e=r.split(":");return e[1]||e[0]||"unknown"}function iu(){if(zr&&(clearInterval(zr),zr=null),qr&&(clearInterval(qr),qr=null),H){try{Ji()}catch(r){u.error("Failed to save database during close: "+r.message)}try{H.close()}catch(r){u.error("Failed to close database: "+r.message)}H=null,u.info("Database closed")}}var Cs={initDatabase:Yh,closeDatabase:iu,storeSessionSnapshot:aa,storeCpuMetrics:la,storeMemoryMetrics:ca,storeNetworkMetrics:ha,storeMetricsSnapshot:su,getSessionsLast24Hours:Xh,getSessionsLast7Days:Jh,getSessionsByHours:ua,getSessionsByDays:da,getCpuMetricsHistory:Qh,getMemoryMetricsHistory:Zh,getNetworkMetricsHistory:eu,getMetricsSummary:tu,cleanupOldData:fa};Es();te();import ns from"blessed";async function ga(r,e){let t=ns.box({parent:r,top:0,left:0,width:"100%",height:"100%",style:{bg:"black"}});ns.text({parent:t,top:Math.floor(r.height/2)-4,left:"center",content:"CLAW DASHBOARD",style:{fg:"brightCyan",bold:!0}}),ns.text({parent:t,top:Math.floor(r.height/2)-2,left:"center",content:"================",style:{fg:"cyan"}}),ns.text({parent:t,top:Math.floor(r.height/2),left:"center",content:`v${pe}`,style:{fg:"gray"}});let s=ns.text({parent:t,top:Math.floor(r.height/2)+3,left:"center",width:35,height:1,content:"Initializing...",style:{fg:"white",bold:!0},align:"center"}),i=ns.text({parent:t,top:Math.floor(r.height/2)+3,left:Math.floor(r.width/2)+18,content:"*",style:{fg:"brightGreen",bold:!0}}),n=ns.text({parent:t,top:Math.floor(r.height/2)+5,left:"center",width:30,content:"[----------------------]",style:{fg:"gray"},align:"center"});r.render();let a=["|","/","-","\\\\"],c=0,d=setInterval(()=>{c=(c+1)%a.length,i.setContent(a[c]),r.render()},150),g=(p,T)=>{T&&s.setContent(T);let b=Math.floor(p/100*22),_="["+"#".repeat(b)+"-".repeat(22-b)+"]";n.setContent(_),n.style.fg=p<50?"red":p<80?"yellow":"green",r.render()};try{e&&await e(g),g(100,"Ready!"),await new Promise(p=>setTimeout(p,400))}finally{clearInterval(d),t.destroy(),r.render()}}te();Q();import os from"blessed";var{PATHS:yp,DASHBOARD_VERSION:wp}=w,Yr=[{id:"navigation",title:"\u{1F4CB} Navigation Tips",content:["Use \u2191/\u2193 arrows to navigate sessions","Use h/l or \u2190/\u2192 to change pages","Press Enter to select a session","Press / to search sessions"],position:{top:"center",left:"center"}},{id:"vi-mode",title:"\u2328\uFE0F Vi-Mode Navigation",content:["h / l : Previous/next page","j / k : Select next/previous session","g / G : Go to first/last page","Ctrl+B / Ctrl+F : Page up/down"],position:{top:"center",left:"center"}},{id:"bookmarks",title:"\u2B50 Bookmarks & Favorites",content:["Press 'f' to toggle favorite on current session","Press 'F' to filter/show favorites only","Favorites persist across restarts","Access them quickly with the F filter"],position:{top:"center",left:"center"}},{id:"widgets",title:"\u{1F4CA} Widget Controls",content:["Use number keys 1-7 to toggle widgets","Tab to cycle through widgets","Resize terminal to adjust layout","Widgets auto-refresh with live data"],position:{top:"center",left:"center"}},{id:"actions",title:"\u26A1 Quick Actions",content:["r : Refresh data immediately","s : Change sort mode","e : Export session data","d : View session details","q : Quit dashboard"],position:{top:"center",left:"center"}}],nu=new Set,Ls=0,Be=null,ou=null;function au(r){return r?.firstRun===!0}function pa(r,e){r&&r.firstRun&&(r.firstRun=!1,typeof e=="function"&&(e(r),u.info("First run hints marked as complete")))}function lu(r,e,t,s){let a=os.box({parent:r,top:"center",left:"center",width:50,height:14,border:{type:"line",fg:"brightCyan"},style:{bg:"black",border:{fg:"brightCyan"}},tags:!0,shadow:!0});os.text({parent:a,top:0,left:"center",width:48,content:` {bold}${e.title}{/bold} `,style:{fg:"brightCyan",bg:"black"},tags:!0}),os.line({parent:a,top:2,left:1,right:1,orientation:"horizontal",style:{fg:"dim"}});let c=3;e.content.forEach(p=>{os.text({parent:a,top:c++,left:2,width:46,content:` ${p}`,style:{fg:"white",bg:"black"}})}),os.line({parent:a,top:10,left:1,right:1,orientation:"horizontal",style:{fg:"dim"}});let d=t<s-1?" {bold}n{/bold}: Next {bold}q{/bold}: Skip all":" {bold}q{/bold}: Close hints {bold}r{/bold}: Show again later";os.text({parent:a,top:11,left:"center",width:48,content:d,style:{fg:"gray",bg:"black"},tags:!0});let g=` (${t+1}/${s})`;return os.text({parent:a,top:12,left:"center",content:g,style:{fg:"dim",bg:"black"}}),a}function ma(r){if(Be&&(Be.destroy(),Be=null),Ls>=Yr.length)return!1;let e=Yr[Ls];return Be=lu(r,e,Ls,Yr.length),r.render(),!0}async function ya(r,e,t){if(au(e))return ou=r,Ls=0,nu.clear(),new Promise(s=>{ma(r);let i=(n,a)=>{(n==="n"||n===" "||a.name==="right")&&(Ls++,ma(r)||(Be&&(Be.destroy(),Be=null),r.removeListener("keypress",i),pa(e,t),r.render(),s())),(n==="q"||a.name==="escape")&&(Be&&(Be.destroy(),Be=null),r.removeListener("keypress",i),pa(e,t),r.render(),s()),n==="r"&&Ls>=Yr.length-1&&(e.firstRun=!0,typeof t=="function"&&t(e),Be&&(Be.destroy(),Be=null),r.removeListener("keypress",i),r.render(),s())};r.on("keypress",i)})}As();import{watch as cu,watchFile as hu,unwatchFile as uu,existsSync as wa,readdirSync as Sp,readFileSync as du}from"fs";import{EventEmitter as fu}from"events";Q();var gu={debounceMs:500,persistent:!0,encoding:"utf8",usePolling:!1,pollInterval:1e3,ignoreInitial:!0},as=class extends fu{constructor(e={}){super(),this.options={...gu,...e},this.watchers=new Map,this.pollWatchers=new Map,this.lastModified=new Map,this.debounceTimers=new Map,this.watchedFiles=new Set,this.isRunning=!1}watchFile(e,t={}){if(!e||typeof e!="string")return u.error("ConfigWatcher: Invalid file path provided"),!1;if(this.watchers.has(e))return u.debug(`ConfigWatcher: Already watching ${e}`),!0;let s={...this.options,...t};if(!wa(e))return u.warn(`ConfigWatcher: File not found: ${e}`),!1;try{return s.usePolling?this._startPolling(e,s):this._startNativeWatch(e,s),this.watchedFiles.add(e),this.lastModified.set(e,Date.now()),this.isRunning=!0,u.info(`ConfigWatcher: Started watching ${e}`),!0}catch(i){return u.error(`ConfigWatcher: Failed to watch ${e}: ${i.message}`),!1}}unwatchFile(e){if(!this.watchers.has(e)&&!this.pollWatchers.has(e))return;let t=this.debounceTimers.get(e);t&&(clearTimeout(t),this.debounceTimers.delete(e));let s=this.watchers.get(e);s&&(s.close(),this.watchers.delete(e)),this.pollWatchers.has(e)&&(uu(e),this.pollWatchers.delete(e)),this.watchedFiles.delete(e),this.lastModified.delete(e),u.info(`ConfigWatcher: Stopped watching ${e}`),this.watchers.size===0&&this.pollWatchers.size===0&&(this.isRunning=!1)}watchFiles(e){let t={successful:[],failed:[]};for(let s of e)this.watchFile(s)?t.successful.push(s):t.failed.push(s);return t}unwatchAll(){for(let e of this.watchedFiles)this.unwatchFile(e)}getWatchedFiles(){return Array.from(this.watchedFiles)}isWatching(e){return this.watchedFiles.has(e)}_startNativeWatch(e,t){let s=cu(e,{persistent:t.persistent,encoding:t.encoding});s.on("change",i=>{i==="change"&&this._handleChange(e,t)}),s.on("error",i=>{u.error(`ConfigWatcher: Watcher error for ${e}: ${i.message}`),this.emit("error",{filePath:e,error:i})}),s.on("close",()=>{this.watchers.delete(e),this.watchers.size===0&&this.pollWatchers.size===0&&(this.isRunning=!1)}),this.watchers.set(e,s)}_startPolling(e,t){hu(e,{persistent:t.persistent,interval:t.pollInterval},(s,i)=>{s.mtimeMs!==i.mtimeMs&&this._handleChange(e,t)}),this.pollWatchers.set(e,!0)}_handleChange(e,t){let s=Date.now(),i=this.lastModified.get(e)||0;this.lastModified.set(e,s);let n=this.debounceTimers.get(e);n&&clearTimeout(n);let a=setTimeout(()=>{this.debounceTimers.delete(e),this._emitReload(e)},t.debounceMs);this.debounceTimers.set(e,a)}_emitReload(e){u.info(`ConfigWatcher: File changed: ${e}`),this.emit("reload",{filePath:e,timestamp:Date.now()})}getStats(){return{isRunning:this.isRunning,watchedFiles:this.watchedFiles.size,nativeWatchers:this.watchers.size,pollWatchers:this.pollWatchers.size,pendingDebounces:this.debounceTimers.size}}};function pu(r={}){return new as(r)}function Ea(r,e,t={}){if(!wa(r))return u.warn(`ConfigWatcher: Settings file not found: ${r}`),null;let s=pu(t);return s.on("reload",async({filePath:i})=>{try{let n=du(i,"utf8"),a=JSON.parse(n);u.info(`ConfigWatcher: Settings reloaded from ${i}`),typeof e=="function"&&await e(a,i)}catch(n){u.error(`ConfigWatcher: Failed to reload settings: ${n.message}`),s.emit("error",{filePath:i,error:n})}}),s.on("error",({filePath:i,error:n})=>{u.error(`ConfigWatcher: Error for ${i}: ${n.message}`)}),s.watchFile(r)?s:null}import{join as Zs,basename as $u}from"path";import{pathToFileURL as Pu}from"url";import{existsSync as cs,readdirSync as Wu}from"fs";Q();te();Es();import{existsSync as Qs,readdirSync as Du}from"fs";import{join as st,basename as $t}from"path";import{pathToFileURL as Ca}from"url";Q();var mu={interpolateEnv:!0,supportLegacy:!0,validateVersion:!0,throwOnError:!1};function yu(r,e=process.env){if(typeof r!="string")return r;let t=/\$\{([^}]+)\}/g;return r.replace(t,(s,i)=>{let n=i.indexOf(":-");if(n!==-1){let a=i.substring(0,n),c=i.substring(n+2);return e[a]!==void 0?e[a]:c}return e[i]!==void 0?e[i]:s})}function Zi(r,e=process.env,t=new Set){if(r==null)return r;if(typeof r=="string")return yu(r,e);if(Array.isArray(r))return r.map(s=>Zi(s,e,t));if(typeof r=="object"&&r.constructor===Object){if(t.has(r))return u.warn("Circular reference detected in config, skipping"),r;t.add(r);let s={};for(let[i,n]of Object.entries(r))s[i]=Zi(n,e,t);return t.delete(r),s}return r}var ks={CURRENT:"1.0.0",MIN_SUPPORTED:"1.0.0"};function ba(r){let e=r.split(".").map(Number);return[e[0]||0,e[1]||0,e[2]||0]}function Sa(r,e){let t=ba(r),s=ba(e);for(let i=0;i<3;i++){if(t[i]<s[i])return-1;if(t[i]>s[i])return 1}return 0}var Qi=new Map;function xa(r,e){if(r===e)return[];let t=`${r}\u2192${e}`;if(Qi.has(t))return[Qi.get(t)];for(let[s,i]of Qi)if(i.fromVersion===r){let n=xa(i.toVersion,e);if(n!==null)return[i,...n]}return null}function wu(r){let e=r?.__version||"1.0.0";return Sa(e,ks.MIN_SUPPORTED)<0?{valid:!1,error:`Config version ${e} is below minimum supported ${ks.MIN_SUPPORTED}`}:Sa(e,ks.CURRENT)>0?{valid:!1,error:`Config version ${e} is newer than current ${ks.CURRENT}. Please upgrade the dashboard.`}:{valid:!0,version:e}}function Eu(r,e=ks.CURRENT){if(!r||typeof r!="object")return{success:!1,error:"Invalid config object"};let t=r.__version||"1.0.0";if(t===e)return{success:!0,config:r,path:[]};let s=xa(t,e);if(s===null)return{success:!1,error:`No migration path from ${t} to ${e}`};let i={...r},n=[];try{for(let a of s)i=a.migrate(i),i.__version=a.toVersion,n.push(`${a.fromVersion}\u2192${a.toVersion}`);return{success:!0,config:i,path:n}}catch(a){return{success:!1,error:`Migration failed: ${a.message}`,path:n}}}function Kr(r,e={}){let t={...mu,...e},s=[];try{let i=r;if(t.validateVersion){let n=wu(i);if(!n.valid){if(n.error?.includes("below minimum")){if(t.throwOnError)throw new Error(n.error);return{success:!1,error:n.error}}if(t.throwOnError)throw new Error(n.error);return{success:!1,error:n.error}}if(n.version!==ks.CURRENT){let a=Eu(i);if(a.success)i=a.config,a.path?.length>0&&s.push(`Migrated config: ${a.path.join(", ")}`);else{if(t.throwOnError)throw new Error(a.error);s.push(`Config migration failed: ${a.error}`)}}}return t.interpolateEnv&&(i=Zi(i)),{success:!0,config:i,warnings:s.length>0?s:void 0}}catch(i){let n=`Config processing failed: ${i.message}`;if(t.throwOnError)throw i;return{success:!1,error:n}}}import{readFileSync as bu}from"fs";import{fileURLToPath as Su}from"url";import{dirname as xu,join as Tu}from"path";var vu=Su(import.meta.url),Iu=xu(vu),Au=Tu(Iu,"..","schemas","plugin-manifest.json"),Xr;try{Xr=JSON.parse(bu(Au,"utf8"))}catch(r){throw new Error(`Failed to load plugin manifest schema: ${r.message}`)}function Ta(r,e){return e==="string"?typeof r=="string":e==="number"?typeof r=="number"&&!isNaN(r):e==="boolean"?typeof r=="boolean":e==="object"?typeof r=="object"&&r!==null&&!Array.isArray(r):e==="array"?Array.isArray(r):!0}function va(r,e){return new RegExp(e).test(r)}function Ru(r){return/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/.test(r)}function _u(r){return/^[a-zA-Z0-9]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/.test(r)}function ls(r){let e=[];if(!r||typeof r!="object")return{valid:!1,errors:["Manifest must be a valid object"]};let t=Xr.required||[];for(let i of t)i in r||e.push(`Missing required field: ${i}`);let s=Xr.properties||{};for(let[i,n]of Object.entries(r)){let a=s[i];if(!a){Xr.additionalProperties===!1&&e.push(`Unknown property: ${i}`);continue}if(a.type&&!Ta(n,a.type)){e.push(`Invalid type for ${i}: expected ${a.type}, got ${typeof n}`);continue}if(a.type==="string"&&(a.minLength!==void 0&&n.length<a.minLength&&e.push(`${i} must be at least ${a.minLength} characters`),a.maxLength!==void 0&&n.length>a.maxLength&&e.push(`${i} must be at most ${a.maxLength} characters`),a.pattern&&!va(n,a.pattern)&&e.push(`${i} format is invalid`)),a.type==="number"&&(a.minimum!==void 0&&n<a.minimum&&e.push(`${i} must be at least ${a.minimum}`),a.maximum!==void 0&&n>a.maximum&&e.push(`${i} must be at most ${a.maximum}`)),a.type==="array"&&Array.isArray(n)&&(a.uniqueItems&&new Set(n).size!==n.length&&e.push(`${i} contains duplicate values`),a.items))for(let c=0;c<n.length;c++){let d=n[c];a.items.type&&!Ta(d,a.items.type)&&e.push(`${i}[${c}] must be of type ${a.items.type}`),a.items.pattern&&!va(d,a.items.pattern)&&e.push(`${i}[${c}] format is invalid`),a.items.enum&&!a.items.enum.includes(d)&&e.push(`${i}[${c}] must be one of: ${a.items.enum.join(", ")}`)}a.enum&&!a.enum.includes(n)&&e.push(`${i} must be one of: ${a.enum.join(", ")}`)}return r.version&&typeof r.version=="string"&&(Ru(r.version)||e.push("version must be a valid semantic version (e.g., 1.0.0)")),{valid:e.length===0,errors:e}}function Ia(r){return!r||typeof r!="string"?{valid:!1,error:"Plugin ID must be a non-empty string"}:_u(r)?r.length>64?{valid:!1,error:"Plugin ID must be 64 characters or less"}:{valid:!0}:{valid:!1,error:"Plugin ID must contain only alphanumeric characters, hyphens, and underscores, and cannot start or end with a hyphen/underscore"}}function Cu(r){if(typeof r=="string")return{id:r,optional:!1};if(typeof r=="object"&&r!==null){if(!r.id||typeof r.id!="string")throw new Error('Dependency object must have a string "id" property');return{id:r.id,optional:r.optional===!0,version:r.version}}throw new Error('Dependency must be a string or an object with an "id" property')}function Lu(r){if(!r.dependencies||!Array.isArray(r.dependencies))return[];let e=[];for(let t of r.dependencies)try{e.push(Cu(t))}catch(s){console.warn(`Invalid dependency format in widget "${r.id||"unknown"}": ${s.message}`)}return e}function Js(r){let e=new Map;for(let[t,s]of r){let i=Lu(s.metadata||{});e.set(t,{id:t,dependencies:i,inDegree:0,dependents:new Set})}for(let[t,s]of e)for(let i of s.dependencies){let n=e.get(i.id);n&&(n.dependents.add(t),s.inDegree++)}return e}function Aa(r){let e=new Set,t=new Set,s=[];function i(n){e.add(n),t.add(n),s.push(n);let a=r.get(n);if(a)for(let c of a.dependencies){let d=c.id;if(e.has(d)){if(t.has(d)){let g=s.indexOf(d);return[...s.slice(g),d]}}else{let g=i(d);if(g)return g}}return s.pop(),t.delete(n),null}for(let[n]of r)if(!e.has(n)){let a=i(n);if(a)return a}return null}function Ra(r,e){if(!r||!e)return!0;let t=n=>{let a=n.replace(/^[=v]+/,"").split(".").map(Number);return{major:a[0]||0,minor:a[1]||0,patch:a[2]||0}},s=t(r),i=t(e.replace(/^[>=^~]+/,""));return e.startsWith(">=")?!(s.major<i.major||s.major===i.major&&s.minor<i.minor||s.major===i.major&&s.minor===i.minor&&s.patch<i.patch):e.startsWith("^")?!(s.major!==i.major||s.major===0&&(s.minor<i.minor||s.minor===i.minor&&s.patch<i.patch)):e.startsWith("~")?!(s.major!==i.major||s.minor!==i.minor||s.patch<i.patch):s.major===i.major&&s.minor===i.minor&&s.patch===i.patch}function ku(r,e){let t={};for(let[s,i]of r){let n=[];for(let a of i.dependencies){if(!a.version)continue;let c=e.get(a.id);if(!c)continue;let d=c.metadata?.version;d?Ra(d,a.version)||n.push({dependency:a.id,constraint:a.version,actual:d,reason:`Version ${d} does not satisfy constraint ${a.version}`}):n.push({dependency:a.id,constraint:a.version,actual:"unknown",reason:"Dependency has no version specified"})}n.length>0&&(t[s]=n)}return Object.keys(t).length>0?t:null}function Ou(r,e){let t={};for(let[s,i]of r){let n=[];for(let a of i.dependencies)!a.optional&&!e.has(a.id)&&n.push(a.id);n.length>0&&(t[s]=n)}return Object.keys(t).length>0?t:null}function Mu(r,e=null){let t=new Map;for(let[a,c]of r)t.set(a,c.inDegree);let s=e?new Set(e):null;if(s){let a=[...e],c=new Set;for(let d of a){if(c.has(d))continue;c.add(d);let g=r.get(d);if(g)for(let p of g.dependencies)r.has(p.id)&&(s.add(p.id),a.push(p.id))}}let i=[];for(let[a,c]of t)c===0&&(!s||s.has(a))&&i.push(a);i.sort();let n=[];for(;i.length>0;){let a=i.shift();n.push(a);let c=r.get(a);if(c)for(let d of c.dependents){if(s&&!s.has(d))continue;let g=t.get(d)-1;if(t.set(d,g),g===0){let p=i.findIndex(T=>T>d);p===-1?i.push(d):i.splice(p,0,d)}}}return n}function en(r,e={}){let{targetIds:t=null,skipVersionCheck:s=!1,allowPartial:i=!1}=e;if(r.size===0)return{success:!0,order:[]};let n=Js(r),a=Aa(n);if(a)return{success:!1,order:[],error:`Circular dependency detected: ${a.join(" -> ")}`,circularPath:a};let c=Ou(n,r);if(c&&!i){let T=Object.entries(c).map(([b,_])=>`"${b}" requires: ${_.join(", ")}`).join("; ");return{success:!1,order:[],error:`Missing required dependencies: ${T}`,missingDeps:c}}if(!s){let T=ku(n,r);if(T){let b=Object.entries(T).map(([_,v])=>`"${_}": ${v.map(S=>S.reason).join(", ")}`).join("; ");return{success:!1,order:[],error:`Version constraint violations: ${b}`,constraintViolations:T}}}let d=t||Array.from(r.keys()),g=Mu(n,d),p=g;if(i&&c){let T=new Set(Object.keys(c));p=g.filter(b=>!T.has(b))}return{success:!0,order:p,...c&&{missingDeps:c}}}function tn(r,e,t={}){let{includeOptional:s=!0}=t,i=new Set,n=new Set;function a(c){if(n.has(c))return;n.add(c);let d=r.get(c);if(d)for(let g of d.dependencies)!s&&g.optional||(i.add(g.id),a(g.id))}return a(e),Array.from(i)}function _a(r,e){let t=new Set,s=new Set;function i(n){if(s.has(n))return;s.add(n);let a=r.get(n);if(a)for(let c of a.dependents)t.add(c),i(c)}return i(e),Array.from(t)}function Jr(r,e){let t=Js(r),s=t.get(e);if(!s)return{valid:!1,error:`Widget "${e}" not found in registry`};let i=[];for(let a of s.dependencies)!a.optional&&!r.has(a.id)&&i.push(a.id);if(i.length>0)return{valid:!1,error:`Missing required dependencies: ${i.join(", ")}`,missing:i};let n=Aa(t);if(n&&n.includes(e))return{valid:!1,error:`Circular dependency detected: ${n.join(" -> ")}`,circularPath:n};for(let a of s.dependencies){if(!a.version)continue;let c=r.get(a.id);if(!c)continue;let d=c.metadata?.version;if(!d)return{valid:!1,error:`Dependency "${a.id}" has no version for constraint "${a.version}"`,constraintViolation:{dependency:a.id,constraint:a.version,actual:null}};if(!Ra(d,a.version))return{valid:!1,error:`Dependency "${a.id}" version ${d} does not satisfy constraint ${a.version}`,constraintViolation:{dependency:a.id,constraint:a.version,actual:d}}}return{valid:!0,dependencies:s.dependencies.map(a=>a.id),allDependencies:tn(t,e)}}As();var P={MANIFEST_NOT_FOUND:"PLUGIN_MANIFEST_NOT_FOUND",MANIFEST_INVALID_JSON:"PLUGIN_MANIFEST_INVALID_JSON",MANIFEST_MISSING_FIELD:"PLUGIN_MANIFEST_MISSING_FIELD",MANIFEST_INVALID_FIELD:"PLUGIN_MANIFEST_INVALID_FIELD",MANIFEST_SCHEMA_ERROR:"PLUGIN_MANIFEST_SCHEMA_ERROR",ENTRY_NOT_FOUND:"PLUGIN_ENTRY_NOT_FOUND",ENTRY_NO_EXPORT:"PLUGIN_ENTRY_NO_EXPORT",ENTRY_INVALID_EXPORT:"PLUGIN_ENTRY_INVALID_EXPORT",ENTRY_RUNTIME_ERROR:"PLUGIN_ENTRY_RUNTIME_ERROR",WIDGET_MISSING_METHODS:"PLUGIN_WIDGET_MISSING_METHODS",WIDGET_NOT_A_CLASS:"PLUGIN_WIDGET_NOT_A_CLASS",WIDGET_CONSTRUCTOR_ERROR:"PLUGIN_WIDGET_CONSTRUCTOR_ERROR",PATH_INVALID:"PLUGIN_PATH_INVALID",NAME_INVALID:"PLUGIN_NAME_INVALID",CONFIG_INVALID:"PLUGIN_CONFIG_INVALID",CONFIG_PROCESSING_ERROR:"PLUGIN_CONFIG_PROCESSING_ERROR",DEPENDENCY_MISSING:"PLUGIN_DEPENDENCY_MISSING",DEPENDENCY_VERSION_MISMATCH:"PLUGIN_DEPENDENCY_VERSION_MISMATCH",DEPENDENCY_CIRCULAR:"PLUGIN_DEPENDENCY_CIRCULAR",PLUGIN_LOAD_ERROR:"PLUGIN_LOAD_ERROR",PLUGIN_INIT_ERROR:"PLUGIN_INIT_ERROR"},Qr={[P.MANIFEST_NOT_FOUND]:{suggestion:"Create a plugin.json file in your plugin directory",docs:"https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md#plugin-structure",example:`{
|
|
127
|
-
"id": "my-widget",
|
|
128
|
-
"name": "My Widget",
|
|
129
|
-
"description": "A custom widget",
|
|
130
|
-
"version": "1.0.0",
|
|
131
|
-
"type": "widget",
|
|
132
|
-
"category": "custom"
|
|
133
|
-
}`},[P.MANIFEST_INVALID_JSON]:{suggestion:"Fix the JSON syntax in your plugin.json file",commonCauses:["Trailing commas after the last property","Missing quotes around property names or string values","Unclosed brackets or braces","Comments (JSON does not support comments)"],fix:"Use a JSON linter or validator to find the syntax error"},[P.MANIFEST_MISSING_FIELD]:{suggestion:"Add the required field to your plugin.json",requiredFields:["id","name","version","type"],docs:"https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md#manifest-schema"},[P.MANIFEST_INVALID_FIELD]:{suggestion:"Correct the invalid field in your plugin.json",commonFixes:{id:"Must contain only letters, numbers, hyphens, and underscores (cannot start/end with hyphen/underscore)",version:'Must follow semantic versioning (e.g., "1.0.0", "2.1.0-beta.1")',type:'Must be "widget" (currently the only supported type)',category:"Must be one of: system, monitoring, custom, example",priority:"Must be a number between 0 and 1000"}},[P.ENTRY_NOT_FOUND]:{suggestion:"Create an index.js file in your plugin directory",docs:"https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md#widget-structure",example:`import { BaseWidget } from 'claw-dashboard/widgets';
|
|
134
|
-
|
|
135
|
-
export default class MyWidget extends BaseWidget {
|
|
136
|
-
async init() { return true; }
|
|
137
|
-
async create(screen, theme) { /* create UI */ }
|
|
138
|
-
async getData() { return { value: 42 }; }
|
|
139
|
-
render(data) { /* render data */ }
|
|
140
|
-
async destroy() { /* cleanup */ }
|
|
141
|
-
}`},[P.ENTRY_NO_EXPORT]:{suggestion:"Export your widget class from index.js",options:["Use default export: export default class MyWidget extends BaseWidget { ... }","Use named export: export class Widget extends BaseWidget { ... }"],docs:"https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md#export-formats"},[P.ENTRY_INVALID_EXPORT]:{suggestion:"Your index.js must export a valid class or constructor function",commonMistakes:["Exporting an object literal instead of a class","Forgetting to import BaseWidget","Exporting a plain function instead of a class"],fix:"Ensure you export a class that extends BaseWidget"},[P.ENTRY_RUNTIME_ERROR]:{suggestion:"Fix the runtime error in your widget code",tips:["Check for syntax errors in your JavaScript","Ensure all imported modules are installed: npm install <dependency>","Check for undefined variables or misspelled function names","Make sure you are using ES modules syntax (import/export)"]},[P.WIDGET_MISSING_METHODS]:{suggestion:"Add the required methods to your widget class",requiredMethods:["render","getData"],optionalMethods:["init","create","destroy"],example:`class MyWidget extends BaseWidget {
|
|
142
|
-
// Required
|
|
143
|
-
async getData() {
|
|
144
|
-
return { value: 123 };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
render(data) {
|
|
148
|
-
if (this.box) {
|
|
149
|
-
this.box.setContent(String(data.value));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Optional but recommended
|
|
154
|
-
async init() { return true; }
|
|
155
|
-
async create(screen, theme) { /* create blessed elements */ }
|
|
156
|
-
async destroy() { /* cleanup */ }
|
|
157
|
-
}`},[P.WIDGET_NOT_A_CLASS]:{suggestion:"Your widget must be a class that extends BaseWidget",example:`import { BaseWidget } from 'claw-dashboard/widgets';
|
|
158
|
-
|
|
159
|
-
export default class MyWidget extends BaseWidget {
|
|
160
|
-
constructor(options) {
|
|
161
|
-
super(options);
|
|
162
|
-
// your initialization
|
|
163
|
-
}
|
|
164
|
-
}`},[P.WIDGET_CONSTRUCTOR_ERROR]:{suggestion:"Fix the error in your widget constructor",tips:["Remember to call super(options) before accessing this","Ensure constructor arguments match the expected signature","Check for null/undefined values in your constructor logic"]},[P.PATH_INVALID]:{suggestion:"Use a valid plugin path within the allowed directory",rules:['Plugin paths cannot contain ".." (directory traversal)',"Plugin paths must be within ~/.openclaw/plugins/ or the configured plugins directory","Plugin names must be alphanumeric with hyphens/underscores only"]},[P.NAME_INVALID]:{suggestion:"Use a valid plugin name",rules:["Must start and end with alphanumeric character","Can contain letters, numbers, hyphens (-), and underscores (_)","Cannot contain spaces or special characters",'Examples: "my-widget", "cpu_monitor", "plugin1"']},[P.CONFIG_INVALID]:{suggestion:"Fix the config in your plugin.json",tips:["Config must be a valid JSON object","Property names must be quoted in JSON","Check for proper nesting of objects and arrays"]},[P.DEPENDENCY_MISSING]:{suggestion:"Install the missing dependency",options:["Install the missing plugin to ~/.openclaw/plugins/","Add the dependency to your plugin's dependencies array in plugin.json","Remove the dependency from your plugin if not needed"]},[P.DEPENDENCY_CIRCULAR]:{suggestion:"Remove circular dependencies between plugins",example:"If Plugin A depends on Plugin B, Plugin B cannot depend on Plugin A"},[P.PLUGIN_LOAD_ERROR]:{suggestion:"Check the plugin documentation and examples",docs:"https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md",examples:"See example plugins in examples/plugins/ directory"}},Ke=class extends Ye{constructor(e,t,s={}){super(t,e,s),this.name="PluginError",this.code=e,this.pluginId=s.pluginId||s.id||"unknown",this.suggestion=this._getSuggestion(),this.docs=this._getDocs(),this.fix=this._getFix()}_getSuggestion(){return Qr[this.code]?.suggestion||"Check the plugin documentation for more information"}_getDocs(){return Qr[this.code]?.docs||null}_getFix(){let e=Qr[this.code];return e?.fix||e?.tips||e?.commonCauses||e?.rules||e?.options||null}getFormattedMessage(){let e=[`Plugin Error [${this.code}]: ${this.message}`,"",`Plugin: ${this.pluginId}`,"",`\u{1F4A1} Suggestion: ${this.suggestion}`];this.docs&&e.push("",`\u{1F4DA} Documentation: ${this.docs}`),this.fix&&(Array.isArray(this.fix)?(e.push("","\u{1F527} Possible fixes:"),this.fix.forEach((s,i)=>e.push(` ${i+1}. ${s}`))):e.push("",`\u{1F527} Fix: ${this.fix}`));let t=Qr[this.code];return t?.example&&e.push("","\u{1F4BB} Example:",...t.example.split(`
|
|
165
|
-
`).map(s=>` ${s}`)),e.join(`
|
|
166
|
-
`)}getHint(){return`${this.suggestion} (see docs: ${this.docs||"PLUGINS.md"})`}toJSON(){return{...super.toJSON(),pluginId:this.pluginId,suggestion:this.suggestion,docs:this.docs,fix:this.fix}}},tt=class{static analyze(e,t,s={}){let{phase:i="unknown",manifest:n=null}=s,a=this._determineErrorCode(e,i),c=this._createMessage(a,e,t,s);return new Ke(a,c,{pluginId:t,originalError:e?.message||e,phase:i,manifest:n,stack:e?.stack})}static _determineErrorCode(e,t){let s=(e?.message||String(e)).toLowerCase();if(t==="manifest")return s.includes("enoent")||s.includes("not found")?P.MANIFEST_NOT_FOUND:s.includes("json")&&(s.includes("parse")||s.includes("syntax")||s.includes("unexpected"))?P.MANIFEST_INVALID_JSON:s.includes("missing")||s.includes("required")?P.MANIFEST_MISSING_FIELD:s.includes("invalid")?P.MANIFEST_INVALID_FIELD:P.MANIFEST_SCHEMA_ERROR;if(t==="entry")return s.includes("enoent")||s.includes("not found")||s.includes("cannot find module")?P.ENTRY_NOT_FOUND:s.includes("export")||s.includes("does not provide")?P.ENTRY_NO_EXPORT:P.ENTRY_RUNTIME_ERROR;if(t==="widget"){if(s.includes("method")||s.includes("render")||s.includes("getdata"))return P.WIDGET_MISSING_METHODS;if(s.includes("class")||s.includes("constructor"))return P.WIDGET_NOT_A_CLASS;if(s.includes("super")||s.includes("this"))return P.WIDGET_CONSTRUCTOR_ERROR}return t==="config"?P.CONFIG_INVALID:s.includes("path")||s.includes("traversal")||s.includes("unsafe")?P.PATH_INVALID:s.includes("name")&&(s.includes("invalid")||s.includes("format"))?P.NAME_INVALID:s.includes("dependency")||s.includes("depends")?s.includes("circular")?P.DEPENDENCY_CIRCULAR:P.DEPENDENCY_MISSING:P.PLUGIN_LOAD_ERROR}static _createMessage(e,t,s,i){let n=t?.message||String(t);switch(e){case P.MANIFEST_NOT_FOUND:return`Plugin "${s}" is missing a plugin.json manifest file`;case P.MANIFEST_INVALID_JSON:return`Plugin "${s}" has invalid JSON in plugin.json: ${n}`;case P.MANIFEST_MISSING_FIELD:return`Plugin "${s}" manifest is missing required fields: ${n}`;case P.MANIFEST_INVALID_FIELD:return`Invalid plugin manifest for "${s}": ${n}`;case P.ENTRY_NOT_FOUND:return`Plugin "${s}" is missing its entry point (index.js)`;case P.ENTRY_NO_EXPORT:return`Plugin "${s}" index.js does not export a widget class`;case P.ENTRY_INVALID_EXPORT:return`Plugin "${s}" exports an invalid widget class: ${n}`;case P.WIDGET_MISSING_METHODS:return`Plugin "${s}" widget is missing required methods: ${n}`;case P.WIDGET_NOT_A_CLASS:return`Plugin "${s}" must export a class that extends BaseWidget`;case P.WIDGET_CONSTRUCTOR_ERROR:return`Plugin "${s}" widget failed to construct: ${n}`;case P.PATH_INVALID:return`Plugin "${s}" has an invalid path: ${n}`;case P.NAME_INVALID:return`Plugin "${s}" has an invalid name format`;case P.DEPENDENCY_MISSING:return`Plugin "${s}" is missing a dependency: ${n}`;case P.DEPENDENCY_CIRCULAR:return`Plugin "${s}" has circular dependencies: ${n}`;default:return`Failed to load plugin "${s}": ${n}`}}static checkCommonMistakes(e){let t=(e?.message||"").toLowerCase(),s=(e?.stack||"").toLowerCase(),i=[{pattern:/super\s*\(/,check:()=>s.includes("super")&&s.includes("constructor"),mistake:"Missing super() call in constructor",fix:"Add super(options) as the first line of your constructor"},{pattern:/cannot find module/,check:()=>t.includes("cannot find module"),mistake:"Missing import/module",fix:"Install the missing module with npm install or check the import path"},{pattern:/is not a function/,check:()=>t.includes("is not a function"),mistake:"Calling a non-function",fix:"Check that the variable is a function before calling it, or verify the import"},{pattern:/cannot read propert/,check:()=>t.includes("cannot read property")||t.includes("cannot read properties"),mistake:"Accessing property of undefined/null",fix:"Add null checks before accessing properties: obj?.property"},{pattern:/trailing comma/,check:()=>t.includes("trailing comma")||t.includes("unexpected token }"),mistake:"Trailing comma in JSON",fix:"Remove the comma after the last property in your JSON file"},{pattern:/unexpected token/i,check:()=>t.includes("unexpected token")&&t.includes("json"),mistake:"Invalid JSON syntax",fix:"Validate your JSON syntax - check for quotes, brackets, and commas"}];for(let n of i)if(n.check())return{mistake:n.mistake,fix:n.fix,pattern:n.pattern};return null}};import{EventEmitter as Nu}from"events";var{PATHS:La,WIDGETS:Kp}=w;function ka(r){if(!r||typeof r!="object")return{};let e={};for(let[t,s]of Object.entries(r))s&&typeof s=="object"&&s.type!==void 0?e[t]=s.default!==void 0?s.default:null:s&&typeof s=="object"&&!Array.isArray(s)?e[t]=ka(s):e[t]=s;return e}var Zr=class extends Nu{constructor(e={}){super(),this.widgetsDir=e.widgetsDir||La.WIDGETS_DIR,this.pluginsDir=e.pluginsDir||La.PLUGINS_DIR,this.loadedWidgets=new Map,this.widgetRegistry=new Map,this.loadPromises=new Map,this.hooks={beforeLoad:[],afterLoad:[],beforeUnload:[]},this.configWatcher=null,this._reloadStats={reloads:0,errors:0,lastReload:null}}register(e,t,s){return this.widgetRegistry.has(e)&&u.warn(`Widget '${e}' is already registered, overwriting`),this.widgetRegistry.set(e,{id:e,metadata:{name:t.name||e,description:t.description||"",version:t.version||"1.0.0",author:t.author||"",category:t.category||"system",priority:t.priority||100,lazyLoad:t.lazyLoad!==!1,dependencies:t.dependencies||[],permissions:t.permissions||[],...t},loader:s,loaded:!1,instance:null,error:null}),u.debug(`Widget '${e}' registered`),this}async unregister(e){let t=this.widgetRegistry.get(e);if(!t)return u.warn(`Widget '${e}' not found in registry`),!1;if(await this.runHooks("beforeUnload",t),t.loaded&&t.instance?.destroy)try{await t.instance.destroy()}catch(s){u.error(`Error destroying widget '${e}': ${s.message}`)}return this.loadedWidgets.delete(e),this.widgetRegistry.delete(e),this.loadPromises.delete(e),u.debug(`Widget '${e}' unregistered`),!0}async load(e){if(this.loadPromises.has(e))return this.loadPromises.get(e);let t=this.widgetRegistry.get(e);if(!t)throw new Error(`Widget '${e}' not registered`);if(t.loaded&&t.instance)return t.instance;let s=this._doLoad(t);this.loadPromises.set(e,s);try{return await s}finally{this.loadPromises.delete(e)}}async loadAndRegister(e,t,s){return this.register(e,t,s),this.load(e)}async _doLoad(e){let t=Date.now();try{await this.runHooks("beforeLoad",e),await this._resolveDependencies(e);let s=await e.loader();if(!s||typeof s!="object")throw new Error("Widget loader did not return a valid object");return this._validateWidget(s,e.id),e.instance=s,e.loaded=!0,e.loadTime=Date.now()-t,e.error=null,this.loadedWidgets.set(e.id,s),await this.runHooks("afterLoad",e),u.debug(`Widget '${e.id}' loaded in ${e.loadTime}ms`),s}catch(s){if(e.error=s,e.loaded=!1,s instanceof Ke)u.error(`Failed to load widget '${e.id}': ${s.getFormattedMessage()}`);else{let i=tt.analyze(s,e.id,{phase:"widget"});u.error(`Failed to load widget '${e.id}': ${i.getFormattedMessage()}`)}throw s}}async _resolveDependencies(e){let t=e.metadata.dependencies||[];for(let s of t){if(!this.widgetRegistry.has(s))throw new Ke(P.DEPENDENCY_MISSING,`Dependency "${s}" not found for widget "${e.id}"`,{pluginId:e.id,dependencyId:s,availableDependencies:Array.from(this.widgetRegistry.keys())});this.widgetRegistry.get(s).loaded||await this.load(s)}}_validateWidget(e,t){let i=["render","getData"].filter(n=>typeof e[n]!="function");if(i.length>0)throw new Ke(P.WIDGET_MISSING_METHODS,`Widget "${t}" is missing required methods: ${i.join(", ")}`,{pluginId:t,missingMethods:i,hasRender:typeof e.render=="function",hasGetData:typeof e.getData=="function"})}async unload(e){let t=this.widgetRegistry.get(e);if(!t||!t.loaded)return!1;if(await this.runHooks("beforeUnload",t),t.instance?.destroy)try{await t.instance.destroy()}catch(s){u.error(`Error destroying widget '${e}': ${s.message}`)}return t.instance=null,t.loaded=!1,this.loadedWidgets.delete(e),u.debug(`Widget '${e}' unloaded`),!0}async loadMany(e){let t=await Promise.allSettled(e.map(n=>this.load(n).then(a=>({id:n,instance:a})))),s=new Map,i=[];for(let n of t)n.status==="fulfilled"?s.set(n.value.id,n.value.instance):i.push(n.reason);return i.length>0&&u.warn(`Failed to load ${i.length} widget(s): ${i.map(n=>n.message).join(", ")}`),s}async preload(e){let t=e.filter(n=>{let a=this.widgetRegistry.get(n);return a&&a.metadata.lazyLoad&&!a.loaded});if(t.length===0)return;u.debug(`Preloading ${t.length} widget(s)`);let s=t.map(n=>({id:n,priority:this.widgetRegistry.get(n).metadata.priority})).sort((n,a)=>n.priority-a.priority);for(let{id:n}of s.filter(a=>a.priority<50))try{await this.load(n)}catch{}let i=s.filter(n=>n.priority>=50).map(n=>n.id);i.length>0&&this.loadMany(i).catch(()=>{})}getMetadata(e){let t=this.widgetRegistry.get(e);return t?{...t.metadata}:null}getAllMetadata(){let e=[];for(let[t,s]of this.widgetRegistry)e.push({id:t,...s.metadata,loaded:s.loaded,hasError:!!s.error});return e.sort((t,s)=>t.priority-s.priority)}get(e){let t=this.widgetRegistry.get(e);return t?.loaded?t.instance:null}isLoaded(e){return this.widgetRegistry.get(e)?.loaded||!1}addHook(e,t){if(!this.hooks[e])throw new Error(`Unknown hook type: ${e}`);this.hooks[e].push(t)}async runHooks(e,t){for(let s of this.hooks[e])try{await s(t)}catch(i){u.error(`Hook error (${e}): ${i.message}`)}}async discoverPlugins(){let e=wt(this.pluginsDir,{allowAbsolute:!0,mustExist:!0,expectedType:"directory"});if(!e.valid)return u.warn(`Plugins directory validation failed: ${e.error}`),[];let t=e.path;if(!Qs(t))return[];let s=[],i=Du(t,{withFileTypes:!0});for(let n of i){if(!n.isDirectory())continue;let a=So(n.name);if(!a.valid){u.warn(`Skipping plugin directory with invalid name '${n.name}': ${a.error}`);continue}let c=st(t,n.name),d=wt(n.name,{allowedDirs:[t],allowAbsolute:!1,mustExist:!0,expectedType:"directory"});if(!d.valid){u.warn(`Skipping plugin with unsafe path '${n.name}': ${d.error}`);continue}let g=st(c,"plugin.json"),p=st(c,"index.js"),T=wt("plugin.json",{allowedDirs:[c],allowAbsolute:!1,mustExist:!0,expectedType:"file"});if(!T.valid){u.warn(`Plugin '${n.name}' has invalid manifest path: ${T.error}`);continue}let b=wt("index.js",{allowedDirs:[c],allowAbsolute:!1,mustExist:!0,expectedType:"file"});if(!b.valid){u.warn(`Plugin '${n.name}' has invalid entry point: ${b.error}`);continue}if(!(!Qs(g)||!Qs(p)))try{let _=JSON.parse(await import("fs").then(S=>S.readFileSync(g,"utf8")));if(_.type!=="widget")continue;let v=ls(_);if(!v.valid){let S=tt.analyze(new Error(v.errors.join(", ")),_.id||n.name,{phase:"manifest",manifest:_});u.warn(S.getFormattedMessage());continue}s.push({id:_.id||n.name,manifest:_,path:c,entryPoint:p})}catch(_){if(_ instanceof Ke)u.warn(_.getFormattedMessage());else{let v=tt.analyze(_,n.name,{phase:"manifest"});u.warn(v.getFormattedMessage())}}}return s}async loadPlugin(e,t={}){let{sanitize:s=!0,fallbackOnError:i=!0,eager:n=!0}=t,a=wt(e,{allowedDirs:[this.pluginsDir],allowAbsolute:!0,mustExist:!0,expectedType:"directory"});if(!a.valid)throw new Error(`Invalid plugin path: ${a.error}`);let c=a.path,d=st(c,"plugin.json"),g=st(c,"index.js"),p=wt(d,{allowedDirs:[c],allowAbsolute:!0,mustExist:!0,expectedType:"file"});if(!p.valid){let k=new Error(`Invalid manifest path: ${p.error}`);if(i)return u.warn(`Failed to load plugin at ${c}: ${k.message}`),null;throw k}let T=wt(g,{allowedDirs:[c],allowAbsolute:!0,mustExist:!0,expectedType:"file"});if(!T.valid){let k=new Error(`Invalid entry point path: ${T.error}`);if(i)return u.warn(`Failed to load plugin at ${c}: ${k.message}`),null;throw k}if(!Qs(d))throw new Ke(P.MANIFEST_NOT_FOUND,`Plugin manifest not found at ${c}`,{pluginId:$t(c)});let b;try{let k=await import("fs").then(F=>F.readFileSync(d,"utf8"));b=JSON.parse(k)}catch(k){let F=tt.analyze(k,$t(c),{phase:"manifest",path:c});if(i)return u.warn(F.getFormattedMessage()),null;throw F}let _=ls(b);if(!_.valid){let k=tt.analyze(new Error(`Validation failed: ${_.errors.join(", ")}`),b.id||$t(c),{phase:"manifest",manifest:b});if(i)return u.warn(k.getFormattedMessage()),null;throw k}!b.id&&!b.name&&(b.id=$t(c));let v=b.id||$t(c);b._pluginPath=c,b._manifestPath=d,b._indexPath=g;let S=ka(b.config);if(b.config){let k=Kr(S,{interpolateEnv:!0,validateVersion:!1,supportLegacy:!0,throwOnError:!1});if(k.success&&(S=k.config,k.warnings&&k.warnings.forEach(F=>{u.debug(`[${v}] ${F}`)})),s)try{S=Tr(S)}catch(F){u.warn(`Failed to sanitize config for plugin '${v}': ${F.message}, using processed config`)}}let M=async()=>{try{let k=await import(Ca(g).href),F=k.default||k.Widget||k;if(typeof F=="function")return new F(S);throw new Ke(P.ENTRY_INVALID_EXPORT,`Plugin "${v}" does not export a valid widget class`,{pluginId:v,exportType:typeof F,hasDefault:!!k.default,hasNamed:!!k.Widget})}catch(k){throw k instanceof Ke?k:tt.analyze(k,v,{phase:"entry",path:g})}};if(this.register(v,b,M),n!==!1&&b.lazyLoad!==!0)try{await this.load(v)}catch(k){if(i)u.warn(`Failed to auto-load plugin '${v}': ${k.message}`);else throw k}return v}async loadAllPluginsWithFallback(e={}){let{sanitize:t=!0,fallbackOnError:s=!0,continueOnError:i=!0,resolveDependencies:n=!0,allowPartial:a=!1}=e,c=await this.discoverPlugins(),d={successful:[],failed:[],skipped:[],dependencyErrors:[]};for(let g of c)try{let p=await this.registerPlugin(g.path,{sanitize:t,fallbackOnError:s});if(p)d.successful.includes(p)||d.successful.push(p);else{d.skipped.push(g.id);let T=d.successful.indexOf(g.id);T>-1&&d.successful.splice(T,1)}}catch(p){d.failed.push({id:g.id,error:p.message});let T=d.successful.indexOf(g.id);T>-1&&d.successful.splice(T,1),u.warn(`Plugin '${g.id}' failed to register: ${p.message}`)}if(n&&this.widgetRegistry.size>0){let g=en(this.widgetRegistry,{allowPartial:a});if(!g.success){d.dependencyErrors.push({error:g.error,circularPath:g.circularPath,missingDeps:g.missingDeps,constraintViolations:g.constraintViolations});let p=g.missingDeps?Object.entries(g.missingDeps).map(([b,_])=>`${b}(${_.join(", ")})`).join("; "):"unknown",T=new Ke(g.circularPath?P.DEPENDENCY_CIRCULAR:P.DEPENDENCY_MISSING,g.error,{pluginId:p,circularPath:g.circularPath,missingDeps:g.missingDeps});if(!i)return u.error(T.getFormattedMessage()),d;u.warn(T.getFormattedMessage())}for(let p of g.order){let T=this.widgetRegistry.get(p);if(!(!T||T.loaded))try{await this.load(p),d.successful.push(p)}catch(b){if(d.failed.push({id:p,error:b.message}),u.warn(`Widget '${p}' failed to load: ${b.message}`),!i&&!s)break}}}else for(let g of c)if(!this.widgetRegistry.has(g.id))try{let p=await this.loadPlugin(g.path,{sanitize:t,fallbackOnError:s});p?d.successful.push(p):d.skipped.push(g.id)}catch(p){if(d.failed.push({id:g.id,error:p.message}),u.warn(`Plugin '${g.id}' failed to load: ${p.message}`),!i&&!s)break}return u.debug(`Plugin loading complete: ${d.successful.length} loaded, ${d.failed.length} failed, ${d.skipped.length} skipped`),d}async registerPlugin(e,t={}){let{sanitize:s=!0,fallbackOnError:i=!0}=t,n=wt(e,{allowedDirs:[this.pluginsDir],allowAbsolute:!0,mustExist:!0,expectedType:"directory"});if(!n.valid)throw new Error(`Invalid plugin path: ${n.error}`);let a=n.path,c=st(a,"plugin.json"),d=st(a,"index.js");if(!Qs(c))return null;let g;try{let v=await import("fs").then(S=>S.readFileSync(c,"utf8"));g=JSON.parse(v)}catch(v){let S=tt.analyze(v,$t(a),{phase:"manifest",path:a});if(i)return u.warn(S.getFormattedMessage()),null;throw S}let p=ls(g);if(!p.valid){let v=tt.analyze(new Error(`Validation failed: ${p.errors.join(", ")}`),g.id||$t(a),{phase:"manifest",manifest:g});if(i)return u.warn(v.getFormattedMessage()),null;throw v}let T=g.id||$t(a);g._pluginPath=a,g._manifestPath=c,g._indexPath=d;let b={};if(g.config){let v=Kr(g.config,{interpolateEnv:!0,validateVersion:!0,supportLegacy:!0,throwOnError:!1});if(v.success&&(b=v.config),s)try{b=Tr(b)}catch(S){u.warn(`Failed to sanitize config for plugin '${T}': ${S.message}`)}}let _=async()=>{try{let v=await import(Ca(d).href),S=v.default||v.Widget||v;return typeof S=="function"?new S(b):S}catch(v){throw u.error(`Failed to load plugin '${T}': ${v.message}`),v}};return this.register(T,g,_),T}async loadInDependencyOrder(e=null,t={}){let{allowPartial:s=!1,continueOnError:i=!0}=t,n=e||Array.from(this.widgetRegistry.keys()),a=en(this.widgetRegistry,{targetIds:n,allowPartial:s}),c={successful:[],failed:[],skipped:[],resolution:a};if(!a.success)return u.error(`Dependency resolution failed: ${a.error}`),c;for(let d of a.order){let g=this.widgetRegistry.get(d);if(!(!g||g.loaded))try{await this.load(d),c.successful.push(d)}catch(p){if(c.failed.push({id:d,error:p.message}),!i)break}}return c}getDependencyInfo(e){let t=this.widgetRegistry.get(e);if(!t)return null;let s=Jr(this.widgetRegistry,e),i=Js(this.widgetRegistry);return{id:e,dependencies:t.metadata.dependencies||[],allDependencies:tn(i,e),dependents:_a(i,e),validation:s}}getDependencyGraph(){let e=Js(this.widgetRegistry),t={};for(let[s,i]of e)t[s]={id:s,dependencies:i.dependencies.map(n=>({id:n.id,optional:n.optional,version:n.version})),dependents:Array.from(i.dependents)};return t}validateDependencies(e=null){if(e)return{[e]:Jr(this.widgetRegistry,e)};let t={};for(let[s]of this.widgetRegistry)t[s]=Jr(this.widgetRegistry,s);return t}getStats(){let e=Array.from(this.widgetRegistry.values());return{total:e.length,loaded:e.filter(t=>t.loaded).length,failed:e.filter(t=>t.error).length,loading:this.loadPromises.size,averageLoadTime:e.filter(t=>t.loadTime).reduce((t,s)=>t+s.loadTime,0)/e.filter(t=>t.loadTime).length||0}}async clear(){let e=Array.from(this.loadedWidgets.keys());await Promise.all(e.map(t=>this.unload(t))),this.widgetRegistry.clear(),this.loadedWidgets.clear(),this.loadPromises.clear()}enableConfigHotReload(e={}){let{debounceMs:t=500,usePolling:s=!1,reloadWidgets:i=!0}=e;return this.configWatcher?(u.debug("Config hot-reload already enabled"),this.configWatcher):(this.configWatcher=new as({debounceMs:t,usePolling:s}),this._reloadStats={reloads:0,errors:0,lastReload:null},this.configWatcher.on("reload",async({filePath:n,timestamp:a})=>{try{let c=this._findWidgetIdByConfigPath(n);if(!c){u.debug(`Config reload: Could not find widget for ${n}`);return}u.info(`Config hot-reload triggered for widget: ${c}`);let d=await this._reloadWidgetConfig(c,n);d.success?(this._reloadStats.reloads++,this._reloadStats.lastReload={widgetId:c,timestamp:a},u.info(`Config hot-reload successful for ${c}`),this.emit?.("configReloaded",{widgetId:c,timestamp:a,config:d.config})):(this._reloadStats.errors++,u.error(`Config hot-reload failed for ${c}: ${d.error}`),this.emit?.("configReloadError",{widgetId:c,error:d.error,timestamp:a}))}catch(c){this._reloadStats.errors++,u.error(`Config hot-reload error: ${c.message}`),this.emit?.("configReloadError",{filePath:n,error:c.message,timestamp:a})}}),this.configWatcher.on("error",({filePath:n,error:a})=>{this._reloadStats.errors++,u.error(`Config watcher error for ${n}: ${a.message}`),this.emit?.("configWatcherError",{filePath:n,error:a.message})}),this._startWatchingWidgetConfigs(),u.info("Widget config hot-reload enabled"),this.configWatcher)}disableConfigHotReload(){this.configWatcher&&(this.configWatcher.unwatchAll(),this.configWatcher=null,u.info("Widget config hot-reload disabled"))}isConfigHotReloadEnabled(){return!!this.configWatcher}getHotReloadStats(){return{enabled:this.isConfigHotReloadEnabled(),...this._reloadStats,watchedFiles:this.configWatcher?.getWatchedFiles().length||0}}_findWidgetIdByConfigPath(e){for(let[t,s]of this.widgetRegistry)if(s.metadata?._pluginPath){let i=st(s.metadata._pluginPath,"plugin.json");if(e===i||e.endsWith(i))return t}return null}async _reloadWidgetConfig(e,t){let s=this.widgetRegistry.get(e);if(!s)return{success:!1,error:"Widget not found in registry"};try{let n=(await import("fs")).readFileSync(t,"utf8"),a=JSON.parse(n),c=ls(a);if(!c.valid)return{success:!1,error:`Manifest validation failed: ${c.errors.join(", ")}`};let d={};if(a.config){let g=Kr(a.config,{interpolateEnv:!0,validateVersion:!0,supportLegacy:!0,throwOnError:!1});if(!g.success)return{success:!1,error:`Config processing failed: ${g.error}`};d=g.config;try{d=Tr(d)}catch(p){return{success:!1,error:`Config sanitization failed: ${p.message}`}}}if(s.metadata={...s.metadata,...a,config:d},s.loaded&&s.instance&&(s.instance.config,s.instance.config=d,typeof s.instance.onConfigChange=="function"))try{await s.instance.onConfigChange(d,s.instance.config)}catch(g){u.warn(`Widget ${e} onConfigChange failed: ${g.message}`)}return{success:!0,config:d}}catch(i){return{success:!1,error:i.message}}}_startWatchingWidgetConfigs(){if(this.configWatcher){for(let[e,t]of this.widgetRegistry)if(t.metadata?._pluginPath){let s=st(t.metadata._pluginPath,"plugin.json");this.configWatcher.watchFile(s)}}}watchWidgetConfig(e){if(!this.configWatcher)return u.warn("Config hot-reload not enabled, call enableConfigHotReload() first"),!1;let t=this.widgetRegistry.get(e);if(!t?.metadata?._pluginPath)return u.warn(`Widget ${e} does not have a plugin path to watch`),!1;let s=st(t.metadata._pluginPath,"plugin.json");return this.configWatcher.watchFile(s)}unwatchWidgetConfig(e){if(!this.configWatcher)return;let t=this.widgetRegistry.get(e);if(!t?.metadata?._pluginPath)return;let s=st(t.metadata._pluginPath,"plugin.json");this.configWatcher.unwatchFile(s)}};Q();te();var{PATHS:Fu}=w,ei=class{constructor(e={}){this.widgetLoader=e.widgetLoader||null,this.pluginsDir=e.pluginsDir||Fu.PLUGINS_DIR,this.watcher=null,this.watchedPlugins=new Map,this.isRunning=!1,this.options={debounceMs:300,persistent:!0,usePolling:!1,pollInterval:500,autoReload:!0,showNotifications:!0,...e},this.hooks={beforeReload:[],afterReload:[],onError:[]}}setWidgetLoader(e){this.widgetLoader=e}addHook(e,t){if(!this.hooks[e])throw new Error(`Unknown hook type: ${e}`);this.hooks[e].push(t)}async runHooks(e,t){for(let s of this.hooks[e])try{await s(t)}catch(i){u.error(`PluginReloadManager hook error (${e}): ${i.message}`)}}start(){if(this.isRunning)return u.debug("PluginReloadManager: Already running"),!0;if(!this.widgetLoader)return u.error("PluginReloadManager: No WidgetLoader set. Call setWidgetLoader() first."),!1;try{return this.watcher=new as({debounceMs:this.options.debounceMs,persistent:this.options.persistent,usePolling:this.options.usePolling,pollInterval:this.options.pollInterval}),this.watcher.on("reload",async({filePath:e})=>{await this._handleFileChange(e)}),this.watcher.on("error",({filePath:e,error:t})=>{u.error(`PluginReloadManager: Watcher error for ${e}: ${t.message}`),this.runHooks("onError",{filePath:e,error:t,type:"watch"})}),this._scanAndWatchPlugins(),this.isRunning=!0,u.info("PluginReloadManager: Started watching for plugin changes"),!0}catch(e){return u.error(`PluginReloadManager: Failed to start: ${e.message}`),!1}}stop(){this.isRunning&&(this.watcher&&(this.watcher.unwatchAll(),this.watcher=null),this.watchedPlugins.clear(),this.isRunning=!1,u.info("PluginReloadManager: Stopped"))}_scanAndWatchPlugins(){if(!cs(this.pluginsDir)){u.warn(`PluginReloadManager: Plugins directory not found: ${this.pluginsDir}`);return}try{let e=Wu(this.pluginsDir,{withFileTypes:!0}),t=0;for(let s of e){if(!s.isDirectory())continue;let i=Zs(this.pluginsDir,s.name),n=Zs(i,"plugin.json"),a=Zs(i,"index.js");cs(n)&&(this.watchedPlugins.set(s.name,{manifestPath:n,indexPath:a,pluginPath:i,id:s.name}),this.watcher.watchFile(n)&&t++,cs(a)&&this.watcher.watchFile(a)&&t++)}u.info(`PluginReloadManager: Watching ${this.watchedPlugins.size} plugins (${t} files)`)}catch(e){u.error(`PluginReloadManager: Failed to scan plugins: ${e.message}`)}}async _handleFileChange(e){let t=this._findPluginByPath(e);if(!t){u.debug(`PluginReloadManager: Changed file not associated with a known plugin: ${e}`);return}let{id:s,pluginPath:i,manifestPath:n,indexPath:a}=t;if(u.info(`PluginReloadManager: Detected change in plugin '${s}'`),!this.options.autoReload){u.info(`PluginReloadManager: Auto-reload disabled, skipping reload of '${s}'`);return}await this.reloadPlugin(s,i,n,a)}_findPluginByPath(e){for(let[t,s]of this.watchedPlugins)if(e===s.manifestPath||e===s.indexPath)return{...s,id:t};return null}async reloadPlugin(e,t,s,i){let n=Date.now();try{await this.runHooks("beforeReload",{id:e,pluginPath:t,manifestPath:s,indexPath:i});let a=this.widgetLoader.isLoaded(e),c=this.widgetLoader.widgetRegistry.has(e);if(u.debug(`PluginReloadManager: Reloading plugin '${e}' (was loaded: ${a}, was registered: ${c})`),c)try{await this.widgetLoader.unregister(e),u.debug(`PluginReloadManager: Unregistered plugin '${e}'`)}catch(p){u.warn(`PluginReloadManager: Error unregistering plugin '${e}': ${p.message}`)}this._clearModuleCache(i);let d=await this.widgetLoader.loadPlugin(t,{sanitize:!0,fallbackOnError:!1}),g=Date.now()-n;return await this._updateWatchedFiles(e,t,s,i),await this.runHooks("afterReload",{id:d,pluginPath:t,manifestPath:s,indexPath:i,loadTime:g,isNew:!c}),this.options.showNotifications&&u.info(`\u2713 Plugin '${d}' reloaded successfully in ${g}ms`),{success:!0,id:d,loadTime:g,isNew:!c}}catch(a){return u.error(`\u2717 Failed to reload plugin '${e}': ${a.message}`),await this.runHooks("onError",{id:e,pluginPath:t,manifestPath:s,indexPath:i,error:a,type:"reload"}),{success:!1,id:e,error:a.message}}}_clearModuleCache(e){try{let t=Pu(e).href;import.meta.resolve&&import.meta.resolve,u.debug(`PluginReloadManager: Module cache cleared for ${e}`)}catch(t){u.debug(`PluginReloadManager: Could not clear module cache: ${t.message}`)}}async _updateWatchedFiles(e,t,s,i){cs(s)&&this.watcher.watchFile(s),cs(i)&&this.watcher.watchFile(i),this.watchedPlugins.set(e,{manifestPath:s,indexPath:i,pluginPath:t,id:e})}async reload(e){let t=this.watchedPlugins.get(e);if(!t)throw new Error(`Plugin '${e}' is not being watched`);return this.reloadPlugin(e,t.pluginPath,t.manifestPath,t.indexPath)}async addPlugin(e){let t=$u(e),s=Zs(e,"plugin.json"),i=Zs(e,"index.js");if(!cs(s))throw new Error(`Plugin manifest not found at ${e}`);this.watchedPlugins.set(t,{manifestPath:s,indexPath:i,pluginPath:e,id:t});let n=0;return this.watcher?.watchFile(s)&&n++,cs(i)&&this.watcher?.watchFile(i)&&n++,u.debug(`PluginReloadManager: Added plugin '${t}' to watch list (${n} files)`),!0}removePlugin(e){let t=this.watchedPlugins.get(e);return t?(this.watcher&&(this.watcher.unwatchFile(t.manifestPath),this.watcher.unwatchFile(t.indexPath)),this.watchedPlugins.delete(e),u.debug(`PluginReloadManager: Removed plugin '${e}' from watch list`),!0):!1}getWatchedPlugins(){return Array.from(this.watchedPlugins.keys())}isWatching(e){return this.watchedPlugins.has(e)}getStats(){return{isRunning:this.isRunning,watchedPlugins:this.watchedPlugins.size,watchedFiles:this.watcher?.getWatchedFiles().length||0,autoReload:this.options.autoReload}}};import{mkdirSync as Uu,writeFileSync as Bu,existsSync as Hu}from"fs";import{join as sn}from"path";import{homedir as Gu}from"os";import Vu from"readline";function ju(){return Vu.createInterface({input:process.stdin,output:process.stdout})}function on(r){return new Promise(e=>{let t=ju();t.question(r,s=>{t.close(),e(s)})})}async function rn(r,e){return(await on(`${r} [${e}]: `)).trim()||e}async function nn(r,e,t=0){let s=e.map((i,n)=>` ${n+1}. ${i}`).join(`
|
|
167
|
-
`);for(;;){let n=(await on(`${r}
|
|
168
|
-
${s}
|
|
169
|
-
Select (1-${e.length}) [${t+1}]: `)).trim()||String(t+1),a=parseInt(n,10);if(!isNaN(a)&&a>=1&&a<=e.length)return e[a-1];console.log("Invalid selection. Please enter a number between 1 and "+e.length)}}async function zu(){console.log(""),console.log("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.log("\u2551 Claw Dashboard - Create New Widget Plugin \u2551"),console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.log("");let r=await on('Plugin ID (kebab-case, e.g., "my-widget"): ');if(!r.trim())return console.log("Error: Plugin ID is required"),null;let e=Oa(r.trim());if(!e.valid)return console.log("Error: "+e.error),null;let t=r.trim().split("-").map(b=>b.charAt(0).toUpperCase()+b.slice(1)).join(" "),s=await rn("Display name",t),i=ti(),n=i.map(b=>b.name+" ("+b.id+")"),a=await nn("Select template:",n,0),c=i[n.indexOf(a)].id,d=await rn("Author name/email",""),g=await nn("Select category:",["Custom","System","Monitoring","Example"],0),p=await rn("Description","A custom widget for Claw Dashboard");return console.log(""),console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),console.log("Summary:"),console.log(" ID: "+r.trim()),console.log(" Name: "+s),console.log(" Template: "+c),console.log(" Category: "+g.toLowerCase()),console.log(" Author: "+(d||"(none)")),console.log(" Description: "+p),console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),console.log(""),await nn("Create plugin?",["Yes","No"],0)!=="Yes"?(console.log("Cancelled."),null):{id:r.trim(),name:s,template:c,author:d,category:g.toLowerCase(),description:p}}var er={basic:{name:"Basic Widget",description:"Simple widget with minimal setup - displays static or simple data",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A custom widget plugin for Claw Dashboard",version:"1.0.0",author:t||"",category:s.category||"custom",type:"widget",lazyLoad:!0,priority:100,config:{message:"Hello, World!",showTimestamp:!0},__version:1}),widgetCode:(r,e)=>`/**
|
|
170
|
-
* ${e} Widget Plugin
|
|
171
|
-
* Generated by clawdash create-plugin
|
|
172
|
-
*/
|
|
173
|
-
|
|
174
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* ${e} - A custom widget for Claw Dashboard
|
|
178
|
-
*/
|
|
179
|
-
export default class ${e} extends BaseWidget {
|
|
180
|
-
constructor(options = {}) {
|
|
181
|
-
super(options);
|
|
182
|
-
this.name = options.name || '${e}';
|
|
183
|
-
this.description = options.description || 'A custom widget';
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Initialize the widget
|
|
188
|
-
* Called once when the widget is first loaded
|
|
189
|
-
*/
|
|
190
|
-
async init() {
|
|
191
|
-
this.log('info', '${e} widget initialized');
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Create the widget UI
|
|
197
|
-
* @param {Object} screen - Blessed screen object
|
|
198
|
-
* @param {Object} theme - Theme colors
|
|
199
|
-
*/
|
|
200
|
-
async create(screen, theme = {}) {
|
|
201
|
-
const C = theme.colors || {};
|
|
202
|
-
const blessed = await import('blessed');
|
|
203
|
-
|
|
204
|
-
// Create main container
|
|
205
|
-
this.box = blessed.default.box({
|
|
206
|
-
parent: screen,
|
|
207
|
-
width: '50%',
|
|
208
|
-
height: 10,
|
|
209
|
-
border: { type: 'line' },
|
|
210
|
-
label: ' ${e.toUpperCase()} ',
|
|
211
|
-
style: {
|
|
212
|
-
border: { fg: C.cyan || 'cyan' },
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
// Create content text
|
|
217
|
-
this.contentText = blessed.default.text({
|
|
218
|
-
parent: this.box,
|
|
219
|
-
top: 2,
|
|
220
|
-
left: 1,
|
|
221
|
-
content: 'Loading...',
|
|
222
|
-
style: { fg: C.white || 'white' },
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
this.loaded = true;
|
|
226
|
-
this.log('debug', '${e} widget UI created');
|
|
227
|
-
|
|
228
|
-
return this;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Get data for the widget
|
|
233
|
-
* Fetch and return data for rendering
|
|
234
|
-
*/
|
|
235
|
-
async getData() {
|
|
236
|
-
const message = this.config.message || 'Hello, World!';
|
|
237
|
-
const showTimestamp = this.config.showTimestamp !== false;
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
message,
|
|
241
|
-
timestamp: showTimestamp ? new Date().toISOString() : null,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Render the widget with data
|
|
247
|
-
* @param {Object} data - Data from getData()
|
|
248
|
-
*/
|
|
249
|
-
render(data) {
|
|
250
|
-
if (!this.box || !data) return;
|
|
251
|
-
|
|
252
|
-
let content = data.message;
|
|
253
|
-
if (data.timestamp) {
|
|
254
|
-
content += '\\n[' + data.timestamp + ']';
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
this.contentText.setContent(content);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Destroy the widget
|
|
262
|
-
* Clean up resources
|
|
263
|
-
*/
|
|
264
|
-
async destroy() {
|
|
265
|
-
if (this.box) {
|
|
266
|
-
this.box.destroy();
|
|
267
|
-
this.box = null;
|
|
268
|
-
}
|
|
269
|
-
this.loaded = false;
|
|
270
|
-
this.log('info', '${e} widget destroyed');
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Export named export for flexibility
|
|
275
|
-
export { ${e} };
|
|
276
|
-
`},api:{name:"API Widget",description:"Widget with API fetching, error handling, and retry logic",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A widget that fetches data from an external API",version:"1.0.0",author:t||"",category:s.category||"monitoring",type:"widget",lazyLoad:!0,priority:100,config:{apiUrl:"${API_URL:-https://api.github.com/zen}",apiKey:"${API_KEY:-}",refreshInterval:6e4,timeout:5e3,retries:3},__version:1}),widgetCode:(r,e)=>`/**
|
|
277
|
-
* ${e} Widget Plugin
|
|
278
|
-
* API-powered widget with error handling and retry logic
|
|
279
|
-
*/
|
|
280
|
-
|
|
281
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* ${e} - API-powered widget for Claw Dashboard
|
|
285
|
-
*/
|
|
286
|
-
export default class ${e} extends BaseWidget {
|
|
287
|
-
constructor(options = {}) {
|
|
288
|
-
super(options);
|
|
289
|
-
this.name = options.name || '${e}';
|
|
290
|
-
this.description = options.description || 'API-powered widget';
|
|
291
|
-
|
|
292
|
-
// Internal state
|
|
293
|
-
this.loading = false;
|
|
294
|
-
this.error = null;
|
|
295
|
-
this.lastFetch = null;
|
|
296
|
-
this.refreshTimer = null;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Initialize the widget
|
|
301
|
-
*/
|
|
302
|
-
async init() {
|
|
303
|
-
this.log('info', '${e} widget initialized');
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Create the widget UI
|
|
309
|
-
* @param {Object} screen - Blessed screen object
|
|
310
|
-
* @param {Object} theme - Theme colors
|
|
311
|
-
*/
|
|
312
|
-
async create(screen, theme = {}) {
|
|
313
|
-
const C = theme.colors || {};
|
|
314
|
-
const blessed = await import('blessed');
|
|
315
|
-
|
|
316
|
-
this.screen = screen;
|
|
317
|
-
this.theme = theme;
|
|
318
|
-
|
|
319
|
-
// Main container
|
|
320
|
-
this.box = blessed.default.box({
|
|
321
|
-
parent: screen,
|
|
322
|
-
width: '50%',
|
|
323
|
-
height: 7,
|
|
324
|
-
border: { type: 'line' },
|
|
325
|
-
label: ' ${e.toUpperCase()} ',
|
|
326
|
-
style: { border: { fg: C.cyan || 'cyan' } },
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// Status line
|
|
330
|
-
this.statusText = blessed.default.text({
|
|
331
|
-
parent: this.box,
|
|
332
|
-
top: 0,
|
|
333
|
-
left: 1,
|
|
334
|
-
content: 'Initializing...',
|
|
335
|
-
style: { fg: C.gray || 'gray' },
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
// Data content
|
|
339
|
-
this.contentText = blessed.default.text({
|
|
340
|
-
parent: this.box,
|
|
341
|
-
top: 1,
|
|
342
|
-
left: 1,
|
|
343
|
-
content: '',
|
|
344
|
-
style: { fg: C.white || 'white' },
|
|
345
|
-
wrap: true,
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Last updated
|
|
349
|
-
this.updatedText = blessed.default.text({
|
|
350
|
-
parent: this.box,
|
|
351
|
-
top: 3,
|
|
352
|
-
left: 1,
|
|
353
|
-
content: 'Never updated',
|
|
354
|
-
style: { fg: C.gray || 'gray' },
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
// Stats
|
|
358
|
-
this.statsText = blessed.default.text({
|
|
359
|
-
parent: this.box,
|
|
360
|
-
top: 4,
|
|
361
|
-
left: 1,
|
|
362
|
-
content: 'Requests: 0 | Errors: 0',
|
|
363
|
-
style: { fg: C.gray || 'gray' },
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
this.loaded = true;
|
|
367
|
-
this.log('debug', '${e} widget UI created');
|
|
368
|
-
|
|
369
|
-
// Start auto-refresh
|
|
370
|
-
const refreshInterval = this.config.refreshInterval || 60000;
|
|
371
|
-
if (refreshInterval > 0) {
|
|
372
|
-
this.startAutoRefresh(refreshInterval);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return this;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Fetch data from the configured API
|
|
380
|
-
*/
|
|
381
|
-
async getData() {
|
|
382
|
-
const apiUrl = this.config.apiUrl || 'https://api.github.com/zen';
|
|
383
|
-
const timeout = this.config.timeout || 5000;
|
|
384
|
-
const maxRetries = this.config.retries || 3;
|
|
385
|
-
|
|
386
|
-
let lastError = null;
|
|
387
|
-
|
|
388
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
389
|
-
try {
|
|
390
|
-
this.loading = true;
|
|
391
|
-
this.error = null;
|
|
392
|
-
this.updateStatus('loading', 'Fetching (attempt ' + attempt + '/' + maxRetries + ')...');
|
|
393
|
-
|
|
394
|
-
const controller = new AbortController();
|
|
395
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
396
|
-
|
|
397
|
-
const response = await fetch(apiUrl, {
|
|
398
|
-
signal: controller.signal,
|
|
399
|
-
headers: {
|
|
400
|
-
'User-Agent': 'Claw-Dashboard-Widget/1.0',
|
|
401
|
-
...(this.config.apiKey && { 'Authorization': 'Bearer ' + this.config.apiKey }),
|
|
402
|
-
},
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
clearTimeout(timeoutId);
|
|
406
|
-
|
|
407
|
-
if (!response.ok) {
|
|
408
|
-
throw new Error('HTTP ' + response.status + ': ' + response.statusText);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// Handle different response types
|
|
412
|
-
const contentType = response.headers.get('content-type') || '';
|
|
413
|
-
let data;
|
|
414
|
-
|
|
415
|
-
if (contentType.includes('application/json')) {
|
|
416
|
-
data = await response.json();
|
|
417
|
-
} else {
|
|
418
|
-
data = await response.text();
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
this.loading = false;
|
|
422
|
-
this.lastFetch = new Date();
|
|
423
|
-
|
|
424
|
-
return {
|
|
425
|
-
success: true,
|
|
426
|
-
data,
|
|
427
|
-
timestamp: this.lastFetch.toISOString(),
|
|
428
|
-
apiUrl,
|
|
429
|
-
};
|
|
430
|
-
} catch (err) {
|
|
431
|
-
lastError = err;
|
|
432
|
-
this.log('warn', 'API fetch attempt ' + attempt + ' failed: ' + err.message);
|
|
433
|
-
|
|
434
|
-
if (err.name === 'AbortError') {
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Exponential backoff
|
|
439
|
-
if (attempt < maxRetries) {
|
|
440
|
-
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// All retries failed
|
|
446
|
-
this.loading = false;
|
|
447
|
-
this.error = lastError;
|
|
448
|
-
|
|
449
|
-
return {
|
|
450
|
-
success: false,
|
|
451
|
-
error: lastError?.message || 'Unknown error',
|
|
452
|
-
timestamp: new Date().toISOString(),
|
|
453
|
-
apiUrl,
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Render the widget with fetched data
|
|
459
|
-
*/
|
|
460
|
-
render(result) {
|
|
461
|
-
if (!this.box) return;
|
|
462
|
-
|
|
463
|
-
if (result.success) {
|
|
464
|
-
this.updateStatus('success', 'Connected');
|
|
465
|
-
|
|
466
|
-
// Format the data for display
|
|
467
|
-
let content;
|
|
468
|
-
if (typeof result.data === 'object') {
|
|
469
|
-
content = JSON.stringify(result.data, null, 0).slice(0, 100);
|
|
470
|
-
} else {
|
|
471
|
-
content = String(result.data).slice(0, 100);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
this.contentText.setContent(content);
|
|
475
|
-
this.contentText.style.fg = this.theme?.colors?.white || 'white';
|
|
476
|
-
} else {
|
|
477
|
-
this.updateStatus('error', 'Error: ' + result.error);
|
|
478
|
-
this.contentText.setContent('Unable to fetch data');
|
|
479
|
-
this.contentText.style.fg = this.theme?.colors?.red || 'red';
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
this.updatedText.setContent('Last: ' + (result.timestamp || 'Never'));
|
|
483
|
-
|
|
484
|
-
const stats = this.getStats();
|
|
485
|
-
this.statsText.setContent('Requests: ' + stats.requests + ' | Errors: ' + stats.errors);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Update the status indicator
|
|
490
|
-
*/
|
|
491
|
-
updateStatus(status, message) {
|
|
492
|
-
const colors = {
|
|
493
|
-
loading: this.theme?.colors?.yellow || 'yellow',
|
|
494
|
-
success: this.theme?.colors?.green || 'green',
|
|
495
|
-
error: this.theme?.colors?.red || 'red',
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
this.statusText.setContent(message);
|
|
499
|
-
this.statusText.style.fg = colors[status] || 'white';
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Track request statistics
|
|
504
|
-
*/
|
|
505
|
-
getStats() {
|
|
506
|
-
if (!this._stats) {
|
|
507
|
-
this._stats = { requests: 0, errors: 0 };
|
|
508
|
-
}
|
|
509
|
-
return this._stats;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* Start auto-refresh timer
|
|
514
|
-
*/
|
|
515
|
-
startAutoRefresh(intervalMs) {
|
|
516
|
-
this.stopAutoRefresh();
|
|
517
|
-
this.refreshTimer = setInterval(() => {
|
|
518
|
-
if (!this.loading) {
|
|
519
|
-
this.getData()
|
|
520
|
-
.then(data => this.render(data))
|
|
521
|
-
.catch(err => this.log('error', 'Auto-refresh failed: ' + err.message));
|
|
522
|
-
}
|
|
523
|
-
}, intervalMs);
|
|
524
|
-
|
|
525
|
-
this.log('debug', 'Auto-refresh started (' + intervalMs + 'ms interval)');
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Stop auto-refresh timer
|
|
530
|
-
*/
|
|
531
|
-
stopAutoRefresh() {
|
|
532
|
-
if (this.refreshTimer) {
|
|
533
|
-
clearInterval(this.refreshTimer);
|
|
534
|
-
this.refreshTimer = null;
|
|
535
|
-
this.log('debug', 'Auto-refresh stopped');
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Destroy the widget
|
|
541
|
-
*/
|
|
542
|
-
async destroy() {
|
|
543
|
-
this.stopAutoRefresh();
|
|
544
|
-
|
|
545
|
-
if (this.box) {
|
|
546
|
-
this.box.destroy();
|
|
547
|
-
this.box = null;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
this.loaded = false;
|
|
551
|
-
this.log('info', '${e} widget destroyed');
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
export { ${e} };
|
|
556
|
-
`},chart:{name:"Chart Widget",description:"Widget with real-time line chart visualization using blessed-contrib",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A widget that displays real-time data with charts",version:"1.0.0",author:t||"",category:s.category||"monitoring",type:"widget",lazyLoad:!0,priority:100,config:{metricType:"cpu",maxDataPoints:30,refreshInterval:2e3,showLegend:!0},__version:1}),widgetCode:(r,e)=>`/**
|
|
557
|
-
* ${e} Widget Plugin
|
|
558
|
-
* Chart widget with real-time data visualization using blessed-contrib
|
|
559
|
-
*/
|
|
560
|
-
|
|
561
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* ${e} - Chart widget for Claw Dashboard
|
|
565
|
-
*/
|
|
566
|
-
export default class ${e} extends BaseWidget {
|
|
567
|
-
constructor(options = {}) {
|
|
568
|
-
super(options);
|
|
569
|
-
this.name = options.name || '${e}';
|
|
570
|
-
this.description = options.description || 'Chart widget with real-time data';
|
|
571
|
-
|
|
572
|
-
// Chart configuration
|
|
573
|
-
this.metricType = this.config.metricType || 'cpu';
|
|
574
|
-
this.maxDataPoints = this.config.maxDataPoints || 30;
|
|
575
|
-
this.refreshInterval = this.config.refreshInterval || 2000;
|
|
576
|
-
this.showLegend = this.config.showLegend !== false;
|
|
577
|
-
|
|
578
|
-
// Data storage for time series
|
|
579
|
-
this.dataHistory = { labels: [], values: [] };
|
|
580
|
-
|
|
581
|
-
// Widget state
|
|
582
|
-
this.chart = null;
|
|
583
|
-
this.refreshTimer = null;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Initialize the widget
|
|
588
|
-
*/
|
|
589
|
-
async init() {
|
|
590
|
-
this.log('info', '${e} widget initialized');
|
|
591
|
-
return true;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* Create the widget UI with blessed-contrib line chart
|
|
596
|
-
* @param {Object} screen - Blessed screen object
|
|
597
|
-
* @param {Object} theme - Theme colors
|
|
598
|
-
*/
|
|
599
|
-
async create(screen, theme = {}) {
|
|
600
|
-
const C = theme.colors || {};
|
|
601
|
-
const blessed = await import('blessed');
|
|
602
|
-
const contrib = await import('blessed-contrib');
|
|
603
|
-
|
|
604
|
-
this.screen = screen;
|
|
605
|
-
this.theme = theme;
|
|
606
|
-
|
|
607
|
-
// Create main container box
|
|
608
|
-
this.box = blessed.default.box({
|
|
609
|
-
parent: screen,
|
|
610
|
-
width: '70%',
|
|
611
|
-
height: 17,
|
|
612
|
-
border: { type: 'line' },
|
|
613
|
-
label: ' ${e.toUpperCase()} ',
|
|
614
|
-
style: {
|
|
615
|
-
border: { fg: C.cyan || 'cyan' },
|
|
616
|
-
},
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
// Create the line chart using blessed-contrib
|
|
620
|
-
this.chart = contrib.default.line({
|
|
621
|
-
parent: this.box,
|
|
622
|
-
top: 1,
|
|
623
|
-
left: 1,
|
|
624
|
-
width: '95%',
|
|
625
|
-
height: 14,
|
|
626
|
-
style: {
|
|
627
|
-
line: C.green || 'green',
|
|
628
|
-
text: C.white || 'white',
|
|
629
|
-
baseline: C.gray || 'gray',
|
|
630
|
-
},
|
|
631
|
-
xLabelPadding: 3,
|
|
632
|
-
xPadding: 5,
|
|
633
|
-
numYLabels: 5,
|
|
634
|
-
showNthLabel: Math.ceil(this.maxDataPoints / 6),
|
|
635
|
-
showLegend: this.showLegend,
|
|
636
|
-
legend: { width: 12 },
|
|
637
|
-
minY: 0,
|
|
638
|
-
maxY: 100,
|
|
639
|
-
wholeNumbersOnly: true,
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
// Add info text
|
|
643
|
-
this.infoText = blessed.default.text({
|
|
644
|
-
parent: this.box,
|
|
645
|
-
bottom: 0,
|
|
646
|
-
left: 1,
|
|
647
|
-
content: 'Initializing...',
|
|
648
|
-
style: { fg: C.gray || 'gray' },
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
this.loaded = true;
|
|
652
|
-
this.log('debug', '${e} widget UI created');
|
|
653
|
-
|
|
654
|
-
// Start auto-refresh
|
|
655
|
-
this.startAutoRefresh();
|
|
656
|
-
|
|
657
|
-
return this;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* Generate sample data - customize this for your data source
|
|
662
|
-
*/
|
|
663
|
-
async getData() {
|
|
664
|
-
const now = new Date();
|
|
665
|
-
const timeLabel = now.getHours().toString().padStart(2, '0') + ':' +
|
|
666
|
-
now.getMinutes().toString().padStart(2, '0') + ':' +
|
|
667
|
-
now.getSeconds().toString().padStart(2, '0');
|
|
668
|
-
|
|
669
|
-
// Generate sample data - replace with actual data fetching
|
|
670
|
-
const baseValue = 30;
|
|
671
|
-
const variance = Math.random() * 40;
|
|
672
|
-
const value = Math.min(100, Math.max(0, Math.floor(baseValue + variance)));
|
|
673
|
-
|
|
674
|
-
// Store in history
|
|
675
|
-
this.dataHistory.labels.push(timeLabel);
|
|
676
|
-
this.dataHistory.values.push(value);
|
|
677
|
-
|
|
678
|
-
// Trim to max data points
|
|
679
|
-
if (this.dataHistory.labels.length > this.maxDataPoints) {
|
|
680
|
-
this.dataHistory.labels.shift();
|
|
681
|
-
this.dataHistory.values.shift();
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
return {
|
|
685
|
-
currentValue: value,
|
|
686
|
-
timestamp: now.toISOString(),
|
|
687
|
-
labels: [...this.dataHistory.labels],
|
|
688
|
-
values: [...this.dataHistory.values],
|
|
689
|
-
dataPoints: this.dataHistory.values.length,
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Render the chart with data
|
|
695
|
-
*/
|
|
696
|
-
render(data) {
|
|
697
|
-
if (!this.chart || !data) return;
|
|
698
|
-
|
|
699
|
-
// Prepare chart data
|
|
700
|
-
const chartData = {
|
|
701
|
-
title: '${e}',
|
|
702
|
-
x: data.labels,
|
|
703
|
-
y: data.values,
|
|
704
|
-
style: { line: 'green' },
|
|
705
|
-
};
|
|
706
|
-
|
|
707
|
-
// Update the chart
|
|
708
|
-
this.chart.setData([chartData]);
|
|
709
|
-
|
|
710
|
-
// Update info text
|
|
711
|
-
const avg = data.values.length > 0
|
|
712
|
-
? Math.floor(data.values.reduce((a, b) => a + b, 0) / data.values.length)
|
|
713
|
-
: 0;
|
|
714
|
-
const current = data.currentValue;
|
|
715
|
-
const max = data.values.length > 0 ? Math.max(...data.values) : 0;
|
|
716
|
-
|
|
717
|
-
this.infoText.setContent(
|
|
718
|
-
'Current: ' + current + ' | Avg: ' + avg + ' | Peak: ' + max +
|
|
719
|
-
' | Points: ' + data.dataPoints + '/' + this.maxDataPoints
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
/**
|
|
724
|
-
* Start auto-refresh timer
|
|
725
|
-
*/
|
|
726
|
-
startAutoRefresh() {
|
|
727
|
-
this.stopAutoRefresh();
|
|
728
|
-
|
|
729
|
-
if (this.refreshInterval > 0) {
|
|
730
|
-
this.refreshTimer = setInterval(async () => {
|
|
731
|
-
try {
|
|
732
|
-
const data = await this.getData();
|
|
733
|
-
this.render(data);
|
|
734
|
-
} catch (err) {
|
|
735
|
-
this.log('error', 'Auto-refresh failed: ' + err.message);
|
|
736
|
-
}
|
|
737
|
-
}, this.refreshInterval);
|
|
738
|
-
|
|
739
|
-
this.log('debug', 'Auto-refresh started (' + this.refreshInterval + 'ms)');
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* Stop auto-refresh timer
|
|
745
|
-
*/
|
|
746
|
-
stopAutoRefresh() {
|
|
747
|
-
if (this.refreshTimer) {
|
|
748
|
-
clearInterval(this.refreshTimer);
|
|
749
|
-
this.refreshTimer = null;
|
|
750
|
-
this.log('debug', 'Auto-refresh stopped');
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
/**
|
|
755
|
-
* Destroy the widget
|
|
756
|
-
*/
|
|
757
|
-
async destroy() {
|
|
758
|
-
this.stopAutoRefresh();
|
|
759
|
-
|
|
760
|
-
// Clear data history
|
|
761
|
-
this.dataHistory = { labels: [], values: [] };
|
|
762
|
-
|
|
763
|
-
if (this.chart) {
|
|
764
|
-
this.chart = null;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (this.box) {
|
|
768
|
-
this.box.destroy();
|
|
769
|
-
this.box = null;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
this.loaded = false;
|
|
773
|
-
this.log('info', '${e} widget destroyed');
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
export { ${e} };
|
|
778
|
-
`},table:{name:"Table Widget",description:"Widget that displays data in a sortable table format",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A widget that displays tabular data",version:"1.0.0",author:t||"",category:s.category||"monitoring",type:"widget",lazyLoad:!0,priority:100,config:{columns:["Name","Status","Value"],refreshInterval:5e3,maxRows:10},__version:1}),widgetCode:(r,e)=>`/**
|
|
779
|
-
* ${e} Widget Plugin
|
|
780
|
-
* Table widget for displaying tabular data
|
|
781
|
-
*/
|
|
782
|
-
|
|
783
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* ${e} - Table widget for Claw Dashboard
|
|
787
|
-
*/
|
|
788
|
-
export default class ${e} extends BaseWidget {
|
|
789
|
-
constructor(options = {}) {
|
|
790
|
-
super(options);
|
|
791
|
-
this.name = options.name || '${e}';
|
|
792
|
-
this.description = options.description || 'Table widget';
|
|
793
|
-
|
|
794
|
-
// Table configuration
|
|
795
|
-
this.columns = this.config.columns || ['Name', 'Status', 'Value'];
|
|
796
|
-
this.refreshInterval = this.config.refreshInterval || 5000;
|
|
797
|
-
this.maxRows = this.config.maxRows || 10;
|
|
798
|
-
|
|
799
|
-
// Widget state
|
|
800
|
-
this.table = null;
|
|
801
|
-
this.refreshTimer = null;
|
|
802
|
-
this.sortColumn = 0;
|
|
803
|
-
this.sortAsc = true;
|
|
804
|
-
this.data = [];
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
/**
|
|
808
|
-
* Initialize the widget
|
|
809
|
-
*/
|
|
810
|
-
async init() {
|
|
811
|
-
this.log('info', '${e} widget initialized');
|
|
812
|
-
return true;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
/**
|
|
816
|
-
* Create the widget UI
|
|
817
|
-
* @param {Object} screen - Blessed screen object
|
|
818
|
-
* @param {Object} theme - Theme colors
|
|
819
|
-
*/
|
|
820
|
-
async create(screen, theme = {}) {
|
|
821
|
-
const C = theme.colors || {};
|
|
822
|
-
const blessed = await import('blessed');
|
|
823
|
-
|
|
824
|
-
this.screen = screen;
|
|
825
|
-
this.theme = theme;
|
|
826
|
-
|
|
827
|
-
// Main container
|
|
828
|
-
this.box = blessed.default.box({
|
|
829
|
-
parent: screen,
|
|
830
|
-
width: '60%',
|
|
831
|
-
height: 15,
|
|
832
|
-
border: { type: 'line' },
|
|
833
|
-
label: ' ${e.toUpperCase()} ',
|
|
834
|
-
style: {
|
|
835
|
-
border: { fg: C.cyan || 'cyan' },
|
|
836
|
-
},
|
|
837
|
-
});
|
|
838
|
-
|
|
839
|
-
// Create table
|
|
840
|
-
this.table = blessed.default.table({
|
|
841
|
-
parent: this.box,
|
|
842
|
-
top: 1,
|
|
843
|
-
left: 1,
|
|
844
|
-
width: '98%',
|
|
845
|
-
height: '90%',
|
|
846
|
-
border: { type: 'none' },
|
|
847
|
-
style: {
|
|
848
|
-
header: { fg: C.cyan || 'cyan', bold: true },
|
|
849
|
-
cell: { fg: C.white || 'white' },
|
|
850
|
-
},
|
|
851
|
-
columns: this.columns,
|
|
852
|
-
rows: [],
|
|
853
|
-
});
|
|
854
|
-
|
|
855
|
-
this.loaded = true;
|
|
856
|
-
this.log('debug', '${e} widget UI created');
|
|
857
|
-
|
|
858
|
-
// Start auto-refresh
|
|
859
|
-
this.startAutoRefresh();
|
|
860
|
-
|
|
861
|
-
return this;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
/**
|
|
865
|
-
* Generate sample data - customize this for your data source
|
|
866
|
-
*/
|
|
867
|
-
async getData() {
|
|
868
|
-
// Sample data - replace with actual data fetching
|
|
869
|
-
const sampleData = [
|
|
870
|
-
['Server 1', 'Online', Math.floor(Math.random() * 100) + '%'],
|
|
871
|
-
['Server 2', 'Online', Math.floor(Math.random() * 100) + '%'],
|
|
872
|
-
['Server 3', 'Warning', Math.floor(Math.random() * 100) + '%'],
|
|
873
|
-
['Server 4', 'Online', Math.floor(Math.random() * 100) + '%'],
|
|
874
|
-
['Server 5', 'Offline', '0%'],
|
|
875
|
-
];
|
|
876
|
-
|
|
877
|
-
// Sort data
|
|
878
|
-
const sorted = [...sampleData].sort((a, b) => {
|
|
879
|
-
const aVal = a[this.sortColumn];
|
|
880
|
-
const bVal = b[this.sortColumn];
|
|
881
|
-
const cmp = aVal.localeCompare(bVal);
|
|
882
|
-
return this.sortAsc ? cmp : -cmp;
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
this.data = sorted.slice(0, this.maxRows);
|
|
886
|
-
|
|
887
|
-
return {
|
|
888
|
-
rows: this.data,
|
|
889
|
-
timestamp: new Date().toISOString(),
|
|
890
|
-
};
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
/**
|
|
894
|
-
* Render the table with data
|
|
895
|
-
*/
|
|
896
|
-
render(result) {
|
|
897
|
-
if (!this.table || !result) return;
|
|
898
|
-
|
|
899
|
-
this.table.setData({
|
|
900
|
-
headers: this.columns,
|
|
901
|
-
rows: result.rows,
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
/**
|
|
906
|
-
* Start auto-refresh timer
|
|
907
|
-
*/
|
|
908
|
-
startAutoRefresh() {
|
|
909
|
-
this.stopAutoRefresh();
|
|
910
|
-
|
|
911
|
-
if (this.refreshInterval > 0) {
|
|
912
|
-
this.refreshTimer = setInterval(async () => {
|
|
913
|
-
try {
|
|
914
|
-
const data = await this.getData();
|
|
915
|
-
this.render(data);
|
|
916
|
-
} catch (err) {
|
|
917
|
-
this.log('error', 'Auto-refresh failed: ' + err.message);
|
|
918
|
-
}
|
|
919
|
-
}, this.refreshInterval);
|
|
920
|
-
|
|
921
|
-
this.log('debug', 'Auto-refresh started (' + this.refreshInterval + 'ms)');
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
/**
|
|
926
|
-
* Stop auto-refresh timer
|
|
927
|
-
*/
|
|
928
|
-
stopAutoRefresh() {
|
|
929
|
-
if (this.refreshTimer) {
|
|
930
|
-
clearInterval(this.refreshTimer);
|
|
931
|
-
this.refreshTimer = null;
|
|
932
|
-
this.log('debug', 'Auto-refresh stopped');
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
/**
|
|
937
|
-
* Destroy the widget
|
|
938
|
-
*/
|
|
939
|
-
async destroy() {
|
|
940
|
-
this.stopAutoRefresh();
|
|
941
|
-
|
|
942
|
-
if (this.table) {
|
|
943
|
-
this.table.destroy();
|
|
944
|
-
this.table = null;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
if (this.box) {
|
|
948
|
-
this.box.destroy();
|
|
949
|
-
this.box = null;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
this.loaded = false;
|
|
953
|
-
this.log('info', '${e} widget destroyed');
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
export { ${e} };
|
|
958
|
-
`},gauge:{name:"Gauge Widget",description:"Widget that displays a circular or linear gauge for single metrics",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A widget that displays metrics with a gauge",version:"1.0.0",author:t||"",category:s.category||"monitoring",type:"widget",lazyLoad:!0,priority:100,config:{gaugeType:"circle",minValue:0,maxValue:100,refreshInterval:2e3,unit:"%"},__version:1}),widgetCode:(r,e)=>`/**
|
|
959
|
-
* ${e} Widget Plugin
|
|
960
|
-
* Gauge widget for displaying single metrics
|
|
961
|
-
*/
|
|
962
|
-
|
|
963
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
964
|
-
|
|
965
|
-
/**
|
|
966
|
-
* ${e} - Gauge widget for Claw Dashboard
|
|
967
|
-
*/
|
|
968
|
-
export default class ${e} extends BaseWidget {
|
|
969
|
-
constructor(options = {}) {
|
|
970
|
-
super(options);
|
|
971
|
-
this.name = options.name || '${e}';
|
|
972
|
-
this.description = options.description || 'Gauge widget';
|
|
973
|
-
|
|
974
|
-
// Gauge configuration
|
|
975
|
-
this.gaugeType = this.config.gaugeType || 'circle';
|
|
976
|
-
this.minValue = this.config.minValue || 0;
|
|
977
|
-
this.maxValue = this.config.maxValue || 100;
|
|
978
|
-
this.refreshInterval = this.config.refreshInterval || 2000;
|
|
979
|
-
this.unit = this.config.unit || '%';
|
|
980
|
-
|
|
981
|
-
// Widget state
|
|
982
|
-
this.gauge = null;
|
|
983
|
-
this.refreshTimer = null;
|
|
984
|
-
this.currentValue = 0;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
/**
|
|
988
|
-
* Initialize the widget
|
|
989
|
-
*/
|
|
990
|
-
async init() {
|
|
991
|
-
this.log('info', '${e} widget initialized');
|
|
992
|
-
return true;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* Create the widget UI
|
|
997
|
-
* @param {Object} screen - Blessed screen object
|
|
998
|
-
* @param {Object} theme - Theme colors
|
|
999
|
-
*/
|
|
1000
|
-
async create(screen, theme = {}) {
|
|
1001
|
-
const C = theme.colors || {};
|
|
1002
|
-
const blessed = await import('blessed');
|
|
1003
|
-
const contrib = await import('blessed-contrib');
|
|
1004
|
-
|
|
1005
|
-
this.screen = screen;
|
|
1006
|
-
this.theme = theme;
|
|
1007
|
-
|
|
1008
|
-
// Main container
|
|
1009
|
-
this.box = blessed.default.box({
|
|
1010
|
-
parent: screen,
|
|
1011
|
-
width: '30%',
|
|
1012
|
-
height: 10,
|
|
1013
|
-
border: { type: 'line' },
|
|
1014
|
-
label: ' ${e.toUpperCase()} ',
|
|
1015
|
-
style: {
|
|
1016
|
-
border: { fg: C.cyan || 'cyan' },
|
|
1017
|
-
},
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
// Create gauge based on type
|
|
1021
|
-
if (this.gaugeType === 'circle') {
|
|
1022
|
-
this.gauge = contrib.default.gauge({
|
|
1023
|
-
parent: this.box,
|
|
1024
|
-
top: 1,
|
|
1025
|
-
left: 'center',
|
|
1026
|
-
width: '90%',
|
|
1027
|
-
height: 6,
|
|
1028
|
-
style: {
|
|
1029
|
-
label: { fg: C.white || 'white' },
|
|
1030
|
-
value: { fg: C.green || 'green' },
|
|
1031
|
-
},
|
|
1032
|
-
label: this.name,
|
|
1033
|
-
});
|
|
1034
|
-
} else {
|
|
1035
|
-
// Linear gauge
|
|
1036
|
-
this.gauge = contrib.default.gauge({
|
|
1037
|
-
parent: this.box,
|
|
1038
|
-
top: 2,
|
|
1039
|
-
left: 1,
|
|
1040
|
-
width: '96%',
|
|
1041
|
-
height: 4,
|
|
1042
|
-
style: {
|
|
1043
|
-
label: { fg: C.white || 'white' },
|
|
1044
|
-
value: { fg: C.green || 'green' },
|
|
1045
|
-
},
|
|
1046
|
-
label: this.name,
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// Value display
|
|
1051
|
-
this.valueText = blessed.default.text({
|
|
1052
|
-
parent: this.box,
|
|
1053
|
-
bottom: 0,
|
|
1054
|
-
left: 'center',
|
|
1055
|
-
content: '0' + this.unit,
|
|
1056
|
-
style: { fg: C.white || 'white', bold: true },
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
this.loaded = true;
|
|
1060
|
-
this.log('debug', '${e} widget UI created');
|
|
1061
|
-
|
|
1062
|
-
// Start auto-refresh
|
|
1063
|
-
this.startAutoRefresh();
|
|
1064
|
-
|
|
1065
|
-
return this;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
/**
|
|
1069
|
-
* Generate sample data - customize this for your data source
|
|
1070
|
-
*/
|
|
1071
|
-
async getData() {
|
|
1072
|
-
// Sample data - replace with actual data fetching
|
|
1073
|
-
const value = Math.floor(Math.random() * (this.maxValue - this.minValue) + this.minValue);
|
|
1074
|
-
this.currentValue = value;
|
|
1075
|
-
|
|
1076
|
-
return {
|
|
1077
|
-
value: value,
|
|
1078
|
-
percentage: ((value - this.minValue) / (this.maxValue - this.minValue)) * 100,
|
|
1079
|
-
timestamp: new Date().toISOString(),
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* Render the gauge with data
|
|
1085
|
-
*/
|
|
1086
|
-
render(result) {
|
|
1087
|
-
if (!this.gauge || !result) return;
|
|
1088
|
-
|
|
1089
|
-
// Set gauge percentage (0-100)
|
|
1090
|
-
this.gauge.setData(result.percentage);
|
|
1091
|
-
|
|
1092
|
-
// Update value text
|
|
1093
|
-
this.valueText.setContent(result.value + this.unit);
|
|
1094
|
-
|
|
1095
|
-
// Color based on value
|
|
1096
|
-
let color = 'green';
|
|
1097
|
-
if (result.percentage > 80) {
|
|
1098
|
-
color = 'red';
|
|
1099
|
-
} else if (result.percentage > 60) {
|
|
1100
|
-
color = 'yellow';
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
this.valueText.style.fg = this.theme?.colors?.[color] || color;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
/**
|
|
1107
|
-
* Start auto-refresh timer
|
|
1108
|
-
*/
|
|
1109
|
-
startAutoRefresh() {
|
|
1110
|
-
this.stopAutoRefresh();
|
|
1111
|
-
|
|
1112
|
-
if (this.refreshInterval > 0) {
|
|
1113
|
-
this.refreshTimer = setInterval(async () => {
|
|
1114
|
-
try {
|
|
1115
|
-
const data = await this.getData();
|
|
1116
|
-
this.render(data);
|
|
1117
|
-
} catch (err) {
|
|
1118
|
-
this.log('error', 'Auto-refresh failed: ' + err.message);
|
|
1119
|
-
}
|
|
1120
|
-
}, this.refreshInterval);
|
|
1121
|
-
|
|
1122
|
-
this.log('debug', 'Auto-refresh started (' + this.refreshInterval + 'ms)');
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
/**
|
|
1127
|
-
* Stop auto-refresh timer
|
|
1128
|
-
*/
|
|
1129
|
-
stopAutoRefresh() {
|
|
1130
|
-
if (this.refreshTimer) {
|
|
1131
|
-
clearInterval(this.refreshTimer);
|
|
1132
|
-
this.refreshTimer = null;
|
|
1133
|
-
this.log('debug', 'Auto-refresh stopped');
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
/**
|
|
1138
|
-
* Destroy the widget
|
|
1139
|
-
*/
|
|
1140
|
-
async destroy() {
|
|
1141
|
-
this.stopAutoRefresh();
|
|
1142
|
-
|
|
1143
|
-
if (this.gauge) {
|
|
1144
|
-
this.gauge.destroy();
|
|
1145
|
-
this.gauge = null;
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
if (this.box) {
|
|
1149
|
-
this.box.destroy();
|
|
1150
|
-
this.box = null;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
this.loaded = false;
|
|
1154
|
-
this.log('info', '${e} widget destroyed');
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
export { ${e} };
|
|
1159
|
-
`},logViewer:{name:"Log Viewer Widget",description:"Widget that displays scrolling log entries with filtering",manifest:(r,e,t,s={})=>({id:r,name:e||r.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),description:s.description||"A widget that displays scrolling log entries",version:"1.0.0",author:t||"",category:s.category||"monitoring",type:"widget",lazyLoad:!0,priority:100,config:{maxLines:50,showTimestamp:!0,filterLevels:["info","warn","error"],refreshInterval:1e3},__version:1}),widgetCode:(r,e)=>`/**
|
|
1160
|
-
* ${e} Widget Plugin
|
|
1161
|
-
* Log viewer widget for displaying scrolling log entries
|
|
1162
|
-
*/
|
|
1163
|
-
|
|
1164
|
-
import { BaseWidget } from 'claw-dashboard/widgets';
|
|
1165
|
-
|
|
1166
|
-
/**
|
|
1167
|
-
* ${e} - Log viewer widget for Claw Dashboard
|
|
1168
|
-
*/
|
|
1169
|
-
export default class ${e} extends BaseWidget {
|
|
1170
|
-
constructor(options = {}) {
|
|
1171
|
-
super(options);
|
|
1172
|
-
this.name = options.name || '${e}';
|
|
1173
|
-
this.description = options.description || 'Log viewer widget';
|
|
1174
|
-
|
|
1175
|
-
// Log viewer configuration
|
|
1176
|
-
this.maxLines = this.config.maxLines || 50;
|
|
1177
|
-
this.showTimestamp = this.config.showTimestamp !== false;
|
|
1178
|
-
this.filterLevels = this.config.filterLevels || ['info', 'warn', 'error'];
|
|
1179
|
-
this.refreshInterval = this.config.refreshInterval || 1000;
|
|
1180
|
-
|
|
1181
|
-
// Widget state
|
|
1182
|
-
this.logBox = null;
|
|
1183
|
-
this.refreshTimer = null;
|
|
1184
|
-
this.logEntries = [];
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
/**
|
|
1188
|
-
* Initialize the widget
|
|
1189
|
-
*/
|
|
1190
|
-
async init() {
|
|
1191
|
-
this.log('info', '${e} widget initialized');
|
|
1192
|
-
|
|
1193
|
-
// Add initial log entries
|
|
1194
|
-
this.addLogEntry('info', 'Log viewer initialized');
|
|
1195
|
-
this.addLogEntry('info', 'Waiting for log data...');
|
|
1196
|
-
|
|
1197
|
-
return true;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
/**
|
|
1201
|
-
* Add a log entry
|
|
1202
|
-
* @param {string} level - Log level (info, warn, error)
|
|
1203
|
-
* @param {string} message - Log message
|
|
1204
|
-
*/
|
|
1205
|
-
addLogEntry(level, message) {
|
|
1206
|
-
const entry = {
|
|
1207
|
-
level,
|
|
1208
|
-
message,
|
|
1209
|
-
timestamp: new Date(),
|
|
1210
|
-
};
|
|
1211
|
-
|
|
1212
|
-
this.logEntries.push(entry);
|
|
1213
|
-
|
|
1214
|
-
// Trim to max lines
|
|
1215
|
-
if (this.logEntries.length > this.maxLines) {
|
|
1216
|
-
this.logEntries.shift();
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
/**
|
|
1221
|
-
* Create the widget UI
|
|
1222
|
-
* @param {Object} screen - Blessed screen object
|
|
1223
|
-
* @param {Object} theme - Theme colors
|
|
1224
|
-
*/
|
|
1225
|
-
async create(screen, theme = {}) {
|
|
1226
|
-
const C = theme.colors || {};
|
|
1227
|
-
const blessed = await import('blessed');
|
|
1228
|
-
|
|
1229
|
-
this.screen = screen;
|
|
1230
|
-
this.theme = theme;
|
|
1231
|
-
|
|
1232
|
-
// Main container
|
|
1233
|
-
this.box = blessed.default.box({
|
|
1234
|
-
parent: screen,
|
|
1235
|
-
width: '70%',
|
|
1236
|
-
height: 15,
|
|
1237
|
-
border: { type: 'line' },
|
|
1238
|
-
label: ' ${e.toUpperCase()} ',
|
|
1239
|
-
style: {
|
|
1240
|
-
border: { fg: C.cyan || 'cyan' },
|
|
1241
|
-
},
|
|
1242
|
-
});
|
|
1243
|
-
|
|
1244
|
-
// Log entries box with scrolling
|
|
1245
|
-
this.logBox = blessed.default.log({
|
|
1246
|
-
parent: this.box,
|
|
1247
|
-
top: 1,
|
|
1248
|
-
left: 1,
|
|
1249
|
-
width: '98%',
|
|
1250
|
-
height: '90%',
|
|
1251
|
-
scrollable: true,
|
|
1252
|
-
scrollbar: {
|
|
1253
|
-
style: {
|
|
1254
|
-
bg: C.gray || 'gray',
|
|
1255
|
-
},
|
|
1256
|
-
},
|
|
1257
|
-
style: {
|
|
1258
|
-
fg: C.white || 'white',
|
|
1259
|
-
bg: C.black || 'black',
|
|
1260
|
-
},
|
|
1261
|
-
});
|
|
1262
|
-
|
|
1263
|
-
this.loaded = true;
|
|
1264
|
-
this.log('debug', '${e} widget UI created');
|
|
1265
|
-
|
|
1266
|
-
// Initial render
|
|
1267
|
-
this.renderLogs();
|
|
1268
|
-
|
|
1269
|
-
// Start auto-refresh
|
|
1270
|
-
this.startAutoRefresh();
|
|
1271
|
-
|
|
1272
|
-
return this;
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
/**
|
|
1276
|
-
* Get filtered log entries
|
|
1277
|
-
*/
|
|
1278
|
-
async getData() {
|
|
1279
|
-
// Sample log generation - replace with actual log fetching
|
|
1280
|
-
const levels = ['info', 'info', 'info', 'warn', 'error'];
|
|
1281
|
-
const messages = [
|
|
1282
|
-
'Request processed successfully',
|
|
1283
|
-
'Connection established',
|
|
1284
|
-
'Data synchronized',
|
|
1285
|
-
'High memory usage detected',
|
|
1286
|
-
'Failed to connect to service',
|
|
1287
|
-
];
|
|
1288
|
-
|
|
1289
|
-
// Randomly add new log entry
|
|
1290
|
-
if (Math.random() > 0.7) {
|
|
1291
|
-
const level = levels[Math.floor(Math.random() * levels.length)];
|
|
1292
|
-
const message = messages[Math.floor(Math.random() * messages.length)];
|
|
1293
|
-
this.addLogEntry(level, message);
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
// Filter by level
|
|
1297
|
-
const filtered = this.logEntries.filter(entry =>
|
|
1298
|
-
this.filterLevels.includes(entry.level)
|
|
1299
|
-
);
|
|
1300
|
-
|
|
1301
|
-
return {
|
|
1302
|
-
entries: filtered,
|
|
1303
|
-
timestamp: new Date().toISOString(),
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
/**
|
|
1308
|
-
* Render the log entries
|
|
1309
|
-
*/
|
|
1310
|
-
renderLogs() {
|
|
1311
|
-
if (!this.logBox) return;
|
|
1312
|
-
|
|
1313
|
-
this.logBox.setContent('');
|
|
1314
|
-
|
|
1315
|
-
for (const entry of this.logEntries) {
|
|
1316
|
-
if (!this.filterLevels.includes(entry.level)) continue;
|
|
1317
|
-
|
|
1318
|
-
let line = '';
|
|
1319
|
-
|
|
1320
|
-
if (this.showTimestamp) {
|
|
1321
|
-
const time = entry.timestamp.toLocaleTimeString();
|
|
1322
|
-
line += '[' + time + '] ';
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
const levelStr = entry.level.toUpperCase().padEnd(5);
|
|
1326
|
-
line += '[' + levelStr + '] ' + entry.message;
|
|
1327
|
-
|
|
1328
|
-
// Set color based on level
|
|
1329
|
-
const colorMap = {
|
|
1330
|
-
info: this.theme?.colors?.white || 'white',
|
|
1331
|
-
warn: this.theme?.colors?.yellow || 'yellow',
|
|
1332
|
-
error: this.theme?.colors?.red || 'red',
|
|
1333
|
-
};
|
|
1334
|
-
|
|
1335
|
-
this.logBox.add(line, colorMap[entry.level] || 'white');
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
// Scroll to bottom
|
|
1339
|
-
this.logBox.setScrollPerc(100);
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
/**
|
|
1343
|
-
* Render the widget with data
|
|
1344
|
-
*/
|
|
1345
|
-
render(result) {
|
|
1346
|
-
if (!result) return;
|
|
1347
|
-
this.renderLogs();
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
/**
|
|
1351
|
-
* Start auto-refresh timer
|
|
1352
|
-
*/
|
|
1353
|
-
startAutoRefresh() {
|
|
1354
|
-
this.stopAutoRefresh();
|
|
1355
|
-
|
|
1356
|
-
if (this.refreshInterval > 0) {
|
|
1357
|
-
this.refreshTimer = setInterval(async () => {
|
|
1358
|
-
try {
|
|
1359
|
-
const data = await this.getData();
|
|
1360
|
-
this.render(data);
|
|
1361
|
-
} catch (err) {
|
|
1362
|
-
this.log('error', 'Auto-refresh failed: ' + err.message);
|
|
1363
|
-
}
|
|
1364
|
-
}, this.refreshInterval);
|
|
1365
|
-
|
|
1366
|
-
this.log('debug', 'Auto-refresh started (' + this.refreshInterval + 'ms)');
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* Stop auto-refresh timer
|
|
1372
|
-
*/
|
|
1373
|
-
stopAutoRefresh() {
|
|
1374
|
-
if (this.refreshTimer) {
|
|
1375
|
-
clearInterval(this.refreshTimer);
|
|
1376
|
-
this.refreshTimer = null;
|
|
1377
|
-
this.log('debug', 'Auto-refresh stopped');
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
/**
|
|
1382
|
-
* Destroy the widget
|
|
1383
|
-
*/
|
|
1384
|
-
async destroy() {
|
|
1385
|
-
this.stopAutoRefresh();
|
|
1386
|
-
|
|
1387
|
-
if (this.logBox) {
|
|
1388
|
-
this.logBox.destroy();
|
|
1389
|
-
this.logBox = null;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
if (this.box) {
|
|
1393
|
-
this.box.destroy();
|
|
1394
|
-
this.box = null;
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
this.logEntries = [];
|
|
1398
|
-
this.loaded = false;
|
|
1399
|
-
this.log('info', '${e} widget destroyed');
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
export { ${e} };
|
|
1404
|
-
`}};function qu(r){return r.split(/[-_]/).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join("")}function Oa(r){return!r||typeof r!="string"?{valid:!1,error:"Plugin ID must be a non-empty string"}:r.length<1||r.length>64?{valid:!1,error:"Plugin ID must be between 1 and 64 characters"}:/^[a-zA-Z0-9]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/.test(r)?["claw","dashboard","admin","system","test"].includes(r.toLowerCase())?{valid:!1,error:`'${r}' is a reserved name`}:{valid:!0}:{valid:!1,error:"Plugin ID must contain only alphanumeric characters, hyphens, and underscores, and cannot start or end with a hyphen/underscore"}}function Yu(r,e,t){let s=er[t]||er.basic;return`# ${e}
|
|
1405
|
-
|
|
1406
|
-
${s.description} for Claw Dashboard.
|
|
1407
|
-
|
|
1408
|
-
## Installation
|
|
1409
|
-
|
|
1410
|
-
1. Copy this directory to your Claw Dashboard plugins folder:
|
|
1411
|
-
\`\`\`bash
|
|
1412
|
-
cp -r ${r} ~/.openclaw/plugins/
|
|
1413
|
-
\`\`\`
|
|
1414
|
-
|
|
1415
|
-
2. Restart Claw Dashboard or reload plugins
|
|
1416
|
-
|
|
1417
|
-
## Configuration
|
|
1418
|
-
|
|
1419
|
-
Edit \`plugin.json\` to customize the widget:
|
|
1420
|
-
|
|
1421
|
-
\`\`\`json
|
|
1422
|
-
{
|
|
1423
|
-
"config": {
|
|
1424
|
-
// See plugin.json for available options
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
\`\`\`
|
|
1428
|
-
|
|
1429
|
-
## Development
|
|
1430
|
-
|
|
1431
|
-
### File Structure
|
|
1432
|
-
|
|
1433
|
-
\`\`\`
|
|
1434
|
-
${r}/
|
|
1435
|
-
\u251C\u2500\u2500 plugin.json # Plugin manifest
|
|
1436
|
-
\u251C\u2500\u2500 index.js # Widget code
|
|
1437
|
-
\u2514\u2500\u2500 README.md # This file
|
|
1438
|
-
\`\`\`
|
|
1439
|
-
|
|
1440
|
-
### Testing
|
|
1441
|
-
|
|
1442
|
-
Run your widget in Claw Dashboard:
|
|
1443
|
-
|
|
1444
|
-
\`\`\`bash
|
|
1445
|
-
clawdash --debug
|
|
1446
|
-
\`\`\`
|
|
1447
|
-
|
|
1448
|
-
## API Reference
|
|
1449
|
-
|
|
1450
|
-
See [Claw Dashboard Plugin Documentation](https://github.com/spleck/claw-dashboard/blob/main/docs/PLUGINS.md) for full API reference.
|
|
1451
|
-
|
|
1452
|
-
## License
|
|
1453
|
-
|
|
1454
|
-
MIT
|
|
1455
|
-
`}function ti(){return Object.entries(er).map(([r,e])=>({id:r,name:e.name,description:e.description}))}async function Ku(r,e={}){let{name:t,author:s,outputDir:i,template:n="basic",dryRun:a=!1,force:c=!1}=e,d=Oa(r);if(!d.valid)return{success:!1,error:d.error,code:"INVALID_ID"};let g=er[n];if(!g)return{success:!1,error:`Unknown template: ${n}. Available: ${Object.keys(er).join(", ")}`,code:"INVALID_TEMPLATE"};let p=i||sn(Gu(),".openclaw","plugins"),T=sn(p,r);if(Hu(T)&&!c)return{success:!1,error:`Plugin directory already exists: ${T}`,code:"ALREADY_EXISTS",path:T};let b=qu(r),_={"plugin.json":JSON.stringify(g.manifest(r,t,s,e),null,2),"index.js":g.widgetCode(r,b),"README.md":Yu(r,t||r,n)};if(a)return{success:!0,dryRun:!0,path:T,files:Object.keys(_),template:n};try{Uu(T,{recursive:!0})}catch(S){return{success:!1,error:`Failed to create directory: ${S.message}`,code:"MKDIR_ERROR"}}let v=[];for(let[S,M]of Object.entries(_)){let j=sn(T,S);try{Bu(j,M),v.push(S)}catch(k){return{success:!1,error:`Failed to write ${S}: ${k.message}`,code:"WRITE_ERROR",path:j}}}return{success:!0,path:T,files:v,id:r,className:b,template:n}}async function an(r){let e=r[0];if(!e||e==="--help"||e==="-h")return console.log(`
|
|
1456
|
-
Plugin Scaffolding CLI for Claw Dashboard
|
|
1457
|
-
|
|
1458
|
-
Usage: clawdash create-plugin <id> [options]
|
|
1459
|
-
|
|
1460
|
-
Arguments:
|
|
1461
|
-
id Plugin ID (kebab-case, e.g., "my-custom-widget")
|
|
1462
|
-
|
|
1463
|
-
Options:
|
|
1464
|
-
-t, --template Template to use (basic, api, chart, table, gauge, logViewer)
|
|
1465
|
-
Default: basic
|
|
1466
|
-
-n, --name Display name for the widget
|
|
1467
|
-
-a, --author Author name or email
|
|
1468
|
-
-c, --category Widget category (system, monitoring, custom, example)
|
|
1469
|
-
Default: custom
|
|
1470
|
-
--desc Widget description
|
|
1471
|
-
-o, --output Output directory (default: ~/.openclaw/plugins/)
|
|
1472
|
-
-f, --force Overwrite existing plugin
|
|
1473
|
-
--dry-run Show what would be created without creating it
|
|
1474
|
-
--list-templates Show available templates
|
|
1475
|
-
-i, --interactive Start interactive mode (prompts for all options)
|
|
1476
|
-
-h, --help Show this help message
|
|
1477
|
-
|
|
1478
|
-
Examples:
|
|
1479
|
-
clawdash create-plugin my-widget
|
|
1480
|
-
clawdash create-plugin api-status --template api --author "John Doe"
|
|
1481
|
-
clawdash create-plugin metrics --template chart --category monitoring
|
|
1482
|
-
clawdash create-plugin my-widget --interactive
|
|
1483
|
-
clawdash create-plugin --list-templates
|
|
1484
|
-
`),0;if(e==="--version"||e==="-v")return console.log("clawdash-create-plugin 1.1.0"),0;if(e==="--list-templates"||e==="list-templates")return console.log("Available Templates:"),console.log(""),ti().forEach(a=>{console.log(` ${a.id.padEnd(12)} ${a.name}`),console.log(` ${a.description}`),console.log("")}),0;let t={name:void 0,author:void 0,category:"custom",description:void 0,template:"basic",outputDir:void 0,force:!1,dryRun:!1},s=null;for(let n=0;n<r.length;n++){let a=r[n];if(!a.startsWith("-")&&!s){s=a;continue}switch(a){case"-t":case"--template":t.template=r[++n];break;case"-n":case"--name":t.name=r[++n];break;case"-a":case"--author":t.author=r[++n];break;case"-c":case"--category":t.category=r[++n];break;case"--desc":t.description=r[++n];break;case"-o":case"--output":t.outputDir=r[++n];break;case"-f":case"--force":t.force=!0;break;case"--dry-run":t.dryRun=!0;break;case"-i":case"--interactive":t.interactive=!0;break;case"-h":case"--help":break}}if(t.interactive){let n=await zu();if(!n)return 0;Object.assign(t,n),s=n.id}if(!s)return console.error("Error: Plugin ID is required"),console.error("Run with --help for usage information"),1;let i=await Ku(s,t);return i.success?(i.dryRun?(console.log("Dry run - would create:"),console.log(` Directory: ${i.path}`),console.log(` Template: ${i.template}`),console.log(" Files:"),i.files.forEach(n=>console.log(` - ${n}`))):(console.log(`\u2713 Created plugin: ${s}`),console.log(` Path: ${i.path}`),console.log(` Template: ${i.template}`),console.log(` Files: ${i.files.join(", ")}`),console.log(""),console.log("Next steps:"),console.log(` 1. Edit ${i.path}/index.js to implement your widget`),console.log(` 2. Update ${i.path}/plugin.json with your configuration`),console.log(" 3. Run clawdash to see your widget in action")),0):(console.error(`Error: ${i.error}`),1)}import.meta.url===`file://${process.argv[1]}`&&(async()=>{let r=await an(process.argv.slice(2));process.exit(r)})();Q();te();As();import Pa from"fs";import Qu from"https";import Zu from"http";import{exec as ed}from"child_process";import{promisify as td}from"util";te();Q();import Da from"crypto";var Ma=["sha256","sha512","md5"];function Xu(r,e=null){let t=e||w.CHECKSUM.ALGORITHM;if(!Ma.includes(t))throw new Error(`Unsupported hash algorithm: ${t}. Supported: ${Ma.join(", ")}`);let s=Da.createHash(t);return s.update(r),s.digest("hex")}function Ju(r,e,t=null){if(!e)return!1;try{let s=Xu(r,t);return Da.timingSafeEqual(Buffer.from(s,"hex"),Buffer.from(e,"hex"))}catch(s){return u.debug(`Checksum verification failed: ${s.message}`),!1}}function Na(r,e){if(!w.CHECKSUM.ENABLED)return{verified:!0,checksum:null,error:null};let t=w.CHECKSUM.HEADER_NAME.toLowerCase(),s=r.headers[t];if(!s)return w.CHECKSUM.STRICT_MODE?{verified:!1,checksum:null,error:`Missing ${w.CHECKSUM.HEADER_NAME} header (strict mode enabled)`}:{verified:!0,checksum:null,error:null};let i=Array.isArray(s)?s[0]:s;return/^[a-f0-9]+$/i.test(i)?Ju(e,i)?{verified:!0,checksum:i,error:null}:{verified:!1,checksum:i,error:"Checksum mismatch: computed checksum does not match header"}:{verified:!1,checksum:i,error:"Invalid checksum format: expected hex string"}}function $a(r){let e=w.CHECKSUM.HEADER_NAME.toLowerCase(),t=r.headers[e];return{algorithm:w.CHECKSUM.ALGORITHM,headerName:w.CHECKSUM.HEADER_NAME,headerPresent:!!t,checksum:t||null,strictMode:w.CHECKSUM.STRICT_MODE,enabled:w.CHECKSUM.ENABLED}}var sd=td(ed);function rd(r){switch(r){case"error":return e=>e.includes("ERROR")||e.includes("error")||e.includes("ERR");case"warn":return e=>e.includes("WARN")||e.includes("warning")||e.includes("WARNING");case"info":return e=>!e.includes("DEBUG")&&!e.includes("debug");case"debug":case"all":default:return()=>!0}}async function Wa(r={}){let{limit:e=200,filter:t="all"}=r;try{let{stdout:s}=await sd(`openclaw logs --limit ${e} --plain 2>/dev/null`,{timeout:w.COMMAND_TIMEOUTS.OPENCLAW_LOGS}),i=rd(t),n=s.trim().split(`
|
|
1485
|
-
`).filter(a=>!a.includes("plugin CLI register skipped")).filter(a=>i(a)).filter(a=>a.length>0);return{logs:n,count:n.length,timestamp:Date.now()}}catch(s){return u.debug(`Failed to fetch OpenClaw logs: ${s.message}`),{logs:[],count:0,timestamp:Date.now(),error:s.message}}}var ln=class{constructor(){this.endpoints=[],this.endpointLatency=new Map,this.endpointFailCount=new Map,this.endpointChecksumFailCount=new Map,this.endpointChecksumVerified=new Map}init(e){e.gatewayEndpoints&&Array.isArray(e.gatewayEndpoints)?this.endpoints=e.gatewayEndpoints.map(t=>({...ws,...t,name:t.name||"unnamed",host:t.host||"localhost",port:t.port||ct.DEFAULT_PORT,enabled:t.enabled!==!1})):this.endpoints=[{...ws}],u.info(`GatewayManager initialized with ${this.endpoints.length} endpoint(s)`)}getEnabledEndpoints(){return this.endpoints.filter(e=>e.enabled)}getAllEndpoints(){return[...this.endpoints]}getEndpoint(e){return this.endpoints.find(t=>t.name===e)}addEndpoint(e){if(this.endpoints.length>=ct.MAX_ENDPOINTS)return u.warn(`Cannot add endpoint: maximum of ${ct.MAX_ENDPOINTS} endpoints reached`),null;if(this.endpoints.some(s=>s.name===e.name))return u.warn(`Cannot add endpoint: name '${e.name}' already exists`),null;let t={...ws,...e,enabled:!0};return this.endpoints.push(t),u.info(`Added gateway endpoint: ${t.name} (${t.host}:${t.port})`),t}removeEndpoint(e){let t=this.endpoints.findIndex(s=>s.name===e);return t===-1?!1:this.endpoints.length<=1?(u.warn("Cannot remove the last gateway endpoint"),!1):(this.endpoints.splice(t,1),u.info(`Removed gateway endpoint: ${e}`),!0)}updateEndpoint(e,t){let s=this.endpoints.findIndex(i=>i.name===e);return s===-1?null:t.name&&t.name!==e&&this.endpoints.some(i=>i.name===t.name)?(u.warn(`Cannot rename endpoint: name '${t.name}' already exists`),null):(this.endpoints[s]={...this.endpoints[s],...t},u.info(`Updated gateway endpoint: ${e}`),this.endpoints[s])}toggleEndpoint(e,t){let s=this.getEndpoint(e);return s?!t&&this.getEnabledEndpoints().length<=1?(u.warn("Cannot disable the last enabled gateway endpoint"),!1):(s.enabled=t,u.info(`Gateway endpoint ${e} ${t?"enabled":"disabled"}`),!0):!1}buildSessionsUrl(e){return`${e.port===443?"https":"http"}://${e.host}:${e.port}/sessions`}async fetchSessionsFromEndpoint(e){let t=Date.now();try{let s=await this.fetchFromHttpApi(e);if(s&&s.length>0)return this.updateEndpointHealth(e.name,!0,Date.now()-t,null,!0,!1),s.map(i=>this.enrichSession(i,e))}catch(s){if(u.debug(`HTTP API fetch failed for ${e.name}: ${s.message}`),s instanceof Is)return this.updateEndpointHealth(e.name,!1,null,s.message,!1,!0),u.error(`Checksum verification failed for ${e.name}: ${s.message}`),[]}if(e.type==="local"||e.host==="localhost"||e.host==="127.0.0.1")try{let s=await this.fetchFromLocalFile(e);if(s)return this.updateEndpointHealth(e.name,!0,Date.now()-t),s.map(i=>this.enrichSession(i,e))}catch(s){u.debug(`Local file fetch failed for ${e.name}: ${s.message}`)}return this.updateEndpointHealth(e.name,!1,null,"Failed to fetch sessions"),[]}fetchFromHttpApi(e){return new Promise((t,s)=>{let i=this.buildSessionsUrl(e),n=i.startsWith("https:")?Qu:Zu,a={timeout:ct.TIMEOUT_MS,headers:{Accept:"application/json"}};e.token&&(a.headers.Authorization=`Bearer ${e.token}`);let c=n.get(i,a,d=>{let g="";d.on("data",p=>g+=p),d.on("end",()=>{if(d.statusCode===200)try{let p=Na(d,g);if(!p.verified){let b=$a(d);u.warn(`Checksum verification failed for ${e.name}: ${p.error}`,{endpoint:e.name,headerPresent:b.headerPresent,strictMode:b.strictMode}),s(new Is(`Response integrity check failed: ${p.error}`,{endpoint:e.name,headerName:b.headerName,headerPresent:b.headerPresent}));return}p.checksum&&u.debug(`Checksum verified for ${e.name}: ${p.checksum.substring(0,16)}...`);let T=JSON.parse(g);t(Array.isArray(T)?T:Object.values(T))}catch(p){p instanceof Is?s(p):s(new qs(`Invalid JSON response: ${p.message}`))}else d.statusCode===401||d.statusCode===403?s(new Fr(`Authentication failed for ${e.name}`)):s(new qs(`HTTP ${d.statusCode}`))})});c.on("error",d=>{s(new Ur(`Connection error: ${d.message}`))}),c.on("timeout",()=>{c.destroy(),s(new Br("Request timeout"))}),c.setTimeout(ct.TIMEOUT_MS)})}async fetchFromLocalFile(e){let t=w.PATHS.AGENTS_DIR+"/main/sessions/sessions.json";if(!Pa.existsSync(t))return null;let s=Pa.readFileSync(t,"utf8"),i=JSON.parse(s);return!i||typeof i!="object"?null:Object.entries(i).map(([n,a])=>({key:n,channel:a.channel||"unknown",displayName:a.displayName||n,updatedAt:a.updatedAt||a.lastMessageAt||0,sessionId:a.sessionId||n,model:a.model||"unknown",contextTokens:a.contextWindow||a.contextTokens||0,totalTokens:a.totalTokens||0,kind:a.kind||"other",deliveryContext:a.deliveryContext||{},systemSent:a.systemSent||!1,abortedLastRun:a.abortedLastRun||!1,lastChannel:a.lastChannel||a.channel||"",lastTo:a.lastTo||"",lastAccountId:a.lastAccountId||"",transcriptPath:a.transcriptPath||""}))}enrichSession(e,t){return{...e,gatewayEndpoint:t.name,gatewayHost:`${t.host}:${t.port}`}}updateEndpointHealth(e,t,s,i=null,n=!1,a=!1){let c=this.getEndpoint(e);if(c){if(c.reachable=t,c.lastSeen=t?Date.now():c.lastSeen,c.error=i,s!==null&&this.endpointLatency.set(e,s),t)this.endpointFailCount.set(e,0);else{let d=this.endpointFailCount.get(e)||0;this.endpointFailCount.set(e,d+1)}if(n&&this.endpointChecksumVerified.set(e,!0),a){let d=this.endpointChecksumFailCount.get(e)||0;this.endpointChecksumFailCount.set(e,d+1)}}}async fetchAllSessions(){let e=this.getEnabledEndpoints();if(e.length===0)return u.warn("No enabled gateway endpoints"),{sessions:[],stats:{totalEndpoints:0,reachableEndpoints:0}};let t=e.map(async c=>{try{let d=await this.fetchSessionsFromEndpoint(c);return{endpoint:c.name,sessions:d,error:null}}catch(d){return u.warn(`Failed to fetch from ${c.name}: ${d.message}`),{endpoint:c.name,sessions:[],error:d.message}}}),s=await Promise.all(t),i=[],n=0;for(let c of s)c.error||(n++,i.push(...c.sessions));let a={totalEndpoints:e.length,reachableEndpoints:n,unreachableEndpoints:e.length-n};return u.debug(`Fetched ${i.length} sessions from ${n}/${e.length} endpoints`),{sessions:i,stats:a}}getEndpointHealth(){return this.endpoints.map(e=>({name:e.name,host:e.host,port:e.port,enabled:e.enabled,reachable:e.reachable||!1,lastSeen:e.lastSeen||null,latency:this.endpointLatency.get(e.name)||null,failCount:this.endpointFailCount.get(e.name)||0,error:e.error||null,checksum:{verified:this.endpointChecksumVerified.get(e.name)||!1,failCount:this.endpointChecksumFailCount.get(e.name)||0,enabled:w.CHECKSUM.ENABLED}}))}async forceRetry(e=null){let t=[],s=e?this.endpoints.filter(n=>n.name===e):this.endpoints.filter(n=>n.enabled&&!n.reachable);if(s.length===0)return{attempted:0,results:[]};u.info(`Force retrying ${s.length} endpoint(s)`);for(let n of s){this.endpointFailCount.set(n.name,0);try{let a=await this.fetchSessionsFromEndpoint(n);t.push({name:n.name,success:n.reachable===!0,sessions:a.length,latency:this.endpointLatency.get(n.name)||null,error:n.error||null})}catch(a){t.push({name:n.name,success:!1,sessions:0,latency:null,error:a.message})}}let i=t.filter(n=>n.success).length;return u.info(`Force retry complete: ${i}/${t.length} endpoints reachable`),{attempted:t.length,successful:i,results:t}}getEndpointFailCount(e){return this.endpointFailCount.get(e)||0}clearEndpointFailCount(e){this.endpointFailCount.set(e,0),u.debug(`Cleared fail count for endpoint: ${e}`)}getTotalFailCount(){let e=0;for(let t of this.endpointFailCount.values())e+=t;return e}clearAllFailCounts(){for(let e of this.endpointFailCount.keys())this.endpointFailCount.set(e,0);u.debug("Cleared all endpoint failure counts")}getSettingsForSave(){return{gatewayEndpoints:this.endpoints.map(e=>({name:e.name,host:e.host,port:e.port,token:e.token,enabled:e.enabled,type:e.type}))}}},id=new ln,Pe=id;import Pm from"blessed";import Fm from"blessed-contrib";Q();import _m from"blessed";te();te();function cn(){let r=process.argv.slice(2),e={help:!1,version:!1,debug:!1,web:!1,webPort:w.WEB.DEFAULT_PORT,webHost:w.WEB.HOST,watch:!1,watchPlugins:!1,command:null,commandArgs:[]};if(r.length>0&&!r[0].startsWith("-")){let t=r[0];if(t==="create-plugin")return e.command="create-plugin",e.commandArgs=r.slice(1),e;if(t==="validate-plugin")return e.command="validate-plugin",e.commandArgs=r.slice(1),e;if(t==="validate-config")return e.command="validate-config",e.commandArgs=r.slice(1),e;if(t==="export-snapshot")return e.command="export-snapshot",e.commandArgs=r.slice(1),e;if(t==="import-snapshot")return e.command="import-snapshot",e.commandArgs=r.slice(1),e;if(t==="list-templates")return e.command="list-templates",e.commandArgs=r.slice(1),e}for(let t=0;t<r.length;t++)switch(r[t]){case"-h":case"--help":e.help=!0;break;case"-v":case"--version":e.version=!0;break;case"-d":case"--debug":e.debug=!0;break;case"-w":case"--web":e.web=!0;break;case"-p":case"--web-port":if(e.web=!0,t+1<r.length){let i=parseInt(r[++t],10);!isNaN(i)&&i>0&&i<65536&&(e.webPort=i)}break;case"--web-host":e.web=!0,t+1<r.length&&(e.webHost=r[++t]);break;case"-W":case"--watch":e.watch=!0;break;case"--watch-plugins":e.watchPlugins=!0;break}return e}function hn(){console.log(`
|
|
1486
|
-
Claw Dashboard - A beautiful terminal dashboard for monitoring OpenClaw instances
|
|
1487
|
-
|
|
1488
|
-
Usage: clawdash [OPTIONS] [COMMAND]
|
|
1489
|
-
|
|
1490
|
-
Commands:
|
|
1491
|
-
create-plugin <id> Create a new widget plugin scaffold
|
|
1492
|
-
Use -h with this command for options
|
|
1493
|
-
validate-plugin <path> Validate a plugin.json manifest file
|
|
1494
|
-
Use -h with this command for options
|
|
1495
|
-
validate-config [path] Validate dashboard configuration file
|
|
1496
|
-
Uses ~/.openclaw/dashboard-settings.json by default
|
|
1497
|
-
export-snapshot [path] Export dashboard configuration snapshot
|
|
1498
|
-
Shareable JSON format for backups and sharing
|
|
1499
|
-
Use -h with this command for options
|
|
1500
|
-
import-snapshot [path] Import dashboard configuration snapshot
|
|
1501
|
-
Use --list to see available snapshots
|
|
1502
|
-
Use -h with this command for options
|
|
1503
|
-
list-templates List available widget templates
|
|
1504
|
-
Shows all templates for create-plugin command
|
|
1505
|
-
export-schedule Manage scheduled metric exports
|
|
1506
|
-
Configure cron-style auto-exports to CSV/JSON
|
|
1507
|
-
Use -h with this command for options
|
|
1508
|
-
|
|
1509
|
-
Options:
|
|
1510
|
-
-h, --help Display this help message
|
|
1511
|
-
-v, --version Display version information
|
|
1512
|
-
-d, --debug Run in debug mode with additional logging
|
|
1513
|
-
-w, --web Run web server mode (no TUI, HTTP API only)
|
|
1514
|
-
-p, --web-port Set web server port (default: 18790, requires --web)
|
|
1515
|
-
--web-host Set web server host (default: 0.0.0.0, requires --web)
|
|
1516
|
-
-W, --watch Enable plugin hot-reload (watches ~/.openclaw/plugins/)
|
|
1517
|
-
|
|
1518
|
-
Developer Mode:
|
|
1519
|
-
--watch Automatically reload plugins when files change
|
|
1520
|
-
Watches plugin.json and index.js files in plugin directories
|
|
1521
|
-
Shows notifications in dashboard when plugins reload
|
|
1522
|
-
|
|
1523
|
-
Web Server Endpoints (when --web is enabled):
|
|
1524
|
-
GET /health Health check
|
|
1525
|
-
GET /metrics System metrics (CPU, memory, GPU, etc.)
|
|
1526
|
-
GET /sessions Active OpenClaw sessions
|
|
1527
|
-
GET /agents Available OpenClaw agents
|
|
1528
|
-
GET /logs Recent OpenClaw logs
|
|
1529
|
-
GET /status Full dashboard status (all data)
|
|
1530
|
-
|
|
1531
|
-
Controls:
|
|
1532
|
-
q, Q, Ctrl+C Quit the dashboard
|
|
1533
|
-
r, R Force refresh data
|
|
1534
|
-
p, Space Pause/resume auto-refresh
|
|
1535
|
-
o Cycle session sort (time/tokens/idle/name)
|
|
1536
|
-
? Toggle help panel
|
|
1537
|
-
s, S Open settings panel
|
|
1538
|
-
1-8 Toggle widgets
|
|
1539
|
-
|
|
1540
|
-
For full documentation, see: man clawdash
|
|
1541
|
-
`)}te();function un(){console.log(`clawdash ${pe}`)}import tr from"fs";import nd from"os";import{dirname as od,join as si,resolve as ad}from"path";async function dn(r){let e=r[0],t=r.includes("--json")||r.includes("-j"),s=r.includes("--verbose")||r.includes("-v");if(r.includes("--help")||r.includes("-h"))return console.log(`
|
|
1542
|
-
Validate Plugin Manifest for Claw Dashboard
|
|
1543
|
-
|
|
1544
|
-
Usage: clawdash validate-plugin <path> [options]
|
|
1545
|
-
|
|
1546
|
-
Arguments:
|
|
1547
|
-
path Path to plugin.json file or plugin directory
|
|
1548
|
-
|
|
1549
|
-
Options:
|
|
1550
|
-
-j, --json Output results as JSON
|
|
1551
|
-
-v, --verbose Show detailed output including code analysis
|
|
1552
|
-
-h, --help Show this help message
|
|
1553
|
-
|
|
1554
|
-
Examples:
|
|
1555
|
-
clawdash validate-plugin ./my-widget/plugin.json
|
|
1556
|
-
clawdash validate-plugin ~/.openclaw/plugins/my-widget
|
|
1557
|
-
clawdash validate-plugin ./my-widget --json
|
|
1558
|
-
clawdash validate-plugin ./my-widget --verbose
|
|
1559
|
-
`),0;if(!e)return console.error("Error: Path is required"),console.error("Run with --help for usage information"),1;let n=e;if(e.startsWith("~")&&(n=si(nd.homedir(),e.slice(1))),n=ad(n),!tr.existsSync(n)){let _={valid:!1,error:`Path does not exist: ${e}`};return t?console.log(JSON.stringify(_,null,2)):console.error(`Error: ${_.error}`),1}let a=n,c=tr.statSync(n);if(c.isDirectory()&&(a=si(n,"plugin.json"),!tr.existsSync(a))){let _={valid:!1,path:n,error:`No plugin.json found in directory: ${e}`};return t?console.log(JSON.stringify(_,null,2)):console.error(`Error: ${_.error}`),1}let d;try{let _=tr.readFileSync(a,"utf8");d=JSON.parse(_)}catch(_){let v={valid:!1,path:a,error:`Failed to read/parse plugin.json: ${_.message}`};return t?console.log(JSON.stringify(v,null,2)):console.error(`Error: ${v.error}`),1}let g=ls(d),p={valid:!0};d.id&&(p=Ia(d.id));let T={valid:g.valid&&p.valid,path:a,errors:g.errors,id:d.id||null,name:d.name||null,version:d.version||null};p.valid||T.errors.push(`Invalid plugin ID: ${p.error}`);let b=[];if(s&&T.valid&&((!d.description||d.description==="A custom widget plugin for Claw Dashboard")&&b.push("Add a meaningful description to your plugin"),d.author||b.push("Missing author - recommended for plugin distribution"),(!d.config||Object.keys(d.config).length===0)&&b.push("Consider adding configurable options to your plugin"),d.type==="widget")){let _=c.isDirectory()?si(n,"index.js"):si(od(n),"index.js");tr.existsSync(_)||(T.valid=!1,T.errors.push("Widget plugins must have an index.js file"))}return t?(s&&(T.warnings=b),console.log(JSON.stringify(T,null,2))):T.valid?(console.log(`\u2713 Valid plugin manifest: ${a}`),console.log(` ID: ${T.id}`),console.log(` Name: ${T.name}`),console.log(` Version: ${T.version}`),s&&b.length>0&&(console.log(""),console.log("Warnings:"),b.forEach(_=>{console.log(` \u26A0 ${_}`)}))):(console.error(`\u2717 Invalid plugin manifest: ${a}`),console.error(" Errors:"),T.errors.forEach(_=>{console.error(` - ${_}`)})),T.valid?0:1}import pd from"os";import{resolve as md,join as yd}from"path";te();import{existsSync as ld,readFileSync as cd}from"fs";import{resolve as hd}from"path";function he(r,e,t){if(r==null)return null;let s=Array.isArray(r)?"array":typeof r;return e==="integer"?Number.isInteger(r)?null:`'${t}' must be an integer, got ${s}`:e==="port"?!Number.isInteger(r)||r<1||r>65535?`'${t}' must be a valid port number (1-65535), got ${r}`:null:s!==e?`'${t}' must be of type ${e}, got ${s}`:null}function ud(r,e){let t=[],s=[],i=`gatewayEndpoints[${e}]`;if(!r||typeof r!="object")return t.push(`'${i}' must be an object`),{errors:t,warnings:s};if(!("name"in r))t.push(`'${i}.name' is required`);else if(typeof r.name=="string"){let c=r.name.length;c<fe.ENDPOINT_NAME.MIN_LENGTH&&t.push(`'${i}.name' must be at least ${fe.ENDPOINT_NAME.MIN_LENGTH} character(s)`),c>fe.ENDPOINT_NAME.MAX_LENGTH&&t.push(`'${i}.name' must be at most ${fe.ENDPOINT_NAME.MAX_LENGTH} characters`),fe.ENDPOINT_NAME.PATTERN.test(r.name)||t.push(`'${i}.name' must match pattern: ${fe.ENDPOINT_NAME.PATTERN.source}`)}if(!("host"in r))t.push(`'${i}.host' is required`);else{let c=he(r.host,"string",`${i}.host`);c&&t.push(c)}if(!("port"in r))t.push(`'${i}.port' is required`);else{let c=he(r.port,"port",`${i}.port`);c&&t.push(c)}if("enabled"in r){let c=he(r.enabled,"boolean",`${i}.enabled`);c&&t.push(c)}if("type"in r&&(fe.VALID_ENDPOINT_TYPES.includes(r.type)||t.push(`'${i}.type' must be one of: ${fe.VALID_ENDPOINT_TYPES.join(", ")}`)),"token"in r&&r.token!==null){let c=he(r.token,"string",`${i}.token`);c&&t.push(c)}let n=["name","host","port","enabled","type","token"],a=Object.keys(r).filter(c=>!n.includes(c));for(let c of a)s.push(`'${i}.${c}' is not a standard endpoint field`);return{errors:t,warnings:s}}function dd(r){let e=[],t=[],s="webInterface";if(!r||typeof r!="object")return e.push(`'${s}' must be an object`),{errors:e,warnings:t};if("enabled"in r){let i=he(r.enabled,"boolean",`${s}.enabled`);i&&e.push(i)}if("port"in r){let i=he(r.port,"port",`${s}.port`);i&&e.push(i)}if("host"in r){let i=he(r.host,"string",`${s}.host`);i&&e.push(i)}if("cors"in r){let i=he(r.cors,"boolean",`${s}.cors`);i&&e.push(i)}if("corsOrigins"in r){let i=r.corsOrigins;if(typeof i!="string"&&!Array.isArray(i))e.push(`'${s}.corsOrigins' must be a string or array`);else if(Array.isArray(i))for(let n=0;n<i.length;n++)typeof i[n]!="string"&&e.push(`'${s}.corsOrigins[${n}]' must be a string`)}if("rateLimit"in r){let i=r.rateLimit;if(!i||typeof i!="object")e.push(`'${s}.rateLimit' must be an object`);else{if("enabled"in i){let n=he(i.enabled,"boolean",`${s}.rateLimit.enabled`);n&&e.push(n)}if("windowMs"in i){let n=he(i.windowMs,"integer",`${s}.rateLimit.windowMs`);n?e.push(n):i.windowMs<1e3&&t.push(`'${s}.rateLimit.windowMs' is less than 1 second (${i.windowMs}ms)`)}if("maxRequests"in i){let n=he(i.maxRequests,"integer",`${s}.rateLimit.maxRequests`);n?e.push(n):i.maxRequests<1&&e.push(`'${s}.rateLimit.maxRequests' must be at least 1`)}}}if("auth"in r){let i=r.auth;if(!i||typeof i!="object")e.push(`'${s}.auth' must be an object`);else{if("enabled"in i){let n=he(i.enabled,"boolean",`${s}.auth.enabled`);n&&e.push(n)}if("keys"in i)if(!Array.isArray(i.keys))e.push(`'${s}.auth.keys' must be an array`);else for(let n=0;n<i.keys.length;n++){let a=i.keys[n];(!a||typeof a!="object")&&e.push(`'${s}.auth.keys[${n}]' must be an object`)}}}return{errors:e,warnings:t}}function fd(r){let e=[],t=[],s="widgetLoading";if(!r||typeof r!="object")return e.push(`'${s}' must be an object`),{errors:e,warnings:t};if("enabled"in r){let i=he(r.enabled,"boolean",`${s}.enabled`);i&&e.push(i)}if("preloadPriority"in r)if(!Array.isArray(r.preloadPriority))e.push(`'${s}.preloadPriority' must be an array`);else for(let i=0;i<r.preloadPriority.length;i++)typeof r.preloadPriority[i]!="string"&&e.push(`'${s}.preloadPriority[${i}]' must be a string`);if("lazyLoadDelay"in r){let i=he(r.lazyLoadDelay,"integer",`${s}.lazyLoadDelay`);i?e.push(i):r.lazyLoadDelay<0&&e.push(`'${s}.lazyLoadDelay' must be non-negative`)}if("maxConcurrent"in r){let i=he(r.maxConcurrent,"integer",`${s}.maxConcurrent`);i?e.push(i):r.maxConcurrent<1&&e.push(`'${s}.maxConcurrent' must be at least 1`)}if("autoDiscover"in r){let i=he(r.autoDiscover,"boolean",`${s}.autoDiscover`);i&&e.push(i)}return{errors:e,warnings:t}}function gd(r,e={}){let{strict:t=!1}=e,s=[],i=[],n=[];if(!r||typeof r!="object")return{valid:!1,errors:["Config must be a valid JSON object"],warnings:[],info:[],stats:{fieldCount:0}};let a=Object.keys(r).length;if("refreshInterval"in r){let c=he(r.refreshInterval,"integer","refreshInterval");c?s.push(c):r.refreshInterval<fe.REFRESH_INTERVAL.MIN?s.push(`'refreshInterval' must be at least ${fe.REFRESH_INTERVAL.MIN}ms`):r.refreshInterval>fe.REFRESH_INTERVAL.MAX&&s.push(`'refreshInterval' must be at most ${fe.REFRESH_INTERVAL.MAX}ms`);let d=[1e3,2e3,5e3,1e4];if(!d.includes(r.refreshInterval)){let g=d.reduce((p,T)=>Math.abs(T-r.refreshInterval)<Math.abs(p-r.refreshInterval)?T:p);n.push(`'refreshInterval' value ${r.refreshInterval}ms is not standard. Closest: ${g}ms`)}}"logLevelFilter"in r&&(fe.VALID_LOG_LEVELS.includes(r.logLevelFilter)||s.push(`'logLevelFilter' must be one of: ${fe.VALID_LOG_LEVELS.join(", ")}`)),"sessionSortMode"in r&&(fe.VALID_SORT_MODES.includes(r.sessionSortMode)||s.push(`'sessionSortMode' must be one of: ${fe.VALID_SORT_MODES.join(", ")}`)),"theme"in r&&(fe.VALID_THEMES.includes(r.theme)||s.push(`'theme' must be one of: ${fe.VALID_THEMES.join(", ")}`)),"exportFormat"in r&&(fe.VALID_EXPORT_FORMATS.includes(r.exportFormat)||s.push(`'exportFormat' must be one of: ${fe.VALID_EXPORT_FORMATS.join(", ")}`));for(let c=1;c<=8;c++){let d=`showWidget${c}`;if(d in r){let g=he(r[d],"boolean",d);g&&s.push(g)}}if("showPerformanceMetrics"in r){let c=he(r.showPerformanceMetrics,"boolean","showPerformanceMetrics");c&&s.push(c)}if("firstRun"in r){let c=he(r.firstRun,"boolean","firstRun");c&&s.push(c)}if("showFavoritesOnly"in r){let c=he(r.showFavoritesOnly,"boolean","showFavoritesOnly");c&&s.push(c)}if("favorites"in r&&(!r.favorites||typeof r.favorites!="object")&&s.push("'favorites' must be an object"),"gatewayEndpoints"in r)if(!Array.isArray(r.gatewayEndpoints))s.push("'gatewayEndpoints' must be an array");else{r.gatewayEndpoints.length===0&&i.push("'gatewayEndpoints' is empty - no endpoints configured"),r.gatewayEndpoints.length>ct.MAX_ENDPOINTS&&s.push(`'gatewayEndpoints' exceeds maximum of ${ct.MAX_ENDPOINTS} endpoints`);for(let c=0;c<r.gatewayEndpoints.length;c++){let d=ud(r.gatewayEndpoints[c],c);s.push(...d.errors),i.push(...d.warnings)}}if("activeGatewayEndpoint"in r){let c=he(r.activeGatewayEndpoint,"string","activeGatewayEndpoint");c&&s.push(c)}if("webInterface"in r){let c=dd(r.webInterface);s.push(...c.errors),i.push(...c.warnings)}if("widgetLoading"in r){let c=fd(r.widgetLoading);s.push(...c.errors),i.push(...c.warnings)}if("plugins"in r)if(!r.plugins||typeof r.plugins!="object")s.push("'plugins' must be an object");else{let c=Object.keys(r.plugins).length;c>0&&n.push(`Found configuration for ${c} plugin(s)`)}if("exportDirectory"in r){let c=he(r.exportDirectory,"string","exportDirectory");c&&s.push(c)}if("sessionSearchQuery"in r){let c=he(r.sessionSearchQuery,"string","sessionSearchQuery");c&&s.push(c)}if(t){let c=Object.keys(Ct);for(let d of Object.keys(r))c.includes(d)||s.push(`Unknown property: '${d}'`)}return{valid:s.length===0,errors:s,warnings:i,info:n,stats:{fieldCount:a}}}function Fa(r,e={}){let t=hd(r);if(!ld(t))return{valid:!1,errors:[`File not found: ${t}`],warnings:[],info:[],stats:{fieldCount:0}};let s;try{let i=cd(t,"utf8");s=JSON.parse(i)}catch(i){return{valid:!1,errors:[`Failed to parse JSON: ${i.message}`],warnings:[],info:[],stats:{fieldCount:0}}}return gd(s,e)}function Ua(r,e=""){let t=[],s=e?` ${e} `:" ";return r.valid?t.push(`\u2713 Configuration${s}is valid`):t.push(`\u2717 Configuration${s}validation failed`),r.stats?.fieldCount!==void 0&&t.push(` ${r.stats.fieldCount} field(s) checked`),r.errors.length>0&&(t.push(""),t.push("Errors:"),r.errors.forEach(i=>t.push(` \u2717 ${i}`))),r.warnings.length>0&&(t.push(""),t.push("Warnings:"),r.warnings.forEach(i=>t.push(` \u26A0 ${i}`))),r.info.length>0&&(t.push(""),t.push("Info:"),r.info.forEach(i=>t.push(` \u2139 ${i}`))),t.join(`
|
|
1560
|
-
`)}function Ba(){return Le.SETTINGS}async function fn(r){let e=r[0],t=r.includes("--json")||r.includes("-j"),s=r.includes("--help")||r.includes("-h"),i=r.includes("--strict")||r.includes("-s");if(s)return console.log(`
|
|
1561
|
-
Validate Dashboard Configuration for Claw Dashboard
|
|
1562
|
-
|
|
1563
|
-
Usage: clawdash validate-config [path] [options]
|
|
1564
|
-
|
|
1565
|
-
Arguments:
|
|
1566
|
-
path Path to configuration file (optional)
|
|
1567
|
-
Defaults to: ~/.openclaw/dashboard-settings.json
|
|
1568
|
-
|
|
1569
|
-
Options:
|
|
1570
|
-
-j, --json Output results as JSON
|
|
1571
|
-
-s, --strict Fail on unknown properties
|
|
1572
|
-
-h, --help Show this help message
|
|
1573
|
-
|
|
1574
|
-
Examples:
|
|
1575
|
-
clawdash validate-config
|
|
1576
|
-
clawdash validate-config ~/.openclaw/dashboard-settings.json
|
|
1577
|
-
clawdash validate-config ./my-config.json --json
|
|
1578
|
-
clawdash validate-config --strict
|
|
1579
|
-
`),0;let n=e||Ba(),a=n;n.startsWith("~")&&(a=yd(pd.homedir(),n.slice(1))),a=md(a);let c=Fa(a,{strict:i});if(t){let d={valid:c.valid,path:a,errors:c.errors,warnings:c.warnings,info:c.info,stats:c.stats};console.log(JSON.stringify(d,null,2))}else console.log(Ua(c,a));return c.valid?0:1}import Ha from"fs";import wd from"os";import{join as Ga,resolve as Ed}from"path";te();function bd(){try{let r=Le.SETTINGS;if(Ha.existsSync(r)){let e=Ha.readFileSync(r,"utf8");return{...Ct,...JSON.parse(e)}}}catch{}return{...Ct}}async function gn(r){let e=r.includes("--json")||r.includes("-j"),t=r.includes("--help")||r.includes("-h"),s=r.findIndex(a=>a==="--name"||a==="-n"),i=s!==-1&&r[s+1]?r[s+1]:"Dashboard Configuration",n=r.find(a=>!a.startsWith("-")&&!r[r.indexOf(a)-1]?.startsWith("-"));if(t)return console.log(`
|
|
1580
|
-
Export Dashboard Snapshot for Claw Dashboard
|
|
1581
|
-
|
|
1582
|
-
Usage: clawdash export-snapshot [path] [options]
|
|
1583
|
-
|
|
1584
|
-
Arguments:
|
|
1585
|
-
path Output file path (optional, defaults to ~/.openclaw/snapshots/)
|
|
1586
|
-
|
|
1587
|
-
Options:
|
|
1588
|
-
-n, --name Snapshot name (default: "Dashboard Configuration")
|
|
1589
|
-
-j, --json Output results as JSON
|
|
1590
|
-
-h, --help Show this help message
|
|
1591
|
-
|
|
1592
|
-
Examples:
|
|
1593
|
-
clawdash export-snapshot
|
|
1594
|
-
clawdash export-snapshot ~/my-layout.json
|
|
1595
|
-
clawdash export-snapshot --name "Production Setup"
|
|
1596
|
-
clawdash export-snapshot ~/backup.json --json
|
|
1597
|
-
`),0;try{let a=bd(),c=kr(a,{name:i,description:`Claw Dashboard v${pe} - Exported via CLI`}),d;if(n){let p=n;n.startsWith("~")&&(p=Ga(wd.homedir(),n.slice(1))),d=Ed(p)}else{let p=bt(),T=Nr(i);d=Ga(p,T)}let g=Mr(c,d);return e?console.log(JSON.stringify({success:g.success,path:g.path,error:g.error,snapshot:{name:c.name,version:c.dashboardVersion,schemaVersion:c.schemaVersion,createdAt:c.createdAt,metadata:c.metadata}},null,2)):g.success?(console.log("\u2713 Snapshot exported successfully"),console.log(` Name: ${c.name}`),console.log(` Path: ${g.path}`),console.log(` Version: ${c.dashboardVersion}`),console.log(` Widgets: ${c.metadata?.widgetCount||"N/A"}`),console.log(` Plugins: ${c.metadata?.pluginCount||"N/A"}`)):console.error(`\u2717 Export failed: ${g.error}`),g.success?0:1}catch(a){return e?console.log(JSON.stringify({success:!1,error:a.message},null,2)):console.error(`\u2717 Export error: ${a.message}`),1}}import sr from"fs";import Sd from"os";import{join as xd,resolve as Td}from"path";te();function vd(r){try{let e=Le.SETTINGS,t=Le.OPENCLAW_DIR;sr.existsSync(t)||sr.mkdirSync(t,{recursive:!0}),sr.writeFileSync(e,JSON.stringify(r,null,2))}catch(e){throw new Error(`Failed to save settings: ${e.message}`)}}async function pn(r){let e=r.includes("--json")||r.includes("-j"),t=r.includes("--dry-run")||r.includes("-d"),s=r.includes("--force")||r.includes("-f"),i=r.includes("--help")||r.includes("-h"),n=r.includes("--list")||r.includes("-l"),a=r.find(c=>!c.startsWith("-"));if(i)return console.log(`
|
|
1598
|
-
Import Dashboard Snapshot for Claw Dashboard
|
|
1599
|
-
|
|
1600
|
-
Usage: clawdash import-snapshot [path] [options]
|
|
1601
|
-
|
|
1602
|
-
Arguments:
|
|
1603
|
-
path Path to snapshot file (optional with --list)
|
|
1604
|
-
|
|
1605
|
-
Options:
|
|
1606
|
-
-l, --list List available snapshots
|
|
1607
|
-
-d, --dry-run Validate without applying
|
|
1608
|
-
-f, --force Skip confirmation
|
|
1609
|
-
-j, --json Output results as JSON
|
|
1610
|
-
-h, --help Show this help message
|
|
1611
|
-
|
|
1612
|
-
Examples:
|
|
1613
|
-
clawdash import-snapshot --list
|
|
1614
|
-
clawdash import-snapshot ~/my-layout.json
|
|
1615
|
-
clawdash import-snapshot ~/.openclaw/snapshots/claw-snapshot-*.json --dry-run
|
|
1616
|
-
clawdash import-snapshot ~/backup.json --force
|
|
1617
|
-
`),0;if(n){let c=$r();return e?console.log(JSON.stringify({snapshots:c},null,2)):c.length===0?console.log("No snapshots found in ~/.openclaw/snapshots/"):(console.log("Available snapshots:"),console.log(""),c.forEach((d,g)=>{let p=new Date(d.createdAt).toLocaleDateString();console.log(` ${g+1}. ${d.name}`),console.log(` Created: ${p}`),console.log(` Path: ${d.path}`),d.metadata&&console.log(` Widgets: ${d.metadata.widgetCount}, Plugins: ${d.metadata.pluginCount}`),console.log("")})),0}if(!a)return e?console.log(JSON.stringify({success:!1,error:"File path is required (use --list to see available snapshots)"},null,2)):(console.error("Error: File path is required"),console.error("Run with --list to see available snapshots"),console.error("Run with --help for usage information")),1;try{let c=a;a.startsWith("~")&&(c=xd(Sd.homedir(),a.slice(1))),c=Td(c);let d=Dr(c);if(!d.success)return e?console.log(JSON.stringify({success:!1,error:d.error,path:c},null,2)):console.error(`\u2717 Import failed: ${d.error}`),1;let{snapshot:g}=d;if(t){let b=zs(g);return e?console.log(JSON.stringify({success:!0,dryRun:!0,path:c,snapshot:{name:g.name,description:g.description,version:g.dashboardVersion,schemaVersion:g.schemaVersion,createdAt:g.createdAt,metadata:g.metadata},summary:b.split(`
|
|
1618
|
-
`)},null,2)):(console.log("\u2713 Snapshot is valid (dry run, no changes applied)"),console.log(""),console.log(b)),0}if(!e&&!s){let b=zs(g);return console.log("Snapshot to import:"),console.log(""),console.log(b),console.log(""),console.log("Run with --force to apply, or --dry-run to preview"),0}let p={...Ct};try{if(sr.existsSync(Le.SETTINGS)){let b=sr.readFileSync(Le.SETTINGS,"utf8");Object.assign(p,JSON.parse(b))}}catch{}let T=Or(p,g.settings);return vd(T),e?console.log(JSON.stringify({success:!0,path:c,snapshot:{name:g.name,version:g.dashboardVersion,createdAt:g.createdAt},applied:Object.keys(g.settings)},null,2)):(console.log("\u2713 Snapshot imported successfully"),console.log(` Name: ${g.name}`),console.log(` Version: ${g.dashboardVersion}`),console.log(""),console.log("Settings have been merged and saved."),console.log("Restart Claw Dashboard to apply all changes.")),0}catch(c){return e?console.log(JSON.stringify({success:!1,error:c.message},null,2)):console.error(`\u2717 Import error: ${c.message}`),1}}async function mn(r){if(r.includes("--help")||r.includes("-h"))return console.log(`
|
|
1619
|
-
List Available Widget Templates
|
|
1620
|
-
|
|
1621
|
-
Usage: clawdash list-templates [options]
|
|
1622
|
-
|
|
1623
|
-
Options:
|
|
1624
|
-
-j, --json Output as JSON
|
|
1625
|
-
-h, --help Show this help message
|
|
1626
|
-
|
|
1627
|
-
Examples:
|
|
1628
|
-
clawdash list-templates
|
|
1629
|
-
clawdash list-templates --json
|
|
1630
|
-
`),0;let t=r.includes("--json")||r.includes("-j");try{let s=ti();return t?console.log(JSON.stringify(s,null,2)):(console.log(""),console.log("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.log("\u2551 Available Widget Templates \u2551"),console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.log(""),s.forEach((i,n)=>{console.log(` ${n+1}. ${i.name}`),console.log(` ID: ${i.id}`),console.log(` ${i.description}`),console.log("")}),console.log("Usage:"),console.log(" clawdash create-plugin <name> --template <id>"),console.log(""),console.log("Example:"),console.log(" clawdash create-plugin my-widget --template api"),console.log("")),0}catch(s){return console.error(`Error: ${s.message}`),1}}Q();te();import Pt from"fs";import ri from"path";import{fileURLToPath as Id}from"url";var Ad=Id(import.meta.url),ky=ri.dirname(Ad),ii=w.PATHS.SETTINGS;function Wt(){try{if(!Pt.existsSync(ii))return w.DEFAULT_SETTINGS;let r=Pt.readFileSync(ii,"utf8"),e=JSON.parse(r),t=Mt.validateSettings(e);return t.valid?t.value:w.DEFAULT_SETTINGS}catch(r){return u.error(`Failed to load settings: ${r.message}`),w.DEFAULT_SETTINGS}}function rr(r){try{let e=ri.dirname(ii);Pt.existsSync(e)||Pt.mkdirSync(e,{recursive:!0}),Pt.writeFileSync(ii,JSON.stringify(r,null,2)),u.info("Settings saved successfully")}catch(e){u.error(`Failed to save settings: ${e.message}`)}}function Va(){let e=Wt().exportSchedule||ut;console.log(`
|
|
1631
|
-
=== Export Schedule Status ===
|
|
1632
|
-
`),console.log(`Enabled: ${e.enabled?"Yes":"No"}`),console.log(`Format: ${e.format}`),console.log(`Schedule: ${e.schedule}`),console.log(`Retention: ${e.retentionDays} days${e.retentionDays===0?" (forever)":""}`),console.log(`Directory: ${e.directory||"(default)"}`),console.log(`Include Metrics: ${e.includeMetrics?"Yes":"No"}`);let t=Object.entries(vs).find(([s,i])=>i===e.schedule);t&&console.log(`Preset: ${t[0]}`),console.log(`
|
|
1633
|
-
=== Available Cron Presets ===
|
|
1634
|
-
`);for(let[s,i]of Object.entries(vs))console.log(` ${s.padEnd(20)} ${i}`);console.log("")}function ja(r){let e=Wt();e.exportSchedule||(e.exportSchedule={...ut}),e.exportSchedule.enabled=!!r,rr(e),console.log(`Export schedule ${r?"enabled":"disabled"}`)}function Rd(r){let e=Wt(),t=r;vs[r]&&(t=vs[r],console.log(`Using preset: ${r} (${t})`));try{let{CronParser:s}=ss;s.parse(t)}catch(s){console.error(`Invalid cron expression: ${s.message}`),console.error(`
|
|
1635
|
-
Available presets:`);for(let[i,n]of Object.entries(vs))console.error(` ${i}: ${n}`);process.exit(1)}e.exportSchedule||(e.exportSchedule={...ut}),e.exportSchedule.schedule=t,rr(e),console.log(`Export schedule set to: ${t}`)}function _d(r){let e=r.toLowerCase();["json","csv"].includes(e)||(console.error(`Invalid format: ${r}`),console.error("Valid formats: json, csv"),process.exit(1));let t=Wt();t.exportSchedule||(t.exportSchedule={...ut}),t.exportSchedule.format=e,rr(t),console.log(`Export format set to: ${e}`)}function Cd(r){let e=parseInt(r,10);(isNaN(e)||e<0||e>365)&&(console.error("Invalid retention days: must be 0-365"),console.error(" 0 = keep forever"),console.error(" 1-365 = keep for N days"),process.exit(1));let t=Wt();t.exportSchedule||(t.exportSchedule={...ut}),t.exportSchedule.retentionDays=e,rr(t),console.log(`Export retention set to: ${e===0?"forever":`${e} days`}`)}function Ld(r){let e=Wt();e.exportSchedule||(e.exportSchedule={...ut}),e.exportSchedule.directory=r||null,rr(e),console.log(`Export directory set to: ${r||"(default)"}`)}async function kd(){let e=Wt().exportSchedule||ut;console.log(`
|
|
1636
|
-
Triggering immediate export...
|
|
1637
|
-
`);let t=new ss(e);t.setMetricsCallback(async()=>({timestamp:new Date().toISOString(),source:"cli-manual-export"}));let s=await t.triggerExport();s.success?console.log(`Export completed successfully: ${s.path}`):(console.error(`Export failed: ${s.error}`),process.exit(1))}function Od(){let t=(Wt().exportSchedule||ut).directory||ri.join(w.PATHS.OPENCLAW_DIR,"snapshots");if(console.log(`
|
|
1638
|
-
=== Recent Exports in ${t} ===
|
|
1639
|
-
`),!Pt.existsSync(t)){console.log("No exports found (directory does not exist)");return}try{let s=Pt.readdirSync(t).filter(i=>i.startsWith("claw-export-")||i.startsWith("claw-snapshot-")).map(i=>{let n=ri.join(t,i),a=Pt.statSync(n);return{name:i,size:a.size,mtime:a.mtime}}).sort((i,n)=>n.mtime-i.mtime).slice(0,20);if(s.length===0){console.log("No exports found");return}console.log("Filename".padEnd(50)+"Size".padEnd(15)+"Modified"),console.log("-".repeat(80));for(let i of s){let n=Md(i.size),a=i.mtime.toISOString().replace("T"," ").slice(0,19);console.log(i.name.padEnd(50)+n.padEnd(15)+a)}console.log("")}catch(s){console.error(`Failed to list exports: ${s.message}`)}}function Md(r){let e=["B","KB","MB","GB"],t=0,s=r;for(;s>=1024&&t<e.length-1;)s/=1024,t++;return`${s.toFixed(1)} ${e[t]}`}function Dd(){console.log(`
|
|
1640
|
-
Export Schedule Management Commands
|
|
1641
|
-
|
|
1642
|
-
Usage: clawdash export-schedule <command> [options]
|
|
1643
|
-
|
|
1644
|
-
Commands:
|
|
1645
|
-
status Show current schedule configuration
|
|
1646
|
-
enable Enable scheduled exports
|
|
1647
|
-
disable Disable scheduled exports
|
|
1648
|
-
set <expression> Set cron schedule (or preset name)
|
|
1649
|
-
format <format> Set export format (json or csv)
|
|
1650
|
-
retention <days> Set retention period (0-365 days, 0=forever)
|
|
1651
|
-
directory <path> Set export directory
|
|
1652
|
-
export Trigger immediate export
|
|
1653
|
-
list List recent exports
|
|
1654
|
-
|
|
1655
|
-
Cron Presets:
|
|
1656
|
-
everyMinute * * * * *
|
|
1657
|
-
every5Minutes */5 * * * *
|
|
1658
|
-
every15Minutes */15 * * * *
|
|
1659
|
-
hourly 0 * * * *
|
|
1660
|
-
every6Hours 0 */6 * * *
|
|
1661
|
-
daily 0 0 * * *
|
|
1662
|
-
weekly 0 0 * * 0
|
|
1663
|
-
monthly 0 0 1 * *
|
|
1664
|
-
|
|
1665
|
-
Examples:
|
|
1666
|
-
clawdash export-schedule status
|
|
1667
|
-
clawdash export-schedule enable
|
|
1668
|
-
clawdash export-schedule set hourly
|
|
1669
|
-
clawdash export-schedule set "*/30 * * * *"
|
|
1670
|
-
clawdash export-schedule format csv
|
|
1671
|
-
clawdash export-schedule retention 7
|
|
1672
|
-
clawdash export-schedule export
|
|
1673
|
-
`)}async function yn(r=[]){let e=r[0],t=r[1];switch(e){case"status":Va();break;case"enable":ja(!0);break;case"disable":ja(!1);break;case"set":if(!t)return console.error("Error: cron expression required"),console.error("Usage: clawdash export-schedule set <expression>"),console.error('Example: clawdash export-schedule set "0 * * * *"'),1;Rd(t);break;case"format":if(!t)return console.error("Error: format required"),console.error("Usage: clawdash export-schedule format <json|csv>"),1;_d(t);break;case"retention":if(t===void 0)return console.error("Error: retention days required"),console.error("Usage: clawdash export-schedule retention <days>"),1;Cd(t);break;case"directory":Ld(t||"");break;case"export":await kd();break;case"list":Od();break;case"help":case"--help":case"-h":Dd();break;default:if(!e)Va();else return console.error(`Unknown command: ${e}`),console.error("Run with --help for usage"),1}return 0}Q();import Ee from"fs";import Nd from"os";import{exec as $d}from"child_process";import{promisify as Pd}from"util";var Yy=Pd($d),za={isContainer:!1,isDocker:!1,isKubernetes:!1,isWSL:!1,wslVersion:0,wslDistro:null,containerId:null,containerName:null,podName:null,namespace:null,runtime:"none"},ni=null,wn=0,Wd=3e4;async function Fd(){try{let r=Ee.readFileSync("/proc/self/cgroup","utf8");return r.includes("docker")||r.includes("containerd")||r.includes("crio")||/[0-9a-f]{64}/.test(r)}catch{return!1}}function Ud(){try{return Ee.accessSync("/.dockerenv",Ee.constants.F_OK),!0}catch{return!1}}async function Bd(){let r={isKubernetes:!1,podName:null,namespace:null};try{if(Ee.existsSync("/var/run/secrets/kubernetes.io")&&(r.isKubernetes=!0),(process.env.KUBERNETES_SERVICE_HOST||process.env.KUBERNETES_PORT)&&(r.isKubernetes=!0),process.env.HOSTNAME){let e=process.env.HOSTNAME;e.includes("-")&&/[a-f0-9]{5,10}$/.test(e)&&(r.podName=e)}try{let e="/var/run/secrets/kubernetes.io/serviceaccount/namespace";Ee.existsSync(e)&&(r.namespace=Ee.readFileSync(e,"utf8").trim())}catch{}!r.namespace&&process.env.KUBERNETES_NAMESPACE&&(r.namespace=process.env.KUBERNETES_NAMESPACE)}catch{}return r}function En(){try{let r=Ee.readFileSync("/proc/version","utf8").toLowerCase();if(r.includes("microsoft")||r.includes("wsl"))return!0}catch{}if(process.env.WSL_DISTRO_NAME||process.env.WSLENV)return!0;try{if(Ee.existsSync("/mnt/c/Windows"))return!0}catch{}return!1}function Hd(){if(!En())return 0;try{let r=Ee.readFileSync("/proc/version","utf8").toLowerCase();if(r.includes("wsl2")||r.includes("microsoft-standard"))return 2}catch{}try{if(Ee.existsSync("/run/systemd/system"))return 2}catch{}try{let e=Ee.readFileSync("/proc/version","utf8").match(/Linux version (\d+)\.(\d+)/);if(e){let t=parseInt(e[1]),s=parseInt(e[2]);if(t>4||t===4&&s>=19)return 2}}catch{}return 1}function Gd(){if(process.env.WSL_DISTRO_NAME)return process.env.WSL_DISTRO_NAME;try{let e=Ee.readFileSync("/etc/os-release","utf8").match(/PRETTY_NAME="([^"]+)"/);if(e)return e[1]}catch{}return null}function Vd(){try{let r=Ee.readFileSync("/proc/self/cgroup","utf8"),e=r.match(/[0-9a-f]{64}/);if(e)return e[0].substring(0,12);let t=r.split(`
|
|
1674
|
-
`);for(let s of t){let i=s.match(/\/docker\/([0-9a-f]{12,64})/i);if(i)return i[1].substring(0,12);let n=s.match(/\/containerd\/.*\/([0-9a-f]{12,64})/i);if(n)return n[1].substring(0,12);let a=s.match(/\/cri-containerd\/([0-9a-f]{12,64})/i);if(a)return a[1].substring(0,12)}}catch{}return null}async function jd(){return process.env.CONTAINER_NAME?process.env.CONTAINER_NAME:process.env.HOSTNAME&&!En()?process.env.HOSTNAME:null}async function zd(){try{let r=Ee.readFileSync("/proc/self/cgroup","utf8");if(r.includes("docker"))return"docker";if(r.includes("containerd"))return"containerd";if(r.includes("crio"))return"cri-o";if(r.includes("podman"))return"podman";if(r.includes("lxc"))return"lxc";if(r.includes("systemd-nspawn"))return"systemd-nspawn";if(Ee.existsSync("/run/containerd"))return"containerd";if(Ee.existsSync("/run/crio"))return"cri-o";if(Ee.existsSync("/run/docker.sock")||Ee.existsSync("/var/run/docker.sock"))return"docker-accessible";if(r.includes("0::/")&&r.split(`
|
|
1675
|
-
`).length>1)return"container"}catch{}return"unknown"}async function qd(){let r=Date.now();if(ni&&r-wn<Wd)return ni;let e={...za};if(Nd.platform()==="win32")return e;try{let[s,i]=await Promise.all([Fd(),Promise.resolve(Ud())]);(s||i)&&(e.isContainer=!0,e.isDocker=!0,e.containerId=Vd(),e.containerName=await jd());let n=await Bd();n.isKubernetes&&(e.isContainer=!0,e.isKubernetes=!0,e.podName=n.podName,e.namespace=n.namespace),e.isWSL=En(),e.isWSL&&(e.wslVersion=Hd(),e.wslDistro=Gd()),e.isContainer&&(e.runtime=await zd()),ni=e,wn=r}catch(s){u.warn(`Container detection failed: ${s.message}`)}return e}function Yd(r){if(!r.isContainer)return"Bare Metal/VM";let e=[];if(r.isKubernetes){if(e.push("Kubernetes"),r.namespace&&e.push(`ns:${r.namespace}`),r.podName){let t=r.podName.length>20?r.podName.substring(0,17)+"...":r.podName;e.push(`pod:${t}`)}}else r.isDocker?(e.push("Docker"),r.containerId&&e.push(`id:${r.containerId}`)):e.push(r.runtime!=="unknown"?r.runtime:"Container");if(r.isWSL){let t=r.wslVersion===2?"WSL2":r.wslVersion===1?"WSL1":"WSL";e.push(`(${t})`)}return e.join(" ")}function Kd(r){return r.isWSL?`\u229E ${r.wslVersion===2?"WSL2":r.wslVersion===1?"WSL1":"WSL"}`:r.isContainer?r.isKubernetes?"\u2638 K8s":r.isDocker?"\u{1F433} Docker":"\u2B21 Container":""}function Xd(){ni=null,wn=0}var oi={detectContainerEnv:qd,getContainerDescription:Yd,getContainerIndicator:Kd,clearContainerCache:Xd,DEFAULT_CONTAINER_ENV:za};import Jd from"blessed";var bn={linear:r=>r,easeIn:r=>r*r,easeOut:r=>1-(1-r)*(1-r),easeInOut:r=>r<.5?2*r*r:1-Math.pow(-2*r+2,2)/2,spring:r=>{let e=2*Math.PI/3;return r===0?0:r===1?1:Math.pow(2,-10*r)*Math.sin((r*10-.75)*e)+1}},qa={duration:200,easing:"easeOut",fade:!0,slide:!1,scale:!1,slideDirection:"up",fadeBackground:!0},He=new Map;function Qd(r,e={}){let t=Jd.box({parent:r,top:0,left:0,width:"100%",height:"100%",style:{bg:"black"},transparent:!0}),s=e.fadeBackground!==!1?0:.4;return t.style.transparent=!0,t._targetOpacity=e.backgroundOpacity||.4,t._currentOpacity=s,t}function dt({from:r,to:e,duration:t=200,easing:s="easeOut",onUpdate:i,onComplete:n}){let a=bn[s]||bn.easeOut,c=Date.now(),d=null,g=!1,p=()=>{if(g)return;let T=Date.now()-c,b=Math.min(T/t,1),_=a(b),v=r+(e-r)*_;i(v),b<1?d=setImmediate(p):n?.()};return d=setImmediate(p),{stop:()=>{g=!0,d&&clearImmediate(d)}}}function Zd(r,e,t={}){let s={...qa,...t},i=`in_${e.uid||Math.random().toString(36).substr(2,9)}`;return He.has(i)&&He.get(i).stop(),new Promise(n=>{let a=[],c=e.top,d=e.left,g=e.width,p=e.height;if(e._originalPosition={top:c,left:d,width:g,height:p},s.fade){e.style.transparent=!0,e._opacity=0;let b=dt({from:0,to:1,duration:s.duration,easing:s.easing,onUpdate:_=>{e._opacity=_,e.style.alpha=_,e.style.transparent=_<.1}});a.push(b)}if(s.slide){let b=c,_=d,v=20;switch(s.slideDirection){case"up":b=c+v;break;case"down":b=c-v;break;case"left":_=d+v;break;case"right":_=d-v;break}e.top=b,e.left=_;let S=dt({from:0,to:1,duration:s.duration,easing:s.easing,onUpdate:M=>{e.top=b+(c-b)*M,e.left=_+(d-_)*M,r.render()}});a.push(S)}if(s.scale){let b=F=>typeof F=="string"&&F.includes("%")?{value:parseInt(F),unit:"%"}:{value:parseInt(F)||10,unit:typeof F=="string"&&F.includes("%")?"%":""},_=b(g),v=b(p),S=.9,M=Math.round(_.value*S),j=Math.round(v.value*S);e.width=M+_.unit,e.height=j+v.unit;let k=dt({from:S,to:1,duration:s.duration,easing:s.easing,onUpdate:F=>{let ee=Math.round(_.value*F),D=Math.round(v.value*F);e.width=ee+_.unit,e.height=D+v.unit,r.render()},onComplete:()=>{e.width=g,e.height=p}});a.push(k)}let T=null;s.fadeBackground&&s.background&&(T=dt({from:0,to:s.background._targetOpacity||.4,duration:s.duration,easing:"linear",onUpdate:b=>{s.background._currentOpacity=b,s.background.style.alpha=b}})),setTimeout(()=>{a.forEach(b=>b.stop()),T&&T.stop(),He.delete(i),e.top=c,e.left=d,e.width=g,e.height=p,e.style.transparent=!1,e.style.alpha=1,r.render(),n()},s.duration),He.set(i,{stop:()=>{a.forEach(b=>b.stop()),T&&T.stop(),He.delete(i)}}),r.render()})}function ef(r,e,t={}){if(!e||e.destroyed)return Promise.resolve();let s={...qa,...t},i=`out_${e.uid||Math.random().toString(36).substr(2,9)}`;return He.has(i)&&He.get(i).stop(),new Promise(n=>{let a=[],c=e._originalPosition||{top:e.top,left:e.left,width:e.width,height:e.height};if(s.fade){let g=dt({from:1,to:0,duration:s.duration,easing:s.easing,onUpdate:p=>{e.style.alpha=p,e.style.transparent=p<.1,r.render()}});a.push(g)}if(s.slide){let g=c.top,p=c.left,T=20;switch(s.slideDirection){case"up":g=c.top-T;break;case"down":g=c.top+T;break;case"left":p=c.left-T;break;case"right":p=c.left+T;break}let b=dt({from:0,to:1,duration:s.duration,easing:s.easing,onUpdate:_=>{e.top=c.top+(g-c.top)*_,e.left=c.left+(p-c.left)*_,r.render()}});a.push(b)}if(s.scale){let g=v=>typeof v=="string"&&v.includes("%")?{value:parseInt(v),unit:"%"}:{value:parseInt(v)||10,unit:typeof v=="string"&&v.includes("%")?"%":""},p=g(c.width),T=g(c.height),_=dt({from:1,to:.9,duration:s.duration,easing:s.easing,onUpdate:v=>{let S=Math.round(p.value*v),M=Math.round(T.value*v);e.width=S+p.unit,e.height=M+T.unit,r.render()}});a.push(_)}let d=null;if(s.fadeBackground&&s.background){let g=s.background._currentOpacity||.4;d=dt({from:g,to:0,duration:s.duration,easing:"linear",onUpdate:p=>{s.background._currentOpacity=p,s.background.style.alpha=p,r.render()}})}setTimeout(()=>{a.forEach(g=>g.stop()),d&&d.stop(),He.delete(i),n()},s.duration),He.set(i,{stop:()=>{a.forEach(g=>g.stop()),d&&d.stop(),He.delete(i)}})})}function Ya(r,e,t,s=150){return!e||e.destroyed?Promise.resolve():new Promise(i=>{dt({from:t?0:1,to:t?1:0,duration:s,easing:"easeOut",onUpdate:c=>{e.style.alpha=c,e.style.transparent=c<.1,r.render()},onComplete:()=>{t?(e.show(),e.style.alpha=1,e.style.transparent=!1):e.hide(),r.render(),i()}})})}function tf(r,e,t,s={}){let i=s.staggerDelay||30,n=s.duration||100,a=e.map((c,d)=>new Promise(g=>{setTimeout(()=>{Ya(r,c,t,n).then(g)},d*i)}));return Promise.all(a)}function sf(){return He.size>0}function rf(){He.forEach(r=>r.stop()),He.clear()}var Te={animate:dt,transitionIn:Zd,transitionOut:ef,quickFade:Ya,staggeredFade:tf,createBackground:Qd,isAnimating:sf,stopAll:rf,EASING:bn};Q();var Sn=class{constructor(){this.states=new Map,this.stats={totalUpdates:0,skippedUpdates:0,actualUpdates:0,screenRenders:0,skippedRenders:0}}_hash(e){return e==null?String(e):typeof e=="object"?JSON.stringify(e):String(e)}trackContent(e,t,s){let i=`${e}:content`,n=this.states.get(i),a=String(t??"");return this.stats.totalUpdates++,n===a?(this.stats.skippedUpdates++,!1):(this.states.set(i,a),this.stats.actualUpdates++,s(a),!0)}trackStyle(e,t,s,i){let n=`${e}:style:${t}`,a=this.states.get(n),c=this._hash(s);return a===c?!1:(this.states.set(n,c),i(s),!0)}trackLabel(e,t,s){let i=`${e}:label`,n=this.states.get(i),a=String(t??"");return n===a?!1:(this.states.set(i,a),s(a),!0)}resetWidget(e){for(let t of this.states.keys())t.startsWith(`${e}:`)&&this.states.delete(t)}resetAll(){this.states.clear(),u.debug("Differential render state reset")}getStats(){let e=this.stats.totalUpdates>0?(this.stats.skippedUpdates/this.stats.totalUpdates*100).toFixed(1):0,t=this.stats.screenRenders>0?(this.stats.skippedRenders/(this.stats.screenRenders+this.stats.skippedRenders)*100).toFixed(1):0;return{...this.stats,efficiency:`${e}%`,renderEfficiency:`${t}%`,trackedWidgets:this.states.size}}resetStats(){this.stats={totalUpdates:0,skippedUpdates:0,actualUpdates:0,screenRenders:0,skippedRenders:0}}},ai=class{constructor(e){this.screen=e,this.tracker=new Sn,this.pendingChanges=new Set,this.batchMode=!1,this.deferredRender=null}beginBatch(){this.batchMode=!0,this.pendingChanges.clear()}endBatch(){this.batchMode=!1;let e=this.pendingChanges.size>0;return this.pendingChanges.clear(),e?(this.tracker.stats.screenRenders++,this.screen.render(),!0):(this.tracker.stats.skippedRenders++,!1)}requestRender(){this.batchMode?this.pendingChanges.add("render"):(this.tracker.stats.screenRenders++,this.screen.render())}setContent(e,t,s){return!t||t.destroyed?!1:this.tracker.trackContent(e,s,n=>{t.setContent(n),this.pendingChanges.add(e)})}setStyle(e,t,s,i){return!t||t.destroyed?!1:this.tracker.trackStyle(e,s,i,a=>{t.style[s]=a,this.pendingChanges.add(`${e}:style`)})}setFg(e,t,s){return this.setStyle(e,t,"fg",s)}setBorderFg(e,t,s){return!t||t.destroyed||!t.style.border?!1:this.tracker.trackStyle(e,"border.fg",s,n=>{t.style.border.fg=n,this.pendingChanges.add(`${e}:border`)})}setLabel(e,t,s){return!t||t.destroyed?!1:this.tracker.trackLabel(e,s,n=>{t.setLabel(n),this.pendingChanges.add(`${e}:label`)})}resetWidget(e){this.tracker.resetWidget(e)}resetAll(){this.tracker.resetAll(),this.pendingChanges.clear()}getStats(){return this.tracker.getStats()}resetStats(){this.tracker.resetStats()}};Q();import nf from"systeminformation";Q();te();var{MEMORY_PRESSURE:ft}=w,Z={NONE:"none",ELEVATED:"elevated",WARNING:"warning",CRITICAL:"critical",EMERGENCY:"emergency"},rt={STABLE:"stable",GROWING:"growing",SHRINKING:"shrinking"},xn=class{constructor(){this.samples=[],this.maxSamples=ft.TREND.SAMPLE_COUNT*2,this.currentLevel=Z.NONE,this.sustainedSince=null,this.lastCheck=Date.now(),this.lastTrend=rt.STABLE,this.lastTrendRate=0,this.rateLimiter=new kt({enabled:!0,windowMs:3e5,maxAlerts:3,alwaysAllowCritical:!0}),this.stats={peakHeapMB:0,pressureEvents:0,sustainedEvents:0,lastPressureTime:null},this.onPressureChange=null,this.onSustainedPressure=null,this.onEmergency=null,this.isRunning=!1}start(){this.isRunning||(this.isRunning=!0,u.debug("Memory pressure monitoring started"))}stop(){this.isRunning=!1,u.debug("Memory pressure monitoring stopped")}recordSample(){let e=process.memoryUsage(),t={timestamp:Date.now(),heapUsed:Math.round(e.heapUsed/1024/1024),heapTotal:Math.round(e.heapTotal/1024/1024),rss:Math.round(e.rss/1024/1024),external:Math.round((e.external||0)/1024/1024)};return this.samples.push(t),this.samples.length>this.maxSamples&&this.samples.shift(),t.heapUsed>this.stats.peakHeapMB&&(this.stats.peakHeapMB=t.heapUsed),t}analyzeTrend(){if(this.samples.length<ft.TREND.SAMPLE_COUNT)return{direction:rt.STABLE,rateMBPerMin:0};let e=this.samples.slice(-ft.TREND.SAMPLE_COUNT),t=e[0],s=e[e.length-1],i=(s.timestamp-t.timestamp)/6e4;if(i<.5)return{direction:rt.STABLE,rateMBPerMin:0};let n=s.heapUsed-t.heapUsed,a=n/i,c=ft.TREND.GROWTH_THRESHOLD_MB;return n>c?{direction:rt.GROWING,rateMBPerMin:a}:n<-c?{direction:rt.SHRINKING,rateMBPerMin:a}:{direction:rt.STABLE,rateMBPerMin:a}}getPressureLevel(e){let{THRESHOLDS:t}=ft;return e>=t.EMERGENCY_MB?Z.EMERGENCY:e>=t.CRITICAL_MB?Z.CRITICAL:e>=t.WARNING_MB?Z.WARNING:e>=t.WARNING_MB*.75?Z.ELEVATED:Z.NONE}checkSustainedPressure(e){if(!(e!==Z.NONE&&e!==Z.ELEVATED))return this.sustainedSince=null,{sustained:!1,durationMs:0};this.sustainedSince||(this.sustainedSince=Date.now());let s=Date.now()-this.sustainedSince;return{sustained:s>=ft.SUSTAINED.DURATION_MS,durationMs:s}}getRecommendations(e){let t=[];if(e.level===Z.EMERGENCY?(t.push("Consider restarting the dashboard immediately"),t.push("Check for memory leaks in custom widgets/plugins")):e.level===Z.CRITICAL?(t.push("Enable performance metrics to identify resource-heavy widgets"),t.push("Consider disabling unused widgets"),e.trend===rt.GROWING&&t.push(`Memory growing at ${e.trendRateMB.toFixed(1)}MB/min - possible leak detected`)):e.level===Z.WARNING&&(e.trend===rt.GROWING&&t.push("Memory trend indicates potential leak - monitor closely"),t.push("Dashboard memory is elevated but stable")),this.samples.length>ft.TREND.SAMPLE_COUNT){let i=(Date.now()-this.samples[0].timestamp)/(1e3*60*60);i>24&&t.push(`Dashboard has been running for ${i.toFixed(1)} hours - consider periodic restarts`)}return t}check(){this.isRunning||this.start();let e=this.recordSample(),t=this.analyzeTrend(),s=this.getPressureLevel(e.heapUsed),{sustained:i,durationMs:n}=this.checkSustainedPressure(s),a=e.heapTotal>0?Math.round(e.heapUsed/e.heapTotal*100):0,c={level:s,heapUsedMB:e.heapUsed,heapTotalMB:e.heapTotal,usagePercent:a,trend:t.direction,trendRateMB:t.rateMBPerMin,sustained:i,sustainedDurationMs:n,recommendations:[]};return c.recommendations=this.getRecommendations(c),s!==this.currentLevel&&(this.handleLevelChange(this.currentLevel,s,c),this.currentLevel=s),i&&n>=ft.SUSTAINED.DURATION_MS&&this.handleSustainedPressure(c),this.lastTrend=t.direction,this.lastTrendRate=t.rateMBPerMin,this.lastCheck=Date.now(),c}handleLevelChange(e,t,s){let i=[Z.NONE,Z.ELEVATED,Z.WARNING,Z.CRITICAL,Z.EMERGENCY],n=i.indexOf(e);i.indexOf(t)>n?(u.warn(`Memory pressure escalating: ${e} -> ${t} (${s.heapUsedMB}MB)`),this.stats.pressureEvents++,this.stats.lastPressureTime=Date.now(),t===Z.EMERGENCY&&this.onEmergency&&this.onEmergency(s)):u.info(`Memory pressure de-escalating: ${e} -> ${t} (${s.heapUsedMB}MB)`),this.onPressureChange&&this.onPressureChange(e,t,s)}handleSustainedPressure(e){if(this.rateLimiter.checkAndRecord("sustained-pressure",e.level).allowed&&(u.warn(`Sustained memory pressure detected: ${e.level} for ${(e.sustainedDurationMs/1e3).toFixed(0)}s`),this.stats.sustainedEvents++,this.onSustainedPressure&&this.onSustainedPressure(e),ft.ACTIONS.REQUEST_GC&&global.gc)){u.debug("Requesting garbage collection");try{global.gc()}catch(s){u.debug("GC request failed:",s.message)}}}getStatus(){let e=this.samples[this.samples.length-1];return{isRunning:this.isRunning,currentLevel:this.currentLevel,samples:this.samples.length,peakHeapMB:this.stats.peakHeapMB,pressureEvents:this.stats.pressureEvents,sustainedEvents:this.stats.sustainedEvents,lastPressureTime:this.stats.lastPressureTime,latest:e||null,trend:{direction:this.lastTrend,rateMBPerMin:this.lastTrendRate},thresholds:ft.THRESHOLDS}}getStatusString(){let t=this.getStatus().latest;if(!t)return"Memory pressure monitoring inactive";let i={[Z.NONE]:"green-fg",[Z.ELEVATED]:"cyan-fg",[Z.WARNING]:"yellow-fg",[Z.CRITICAL]:"red-fg",[Z.EMERGENCY]:"red-fg"}[this.currentLevel]||"white-fg",n=this.lastTrend===rt.GROWING?"\u2191":this.lastTrend===rt.SHRINKING?"\u2193":"\u2192";return`{${i}}MEM:${t.heapUsed}MB ${n}{/${i}}`}isElevated(){return this.currentLevel===Z.WARNING||this.currentLevel===Z.CRITICAL||this.currentLevel===Z.EMERGENCY}isCritical(){return this.currentLevel===Z.CRITICAL||this.currentLevel===Z.EMERGENCY}reset(){this.samples=[],this.currentLevel=Z.NONE,this.sustainedSince=null,this.lastTrend=rt.STABLE,this.lastTrendRate=0,this.stats={peakHeapMB:0,pressureEvents:0,sustainedEvents:0,lastPressureTime:null},this.rateLimiter.reset(),u.debug("Memory pressure detector reset")}getCurrentRecommendations(){if(this.samples.length===0)return[];let e={level:this.currentLevel,trend:this.lastTrend,trendRateMB:this.lastTrendRate,heapUsedMB:this.samples[this.samples.length-1]?.heapUsed||0};return this.getRecommendations(e)}},gt=new xn;var Tn=null;function Ka(r){Tn=r}function of(){if(!Tn)return null;try{return Tn.getStatus()}catch(r){return u.debug("Failed to get worker pool metrics:",r.message),null}}var vn=class{constructor(){this.history=[],this.maxHistory=60,this.lastCheck=Date.now(),this.lastCPUUsage=process.cpuUsage(),this.isTracking=!1,this.memoryPressure=gt,this.enableMemoryPressure=!0,this.metrics={avgRefreshRate:0,avgMemoryUsed:0,peakMemoryUsed:0,avgHeapUsed:0,peakHeapUsed:0,avgCpuPercent:0,avgEventLoopLag:0,slowOperations:null,totalRefreshTime:0}}start(){this.isTracking=!0,this.lastCheck=Date.now(),this.lastCPUUsage=process.cpuUsage(),gt.start(),u.debug("Performance monitoring started")}stop(){this.isTracking=!1,gt.stop(),u.debug("Performance monitoring stopped")}async record(e=2e3,t={}){if(!this.isTracking)return null;let s=Date.now(),i=process.memoryUsage(),n=process.cpuUsage(this.lastCPUUsage),a=null;try{a=await nf.mem()}catch{}let c=s-this.lastCheck,d=c>0?Math.min(100,(n.user+n.system)/1e3/c*100):0,g=Math.max(0,s-this.lastCheck-e),p=a?a.available?a.total-a.available:a.used:i.heapUsed,T=a?a.total:i.heapTotal,b=a&&a.total>0?Math.round(p/a.total*100):0,_={timestamp:s,refreshRate:e,heapUsed:Math.round(i.heapUsed/1024/1024),heapTotal:Math.round(i.heapTotal/1024/1024),heapPercent:i.heapTotal>0?Math.round(i.heapUsed/i.heapTotal*100):0,memoryUsed:Math.round(p/1024/1024),memoryTotal:Math.round(T/1024/1024),memoryPercent:b,cpuPercent:Math.round(d*10)/10,eventLoopLag:Math.round(g),uptime:Math.floor(process.uptime()),operationTimings:t.operationTimings||{},slowOperations:t.slowOperations||null,totalRefreshTime:t.totalRefreshTime||0};return this.history.push(_),this.history.length>this.maxHistory&&this.history.shift(),this._updateMetrics(),this.lastCheck=s,this.lastCPUUsage=process.cpuUsage(),_}_updateMetrics(){if(this.history.length===0)return;let e=this.history.length,t=(i,n)=>i.reduce((a,c)=>a+(c[n]||0),0),s=this.history[this.history.length-1];this.metrics={avgRefreshRate:Math.round(t(this.history,"refreshRate")/e),avgMemoryUsed:Math.round(t(this.history,"memoryUsed")/e),peakMemoryUsed:Math.max(...this.history.map(i=>i.memoryUsed)),avgHeapUsed:Math.round(t(this.history,"heapUsed")/e),peakHeapUsed:Math.max(...this.history.map(i=>i.heapUsed)),avgCpuPercent:Math.round(t(this.history,"cpuPercent")/e*10)/10,avgEventLoopLag:Math.round(t(this.history,"eventLoopLag")/e),slowOperations:s.slowOperations||null,totalRefreshTime:s.totalRefreshTime||0}}getMetrics(){return{current:this.history[this.history.length-1]||null,history:[...this.history],aggregates:{...this.metrics},isTracking:this.isTracking}}getStatusString(e=!1){let t=this.history[this.history.length-1];if(!t)return"Performance monitoring inactive";let s=t.memoryPercent>=80?"red-fg":t.memoryPercent>=60?"yellow-fg":"green-fg",i=t.cpuPercent>=80?"red-fg":t.cpuPercent>=50?"yellow-fg":"green-fg",n=`{${s}}MEM: ${t.memoryUsed}MB (${t.memoryPercent}%){/${s}`;if(this.enableMemoryPressure){let c=gt.getStatusString();gt.isElevated()&&(n+=` | ${c}`)}if(n+=` | {${i}}CPU: ${t.cpuPercent}%{/${i}}`,n+=` | Refresh: ${t.refreshRate}ms`,e&&this.metrics.avgEventLoopLag>0){let c=this.metrics.avgEventLoopLag>100?"red-fg":this.metrics.avgEventLoopLag>50?"yellow-fg":"gray-fg";n+=` | {${c}}Lag: ${this.metrics.avgEventLoopLag}ms{/${c}}`}let a=of();if(a){let c=a.pendingTasks>0?"yellow-fg":"green-fg",d=a.busyWorkers||0,g=a.totalWorkers||0,p=a.pendingTasks||0;n+=` | {${c}}Workers: ${d}/${g}{/${c}}`,p>0&&(n+=` ({yellow-fg}${p} pending{/${yellow-fg}})`)}if(e&&this.enableMemoryPressure){let c=gt.getStatus();if(c.currentLevel!=="none"){let d=c.currentLevel==="emergency"||c.currentLevel==="critical"?"red-fg":c.currentLevel==="warning"?"yellow-fg":"cyan-fg";n+=` | {${d}}Pressure: ${c.currentLevel}{/${d}}`,c.trend?.direction==="growing"&&(n+=` {yellow-fg}\u2191${c.trend.rateMBPerMin.toFixed(0)}MB/min{/}`)}}return n}getMemorySparkline(e=30){let t=this.history.slice(-e).map(s=>s.memoryUsed);return t.length>0?t:[0]}getCpuSparkline(e=30){let t=this.history.slice(-e).map(s=>s.cpuPercent);return t.length>0?t:[0]}checkHealth(){let e=[],t=this.history[this.history.length-1];if(!t)return{degraded:!1,reasons:[]};t.memoryPercent>=85&&e.push(`High memory usage: ${t.memoryPercent}%`),t.cpuPercent>=80&&e.push(`High CPU usage: ${t.cpuPercent}%`),this.metrics.avgEventLoopLag>100&&e.push(`Event loop lag: ${this.metrics.avgEventLoopLag}ms`);let s=gt.check();return s.level!=="none"&&s.level!=="elevated"&&e.push(`Memory pressure: ${s.level} (${s.heapUsedMB}MB)`),{degraded:e.length>0,reasons:e}}checkMemoryPressure(){return gt.check()}reset(){this.history=[],this.lastCheck=Date.now(),this.lastCPUUsage=process.cpuUsage(),this.metrics={avgRefreshRate:0,avgMemoryUsed:0,peakMemoryUsed:0,avgCpuPercent:0,avgEventLoopLag:0},gt.reset(),u.debug("Performance metrics reset")}},St=new vn;Yi();Q();te();Es();import af from"http";import lf from"url";var{WEB:q,DASHBOARD_VERSION:cf}=w,In=class{constructor(e={}){this.enabled=e.enabled??q.RATE_LIMIT.ENABLED,this.windowMs=e.windowMs??q.RATE_LIMIT.WINDOW_MS,this.maxRequests=e.maxRequests??q.RATE_LIMIT.MAX_REQUESTS,this.trustProxy=e.trustProxy??q.RATE_LIMIT.TRUST_PROXY,this.requests=new Map,this.blocked=new Map,this.cleanupInterval=setInterval(()=>this.cleanup(),this.windowMs)}getClientIp(e){if(this.trustProxy){let t=e.headers["x-forwarded-for"];if(t)return t.split(",")[0].trim();let s=e.headers["x-real-ip"];if(s)return s}return e.socket?.remoteAddress||e.connection?.remoteAddress||"unknown"}check(e){if(!this.enabled)return{allowed:!0,remaining:this.maxRequests};let t=this.getClientIp(e),s=Date.now(),i=this.blocked.get(t);if(i&&s<i)return{allowed:!1,retryAfter:Math.ceil((i-s)/1e3),ip:t};i&&s>=i&&this.blocked.delete(t);let n=this.requests.get(t);n||(n=[],this.requests.set(t,n));let a=s-this.windowMs,c=n.filter(d=>d>a);if(this.requests.set(t,c),c.length>=this.maxRequests){let d=c[0],g=Math.ceil((d+this.windowMs-s)/1e3);return this.blocked.set(t,s+this.windowMs),u.warn(`[RATE LIMIT] IP ${t} blocked - exceeded ${this.maxRequests} requests in ${this.windowMs}ms`),{allowed:!1,retryAfter:Math.max(1,g),ip:t}}return{allowed:!0,remaining:this.maxRequests-c.length,ip:t}}record(e){if(!this.enabled)return;let t=this.getClientIp(e),s=this.requests.get(t)||[];s.push(Date.now()),this.requests.set(t,s)}cleanup(){let e=Date.now(),t=e-this.windowMs;for(let[s,i]of this.requests.entries()){let n=i.filter(a=>a>t);n.length===0?this.requests.delete(s):this.requests.set(s,n)}for(let[s,i]of this.blocked.entries())e>=i&&this.blocked.delete(s)}getStatus(e){let t=this.getClientIp(e);if(!this.enabled)return{enabled:!1,limit:this.maxRequests,remaining:this.maxRequests,current:0,resetTime:null,ip:t};let s=this.requests.get(t)||[],n=Date.now()-this.windowMs,a=s.filter(d=>d>n),c=null;if(a.length>0){let d=Math.min(...a);c=new Date(d+this.windowMs).toISOString()}return{enabled:!0,limit:this.maxRequests,remaining:Math.max(0,this.maxRequests-a.length),current:a.length,resetTime:c,ip:t}}stop(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null)}},An=class{constructor(e={}){this.allowedOrigins=e.allowedOrigins??q.CORS.ALLOWED_ORIGINS,this.allowedMethods=e.allowedMethods??q.CORS.ALLOWED_METHODS,this.allowedHeaders=e.allowedHeaders??q.CORS.ALLOWED_HEADERS,this.credentials=e.credentials??q.CORS.CREDENTIALS,this.maxAge=e.maxAge??q.CORS.MAX_AGE}isOriginAllowed(e){return this.allowedOrigins==="*"||!e?!0:Array.isArray(this.allowedOrigins)?this.allowedOrigins.some(t=>{if(t.includes("*")){let s=t.replace(/\*/g,".*");return new RegExp(`^${s}$`).test(e)}return t===e}):this.allowedOrigins===e}getHeaders(e){let t=e.headers.origin,s={"Access-Control-Allow-Methods":this.allowedMethods.join(", "),"Access-Control-Allow-Headers":this.allowedHeaders.join(", "),"Access-Control-Max-Age":this.maxAge.toString(),"Content-Type":"application/json"};return this.allowedOrigins==="*"?this.credentials&&t?(s["Access-Control-Allow-Origin"]=t,s["Access-Control-Allow-Credentials"]="true"):s["Access-Control-Allow-Origin"]="*":this.isOriginAllowed(t)&&(s["Access-Control-Allow-Origin"]=t||"*",this.credentials&&(s["Access-Control-Allow-Credentials"]="true")),s}allowsCredentials(){return this.credentials}};function hs(r,e,t,s={}){r.writeHead(e,{...s,"Content-Type":"application/json"}),r.end(JSON.stringify(t,null,2))}function Oe(r,e,t,s={},i={}){hs(r,e,{error:t,status:e,...i},s)}var Rn=class{constructor(e={}){this.port=e.port||q.DEFAULT_PORT,this.host=e.host||q.HOST,this.server=null,this.dataProvider=null,this.startTime=Date.now(),this.requestCount=0,this.errorCount=0,this.rateLimiter=new In({enabled:e.rateLimit?.enabled??q.RATE_LIMIT.ENABLED,windowMs:e.rateLimit?.windowMs??q.RATE_LIMIT.WINDOW_MS,maxRequests:e.rateLimit?.maxRequests??q.RATE_LIMIT.MAX_REQUESTS,trustProxy:e.rateLimit?.trustProxy??q.RATE_LIMIT.TRUST_PROXY}),this.corsManager=new An({allowedOrigins:e.corsOrigins??q.CORS.ALLOWED_ORIGINS,allowedMethods:e.corsMethods??q.CORS.ALLOWED_METHODS,allowedHeaders:e.corsHeaders??q.CORS.ALLOWED_HEADERS,credentials:e.corsCredentials??q.CORS.CREDENTIALS,maxAge:e.corsMaxAge??q.CORS.MAX_AGE}),this.apiKeyAuth=new xr({enabled:e.auth?.enabled??q.AUTH.ENABLED,headerName:e.auth?.headerName??q.AUTH.HEADER_NAME,scheme:e.auth?.scheme??q.AUTH.SCHEME,keyPrefix:e.auth?.keyPrefix??q.AUTH.KEY_PREFIX,keyLength:e.auth?.keyLength??q.AUTH.KEY_LENGTH,maxKeys:e.auth?.maxKeys??q.AUTH.MAX_KEYS}),this.generateApiKey=this.generateApiKey.bind(this),this.revokeApiKey=this.revokeApiKey.bind(this),this.listApiKeys=this.listApiKeys.bind(this)}setDataProvider(e){this.dataProvider=e}getHealth(){let e=Date.now()-this.startTime;return{status:"healthy",version:cf,uptime:e,uptimeHuman:this.formatUptime(e),timestamp:new Date().toISOString()}}formatUptime(e){let t=Math.floor(e/1e3),s=Math.floor(t/60),i=Math.floor(s/60),n=Math.floor(i/24);return n>0?`${n}d ${i%24}h ${s%60}m`:i>0?`${i}h ${s%60}m ${t%60}s`:s>0?`${s}m ${t%60}s`:`${t}s`}sendRateLimitResponse(e,t){let s=this.corsManager.getHeaders({headers:{}});s["Retry-After"]=t.retryAfter.toString(),s["X-RateLimit-Limit"]=this.rateLimiter.maxRequests.toString(),s["X-RateLimit-Remaining"]="0",s["X-RateLimit-Reset"]=(Date.now()+t.retryAfter*1e3).toString(),Oe(e,429,"Too many requests",s,{retryAfter:t.retryAfter})}sendCorsError(e){Oe(e,403,"Origin not allowed",{"Content-Type":"application/json"})}addRateLimitHeaders(e,t){e.setHeader("X-RateLimit-Limit",t.limit.toString()),e.setHeader("X-RateLimit-Remaining",t.remaining.toString()),t.resetTime&&e.setHeader("X-RateLimit-Reset",new Date(t.resetTime).getTime().toString())}sendAuthError(e,t,s={}){let i={...s};t.retryAfter&&(i["Retry-After"]=t.retryAfter.toString());let n=this.apiKeyAuth.scheme||"Bearer";i["WWW-Authenticate"]=`${n} realm="Claw Dashboard API"`;let a=t.code==="AUTH_BLOCKED"?429:401,c=t.retryAfter?{retryAfter:t.retryAfter}:{};Oe(e,a,t.error,i,{code:t.code,...c})}generateApiKey(e){return this.apiKeyAuth.generateKey(e)}revokeApiKey(e){let t=this.apiKeyAuth.revokeKey(e);return t&&u.info(`[AUTH] Revoked API key: ${e}`),t}listApiKeys(){return this.apiKeyAuth.listKeys()}isAuthEnabled(){return this.apiKeyAuth.isEnabled()}enableAuth(){this.apiKeyAuth.enable(),u.info("[AUTH] Authentication enabled")}disableAuth(){this.apiKeyAuth.disable(),u.info("[AUTH] Authentication disabled")}async handleRequest(e,t){this.requestCount++;let i=lf.parse(e.url,!0).pathname,n=this.corsManager.getHeaders(e),a=e.headers.origin;if(a&&!this.corsManager.isOriginAllowed(a)){this.errorCount++,u.warn(`[CORS] Rejected request from disallowed origin: ${a}`),this.sendCorsError(t);return}if(e.method==="OPTIONS"){t.writeHead(200,n),t.end();return}if(i!==q.ENDPOINTS.HEALTH){let c=this.rateLimiter.check(e);if(!c.allowed){this.errorCount++,this.sendRateLimitResponse(t,c);return}this.rateLimiter.record(e);let d=this.rateLimiter.getStatus(e);this.addRateLimitHeaders(t,d)}if(i!==q.ENDPOINTS.HEALTH){let c=this.rateLimiter.getClientIp(e),d=this.apiKeyAuth.authenticate(e.headers,c);if(!d.authenticated){this.errorCount++,u.warn(`[AUTH] Failed authentication from ${c}: ${d.error}`),this.sendAuthError(t,d,n);return}d.keyId&&t.setHeader("X-Auth-Key-Id",d.keyId)}try{switch(i){case q.ENDPOINTS.HEALTH:this.handleHealth(e,t,n);break;case q.ENDPOINTS.METRICS:await this.handleMetrics(e,t,n);break;case q.ENDPOINTS.SESSIONS:await this.handleSessions(e,t,n);break;case q.ENDPOINTS.AGENTS:await this.handleAgents(e,t,n);break;case q.ENDPOINTS.LOGS:await this.handleLogs(e,t,n);break;case q.ENDPOINTS.STATUS:await this.handleStatus(e,t,n);break;default:Oe(t,404,"Not found",n)}}catch(c){this.errorCount++,u.error(`Web server error: ${c.message}`),Oe(t,500,"Internal server error",n)}}handleHealth(e,t,s){let i=this.getHealth(),n=this.rateLimiter.getStatus(e);hs(t,200,{...i,rateLimit:{enabled:n.enabled,limit:n.limit},auth:{enabled:this.apiKeyAuth.isEnabled(),scheme:this.apiKeyAuth.scheme,keyCount:this.apiKeyAuth.getKeyCount()}},s)}async handleMetrics(e,t,s){if(!this.dataProvider){Oe(t,503,"Data provider not available",s);return}try{let i=await this.dataProvider("metrics");hs(t,200,{timestamp:new Date().toISOString(),metrics:i||{}},s)}catch(i){u.error(`Metrics error: ${i.message}`),Oe(t,500,"Failed to fetch metrics",s)}}async handleSessions(e,t,s){if(!this.dataProvider){Oe(t,503,"Data provider not available",s);return}try{let i=await this.dataProvider("sessions");hs(t,200,{timestamp:new Date().toISOString(),sessions:i||[],count:i?.length||0},s)}catch(i){u.error(`Sessions error: ${i.message}`),Oe(t,500,"Failed to fetch sessions",s)}}async handleAgents(e,t,s){if(!this.dataProvider){Oe(t,503,"Data provider not available",s);return}try{let i=await this.dataProvider("agents");hs(t,200,{timestamp:new Date().toISOString(),agents:i||[],count:i?.length||0},s)}catch(i){u.error(`Agents error: ${i.message}`),Oe(t,500,"Failed to fetch agents",s)}}async handleLogs(e,t,s){if(!this.dataProvider){Oe(t,503,"Data provider not available",s);return}try{let i=await this.dataProvider("logs");hs(t,200,{timestamp:new Date().toISOString(),logs:i||[],count:i?.length||0},s)}catch(i){u.error(`Logs error: ${i.message}`),Oe(t,500,"Failed to fetch logs",s)}}async handleStatus(e,t,s){if(!this.dataProvider){Oe(t,503,"Data provider not available",s);return}try{let[i,n,a,c]=await Promise.all([this.dataProvider("metrics"),this.dataProvider("sessions"),this.dataProvider("agents"),this.dataProvider("logs")]);hs(t,200,{timestamp:new Date().toISOString(),health:this.getHealth(),metrics:i||{},sessions:n||[],agents:a||[],logs:c||[],summary:{sessionCount:n?.length||0,agentCount:a?.length||0,logCount:c?.length||0}},s)}catch(i){u.error(`Status error: ${i.message}`),Oe(t,500,"Failed to fetch status",s)}}async start(){return new Promise((e,t)=>{this.server=af.createServer((s,i)=>this.handleRequest(s,i)),this.server.on("error",s=>{u.error(`Web server error: ${s.message}`),t(s)}),this.server.listen(this.port,this.host,()=>{let s=this.rateLimiter.enabled?"enabled":"disabled",i=this.corsManager.allowedOrigins==="*"?"allow-all":"restricted",n=this.apiKeyAuth.isEnabled()?"enabled":"disabled";u.info(`Web server listening on http://${this.host}:${this.port} (rate-limit: ${s}, cors: ${i}, auth: ${n})`),e(this)})})}async stop(){if(this.server)return this.rateLimiter.stop(),new Promise(e=>{this.server.close(()=>{u.info("Web server stopped"),e()})})}getInfo(){let e=this.rateLimiter.getStatus({headers:{},socket:{}});return{host:this.host,port:this.port,url:`http://${this.host}:${this.port}`,endpoints:{health:`${q.ENDPOINTS.HEALTH}`,metrics:`${q.ENDPOINTS.METRICS}`,sessions:`${q.ENDPOINTS.SESSIONS}`,agents:`${q.ENDPOINTS.AGENTS}`,logs:`${q.ENDPOINTS.LOGS}`,status:`${q.ENDPOINTS.STATUS}`},uptime:this.formatUptime(Date.now()-this.startTime),requests:this.requestCount,errors:this.errorCount,security:{rateLimit:{enabled:this.rateLimiter.enabled,windowMs:this.rateLimiter.windowMs,maxRequests:this.rateLimiter.maxRequests},cors:{mode:this.corsManager.allowedOrigins==="*"?"allow-all":"restricted",credentials:this.corsManager.credentials},auth:{enabled:this.apiKeyAuth.isEnabled(),scheme:this.apiKeyAuth.scheme,headerName:this.apiKeyAuth.headerName,activeKeys:this.apiKeyAuth.getKeyCount()}}}}},Xa=Rn;Q();var _n={dots:{frames:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],interval:80},line:{frames:["-","\\","|","/"],interval:100},pulse:{frames:["\u25CB","\u25D4","\u25D1","\u25D5","\u25CF","\u25D5","\u25D1","\u25D4"],interval:100},blocks:{frames:["\u2581","\u2583","\u2584","\u2585","\u2586","\u2587","\u2588","\u2587","\u2586","\u2585","\u2584","\u2583"],interval:80},arrows:{frames:["\u2190","\u2196","\u2191","\u2197","\u2192","\u2198","\u2193","\u2199"],interval:100},bouncing:{frames:["( \u25CF )","( \u25CF )","( \u25CF )","( \u25CF )","( \u25CF)","( \u25CF )","( \u25CF )","( \u25CF )","( \u25CF )","(\u25CF )"],interval:80}},hf={blocks:["\u2591","\u2592","\u2593","\u2588"],bars:[" ","\u258F","\u258E","\u258D","\u258C","\u258B","\u258A","\u2589","\u2588"],ascii:[" ","=","=","=","=","=","=","=","#"],dots:[" ","\xB7","\u2219","\u25CF"],minimal:["\u25CB","\u25D0","\u25D1","\u25CF"]},Cn=class{constructor(){this.activeStates=new Map,this.globalSpinner=null,this.animationFrameId=null}create(e,t={}){let{type:s="spinner",message:i="Loading...",style:n="dots",total:a=100}=t,c={id:e,type:s,message:i,style:n,total:a,current:0,frames:_n[n]?.frames||_n.dots.frames,frameIndex:0,interval:_n[n]?.interval||80,startTime:Date.now(),timerId:null,listeners:new Set,isComplete:!1};return this.activeStates.set(e,c),s==="spinner"&&this._startSpinnerAnimation(c),u.debug(`Loading state created: ${e} (${s})`),{id:e,update:d=>this.updateMessage(e,d),progress:(d,g)=>this.updateProgress(e,d,g),complete:d=>this.complete(e,d),onUpdate:d=>this._addListener(e,d),getFrame:()=>this._getCurrentFrame(c),elapsed:()=>Date.now()-c.startTime}}_startSpinnerAnimation(e){e.timerId=setInterval(()=>{e.frameIndex=(e.frameIndex+1)%e.frames.length,this._notifyListeners(e)},e.interval)}_getCurrentFrame(e){let s=ke().colors,i=e.frames[e.frameIndex];return e.type==="progress"?this._renderProgressBar(e,s):{frame:i,message:e.message,elapsed:this._formatElapsed(Date.now()-e.startTime),color:s.branding.logo}}_renderProgressBar(e,t){let{bars:s}=hf,i=Math.min(100,Math.max(0,e.current/e.total*100)),n=Math.floor(i/100*s.length),a=s[s.length-1].repeat(n),c=s[0].repeat(s.length-n);return{bar:`[${a}${c}]`,percentage:i.toFixed(1),current:e.current,total:e.total,message:e.message,color:i<30?t.gauge.low:i<70?t.gauge.medium:i<90?t.gauge.high:t.gauge.critical}}_formatElapsed(e){if(e<1e3)return`${e}ms`;if(e<6e4)return`${(e/1e3).toFixed(1)}s`;let t=Math.floor(e/6e4),s=(e%6e4/1e3).toFixed(0);return`${t}m ${s}s`}_addListener(e,t){let s=this.activeStates.get(e);return s?(s.listeners.add(t),()=>s.listeners.delete(t)):()=>{}}_notifyListeners(e){let t=this._getCurrentFrame(e);e.listeners.forEach(s=>{try{s(t,e)}catch(i){u.debug(`Loading state listener error: ${i.message}`)}})}updateMessage(e,t){let s=this.activeStates.get(e);s&&(s.message=t,this._notifyListeners(s))}updateProgress(e,t,s){let i=this.activeStates.get(e);i&&(i.current=t,s!==void 0&&(i.total=s),this._notifyListeners(i))}complete(e,t){let s=this.activeStates.get(e);s&&(s.isComplete=!0,s.timerId&&(clearInterval(s.timerId),s.timerId=null),t&&(s.message=t),this._notifyListeners(s),u.debug(`Loading state completed: ${e} (${this._formatElapsed(Date.now()-s.startTime)})`))}remove(e){let t=this.activeStates.get(e);t&&(t.timerId&&clearInterval(t.timerId),this.activeStates.delete(e),u.debug(`Loading state removed: ${e}`))}getActive(){return Array.from(this.activeStates.keys())}clearAll(){for(let[e,t]of this.activeStates)t.timerId&&clearInterval(t.timerId);this.activeStates.clear(),u.debug("All loading states cleared")}},yw=new Cn;Q();var Ft={width:28,height:14,margin:2},us={header:"Theme Preview",border:"\u2500".repeat(24),textSample:"Aa Bb Cc 123",statusActive:"\u25CF Active",statusIdle:"\u25CB Idle",gauge:"\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591 40%",chart:"\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"};function uf(r,e,t){let s=Io(),i=Cr(),n=s.indexOf(i);n===-1&&(n=0);let a=null,c=[],d=null,g=null,p=null;function T(D,O,I=!1){I?D.style.bg=O:D.style.fg=O}function b(D,O){let I=D.colors;return[`{${I.branding.title}-fg}{bold}${us.header}{/bold}{/${I.branding.title}-fg}`,`{${I.border.cpu}-fg}${us.border}{/${I.border.cpu}-fg}`,"",` {${I.text.primary}-fg}${us.textSample}{/${I.text.primary}-fg}`,"",` {${I.status.active}-fg}${us.statusActive}{/${I.status.active}-fg}`,` {${I.status.idle}-fg}${us.statusIdle}{/${I.status.idle}-fg}`,"",` {${I.gauge.medium}-fg}${us.gauge}{/${I.gauge.medium}-fg}`,"",` {${I.chart.line}-fg}${us.chart}{/${I.chart.line}-fg}`,"",`{center}{${I.text.secondary}-fg}${D.name}{/${I.text.secondary}-fg}{/center}`].join(`
|
|
1676
|
-
`)}function _(){let D=r.width,O=r.height,I=Math.min(3,s.length),G=(Ft.width+Ft.margin)*I+4,W=Math.ceil(s.length/I),U=Ft.height*W+8;a=e.box({parent:r,top:"center",left:"center",width:Math.min(G,D-4),height:Math.min(U,O-4),border:{type:"line"},style:{border:{fg:"cyan"},bg:"black"},tags:!0,label:" {bold}Theme Selector{/bold} ",scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" ",style:{bg:"cyan"}}}),e.text({parent:a,top:1,left:"center",width:G-4,content:"{center}Select a theme with arrow keys, press Enter to apply{/center}",style:{fg:"white"},tags:!0}),s.forEach((oe,ae)=>{let K=Math.floor(ae/I),me=ae%I,se=oe==="auto"?ke():Vs(oe),ue=ae===n,Me=oe===i,nt=2+me*(Ft.width+Ft.margin),le=3+K*Ft.height,_e=e.box({parent:a,top:le,left:nt,width:Ft.width,height:Ft.height,border:{type:"line",fg:ue?"brightCyan":"gray"},style:{bg:ue?"brightBlack":"black",border:{fg:ue?"brightCyan":"gray"}},tags:!0,content:b(se,e)});Me&&e.text({parent:_e,top:0,right:0,content:"\u25CF",style:{fg:"green"}}),c.push({box:_e,themeName:oe,index:ae})}),d=e.text({parent:a,bottom:2,left:"center",width:G-4,content:v(),style:{fg:"gray"},tags:!0}),g=e.text({parent:a,bottom:1,left:"center",width:G-4,content:"{center}\u2191/\u2193/\u2190/\u2192: Navigate Enter: Apply t: Cycle themes q/Esc: Close{/center}",style:{fg:"gray"},tags:!0}),r.render()}function v(){let D=s[n],O=Vs(D);return D==="auto"?`{center}Auto-detect \u2192 ${ke().name} (currently selected: ${i}){/center}`:`{center}${O.name}${D===i?" (current)":""}{/center}`}function S(){c.forEach(({box:D,index:O})=>{let I=O===n,G=s[O]===i;D.style.bg=I?"brightBlack":"black",D.style.border.fg=I?"brightCyan":"gray"}),d&&d.setContent(v()),r.render()}function M(D){let O=Math.min(3,s.length),I=Math.ceil(s.length/O);D===-O&&n-O>=0?n-=O:D===O&&n+O<s.length?n+=O:D===-1&&n%O>0?n--:D===1&&(n+1)%O!==0&&n+1<s.length&&n++,S()}function j(){let D=s[n];D!==i&&(Ss(D),Zt(),u.info(`Theme changed to: ${D}`)),F()}function k(){n=(n+1)%s.length;let D=s[n];Ss(D),Zt(),S(),c.forEach(({box:O,index:I})=>{let G=s[I]===D,W=s[I]==="auto"?ke():Vs(s[I]);O.setContent(b(W,e))}),r.render()}function F(){p&&p(),a&&(a.destroy(),a=null),c=[],t&&t(),r.render()}function ee(D,O){O.name==="up"?M(-3):O.name==="down"?M(3):O.name==="left"?M(-1):O.name==="right"?M(1):O.name==="return"?j():D==="t"?k():(D==="q"||O.name==="escape")&&F()}return _(),p=Rr(()=>{c.forEach(({box:D,index:O})=>{let I=s[O]==="auto"?ke():Vs(s[O]);D.setContent(b(I,e))}),r.render()}),{handleKey:ee,close:F,isActive:()=>a!==null}}async function Ja(r,e,t){return new Promise(s=>{let i=uf(r,e,()=>{r.removeListener("keypress",n),t&&t(),s()});function n(a,c){i.handleKey(a,c)}r.on("keypress",n)})}Q();Es();te();import Xe from"fs";import Ut from"path";import Ln from"os";function Qa(r){if(!r||typeof r!="string")return{valid:!1,error:"Path must be a non-empty string"};let e=r.startsWith("~")?Ut.join(Ln.homedir(),r.slice(1)):Ut.resolve(r),t=Ln.homedir(),s=["/tmp",Ln.tmpdir()];return e.startsWith(t)||s.some(n=>e.startsWith(n))?Di(e)?{valid:!0,resolvedPath:e}:{valid:!1,error:"Invalid path characters"}:{valid:!1,error:"Path must be within home or temp directory"}}var li=class{constructor(e={}){this.intervalMs=e.intervalMs||3e4,this.enabled=e.enabled!==!1,this.statePath=e.statePath||Le.STATE,this.getState=e.getState,this.getSettings=e.getSettings,this.saveSettings=e.saveSettings,this.timer=null,this.isDirty=!1,this.lastSaveTime=0,this.saveCount=0,this.consecutiveFailures=0,this.maxConsecutiveFailures=3,this.lastStateChecksum=null,this.backupEnabled=e.backupEnabled!==!1,this.backupCount=e.backupCount||5,this.lastStatsLogTime=0,this.statsLogIntervalMs=e.statsLogIntervalMs||3e5,this.stats={totalBytesWritten:0,totalBackupsCreated:0,totalBackupsCleaned:0,lastBackupPath:null,averageSaveTimeMs:0,totalSaveTimeMs:0}}createBackup(e){if(!this.backupEnabled)return null;try{if(!Xe.existsSync(e)||Xe.statSync(e).size===0)return null;let i=new Date().toISOString().replace(/[:.]/g,"-"),a=`${e}.${i}.backup`,c=1;for(;Xe.existsSync(a);)a=`${e}.${i}-${c}.backup`,c++;return Xe.copyFileSync(e,a),Jt(a),this.stats.totalBackupsCreated++,this.stats.lastBackupPath=a,u.debug(`Created state backup: ${Ut.basename(a)}`),a}catch(t){return u.debug(`Failed to create backup: ${t.message}`),null}}cleanupBackups(e){if(!(!this.backupEnabled||this.backupCount<=0))try{let t=Ut.dirname(e),s=Ut.basename(e),i=Xe.readdirSync(t).filter(a=>a.startsWith(s)&&a.endsWith(".backup")).map(a=>({name:a,path:Ut.join(t,a),mtime:Xe.statSync(Ut.join(t,a)).mtime})).sort((a,c)=>c.mtime-a.mtime),n=0;for(let a=this.backupCount;a<i.length;a++)try{Xe.unlinkSync(i[a].path),n++,u.debug(`Cleaned up old backup: ${i[a].name}`)}catch{}n>0&&(this.stats.totalBackupsCleaned+=n,u.debug(`Backup cleanup complete: removed ${n} old backups`))}catch(t){u.debug(`Backup cleanup failed: ${t.message}`)}}logStats(){let e=Date.now();if(e-this.lastStatsLogTime<this.statsLogIntervalMs)return;this.lastStatsLogTime=e;let t=e-(this.lastSaveTime>0?this.lastSaveTime-this.saveCount*this.intervalMs:e),s=this.saveCount>0?(this.stats.totalSaveTimeMs/this.saveCount).toFixed(2):0,i=this.lastSaveTime>0?((e-this.lastSaveTime)/1e3).toFixed(0):"never";["=== Auto-Save Statistics ===",` Enabled: ${this.enabled}`,` Interval: ${this.intervalMs}ms`,` Backup rotation: ${this.backupEnabled?"on":"off"} (keep ${this.backupCount})`,` Saves performed: ${this.saveCount}`,` Consecutive failures: ${this.consecutiveFailures}`,` Total bytes written: ${this.stats.totalBytesWritten.toLocaleString()}`,` Total backups created: ${this.stats.totalBackupsCreated}`,` Total backups cleaned: ${this.stats.totalBackupsCleaned}`,` Average save time: ${s}ms`,` Last save: ${i}s ago`,` State file: ${this.statePath}`,` Last backup: ${this.stats.lastBackupPath?Ut.basename(this.stats.lastBackupPath):"none"}`,"==========================="].forEach(a=>u.debug(a))}start(){if(!this.enabled){u.debug("Auto-save is disabled");return}this.timer&&this.stop(),this.timer=setInterval(()=>{this.performAutoSave()},this.intervalMs),this.timer.unref&&this.timer.unref(),u.info(`Auto-save started (interval: ${this.intervalMs}ms)`)}stop(){this.timer&&(clearInterval(this.timer),this.timer=null,u.debug("Auto-save stopped"))}markDirty(e=!1){this.isDirty=!0,e&&this.performAutoSave()}calculateChecksum(e){try{let{timestamp:t,...s}=e;return JSON.stringify(s)}catch{return null}}getStateSnapshot(){let e={timestamp:Date.now(),settings:null,ui:{}};if(this.getSettings&&(e.settings=this.getSettings()),this.getState){let t=this.getState();t&&(e.ui={selectedSessionIndex:t.selectedSessionIndex||0,paginationOffset:t.paginationOffset||0,sessionSearchQuery:t.sessionSearchQuery||"",isSearchMode:t.isSearchMode||!1,showFavoritesOnly:t.showFavoritesOnly||!1,focusedWidgetIndex:t.focusedWidgetIndex||-1,currentRefreshInterval:t.currentRefreshInterval||2e3})}return e}performAutoSave(){if(!this.enabled)return!1;let e=Date.now();try{let t=this.getStateSnapshot(),s=this.calculateChecksum(t);if(s===this.lastStateChecksum&&!this.isDirty)return!0;let i=Qa(this.statePath);if(!i.valid)return u.warn(`Auto-save path validation failed: ${i.error}`),!1;let n=i.resolvedPath.substring(0,i.resolvedPath.lastIndexOf("/"));Xe.existsSync(n)||Xe.mkdirSync(n,{recursive:!0}),this.createBackup(i.resolvedPath);let a=JSON.stringify(t,null,2);Xe.writeFileSync(i.resolvedPath,a),Jt(i.resolvedPath),this.cleanupBackups(i.resolvedPath),this.lastStateChecksum=s,this.isDirty=!1,this.lastSaveTime=Date.now(),this.saveCount++,this.consecutiveFailures=0,this.stats.totalBytesWritten+=Buffer.byteLength(a,"utf8");let c=Date.now()-e;return this.stats.totalSaveTimeMs+=c,this.stats.averageSaveTimeMs=this.stats.totalSaveTimeMs/this.saveCount,this.logStats(),u.debug(`Auto-save completed successfully (${c}ms)`),!0}catch(t){return this.consecutiveFailures++,u.error(`Auto-save failed (${this.consecutiveFailures}/${this.maxConsecutiveFailures}): ${t.message}`),this.consecutiveFailures>=this.maxConsecutiveFailures&&(u.error("Auto-save disabled due to repeated failures"),this.enabled=!1,this.stop()),!1}}saveNow(){return this.performAutoSave()}getStats(){return{enabled:this.enabled,intervalMs:this.intervalMs,lastSaveTime:this.lastSaveTime,saveCount:this.saveCount,consecutiveFailures:this.consecutiveFailures,isDirty:this.isDirty,statePath:this.statePath,backupEnabled:this.backupEnabled,backupCount:this.backupCount,totalBytesWritten:this.stats.totalBytesWritten,totalBackupsCreated:this.stats.totalBackupsCreated,totalBackupsCleaned:this.stats.totalBackupsCleaned,lastBackupPath:this.stats.lastBackupPath,averageSaveTimeMs:this.stats.averageSaveTimeMs,totalSaveTimeMs:this.stats.totalSaveTimeMs}}updateConfig(e={}){e.intervalMs!==void 0&&(this.intervalMs=e.intervalMs),e.enabled!==void 0&&(this.enabled=e.enabled),this.timer&&(this.stop(),this.start())}};function Za(r){try{let e=Qa(r);if(!e.valid)return u.warn(`State path validation failed: ${e.error}`),null;if(!Xe.existsSync(e.resolvedPath))return null;let t=Xe.readFileSync(e.resolvedPath,"utf8"),s=JSON.parse(t);return u.info("Loaded dashboard state from "+e.resolvedPath),s}catch(e){return u.warn("Failed to load dashboard state: "+e.message),null}}function el(r,e){if(!r||!r.ui)return!1;try{let t=r.ui;return t.selectedSessionIndex!==void 0&&(e.selectedSessionIndex=t.selectedSessionIndex),t.paginationOffset!==void 0&&(e.paginationOffset=t.paginationOffset),t.sessionSearchQuery!==void 0&&(e.sessionSearchQuery=t.sessionSearchQuery,e.sessionSearchQuery&&(e.isSearchMode=!0)),t.isSearchMode!==void 0&&(e.isSearchMode=t.isSearchMode),t.showFavoritesOnly!==void 0&&(e.showFavoritesOnly=t.showFavoritesOnly),t.focusedWidgetIndex!==void 0&&(e.focusedWidgetIndex=t.focusedWidgetIndex),t.currentRefreshInterval!==void 0&&(e.currentRefreshInterval=t.currentRefreshInterval),u.info("Dashboard state restored"),!0}catch(t){return u.error("Failed to restore dashboard state: "+t.message),!1}}Q();import xt from"blessed";Q();As();var tl=u||{info:()=>{},warn:()=>{},error:()=>{},debug:()=>{}},Re={HEALTHY:"healthy",DEGRADED:"degraded",FAILED:"failed",RECOVERING:"recovering"},Ge={INIT_ERROR:"init_error",CREATE_ERROR:"create_error",DATA_ERROR:"data_error",RENDER_ERROR:"render_error",DESTROY_ERROR:"destroy_error",TIMEOUT_ERROR:"timeout_error",UNKNOWN_ERROR:"unknown_error"},sl={maxConsecutiveErrors:3,errorWindowMs:6e4,autoRecover:!0,recoveryDelayMs:5e3,maxRecoveryAttempts:3,initTimeoutMs:5e3,createTimeoutMs:5e3,dataTimeoutMs:1e4,renderTimeoutMs:1e3,destroyTimeoutMs:3e3,failSilently:!0,logErrors:!0,degradeOnError:!0},ci=class extends Ye{constructor(e,t,s,i=Ge.UNKNOWN_ERROR){super(`Widget '${e}' ${t} failed: ${s?.message||"Unknown error"}`,"WIDGET_ISOLATED_ERROR",500,{widgetId:e,operation:t,type:i,originalError:s?.message}),this.widgetId=e,this.operation=t,this.errorType=i,this.originalError=s}},kn=class{constructor(e={}){this.config={...sl,...e},this.healthStatus=new Map,this.errorHistory=new Map}_getHealthRecord(e){return this.healthStatus.has(e)||this.healthStatus.set(e,{status:Re.HEALTHY,consecutiveErrors:0,totalErrors:0,recoveryAttempts:0,lastError:null,lastSuccess:Date.now(),firstFailure:null,degradedSince:null,failedSince:null}),this.healthStatus.get(e)}recordSuccess(e){let t=this._getHealthRecord(e);t.status=Re.HEALTHY,t.consecutiveErrors=0,t.lastSuccess=Date.now(),t.recoveryAttempts=0,this.errorHistory.delete(e)}recordError(e,t,s=Ge.UNKNOWN_ERROR){let i=this._getHealthRecord(e),n=Date.now();i.consecutiveErrors++,i.totalErrors++,i.lastError={message:t?.message,type:s,timestamp:n,stack:t?.stack},this.errorHistory.has(e)||this.errorHistory.set(e,[]);let a=this.errorHistory.get(e);a.push(n);let c=n-this.config.errorWindowMs;for(;a.length>0&&a[0]<c;)a.shift();return i.firstFailure===null&&(i.firstFailure=n),a.length>=this.config.maxConsecutiveErrors?(i.status=Re.FAILED,i.failedSince=n):this.config.degradeOnError&&i.status===Re.HEALTHY&&(i.status=Re.DEGRADED,i.degradedSince=n),{...i}}markRecovering(e){let t=this._getHealthRecord(e);t.status=Re.RECOVERING,t.recoveryAttempts++}getHealth(e){let t=this.healthStatus.get(e);if(!t)return null;let s=this.errorHistory.get(e)||[];return{...t,recentErrorCount:s.length,isHealthy:t.status===Re.HEALTHY,isOperational:t.status!==Re.FAILED}}getAllHealth(){let e={};for(let[t,s]of this.healthStatus)e[t]=this.getHealth(t);return e}canRecover(e){let t=this._getHealthRecord(e);return!this.config.autoRecover||t.recoveryAttempts>=this.config.maxRecoveryAttempts?!1:t.status===Re.FAILED?Date.now()-(t.failedSince||0)>=this.config.recoveryDelayMs:t.status!==Re.HEALTHY}resetHealth(e){this.healthStatus.delete(e),this.errorHistory.delete(e)}getStats(){let e=Array.from(this.healthStatus.values());return{total:e.length,healthy:e.filter(t=>t.status===Re.HEALTHY).length,degraded:e.filter(t=>t.status===Re.DEGRADED).length,failed:e.filter(t=>t.status===Re.FAILED).length,recovering:e.filter(t=>t.status===Re.RECOVERING).length,totalErrors:e.reduce((t,s)=>t+s.totalErrors,0)}}},hi=class{constructor(e={}){this.config={...sl,...e},this.healthTracker=new kn(this.config),this.failedWidgets=new Set,this.recoveryTimers=new Map}_createTimeout(e,t){return new Promise((s,i)=>{setTimeout(()=>i(new Error(t)),e)})}async _wrapOperation(e,t,s,i,n){if(this.healthTracker.getHealth(e)?.status===Re.FAILED){if(this.config.failSilently)return null;throw new ci(e,t,new Error("Widget is in failed state"),n)}try{let c=await Promise.race([s(),this._createTimeout(i,`Operation timed out after ${i}ms`)]);return this.healthTracker.recordSuccess(e),this.failedWidgets.delete(e),c}catch(c){if(this.healthTracker.recordError(e,c,n),this.config.logErrors&&tl.warn(`Widget '${e}' ${t} failed: ${c.message}`),this._scheduleRecovery(e),this.config.failSilently)return null;throw new ci(e,t,c,n)}}_scheduleRecovery(e){if(this.recoveryTimers.has(e)||!this.healthTracker.canRecover(e))return;let t=setTimeout(()=>{this.recoveryTimers.delete(e),this.healthTracker.markRecovering(e),this.config.logErrors&&tl.info(`Attempting recovery for widget '${e}'`)},this.config.recoveryDelayMs);this.recoveryTimers.set(e,t)}async wrapInit(e,t){return this._wrapOperation(e,"init",t,this.config.initTimeoutMs,Ge.INIT_ERROR)}async wrapCreate(e,t){return this._wrapOperation(e,"create",t,this.config.createTimeoutMs,Ge.CREATE_ERROR)}async wrapGetData(e,t){return this._wrapOperation(e,"getData",t,this.config.dataTimeoutMs,Ge.DATA_ERROR)}async wrapRender(e,t){return this._wrapOperation(e,"render",t,this.config.renderTimeoutMs,Ge.RENDER_ERROR)}async wrapDestroy(e,t){return this._wrapOperation(e,"destroy",t,this.config.destroyTimeoutMs,Ge.DESTROY_ERROR)}getHealth(e){return this.healthTracker.getHealth(e)}getAllHealth(){return this.healthTracker.getAllHealth()}isOperational(e){let t=this.getHealth(e);return!t||t.status!==Re.FAILED}resetWidget(e){this.healthTracker.resetHealth(e),this.failedWidgets.delete(e);let t=this.recoveryTimers.get(e);t&&(clearTimeout(t),this.recoveryTimers.delete(e))}getStats(){return{...this.healthTracker.getStats(),failedWidgetCount:this.failedWidgets.size,pendingRecoveries:this.recoveryTimers.size}}shutdown(){for(let[e,t]of this.recoveryTimers)clearTimeout(t);this.recoveryTimers.clear(),this.failedWidgets.clear()}};var On={CONTAINER:{border:{type:"line"},style:{border:{fg:"red"},bg:"black"}},TITLE:{fg:"red",bold:!0},MESSAGE:{fg:"white",bg:"black"},ERROR_DETAIL:{fg:"gray",bg:"black"},RETRY_BUTTON:{fg:"black",bg:"green",bold:!0},RETRY_BUTTON_FOCUSED:{fg:"black",bg:"bright-green",bold:!0},DISMISS_BUTTON:{fg:"white",bg:"gray"},ICON:{fg:"red",bg:"black"}},Mn=class{constructor(e,t={}){this.widget=e,this.options={maxRetries:t.maxRetries??3,retryDelay:t.retryDelay??5e3,showErrorDetails:t.showErrorDetails??!0,allowDismiss:t.allowDismiss??!0,errorTitle:t.errorTitle??"Widget Error",onRetry:t.onRetry??null,onDismiss:t.onDismiss??null,onError:t.onError??null,theme:t.theme??{}},this.errorState={hasError:!1,error:null,retryCount:0,lastError:null,isRecovering:!1},this.isolator=new hi({maxConsecutiveErrors:this.options.maxRetries,recoveryDelayMs:this.options.retryDelay,autoRecover:!0}),this.errorContainer=null,this.retryButton=null,this.dismissButton=null,this.errorText=null,this.originalBox=null,this.parentScreen=null,this.handleRetry=this.handleRetry.bind(this),this.handleDismiss=this.handleDismiss.bind(this),this.handleKeypress=this.handleKeypress.bind(this)}async create(e,t={}){this.parentScreen=e,this.options.theme={...this.options.theme,...t};try{return await this.isolator.wrapCreate(this.widget.id||"widget",()=>this.widget.create(e,t))===null?(this.showErrorBoundary(this.isolator.getHealth(this.widget.id)?.lastError?.message||"Widget creation failed"),this):(this.originalBox=this.widget.box,this)}catch(s){return this.handleError(s,Ge.CREATE_ERROR),this}}showErrorBoundary(e,t=null){if(!this.parentScreen){u.error("Cannot show error boundary without parent screen");return}let s=this.options.theme.colors||{},i=this.getErrorStyles(s);this.originalBox&&!this.originalBox.destroyed&&this.originalBox.hide(),this.errorContainer=xt.box({parent:this.parentScreen,...i.container,label:` ${this.options.errorTitle} `,tags:!0}),this.originalBox&&(this.errorContainer.top=this.originalBox.top,this.errorContainer.left=this.originalBox.left,this.errorContainer.width=this.originalBox.width,this.errorContainer.height=this.originalBox.height),xt.text({parent:this.errorContainer,top:1,left:"center",content:"{red-fg}\u2716{/red-fg}",tags:!0,style:i.icon}),xt.text({parent:this.errorContainer,top:2,left:"center",content:"{bold}Widget Failed{/bold}",tags:!0,style:i.title});let n=e.length>40?e.substring(0,37)+"...":e;this.errorText=xt.text({parent:this.errorContainer,top:3,left:"center",content:n,tags:!0,style:i.message});let a=4;if(this.options.showErrorDetails&&t?.stack){let c=t.stack.split(`
|
|
1677
|
-
`).slice(0,3);xt.text({parent:this.errorContainer,top:a++,left:"center",content:c[0]||"",tags:!0,style:i.errorDetail})}this.errorState.retryCount>0&&xt.text({parent:this.errorContainer,top:a++,left:"center",content:`Retry ${this.errorState.retryCount}/${this.options.maxRetries}`,tags:!0,style:i.errorDetail}),a++,this.retryButton=xt.button({parent:this.errorContainer,top:a,left:"center",width:12,height:1,content:" Retry ",align:"center",valign:"middle",tags:!0,style:{fg:i.retryButton.fg,bg:i.retryButton.bg,bold:i.retryButton.bold,focus:{fg:i.retryButtonFocused.fg,bg:i.retryButtonFocused.bg,bold:i.retryButtonFocused.bold},hover:{fg:i.retryButtonFocused.fg,bg:i.retryButtonFocused.bg}}}),this.retryButton.on("press",this.handleRetry),this.options.allowDismiss&&(this.dismissButton=xt.button({parent:this.errorContainer,top:a+2,left:"center",width:12,height:1,content:" Dismiss ",align:"center",valign:"middle",tags:!0,style:{fg:i.dismissButton.fg,bg:i.dismissButton.bg,focus:{fg:"black",bg:"white"},hover:{fg:"black",bg:"white"}}}),this.dismissButton.on("press",this.handleDismiss)),this.retryButton.focus(),this.parentScreen.on("keypress",this.handleKeypress),this.errorState.hasError=!0,this.errorState.lastError=t,this.options.onError&&this.options.onError(t||new Error(e),this.errorState.retryCount),u.warn(`Error boundary shown for widget '${this.widget.id}': ${e}`)}getErrorStyles(e){return{container:{border:{type:"line"},style:{border:{fg:e.error||"red"},bg:"black"}},title:{fg:e.error||"red",bold:!0},message:{fg:"white",bg:"black"},errorDetail:{fg:e.gray||"gray",bg:"black"},retryButton:On.RETRY_BUTTON,retryButtonFocused:On.RETRY_BUTTON_FOCUSED,dismissButton:On.DISMISS_BUTTON,icon:{fg:e.error||"red",bg:"black"}}}handleKeypress(e,t){this.errorState.hasError&&(t.name==="r"||t.name==="return"?this.handleRetry():t.name==="d"||t.name==="escape"?this.handleDismiss():t.name==="tab"&&this.dismissButton&&(this.retryButton.focused?this.dismissButton.focus():this.retryButton.focus()))}async handleRetry(){if(!this.errorState.isRecovering){this.errorState.isRecovering=!0,this.errorState.retryCount++,u.info(`Retrying widget '${this.widget.id}' (attempt ${this.errorState.retryCount})`),this.retryButton&&(this.retryButton.setContent("Retrying..."),this.retryButton.style.bg="yellow");try{this.clearErrorBoundary(),this.isolator.resetWidget(this.widget.id);let e=null,t=null;if(this.widget.init&&(e=await this.isolator.wrapInit(this.widget.id,()=>this.widget.init())),this.widget.create&&e!==null&&(t=await this.isolator.wrapCreate(this.widget.id,()=>this.widget.create(this.parentScreen,this.options.theme))),e===null&&this.widget.init)throw new Error("Widget initialization failed");if(t===null&&this.widget.create)throw new Error("Widget creation failed");this.errorState.hasError=!1,this.errorState.error=null,this.originalBox=this.widget.box,this.options.onRetry&&this.options.onRetry(!0,this.errorState.retryCount),u.info(`Widget '${this.widget.id}' recovered successfully`)}catch(e){this.errorState.hasError=!0,this.errorState.error=e,this.errorState.retryCount>=this.options.maxRetries?(this.showErrorBoundary(`Widget failed after ${this.options.maxRetries} retries`,e),xt.text({parent:this.errorContainer,top:this.errorContainer.children.length-2,left:"center",content:"{red-fg}Max retries reached{/red-fg}",tags:!0,style:{fg:"red"}})):this.showErrorBoundary(e.message||"Widget failed to recover",e),this.options.onRetry&&this.options.onRetry(!1,this.errorState.retryCount,e),u.error(`Widget '${this.widget.id}' retry failed: ${e.message}`)}finally{this.errorState.isRecovering=!1}}}handleDismiss(){u.info(`Widget '${this.widget.id}' error boundary dismissed`),this.clearErrorBoundary(),this.options.onDismiss&&this.options.onDismiss()}clearErrorBoundary(){this.parentScreen&&this.parentScreen.removeListener("keypress",this.handleKeypress),this.errorContainer&&!this.errorContainer.destroyed&&(this.errorContainer.destroy(),this.errorContainer=null),this.originalBox&&!this.originalBox.destroyed&&this.originalBox.show(),this.retryButton=null,this.dismissButton=null,this.errorText=null}handleError(e,t=Ge.UNKNOWN_ERROR){this.errorState.error=e,this.errorState.hasError=!0,this.isolator.healthTracker.recordError(this.widget.id,e,t),this.showErrorBoundary(e.message,e)}async getData(e){if(this.errorState.hasError)return null;let t=await this.isolator.wrapGetData(this.widget.id,()=>this.widget.getData(e));if(t===null){let s=this.isolator.getHealth(this.widget.id);if(s?.lastError&&!this.errorState.hasError){let i=new Error(s.lastError.message||"Data fetch failed");i.stack=s.lastError.stack,this.handleError(i,Ge.DATA_ERROR)}}return t}async render(e){if(this.errorState.hasError)return;if(await this.isolator.wrapRender(this.widget.id,()=>this.widget.render(e))===null){let s=this.isolator.getHealth(this.widget.id);if(s?.lastError&&!this.errorState.hasError){let i=new Error(s.lastError.message||"Render failed");i.stack=s.lastError.stack,this.handleError(i,Ge.RENDER_ERROR)}}}update(e){if(!(this.errorState.hasError||!this.widget.update))try{this.widget.update(e)}catch(t){this.handleError(t,Ge.RENDER_ERROR)}}async destroy(){this.clearErrorBoundary();try{await this.isolator.wrapDestroy(this.widget.id,()=>this.widget.destroy())}catch(e){u.error(`Error destroying widget '${this.widget.id}': ${e.message}`)}this.isolator.shutdown()}getErrorState(){return{...this.errorState,health:this.isolator.getHealth(this.widget.id)}}hasError(){return this.errorState.hasError}showError(e,t=null){this.errorState.hasError=!0,this.errorState.error=t||new Error(e),this.errorState.lastError=t||new Error(e),this.parentScreen?this.showErrorBoundary(e,t):this._pendingErrorMessage=e}async reset(){this.clearErrorBoundary(),this.errorState.hasError=!1,this.errorState.error=null,this.errorState.retryCount=0,this.isolator.resetWidget(this.widget.id)}};var ui=class{constructor(){this.boundaries=new Map,this.globalOptions={}}setGlobalOptions(e){this.globalOptions={...this.globalOptions,...e}}wrap(e,t={}){let s={...this.globalOptions,...t},i=new Mn(e,s);return this.boundaries.set(e.id,i),i}get(e){return this.boundaries.get(e)||null}remove(e){let t=this.boundaries.get(e);t&&(t.destroy(),this.boundaries.delete(e))}getAllErrorStates(){let e={};for(let[t,s]of this.boundaries)e[t]=s.getErrorState();return e}async retryAll(){let e={};for(let[t,s]of this.boundaries)if(s.hasError())try{await s.handleRetry(),e[t]={success:!0}}catch(i){e[t]={success:!1,error:i.message}}return e}clearAll(){for(let e of this.boundaries.values())e.destroy();this.boundaries.clear()}getStats(){let e=Array.from(this.boundaries.values());return{total:e.length,inError:e.filter(t=>t.hasError()).length,healthy:e.filter(t=>!t.hasError()).length}}};var{debounce:wf,throttle:QE}=xe,Ef=pf(import.meta.url),ZE=mf(Ef),be=ff(df);function fi(r,e=[]){try{if(!r||typeof r!="string")return{valid:!1,resolvedPath:r,error:"Invalid file path"};let t=r.startsWith("~")?yf(it.homedir(),r.slice(1)):r,s=rl(t),i=it.homedir();return[...[i,i+"/.openclaw",i+"/.openclaw/agents","/tmp"],...e].some(d=>{let g=rl(d);return s.startsWith(g+"/")||s===g})?{valid:!0,resolvedPath:s}:{valid:!1,resolvedPath:s,error:"Path not in allowed directories"}}catch(t){return{valid:!1,resolvedPath:r,error:t.message}}}var eb=w.REFRESH_INTERVALS.DEFAULT,il=w.HISTORY.LENGTH,nl=w.HISTORY.NETWORK_LENGTH,Nn=w.PATHS.SETTINGS,tb=w.DEFAULT_SETTINGS,bf=w.REFRESH_INTERVALS.ACTIVE,Sf=w.REFRESH_INTERVALS.IDLE,ol=w.IDLE_THRESHOLD_MS,we=cn();we.help?(hn(),process.exit(0)):we.version&&(un(),process.exit(0));function xf(){try{let r=fi(Nn);if(!r.valid)return u.warn(`Settings path validation failed: ${r.error}`),Mt.getDefaultSettings();let e=Bt.readFileSync(r.resolvedPath,"utf8"),t=JSON.parse(e),s=Mt.validateSettings(t);return s.valid?s.value:Mt.getDefaultSettings()}catch{return Mt.getDefaultSettings()}}function ge(r){try{let e=fi(Nn);if(!e.valid){u.warn(`Settings path validation failed: ${e.error}`);return}let t=w.PATHS.OPENCLAW_DIR;Bt.existsSync(t)||Bt.mkdirSync(t,{recursive:!0}),Bt.writeFileSync(e.resolvedPath,JSON.stringify(r,null,2)),Jt(e.resolvedPath)}catch(e){u.error(`Failed to save settings: ${e.message}`)}}var E={green:"green",brightGreen:"bright-green",yellow:"yellow",brightYellow:"bright-yellow",red:"red",brightRed:"bright-red",cyan:"cyan",brightCyan:"bright-cyan",magenta:"magenta",brightMagenta:"bright-magenta",blue:"blue",brightBlue:"bright-blue",white:"white",brightWhite:"bright-white",gray:"gray",black:"black"},Tf={error:E.brightRed,fatal:E.brightRed,critical:E.brightRed,warn:E.brightYellow,warning:E.brightYellow,info:E.cyan,debug:E.gray,trace:E.gray,verbose:E.gray};function vf(r){return r.replace(/([A-Z])/g,"-$1").toLowerCase()}function If(r){if(!r||typeof r!="string")return r;let e=null,t=-1,s=-1;for(let g of["error","warn","info","debug"]){let p=g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),T=new RegExp(`\\[${p.toUpperCase()}\\]`,"i"),b=r.match(T);if(b){e=g,t=b.index,s=t+b[0].length;break}}if(!e){let g=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+(\w+)/i,p=r.match(g);if(p){let T=p[2].toLowerCase();["error","warn","info","debug"].includes(T)&&(e=T,t=p[1].length+1,s=t+e.length)}}if(!e)return"{gray-fg}"+r+"{/gray-fg}";let i=Tf[e]||"gray",n=vf(i),a=r.substring(0,t),c=r.substring(t,s),d=r.substring(s);return"{"+n+"-fg}"+a+"{/"+n+"-fg}{white-fg}"+c+"{/white-fg}{"+n+"-fg}"+d+"{/"+n+"-fg}"}function al(r){if(r==="all")return()=>!0;let e={error:4,warn:3,info:2,debug:1},t=e[r]||0,s=r==="debug";return i=>{if(!i)return!1;let n=i.toUpperCase(),a=0;for(let[c,d]of Object.entries(e))(n.includes("["+c.toUpperCase()+"]")||n.includes(c.toUpperCase()+":")||n.includes("-"+c.toUpperCase()+"-"))&&(a=Math.max(a,d));return a===0?t<=1:s?a===t:a>=t}}function Af(r,e){if(!r||e<=0)return 1;let t=r.split(" "),s=1,i=0;for(let n of t)i+n.length+1>e?(s++,i=n.length):i+=n.length+1;return s}var Rf=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 "," \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 "," \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2557 \u2588\u2588\u2551 "," \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2551 "," \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2554\u2588\u2588\u2588\u2554\u255D "," \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D "];function di(r){return r>=80?E.red:r>=60?E.yellow:E.green}function ll(r){let e=r*8;return e===0?"0":e<1e3?Math.round(e)+"b":e<1e6?(e/1e3).toFixed(0)+"K":(e/1e6).toFixed(1)+"M"}async function _f(){try{return await new Promise(r=>{gf.get("https://api.github.com/repos/openclaw/openclaw/releases/latest",{headers:{"User-Agent":"claw-dashboard"}},e=>{let t="";e.on("data",s=>t+=s),e.on("end",()=>{try{r(JSON.parse(t).tag_name?.replace(/^v/,""))}catch{r(null)}})}).on("error",()=>r(null)).setTimeout(3e3)})}catch{return null}}function cl(r){if(!r||r<0)return"--";let e=Math.floor(r/86400),t=Math.floor(r%86400/3600),s=Math.floor(r%3600/60);return e>0?`${e}d ${t}h`:t>0?`${t}h ${s}m`:`${s}m`}async function Cf(){try{let{stdout:r}=await be("launchctl list | grep gateway 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.LAUNCHCTL}),e=r.trim().match(/^(\d+)\s/);if(!e)return null;let t=e[1],{stdout:s}=await be(`ps -o lstart= -p ${t} 2>/dev/null`,{timeout:w.COMMAND_TIMEOUTS.LAUNCHCTL}),i=new Date(s.trim());return isNaN(i.getTime())?null:Math.floor((Date.now()-i.getTime())/1e3)}catch{return null}}async function Lf(){let r=null,e=null,t=null;try{let{stdout:s}=await be("system_profiler SPDisplaysDataType -json 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.SYSTEM_PROFILER}),n=JSON.parse(s)?.SPDisplaysDataType;n?.length>0&&(r=n[0].sppci_model||n[0]._name,n[0].spdisplays_utilization&&(e=parseFloat(n[0].spdisplays_utilization)))}catch{}try{let{stdout:s}=await be('ioreg -l -w 0 2>/dev/null | grep -E "(AGX|G14G|G13G|G15G)" | head -5',{timeout:w.COMMAND_TIMEOUTS.IOREG});s.includes("AGX")&&!r&&(s.includes("G15G")||s.includes("G16G")?r="Apple M3 GPU":s.includes("G14G")?r="Apple M2 GPU":s.includes("G13G")?r="Apple M1 GPU":r="Apple Silicon GPU")}catch{}try{let{stdout:s}=await be('powermetrics --samplers gpu_power -n 1 -i 50 2>&1 | grep -E "(GPU active|GPU frequency)" | head -5',{timeout:w.COMMAND_TIMEOUTS.POWERMETRICS}),i=s.match(/GPU active residency:\s+(\d+\.?\d*)%/),n=s.match(/GPU frequency:\s+(\d+)\s*MHz/);i&&(e=parseFloat(i[1])),n&&(t=parseInt(n[1]))}catch{}if(!r)try{let s=await xe.getGpuData();s.controllers?.[0]&&(r=s.controllers[0].model)}catch{}return r?{model:r.trim(),short:r.replace(/Apple /,"").substring(0,16),utilization:e,frequency:t}:null}function kf(){return it.platform()}async function Of(){let r=await oi.detectContainerEnv();if(r.isWSL&&r.wslVersion===2){let a=await Mf();if(a)return a}let e=null,t=null,s=null,i=null,n=null;try{let{stdout:a}=await be("nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.NVIDIA_SMI});if(a&&a.trim()){let c=a.trim().split(",").map(d=>d.trim());e=c[0]||null,t=c[1]?parseFloat(c[1]):null,s=c[2]?parseFloat(c[2]):null,i=c[3]?parseFloat(c[3]):null,n=c[4]?parseFloat(c[4]):null}}catch{}if(!e){try{let{stdout:a}=await be('lspci -vmm 2>/dev/null | grep -E "VGA|Display" | head -10',{timeout:w.COMMAND_TIMEOUTS.LSPCI});if(a){let c=a.match(/Device:\s+(.+)/i)||a.match(/VGA.*?:\s*(.+)/i);c&&(e=c[1].trim())}}catch{}if(e&&(e.toLowerCase().includes("amd")||e.toLowerCase().includes("radeon")))try{let{stdout:a}=await be("radeontop -d - -l 1 2>/dev/null | head -5",{timeout:w.COMMAND_TIMEOUTS.RADEONTOP});if(a){let c=a.match(/gpu\s+(\d+\.?\d*)/i);c&&(t=parseFloat(c[1]))}}catch{}}if(!e)try{let a=await xe.getGpuData();a?.controllers?.[0]&&(e=a.controllers[0].model,t=a.controllers[0].utilization||null)}catch{}return e?{model:e.trim(),short:e.replace(/NVIDIA|AMD|Radeon/gi,"").trim().substring(0,16),utilization:t,memoryUsed:s,memoryTotal:i,temperature:n}:null}async function Mf(){let r=null,e=null,t=null,s=null,i=null;try{let{stdout:n}=await be("/mnt/c/Windows/System32/nvidia-smi.exe --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null || nvidia-smi.exe --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null || /c/Windows/System32/nvidia-smi.exe --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.WSL_SMI});if(n&&n.trim()){let a=n.trim().split(",").map(c=>c.trim());r=a[0]||null,e=a[1]?parseFloat(a[1]):null,t=a[2]?parseFloat(a[2]):null,s=a[3]?parseFloat(a[3]):null,i=a[4]?parseFloat(a[4]):null}}catch{}if(!r)try{let{stdout:n}=await be('/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command "Get-CimInstance Win32_VideoController | Select-Object -First 1 Name, AdapterRAM | ConvertTo-Json" 2>/dev/null || powershell.exe -Command "Get-CimInstance Win32_VideoController | Select-Object -First 1 Name, AdapterRAM | ConvertTo-Json" 2>/dev/null',{timeout:w.COMMAND_TIMEOUTS.POWERSHELL});if(n&&n.trim()){let a=JSON.parse(n);a.Name&&(r=a.Name),a.AdapterRAM&&(s=Math.round(a.AdapterRAM/1024**3))}}catch{}if(!r)try{let{stdout:n}=await be("wsl.exe -e nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.WSL_SMI});if(n&&n.trim()){let a=n.trim().split(",").map(c=>c.trim());r=a[0]||null,e=a[1]?parseFloat(a[1]):null,t=a[2]?parseFloat(a[2]):null,s=a[3]?parseFloat(a[3]):null,i=a[4]?parseFloat(a[4]):null}}catch{}if(!r)try{let{stdout:n}=await be("nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.NVIDIA_SMI});if(n&&n.trim()){let a=n.trim().split(",").map(c=>c.trim());r=a[0]||null,e=a[1]?parseFloat(a[1]):null,t=a[2]?parseFloat(a[2]):null,s=a[3]?parseFloat(a[3]):null,i=a[4]?parseFloat(a[4]):null}}catch{}if(!r)try{let n=await xe.getGpuData();n?.controllers?.[0]&&(r=n.controllers[0].model,e=n.controllers[0].utilization||null,s=n.controllers[0].memoryTotal||null,t=n.controllers[0].memoryUsed||null,i=n.controllers[0].temperature||null)}catch{}return r?{model:r.trim(),short:r.replace(/NVIDIA|AMD|Radeon/gi,"").trim().substring(0,16),utilization:e,memoryUsed:t,memoryTotal:s,temperature:i,source:"wsl2"}:null}async function Df(){let r=null,e=null,t=null,s=null,i=null;try{let{stdout:n}=await be('powershell -Command "Get-CimInstance Win32_VideoController | Select-Object Name, AdapterRAM, VideoProcessor | ConvertTo-Json"',{timeout:w.COMMAND_TIMEOUTS.POWERSHELL});if(n&&n.trim()){let a=JSON.parse(n),c=Array.isArray(a)?a[0]:a;c&&(r=c.Name||null,c.AdapterRAM&&(s=Math.round(c.AdapterRAM/1024**3)))}}catch{}try{let{stdout:n}=await be(`powershell -Command "Get-Counter '\\GPU Engine(*)\\Utilization Percentage' -ErrorAction SilentlyContinue | Select-Object -First 1 | ConvertTo-Json"`,{timeout:w.COMMAND_TIMEOUTS.POWERSHELL});if(n&&n.trim()){let a=JSON.parse(n);a?.CounterSamples?.[0]?.CookedValue&&(e=Math.round(parseFloat(a.CounterSamples[0].CookedValue)))}}catch{}if(!e&&r?.toLowerCase().includes("nvidia"))try{let{stdout:n}=await be('powershell -Command "Get-CimInstance -Namespace root\\CIMV2\\NV\\ -ClassName gpu | Select-Object name, gpuUtilization, memoryTotal, memoryFree, temperature | ConvertTo-Json" 2>$null',{timeout:w.COMMAND_TIMEOUTS.NVIDIA_SMI});if(n&&n.trim()){let a=JSON.parse(n),c=Array.isArray(a)?a[0]:a;if(c&&(c.gpuUtilization!==void 0&&(e=parseInt(c.gpuUtilization)),c.temperature!==void 0&&(i=parseInt(c.temperature)),c.memoryTotal&&c.memoryFree)){let d=parseInt(c.memoryTotal),g=parseInt(c.memoryFree);s=Math.round(d/1024),t=Math.round((d-g)/1024)}}}catch{}if(!e&&r?.toLowerCase().includes("nvidia"))try{let{stdout:n}=await be("nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>nul",{timeout:w.COMMAND_TIMEOUTS.NVIDIA_SMI});if(n&&n.trim()){let a=n.trim().split(",").map(c=>c.trim());r=a[0]||r,e=a[1]?parseFloat(a[1]):null,t=a[2]?parseFloat(a[2]):null,s=a[3]?parseFloat(a[3]):null,i=a[4]?parseFloat(a[4]):null}}catch{}if(!r)try{let n=await xe.getGpuData();n?.controllers?.[0]&&(r=n.controllers[0].model,e=n.controllers[0].utilization||null)}catch{}return r?{model:r.trim(),short:r.replace(/NVIDIA|AMD|Radeon|Intel/gi,"").trim().substring(0,16),utilization:e,memoryUsed:t,memoryTotal:s,temperature:i}:null}function Nf(r,e,t){if(!r||!e||t<100)return null;let s=r.totalTokens||0,i=e.totalTokens||0,n=s-i;if(n<=0)return null;let a=n/(t/1e3);return a>0?parseFloat(a.toFixed(1)):null}var gi=class{constructor(){this.settings=xf(),Bi(),this.themeWatcher=Ui(),this.autoSaveManager=new li({enabled:this.settings.autoSave?.enabled??!0,intervalMs:this.settings.autoSave?.intervalMs??3e4,statePath:w.PATHS.STATE,getState:()=>this.getDashboardState(),getSettings:()=>this.settings,saveSettings:i=>ge(i)}),this.exportScheduler=new ss({enabled:this.settings.exportSchedule?.enabled??!1,format:this.settings.exportSchedule?.format??"json",schedule:this.settings.exportSchedule?.schedule??"0 * * * *",retentionDays:this.settings.exportSchedule?.retentionDays??30,directory:this.settings.exportSchedule?.directory,includeMetrics:this.settings.exportSchedule?.includeMetrics??!0}),this.exportScheduler.setMetricsCallback(()=>this.getCurrentMetrics()),this.errorBoundaryManager=new ui,this.widgetErrorState=new Map;let e=Za(w.PATHS.STATE);e&&el(e,this),this.unsubscribeThemeChange=Rr(()=>{this.render()}),this.screen=C.screen({smartCSR:!0,title:"Claw Dashboard",mouse:!0}),this.diffRenderer=new ai(this.screen),this.selectedSessionIndex=0,this.paginationOffset=0,this.sessionSearchQuery=this.settings.sessionSearchQuery||"",this.isSearchMode=!1,this.filteredSessions=[],this.focusedWidgetIndex=0,this.focusableWidgets=[],this.sessionSearchQuery&&(this.isSearchMode=!0,this.filterSessions()),this.showFavoritesOnly=this.settings.showFavoritesOnly||!1,this.history={cpu:new Array(il).fill(0),memory:new Array(il).fill(0),netRx:new Array(nl).fill(0),netTx:new Array(nl).fill(0)},this.data={cpu:[],memory:{},openclaw:null,gpu:null,network:null,sessions:[],agents:[],version:null,latest:null,sessionTPS:{},sessionLastTPS:{}},this.dataTimestamps={cpu:null,memory:null,gpu:null,network:null,disk:null,system:null,sessions:null},this.prev=null,this.lastTime=Date.now(),this.logLines=[],this.isPaused=!1,this.corruptedSessionsCount=0,this.corruptedSessionsWarningShown=!1,this.focusableWidgets=[],this.focusedWidgetIndex=-1,this.isWidgetArrangeMode=!1,this.arrangeWidgetIndex=-1,this.init(),this.currentRefreshInterval=this.settings.refreshInterval,this.lastActivityTime=Date.now(),this.activeAgentCount=0,this.settings.theme==="auto"&&this.startThemeWatcher(),process.stdout.on("error",i=>{i.code}),process.on("uncaughtException",i=>{throw(i.code==="EPIPE"||i.message?.includes("EPIPE")||i.message?.includes("write"))&&process.exit(0),i}),this.lastTerminalWidth=process.stdout.columns||80,this.lastTerminalHeight=process.stdout.rows||24,this.resizeTimeout=null,this.isModalActive=!1,this.terminalTooSmall=!1,this._settingsClosing=!1,this._commandPaletteClosing=!1;let t=this.toggleSettings.bind(this);this.toggleSettings=(...i)=>{let n=this.w.settingsBox||this.w.detailBox||this.w.searchBox||this.w.helpBox;t(...i);let a=this.w.settingsBox||this.w.detailBox||this.w.searchBox||this.w.helpBox;this.isModalActive=!!a};let s=this.toggleHelp.bind(this);if(this.toggleHelp=(...i)=>{s(...i),this.isModalActive=!!this.w.helpBox},this.toggleSearch){let i=this.toggleSearch.bind(this);this.toggleSearch=(...n)=>{i(...n),this.isModalActive=!!this.w.searchBox}}if(this.showDetail){let i=this.showDetail.bind(this);this.showDetail=(...n)=>{i(...n),this.isModalActive=!!this.w.detailBox}}this.debouncedResize=wf(()=>{this.handleResize()},100),this.screen.on("resize",this.debouncedResize),process.stdout.on("resize",this.debouncedResize),this.configWatcher=null,this.pluginReloadManager=null}handleResize(){let e=this.screen.width||process.stdout.columns||80,t=this.screen.height||process.stdout.rows||24;if(!(e===this.lastTerminalWidth&&t===this.lastTerminalHeight||(this.lastTerminalWidth=e,this.lastTerminalHeight=t,e<80||t<24?(this.terminalTooSmall=!0,this.showTerminalSizeWarning(e,t)):(this.terminalTooSmall=!1,this.hideTerminalSizeWarning()),this.isModalActive)))try{this.screen.render()}catch(n){if(n.code==="EPIPE"||n.message?.includes("write"))return;throw n}}showTerminalSizeWarning(e,t){this.w.terminalSizeWarning&&(this.w.terminalSizeWarning.destroy(),delete this.w.terminalSizeWarning);let s=80,i=24;this.w.terminalSizeWarning=C.box({parent:this.screen,top:"center",left:"center",width:50,height:7,border:{type:"line"},label:" Terminal Too Small ",style:{border:{fg:"red"},bg:"black"}});let n=C.text({parent:this.w.terminalSizeWarning,top:1,left:"center",width:"90%",content:`Terminal is ${e}x${t}.
|
|
1678
|
-
Minimum required: ${s}x${i}.
|
|
1679
|
-
Please resize your terminal.`,style:{fg:"yellow",bold:!0},align:"center"});try{this.screen.render()}catch{}}hideTerminalSizeWarning(){if(this.w.terminalSizeWarning){this.w.terminalSizeWarning.destroy(),delete this.w.terminalSizeWarning;try{this.screen.render()}catch{}}}getVisibleWidgets(){return{cpu:this.settings.showWidget1!==!1,memory:this.settings.showWidget2!==!1,gpu:this.settings.showWidget3!==!1,network:this.settings.showWidget4!==!1,disk:this.settings.showWidget5!==!1,system:this.settings.showWidget6!==!1,uptime:this.settings.showWidget7!==!1,health:this.settings.showWidget8!==!1,gateway:this.settings.showWidget9!==!1}}getNewlyVisibleWidgets(){let e=this.getVisibleWidgets(),t=this._previousVisibleState||e;this._previousVisibleState={...e};let s={};for(let[i,n]of Object.entries(e))s[i]=n&&!t[i];return s}shouldWidgetUpdate(e,t=Date.now()){let s=this.widgetRefreshState[e];if(!s)return{shouldUpdate:!0,reason:"no_state"};let n=Nt.getStatus().degradation?.level||"none";if((w.WIDGET_DEGRADATION?.CRITICAL_WIDGETS||["cpu","memory"]).includes(e)){let p=s.customInterval||s.defaultInterval||this.settings.refreshInterval;return t-s.lastUpdate>=p?{shouldUpdate:!0,reason:"critical_widget"}:{shouldUpdate:!1,reason:"interval_not_elapsed"}}if(n==="critical")return s.skipCount++,{shouldUpdate:!1,reason:"degradation_critical_skip"};let c=s.customInterval||s.defaultInterval||this.settings.refreshInterval,d=c;if(n==="warning"){let p=w.WIDGET_DEGRADATION?.WARNING?.EXTEND_INTERVAL_MULTIPLIER||1.5;d=c*p}return t-s.lastUpdate<d?{shouldUpdate:!1,reason:"interval_not_elapsed"}:{shouldUpdate:!0,reason:"ok"}}recordWidgetUpdate(e,t=Date.now()){let s=this.widgetRefreshState[e];s&&(s.lastUpdate=t,s.updateCount++)}setWidgetRefreshInterval(e,t){let s=this.widgetRefreshState[e];if(s){let i=w.WIDGET_REFRESH_VALIDATION?.MIN_INTERVAL||500,n=w.WIDGET_REFRESH_VALIDATION?.MAX_INTERVAL||6e4;if(t!==null&&(t<i||t>n))throw new Error(`Invalid refresh interval: ${t}. Must be between ${i} and ${n}ms`);s.customInterval=t,u.info(`Widget '${e}' refresh interval set to ${t}ms`)}}getWidgetRefreshStats(e){if(e){let i=this.widgetRefreshState[e];if(!i)return null;let n=Nt.getStatus();return{...i,degradationLevel:n.degradation?.level||"none"}}let t={},s=Nt.getStatus();for(let[i,n]of Object.entries(this.widgetRefreshState))t[i]={...n,degradationLevel:s.degradation?.level||"none"};return t}getDashboardState(){return{selectedSessionIndex:this.selectedSessionIndex,paginationOffset:this.paginationOffset,sessionSearchQuery:this.sessionSearchQuery,isSearchMode:this.isSearchMode,showFavoritesOnly:this.showFavoritesOnly,focusedWidgetIndex:this.focusedWidgetIndex,currentRefreshInterval:this.currentRefreshInterval}}saveSettingsAndMarkDirty(e){ge(e),this.autoSaveManager&&this.autoSaveManager.markDirty()}async init(){this.createWidgets(),this.setupKeys(),this.setupMouse(),this.focusableWidgets=this.buildFocusableWidgets(),this.focusedWidgetIndex=0,this.applyFocusIndicator();let e=ke();this.settings.theme=e.name.toLowerCase().replace(" ","-").replace("high-contrast","high-contrast"),this.applyTheme(),await ga(this.screen,async t=>{await this.start(t),this.fetchVersion()}),await ya(this.screen,this.settings,ge)}fetchVersion(){let e=Date.now(),t=this.settings.versionCheckInterval||432e5,s=this.settings.lastVersionCheck||0;e-s<t||(this.settings.lastVersionCheck=e,ge(this.settings),this._fetchVersionAsync())}async _fetchVersionAsync(){try{let{stdout:e}=await be('openclaw --version 2>/dev/null || echo "unknown"',{timeout:w.COMMAND_TIMEOUTS.OPENCLAW_VERSION});this.data.version=e.trim()}catch{this.data.version="unknown"}_f().then(e=>{this.data.latest=e}).catch(()=>{this.data.latest=null})}createWidgets(){this.w={},this.widgetRefreshState={cpu:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.CPU},memory:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.MEMORY},gpu:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.GPU},network:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.NETWORK},disk:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.DISK},system:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.SYSTEM},uptime:{lastUpdate:0,updateCount:0,skipCount:0,defaultInterval:w.WIDGET_REFRESH_INTERVALS.UPTIME}};let e=40;this.w.logo=C.text({parent:this.screen,top:2,left:1,width:e,content:Rf.join(`
|
|
1680
|
-
`),style:{fg:E.brightCyan,bold:!0}}),this.w.title=C.text({parent:this.screen,top:8,left:3,content:`Dashboard ${pe}, openclaw checking...`,style:{fg:E.brightWhite,bold:!0}}),this.w.clock=C.text({parent:this.screen,top:0,left:0,width:26,content:"--:--",style:{fg:E.brightCyan,bold:!0},align:"left",tags:!0}),this.createWidgetBoxes(),this.w.sessBox=C.box({parent:this.screen,left:0,width:"100%",height:9,border:{type:"line"},label:" SESSIONS ",style:{border:{fg:E.blue}},tags:!0,overflow:"hidden",scrollable:!1}),this.w.sessHeader=C.text({parent:this.w.sessBox,top:0,left:1,width:"98%",content:" STATUS AGENT MODEL CONTEXT IDLE CHAN",style:{fg:E.brightWhite,bold:!0},overflow:"hidden"}),this.w.sessList=C.text({parent:this.w.sessBox,top:1,left:1,width:"98%",height:6,content:"",style:{fg:E.white},tags:!0,overflow:"hidden",scrollable:!1}),this.w.sessCount=C.text({parent:this.w.sessBox,top:0,right:2,content:"",style:{fg:E.gray}}),this.w.sessTruncated=C.text({parent:this.w.sessBox,top:7,left:2,content:"",style:{fg:E.yellow}}),this.w.logBox=C.box({parent:this.screen,left:0,width:"100%",height:19,border:{type:"line"},label:" OPENCLAW LOGS ",style:{border:{fg:E.cyan}},scrollable:!0,alwaysScroll:!0}),this.w.logContent=C.text({parent:this.w.logBox,top:0,left:1,width:"95%-2",content:"Loading logs...",style:{fg:E.gray},tags:!0}),this.w.footer=C.box({parent:this.screen,bottom:0,left:0,width:"100%",height:1,style:{bg:E.black,fg:E.gray}}),this.w.footerText=C.text({parent:this.w.footer,top:0,left:"center",content:"",style:{fg:E.gray},tags:!0}),this.recalculateLayout()}createWidgetBoxes(){this.w.cpuBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" CPU ",style:{border:{fg:E.cyan}}}),this.w.cpuValue=C.text({parent:this.w.cpuBox,top:0,left:"center",content:"0%",style:{fg:E.brightGreen,bold:!0}}),this.w.cpuDetail=C.text({parent:this.w.cpuBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.memBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" MEMORY ",style:{border:{fg:E.magenta}}}),this.w.memValue=C.text({parent:this.w.memBox,top:0,left:"center",content:"0%",style:{fg:E.brightMagenta,bold:!0}}),this.w.memDetail=C.text({parent:this.w.memBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.gpuBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" GPU ",style:{border:{fg:E.yellow}}}),this.w.gpuValue=C.text({parent:this.w.gpuBox,top:0,left:"center",content:"Detecting...",style:{fg:E.brightYellow,bold:!0}}),this.w.gpuDetail=C.text({parent:this.w.gpuBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.netBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" NETWORK ",style:{border:{fg:E.brightCyan}}}),this.w.netValue=C.text({parent:this.w.netBox,top:0,left:"center",content:"Loading...",style:{fg:E.brightCyan,bold:!0}}),this.w.netDetail=C.text({parent:this.w.netBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.diskBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" DISK ",style:{border:{fg:E.green}}}),this.w.diskValue=C.text({parent:this.w.diskBox,top:0,left:"center",content:"0%",style:{fg:E.brightGreen,bold:!0}}),this.w.diskDetail=C.text({parent:this.w.diskBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.sysBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" SYSTEM ",style:{border:{fg:E.gray}}}),this.w.sysInfoLine1=C.text({parent:this.w.sysBox,top:0,left:"center",content:"...",style:{fg:E.gray}}),this.w.sysInfoLine2=C.text({parent:this.w.sysBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.uptimeBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" UPTIME ",style:{border:{fg:E.brightMagenta}}}),this.w.uptimeSys=C.text({parent:this.w.uptimeBox,top:0,left:"center",content:"Sys: --",style:{fg:E.brightMagenta,bold:!0}}),this.w.uptimeClaw=C.text({parent:this.w.uptimeBox,top:1,left:"center",content:"Claw: --",style:{fg:E.brightMagenta,bold:!0}}),this.w.healthBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" DATA HEALTH ",style:{border:{fg:E.green}}}),this.w.healthStatus=C.text({parent:this.w.healthBox,top:0,left:"center",content:"All Fresh",style:{fg:E.brightGreen,bold:!0}}),this.w.healthDetail=C.text({parent:this.w.healthBox,top:1,left:"center",content:"",style:{fg:E.gray}}),this.w.gatewayBox=C.box({parent:this.screen,height:5,border:{type:"line"},label:" GATEWAY ",style:{border:{fg:E.cyan}}}),this.w.gatewayStatus=C.text({parent:this.w.gatewayBox,top:0,left:"center",content:"Checking...",style:{fg:E.brightCyan,bold:!0}}),this.w.gatewayDetail=C.text({parent:this.w.gatewayBox,top:1,left:"center",content:"",style:{fg:E.gray}})}recalculateLayout(){let e=S=>{let M=this.settings.widgetSizes?.[S]||"medium";return Sr[M]||Sr.medium},c=[{name:"cpu",box:this.w.cpuBox,visible:this.settings.showWidget1},{name:"mem",box:this.w.memBox,visible:this.settings.showWidget2},{name:"gpu",box:this.w.gpuBox,visible:this.settings.showWidget3},{name:"net",box:this.w.netBox,visible:this.settings.showWidget4},{name:"disk",box:this.w.diskBox,visible:this.settings.showWidget5},{name:"sys",box:this.w.sysBox,visible:this.settings.showWidget6},{name:"uptime",box:this.w.uptimeBox,visible:this.settings.showWidget7},{name:"health",box:this.w.healthBox,visible:this.settings.showWidget8},{name:"gateway",box:this.w.gatewayBox,visible:this.settings.showWidget9}];c.forEach(S=>{S.height=e(S.name)});let d=this.settings.widgetOrder||[];if(d.length>0){let S=new Map(d.map((M,j)=>[M,j]));c.sort((M,j)=>{let k=S.has(M.name)?S.get(M.name):1/0,F=S.has(j.name)?S.get(j.name):1/0;return k-F})}let g=this.settings.pinnedWidgets||[],p=c.filter(S=>S.visible&&g.includes(S.name)),T=c.filter(S=>S.visible&&!g.includes(S.name)),b=p.length,_=T.length;if(b+_===0){this.w.sessBox.position={top:10},this.w.sessBox.height=9;let S=Math.max(19,19);this.w.logBox.position={top:S},this.w.logBox.height="100%-"+(S+1)}else{if(b>0){let ee=Math.floor(65/b);p.forEach((D,O)=>{let I=35+O*ee;D.box.top=0,D.box.left=I+"%",D.box.width=ee+"%",D.box.height=D.height,D.box.show()})}if(_>0){let ee=b>0?1:0,D,O;ee===0?(D=Math.ceil(_/2),O=_-D):(D=_,O=0),T.forEach((I,G)=>{let W=G<D?0:1,U=ee+W,oe=W===0?G:G-D,K=Math.floor(65/(W===0?D:O)),me=35+oe*K;I.box.top=U*I.height,I.box.left=me+"%",I.box.width=K+"%",I.box.height=I.height,I.box.show()})}c.filter(ee=>!ee.visible).forEach(ee=>{ee.box.hide()});let j=p.length>0?Math.max(...p.map(ee=>ee.height)):0,k=b>0?10+j:10;this.w.sessBox.position={top:k},this.w.sessBox.height=9;let F=Math.max(19,k+9);this.w.logBox.position={top:F},this.w.logBox.height="100%-"+(F+1)}}setupKeys(){this.screen.key(["q","C-c"],()=>{if(!!(this.w.settingsBox||this.w.detailBox||this.w.searchBox||this.w.helpBox||this.w.commandPaletteBox||this.w.snapshotPickerBox||this.w.snapshotConfirmBox||this.w.perfOverlayBox)){this.w.searchBox?this.closeSearch():this.w.detailBox?this.closeSessionDetail():this.w.settingsBox?this.closeSettings():this.w.helpBox?this.toggleHelp():this.w.commandPaletteBox?this.closeCommandPalette():this.w.snapshotPickerBox?this.closeSnapshotPicker():this.w.snapshotConfirmBox?this.closeSnapshotConfirmation():this.w.perfOverlayBox&&this.togglePerformanceOverlay();return}this.isModalActive&&this.resetModalState(),clearInterval(this.timer),this.stopConfigWatcher(),this.stopPluginWatcher(),St.stop(),this.themeWatcher&&this.themeWatcher.stop(),this.unsubscribeThemeChange&&this.unsubscribeThemeChange(),this.exportScheduler&&this.exportScheduler.stop(),this.screen.destroy(),process.exit(0)}),this.screen.key("r",()=>this.refresh()),this.screen.key(["?"],()=>this.toggleHelp()),this.screen.key(["s","S"],()=>this.toggleSettings()),this.screen.key(["p"],()=>this.togglePerformanceOverlay()),this.screen.key(["P"],()=>this.togglePause()),this.screen.key([" "],()=>this.togglePause()),this.screen.key("o",()=>this.cycleSessionSort()),this.screen.key("e",()=>this.exportDashboard()),this.screen.key("E",()=>this.cycleExportFormat()),this.screen.key("C-s",()=>this.exportSnapshot()),this.screen.key("C-o",()=>this.importSnapshot()),this.screen.key("t",()=>this.cycleTheme()),this.screen.key("T",()=>this.showThemeSelector()),this.screen.key("v",()=>this.showVersionInfo()),this.screen.key("G",()=>this.retryGatewayConnection()),this.screen.key("w",()=>this.toggleWidgetArrangeMode()),this.screen.key("X",()=>this.retryFailedWidgets()),this.screen.key("C-k",()=>{this.isModalActive&&!this.w.commandPaletteBox||this.toggleCommandPalette()}),this.screen.key("m",()=>{this.isModalActive||this.toggleWidgetArrangeMode()}),this.screen.key("escape",()=>{if(this.isWidgetArrangeMode){this.toggleWidgetArrangeMode();return}this.w.commandPaletteBox?this.closeCommandPalette():this.w.snapshotConfirmBox?this.closeSnapshotConfirmation():this.w.snapshotPickerBox?this.closeSnapshotPicker():this.w.detailBox?this.closeSessionDetail():this.w.settingsBox?this.closeSettings():this.w.helpBox?this.toggleHelp():this.w.searchBox?this.closeSearch():this.w.perfOverlayBox&&this.togglePerformanceOverlay()}),this.screen.key("return",()=>{if(!this.isModalActive){if(this.focusedWidgetIndex>=0&&this.focusableWidgets.length>0){let e=this.focusableWidgets[this.focusedWidgetIndex];if(e&&e.type!=="list"){if(e.type==="metric"){this.togglePerformanceOverlay();return}return}}this.showSessionDetail()}}),this.screen.key("/",()=>{this.isModalActive||this.showSearch()}),this.screen.key(["up","\x1B[A"],()=>{if(!(this.w.searchInput&&this.w.searchInput.focused)&&!(this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)){if(this.isWidgetArrangeMode){this.moveWidget(-1);return}this.selectedSessionIndex>0&&(this.selectedSessionIndex--,this.render())}}),this.screen.key("k",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||this.selectedSessionIndex>0&&(this.selectedSessionIndex--,this.render())}),this.screen.key(["down","\x1B[B"],()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;if(this.isWidgetArrangeMode){this.moveWidget(1);return}let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.min(6,e?.length||0);this.selectedSessionIndex<t-1&&(this.selectedSessionIndex++,this.render())}),this.screen.key("j",()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;if(this.isWidgetArrangeMode){this.moveWidget(1);return}let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.min(6,e?.length||0);this.selectedSessionIndex<t-1&&(this.selectedSessionIndex++,this.render())}),this.screen.key(["pageup","["],()=>{let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset>0&&(this.paginationOffset--,this.selectedSessionIndex=0,this.render())}),this.screen.key("C-b",()=>{let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset>0&&(this.paginationOffset--,this.selectedSessionIndex=0,this.render())}),this.screen.key(["left","\x1B[D"],()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset>0&&(this.paginationOffset--,this.selectedSessionIndex=0,this.render())}),this.screen.key("h",()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset>0&&(this.paginationOffset--,this.selectedSessionIndex=0,this.render())}),this.screen.key(["pagedown","]"],()=>{let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset<t-1&&(this.paginationOffset++,this.selectedSessionIndex=0,this.render())}),this.screen.key("C-f",()=>{let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset<t-1&&(this.paginationOffset++,this.selectedSessionIndex=0,this.render())}),this.screen.key("l",()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset<t-1&&(this.paginationOffset++,this.selectedSessionIndex=0,this.render())}),this.screen.key(["right","\x1B[C"],()=>{if(this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused)return;let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.ceil(e.length/6);this.paginationOffset<t-1&&(this.paginationOffset++,this.selectedSessionIndex=0,this.render())}),this.screen.key("g",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||(this.paginationOffset=0,this.selectedSessionIndex=0,this.render())}),this.screen.key("f",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||this.w.detailBox||this.toggleFavorite()}),this.screen.key("F",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||this.w.detailBox||this.toggleFavoritesFilter()}),this.screen.key("1",()=>this.toggleWidget("showWidget1")),this.screen.key("2",()=>this.toggleWidget("showWidget2")),this.screen.key("3",()=>this.toggleWidget("showWidget3")),this.screen.key("4",()=>this.toggleWidget("showWidget4")),this.screen.key("5",()=>this.toggleWidget("showWidget5")),this.screen.key("6",()=>this.toggleWidget("showWidget6")),this.screen.key("7",()=>this.toggleWidget("showWidget7")),this.screen.key("8",()=>this.toggleWidget("showWidget8")),this.screen.key("9",()=>this.toggleWidget("showWidget9")),this.screen.key("M-1",()=>this.togglePinWidget("cpu")),this.screen.key("M-2",()=>this.togglePinWidget("mem")),this.screen.key("M-3",()=>this.togglePinWidget("gpu")),this.screen.key("M-4",()=>this.togglePinWidget("net")),this.screen.key("M-5",()=>this.togglePinWidget("disk")),this.screen.key("M-6",()=>this.togglePinWidget("sys")),this.screen.key("M-7",()=>this.togglePinWidget("uptime")),this.screen.key("M-8",()=>this.togglePinWidget("health")),this.screen.key("M-9",()=>this.togglePinWidget("gateway")),this.screen.key("!",()=>this.togglePinWidget("cpu")),this.screen.key("@",()=>this.togglePinWidget("mem")),this.screen.key("#",()=>this.togglePinWidget("gpu")),this.screen.key("$",()=>this.togglePinWidget("net")),this.screen.key("%",()=>this.togglePinWidget("disk")),this.screen.key("^",()=>this.togglePinWidget("sys")),this.screen.key("&",()=>this.togglePinWidget("uptime")),this.screen.key("*",()=>this.togglePinWidget("health")),this.screen.key("(",()=>this.togglePinWidget("gateway")),this.screen.key("tab",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||this.w.detailBox||this.cycleFocus(1)}),this.screen.key("S-tab",()=>{this.w.searchInput&&this.w.searchInput.focused||this._settingsClosing||this.w.settingsList&&this.w.settingsList.focused||this._commandPaletteClosing||this.w.commandPaletteBox&&this.w.commandPaletteInput&&this.w.commandPaletteInput.focused||this.w.detailBox||this.cycleFocus(-1)})}setupMouse(){this.w.sessBox.on("click",t=>{if(this.w.detailBox||this.w.settingsBox)return;let s=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions;if(!s||s.length===0)return;let i=t.y-this.w.sessBox.position.top-1,n=Math.min(6,s.length);i>=0&&i<n&&(this.selectedSessionIndex=i,this.showSessionDetail())}),[{box:this.w.cpuBox,key:"showWidget1"},{box:this.w.memBox,key:"showWidget2"},{box:this.w.gpuBox,key:"showWidget3"},{box:this.w.netBox,key:"showWidget4"},{box:this.w.diskBox,key:"showWidget5"},{box:this.w.sysBox,key:"showWidget6"},{box:this.w.uptimeBox,key:"showWidget7"}].forEach(({box:t,key:s})=>{t&&t.on("click",()=>{this.w.settingsBox&&this.toggleWidget(s)})})}toggleWidget(e){let t=this.settings[e];this.settings[e]=!t;let s=this.settings[e];if(ge(this.settings),this.autoSaveManager&&this.autoSaveManager.markDirty(),this.recalculateLayout(),this.clearFocusIndicator(),this.focusableWidgets=this.buildFocusableWidgets(),this.focusedWidgetIndex>=this.focusableWidgets.length&&(this.focusedWidgetIndex=Math.max(0,this.focusableWidgets.length-1)),this.applyFocusIndicator(),!t&&s){let n={showWidget1:"cpu",showWidget2:"memory",showWidget3:"gpu",showWidget4:"network",showWidget5:"disk",showWidget6:"system",showWidget7:"uptime",showWidget8:"health",showWidget9:"gateway"}[e];if(n){this._previousVisibleState&&(this._previousVisibleState[n]=!1),this.refresh();return}}this.screen.render()}togglePinWidget(e){let t=this.settings.pinnedWidgets||[];if(t.includes(e))this.settings.pinnedWidgets=t.filter(i=>i!==e),this.showToast(`Unpinned ${e.toUpperCase()} widget`);else{if(t.length>=4){this.showToast("Maximum 4 widgets can be pinned (use Alt+1-9 to unpin)");return}this.settings.pinnedWidgets=[...t,e],this.showToast(`Pinned ${e.toUpperCase()} widget to favorites row`)}ge(this.settings),this.autoSaveManager&&this.autoSaveManager.markDirty(),this.recalculateLayout(),this.screen.render()}showToast(e,t=2e3){if(!this.w.footerText)return;let s=this.w.footerText.content;this.w.footerText.setContent(` {green-fg}${e}{/green-fg}`),this.screen.render(),setTimeout(()=>{this.w.footerText.setContent(s),this.screen.render()},t)}buildFocusableWidgets(){let e=[];this.w.sessBox&&e.push({box:this.w.sessBox,name:"sessions",type:"list"});let t=[{box:this.w.cpuBox,name:"cpu",setting:"showWidget1"},{box:this.w.memBox,name:"memory",setting:"showWidget2"},{box:this.w.gpuBox,name:"gpu",setting:"showWidget3"},{box:this.w.netBox,name:"network",setting:"showWidget4"},{box:this.w.diskBox,name:"disk",setting:"showWidget5"},{box:this.w.sysBox,name:"system",setting:"showWidget6"},{box:this.w.uptimeBox,name:"uptime",setting:"showWidget7"},{box:this.w.healthBox,name:"health",setting:"showWidget8"},{box:this.w.gatewayBox,name:"gateway",setting:"showWidget9"}];for(let s of t)s.box&&this.settings[s.setting]!==!1&&e.push({box:s.box,name:s.name,type:"metric"});return this.w.logBox&&e.push({box:this.w.logBox,name:"logs",type:"panel"}),e}getOrderedWidgets(){let e=["cpu","mem","gpu","net","disk","sys","uptime","health","gateway"],t=this.settings.widgetOrder||[],s=e.filter(a=>{let c=this.getWidgetSettingKey(a);return this.settings[c]!==!1}),i=[],n=new Set;for(let a of t)s.includes(a)&&!n.has(a)&&(i.push(a),n.add(a));for(let a of s)n.has(a)||(i.push(a),n.add(a));return i}getWidgetSettingKey(e){return{cpu:"showWidget1",mem:"showWidget2",gpu:"showWidget3",net:"showWidget4",disk:"showWidget5",sys:"showWidget6",uptime:"showWidget7",health:"showWidget8",gateway:"showWidget9"}[e]||""}toggleWidgetArrangeMode(){this.isWidgetArrangeMode=!this.isWidgetArrangeMode,this.isWidgetArrangeMode?(this.arrangeWidgetIndex=0,this.showToast("Widget Arrangement Mode - Use arrow keys to reorder, ESC to exit",3e3),this.updateArrangeIndicator()):(this.clearArrangeIndicator(),this.saveWidgetOrder(),this.showToast("Widget order saved",1500)),this.screen.render()}updateArrangeIndicator(){let e=this.getOrderedWidgets();if(this.arrangeWidgetIndex<0||this.arrangeWidgetIndex>=e.length)return;let t=e[this.arrangeWidgetIndex],s=this.getWidgetBox(t);s&&(s._originalBorderStyle||(s._originalBorderStyle={...s.style.border}),s.style.border={fg:"bright-yellow",bold:!0})}clearArrangeIndicator(){let e=this.getOrderedWidgets();for(let t of e){let s=this.getWidgetBox(t);s&&s._originalBorderStyle&&(s.style.border=s._originalBorderStyle,delete s._originalBorderStyle)}}getWidgetBox(e){return{cpu:this.w.cpuBox,mem:this.w.memBox,gpu:this.w.gpuBox,net:this.w.netBox,disk:this.w.diskBox,sys:this.w.sysBox,uptime:this.w.uptimeBox,health:this.w.healthBox,gateway:this.w.gatewayBox}[e]}moveWidget(e){let t=this.getOrderedWidgets();if(t.length<=1)return;this.clearArrangeIndicator();let s=t[this.arrangeWidgetIndex],i=this.arrangeWidgetIndex,n=i+e;n<0&&(n=t.length-1),n>=t.length&&(n=0);let a=[...t];a.splice(i,1),a.splice(n,0,s),this.settings.widgetOrder=a,this.arrangeWidgetIndex=n,this.updateArrangeIndicator(),this.recalculateLayout(),this.screen.render()}saveWidgetOrder(){ge(this.settings)}cycleFocus(e){this.focusableWidgets=this.buildFocusableWidgets(),this.focusableWidgets.length!==0&&(this.clearFocusIndicator(),this.focusedWidgetIndex=(this.focusedWidgetIndex+e+this.focusableWidgets.length)%this.focusableWidgets.length,this.applyFocusIndicator(),this.screen.render())}clearFocusIndicator(){if(this.focusableWidgets.length===0)return;let e=this.focusableWidgets[this.focusedWidgetIndex];if(!e||!e.box)return;let s={sessions:"magenta",cpu:"cyan",memory:"green",gpu:"yellow",network:"cyan",disk:"yellow",system:"blue",uptime:"magenta",health:"green",gateway:"cyan",logs:"gray"}[e.name]||"white";e.box.style.border={fg:s},e.box.style.border.bold=!1}applyFocusIndicator(){if(this.focusableWidgets.length===0)return;let e=this.focusableWidgets[this.focusedWidgetIndex];!e||!e.box||(e.box.style.border={fg:"bright-white",bold:!0})}cycleSessionSort(){let e=["time","tokens","idle","name"],t=e.indexOf(this.settings.sessionSortMode);this.settings.sessionSortMode=e[(t+1)%e.length],ge(this.settings),this.render()}cycleLogLevel(){let e=["all","debug","info","warn","error"],t=e.indexOf(this.settings.logLevelFilter);this.settings.logLevelFilter=e[(t+1)%e.length],ge(this.settings),this.screen.render()}cycleTheme(){let e=Ao();Zt(),this.settings.theme=e,ge(this.settings),e==="auto"?this.themeWatcher=Ui():this.themeWatcher&&(vo(),this.themeWatcher=null),this.applyTheme(),this.screen.render()}async showThemeSelector(){this.isModalActive=!0,await Ja(this.screen,C,()=>{this.applyTheme(),this.screen.render()}),this.isModalActive=!1}cycleExportFormat(){let e=["json","csv"],t=e.indexOf(this.settings.exportFormat);this.settings.exportFormat=e[(t+1)%e.length],ge(this.settings),this.w.footerText.setContent(`{green-fg}Export format set to ${this.settings.exportFormat.toUpperCase()}{/green-fg}`),this.screen.render(),setTimeout(()=>this.render(),3e3)}showVersionInfo(){let e=this.data.version||"unknown";this.w.footerText.setContent(`{cyan-fg}clawdash ${pe} | openclaw ${e}{/cyan-fg}`),this.screen.render(),setTimeout(()=>this.render(),5e3)}async retryGatewayConnection(){let t=Pe.getEndpointHealth().filter(s=>s.enabled&&!s.reachable).length;if(t===0){this.w.footerText.setContent("{green-fg}\u2713 All gateways reachable{/green-fg}"),this.screen.render(),setTimeout(()=>this.render(),2e3);return}this.w.footerText.setContent(`{yellow-fg}\u27F3 Retrying ${t} unreachable gateway(s)...{/yellow-fg}`),this.screen.render();try{let s=await Pe.forceRetry();if(s.successful>0)this.w.footerText.setContent(`{green-fg}\u2713 ${s.successful}/${s.attempted} gateway(s) reconnected{/green-fg}`),this.screen.render(),setTimeout(()=>this.refresh(),500);else{let i=s.results.filter(n=>!n.success&&n.error).map(n=>`${n.name}: ${n.error}`).join(", ");this.w.footerText.setContent(`{red-fg}\u2717 Retry failed - ${i.substring(0,50)}...{/red-fg}`),this.screen.render()}setTimeout(()=>this.render(),3e3)}catch(s){this.w.footerText.setContent(`{red-fg}\u2717 Retry error: ${s.message.substring(0,40)}{/red-fg}`),this.screen.render(),setTimeout(()=>this.render(),3e3)}}async retryFailedWidgets(){let e=this.errorBoundaryManager.getAllErrorStates(),t=Object.entries(e).filter(([n,a])=>a?.hasError);if(t.length===0){this.w.footerText.setContent("{green-fg}\u2713 No widgets to retry{/green-fg}"),this.screen.render(),setTimeout(()=>this.render(),2e3);return}let s=t.length,i=t.map(([n])=>n).join(", ");this.w.footerText.setContent(`{yellow-fg}\u27F3 Retrying ${s} failed widget(s): ${i}{/yellow-fg}`),this.screen.render();try{this.errorBoundaryManager.clearAll(),this.widgetErrorState.clear(),await this.refresh(),this.w.footerText.setContent("{green-fg}\u2713 Widget data refreshed{/green-fg}"),this.screen.render()}catch(n){this.w.footerText.setContent(`{red-fg}\u2717 Retry error: ${n.message.substring(0,40)}{/red-fg}`),this.screen.render()}setTimeout(()=>this.render(),3e3)}recordWidgetError(e,t){if(u.warn(`Widget '${e}' error: ${t.message}`),!this.errorBoundaryManager.get(e)){let n={id:e,box:this.w[`${e}Box`]};this.errorBoundaryManager.wrap(n,{maxRetries:3,retryDelay:5e3})}let i=this.errorBoundaryManager.get(e);i&&i.showError(t.message,t),this.widgetErrorState.set(e,{hasError:!0,error:t.message,timestamp:Date.now(),retryCount:(this.widgetErrorState.get(e)?.retryCount||0)+1})}clearWidgetError(e){this.widgetErrorState.delete(e);let t=this.errorBoundaryManager.get(e);t&&t.reset()}applyTheme(){let t=ke().colors;this.w.sessBox&&(this.w.sessBox.style.border.fg=t.border.sessions),this.w.logBox&&(this.w.logBox.style.border.fg=t.border.logs),this.w.cpuBox&&(this.w.cpuBox.style.border.fg=t.border.cpu),this.w.memBox&&(this.w.memBox.style.border.fg=t.border.memory),this.w.gpuBox&&(this.w.gpuBox.style.border.fg=t.border.gpu),this.w.netBox&&(this.w.netBox.style.border.fg=t.border.network),this.w.diskBox&&(this.w.diskBox.style.border.fg=t.border.disk),this.w.sysBox&&(this.w.sysBox.style.border.fg=t.border.system),this.w.uptimeBox&&(this.w.uptimeBox.style.border.fg=t.border.uptime),this.w.gatewayBox&&(this.w.gatewayBox.style.border.fg=t.border.gateway),this.w.sessHeader&&(this.w.sessHeader.style.fg=t.text.header),this.w.sessList&&(this.w.sessList.style.fg=t.text.primary),this.w.sessCount&&(this.w.sessCount.style.fg=t.text.secondary),this.w.logContent&&(this.w.logContent.style.fg=t.text.secondary),this.w.logo&&(this.w.logo.style.fg=t.branding.logo),this.w.title&&(this.w.title.style.fg=t.branding.title),this.w.clock&&(this.w.clock.style.fg=t.branding.clock),this.w.footer&&(this.w.footer.style.bg=t.footer.bg),this.w.footer&&(this.w.footer.style.fg=t.footer.fg),this.w.footerText&&(this.w.footerText.style.fg=t.footer.fg)}togglePause(){this.isPaused=!this.isPaused,this.isPaused?clearInterval(this.timer):(this.refresh(),this.timer=setInterval(()=>this.refresh(),this.settings.refreshInterval)),this.render()}async togglePerformanceOverlay(){if(this.w.perfOverlayBox){try{await Te.transitionOut(this.screen,this.w.perfOverlayBox,{duration:150,fade:!0,scale:!0})}catch{}this.w.perfOverlayBox&&(this.w.perfOverlayBox.destroy(),delete this.w.perfOverlayBox),this.w.perfContent&&(this.w.perfContent.destroy(),delete this.w.perfContent),this.updateModalState(),this.screen.render()}else await this.showPerformanceOverlay()}showPerformanceOverlay(){let e=St.getMetrics(),t=ke().colors,s=e.current,i=e.aggregates,n=St.checkHealth(),a=`{center}{bold}PERFORMANCE METRICS{/bold}{/center}
|
|
1681
|
-
|
|
1682
|
-
`;if(!s)a+=`{red-fg}Performance monitoring is not active{/red-fg}
|
|
1683
|
-
`,a+=`Start monitoring to see metrics.
|
|
1684
|
-
`;else{a+=`{bold}Current Metrics{/bold}
|
|
1685
|
-
`;let c=s.memoryPercent>=80?"red-fg":s.memoryPercent>=60?"yellow-fg":"green-fg",d=s.cpuPercent>=80?"red-fg":s.cpuPercent>=50?"yellow-fg":"green-fg",g=s.heapPercent>=80?"red-fg":s.heapPercent>=60?"yellow-fg":"gray-fg";if(a+=` System Memory: {${c}}${s.memoryUsed}MB / ${s.memoryTotal}MB (${s.memoryPercent}%){/${c}}
|
|
1686
|
-
`,a+=` Heap Memory: {${g}}${s.heapUsed}MB / ${s.heapTotal}MB (${s.heapPercent}%){/${g}}
|
|
1687
|
-
`,a+=` CPU: {${d}}${s.cpuPercent}%{/${d}}
|
|
1688
|
-
`,a+=` Refresh Rate: ${s.refreshRate}ms
|
|
1689
|
-
`,a+=` Uptime: ${Math.floor(s.uptime/60)}m ${s.uptime%60}s
|
|
1690
|
-
`,i.avgEventLoopLag>0){let T=i.avgEventLoopLag>100?"red-fg":i.avgEventLoopLag>50?"yellow-fg":"gray-fg";a+=` Event Loop Lag: {${T}}${i.avgEventLoopLag}ms{/${T}}
|
|
1691
|
-
`}if(a+=`
|
|
1692
|
-
{bold}Averages (last ${e.history.length} samples){/bold}
|
|
1693
|
-
`,a+=` Memory: ${i.avgMemoryUsed}MB (peak: ${i.peakMemoryUsed}MB)
|
|
1694
|
-
`,a+=` CPU: ${i.avgCpuPercent}%
|
|
1695
|
-
`,i.slowOperations){a+=`
|
|
1696
|
-
{yellow-fg}{bold}\u26A0 Slow Operations:{/bold}{/yellow-fg}
|
|
1697
|
-
`;let T=i.slowOperations.split(", ");T.slice(0,3).forEach(b=>{a+=` {red-fg}\u2022 ${b}{/red-fg}
|
|
1698
|
-
`}),T.length>3&&(a+=` {gray-fg}...and ${T.length-3} more{/gray-fg}
|
|
1699
|
-
`)}if(i.totalRefreshTime>0){let T=i.totalRefreshTime>5e3?"red-fg":i.totalRefreshTime>2e3?"yellow-fg":"gray-fg";a+=`
|
|
1700
|
-
{${T}}Total refresh: ${i.totalRefreshTime}ms{/${T}}
|
|
1701
|
-
`}let p=Nt.getStatus();if(a+=`
|
|
1702
|
-
{bold}Worker Pool{/bold}
|
|
1703
|
-
`,p.enabled&&p.supported){let T=p.busyWorkers===p.totalWorkers?"yellow-fg":"green-fg";if(a+=` Status: {green-fg}enabled{/green-fg}
|
|
1704
|
-
`,a+=` Workers: {${T}}${p.busyWorkers}/${p.totalWorkers} busy{/${T}}
|
|
1705
|
-
`,a+=` Ready: ${p.readyWorkers}/${p.totalWorkers}
|
|
1706
|
-
`,p.pendingTasks>0||p.queuedTasks>0){let b=p.pendingTasks+p.queuedTasks>5?"yellow-fg":"gray-fg";a+=` Tasks: {${b}}${p.pendingTasks} pending, ${p.queuedTasks} queued{/${b}}
|
|
1707
|
-
`}}else a+=` Status: {gray-fg}${p.enabled?"unsupported":"disabled"}{/gray-fg}
|
|
1708
|
-
`;n.degraded&&(a+=`
|
|
1709
|
-
{yellow-fg}{bold}\u26A0 Performance Issues{/bold}{/yellow-fg}
|
|
1710
|
-
`,n.reasons.forEach(T=>{a+=` \u2022 {red-fg}${T}{/red-fg}
|
|
1711
|
-
`}))}a+=`
|
|
1712
|
-
{center}{gray-fg}Press p to close{/gray-fg}{/center}`,this.w.perfOverlayBox=C.box({parent:this.screen,top:"center",left:"center",width:50,height:26,border:{type:"line"},style:{border:{fg:t.brightMagenta},bg:t.black},label:" PERF "}),this.w.perfContent=C.text({parent:this.w.perfOverlayBox,top:1,left:1,width:"95%",height:"90%",content:a,style:{fg:t.white},tags:!0}),Te.transitionIn(this.screen,this.w.perfOverlayBox,{duration:150,fade:!0,scale:!0}),this.w.perfOverlayBox.focus(),this.w.perfOverlayBox.key(["q","Q","escape","p","P"],()=>{this.togglePerformanceOverlay()}),this.w.perfOverlayBox.key(["up","down","left","right","k","j","h","l"],()=>{}),this.isModalActive=!0}exportDashboard(){let e=this.settings.exportDirectory||it.homedir()+"/.openclaw/exports",t=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),s=this.settings.exportFormat||"json",i=`dashboard-${t}.${s}`,n=fi(e);if(!n.valid){u.warn("Export directory validation failed: "+n.error),this.w.footerText.setContent("Export failed: Invalid directory"),this.screen.render();return}let a=n.resolvedPath,c=a+"/"+i;try{if(Bt.existsSync(a)||Bt.mkdirSync(a,{recursive:!0}),s==="csv"){let d=`exportTime,dashboardVersion,sessionId,sessionType,model,status,runtime,tokens,cost
|
|
1713
|
-
`,g=new Date().toISOString(),p=pe;if(this.data.sessions&&this.data.sessions.length>0)for(let T of this.data.sessions){let b=[g,p,T.id||"",T.type||"",T.model||"",T.status||"",T.runtime||"",T.tokens||0,T.cost||0].map(_=>`"${String(_).replace(/"/g,'""')}"`).join(",");d+=b+`
|
|
1714
|
-
`}else{let T=[g,p,"system","system","N/A","active",this.data.systemUptime||"",0,0].map(b=>`"${String(b).replace(/"/g,'""')}"`).join(",");d+=T+`
|
|
1715
|
-
`}Bt.writeFileSync(c,d)}else{let d={exportedAt:new Date().toISOString(),dashboardVersion:pe,settings:this.settings,system:this.data.system,systemUptime:this.data.systemUptime,gatewayUptime:this.data.gatewayUptime,cpu:this.data.cpu,memory:this.data.memory,gpu:this.data.gpu,disk:this.data.disk,network:this.data.network,openclaw:this.data.openclaw,sessions:this.data.sessions,logLines:this.logLines};Bt.writeFileSync(c,JSON.stringify(d,null,2))}this.w.footerText.setContent(`{green-fg}Exported to ${i} (${s.toUpperCase()}){/green-fg}`),this.screen.render(),setTimeout(()=>this.render(),3e3)}catch(d){this.w.footerText.setContent(`{red-fg}Export failed: ${d.message}{/red-fg}`),this.screen.render(),setTimeout(()=>this.render(),5e3)}}exportSnapshot(){try{let e=kr(this.settings,{name:"Dashboard Configuration",description:`Claw Dashboard v${pe}`}),t=bt(),s=Nr("dashboard"),i=`${t}/${s}`,n=Mr(e,i);n.success?(this.w.footerText.setContent(`{green-fg}\u2713 Snapshot exported: ${s}{/green-fg}`),u.info(`Dashboard snapshot exported to: ${n.path}`)):(this.w.footerText.setContent(`{red-fg}\u2717 Snapshot failed: ${n.error}{/red-fg}`),u.warn(`Snapshot export failed: ${n.error}`))}catch(e){this.w.footerText.setContent(`{red-fg}\u2717 Snapshot error: ${e.message}{/red-fg}`),u.error(`Snapshot export error: ${e.message}`)}this.screen.render(),setTimeout(()=>this.render(),3e3)}async importSnapshot(){let e=bt(),t=$r();if(t.length===0){await this.promptForSnapshotImport();return}await this.showSnapshotPicker(t)}async promptForSnapshotImport(){this.w.snapshotPrompt=C.prompt({parent:this.screen,top:"center",left:"center",width:60,height:"shrink",border:{type:"line"},style:{border:{fg:E.cyan},bg:E.black},label:" Import Snapshot "}),this.w.snapshotPrompt.input("Enter snapshot file path:","",(e,t)=>{if(!e&&t&&t.trim()){let s=t.trim();s.startsWith("~")&&(s=it.homedir()+s.substring(1)),this.loadAndApplySnapshot(s)}this.w.snapshotPrompt.destroy(),delete this.w.snapshotPrompt,this.screen.render()}),this.screen.render()}async showSnapshotPicker(e){let t=ke().colors;this.w.snapshotPickerBox=C.box({parent:this.screen,top:"center",left:"center",width:70,height:18,border:{type:"line"},style:{border:{fg:t.brightCyan},bg:t.black},label:" IMPORT SNAPSHOT "}),C.text({parent:this.w.snapshotPickerBox,top:1,left:"center",content:"{bold}Select a snapshot to import{/bold}",style:{fg:t.brightWhite},tags:!0});let s=e.slice(0,8).map(i=>{let n=new Date(i.createdAt).toLocaleDateString(),a=i.metadata?.widgetCount||0;return`${i.name} (${n}) - ${a} widgets`});s.push("{cyan-fg}Browse for file...{/cyan-fg}"),this.w.snapshotList=C.list({parent:this.w.snapshotPickerBox,top:3,left:2,width:66,height:10,items:s,style:{fg:t.white,bg:t.black,selected:{fg:t.black,bg:t.cyan,bold:!0},item:{fg:t.white}},keys:!0,vi:!0}),C.text({parent:this.w.snapshotPickerBox,bottom:1,left:"center",content:"{gray}Enter: Import j/k: Navigate Esc: Cancel{/gray}",style:{fg:t.gray},tags:!0}),this.w.snapshotList.focus(),this.w.snapshotList.on("select",async(i,n)=>{if(n===s.length-1)this.closeSnapshotPicker(),await this.promptForSnapshotImport();else{let a=e[n];this.closeSnapshotPicker(),this.loadAndApplySnapshot(a.path)}}),this.w.snapshotList.key(["escape","q"],()=>{this.closeSnapshotPicker()}),this.screen.render()}closeSnapshotPicker(){this.w.snapshotPickerBox&&(this.w.snapshotPickerBox.destroy(),delete this.w.snapshotPickerBox,delete this.w.snapshotList,this.screen.render())}loadAndApplySnapshot(e){let t=Dr(e);if(!t.success){this.w.footerText.setContent(`{red-fg}\u2717 Import failed: ${t.error}{/red-fg}`),this.screen.render(),setTimeout(()=>this.render(),5e3);return}let s=zs(t.snapshot);this.showSnapshotConfirmation(t.snapshot,s)}showSnapshotConfirmation(e,t){let s=ke().colors;this.w.snapshotConfirmBox=C.box({parent:this.screen,top:"center",left:"center",width:60,height:14,border:{type:"line"},style:{border:{fg:s.yellow},bg:s.black},label:" CONFIRM IMPORT "}),C.text({parent:this.w.snapshotConfirmBox,top:1,left:"center",content:"{bold}Import this snapshot?{/bold}",style:{fg:s.brightYellow},tags:!0}),C.text({parent:this.w.snapshotConfirmBox,top:3,left:2,right:2,content:t,style:{fg:s.white},tags:!0}),C.text({parent:this.w.snapshotConfirmBox,bottom:2,left:"center",content:"{green-fg}y{/green-fg}: Import {red-fg}n{/red-fg}: Cancel",style:{fg:s.gray},tags:!0}),this.w.snapshotConfirmBox.key(["y","Y"],()=>{this.applySnapshot(e),this.closeSnapshotConfirmation()}),this.w.snapshotConfirmBox.key(["n","N","escape","q"],()=>{this.w.footerText.setContent("{gray-fg}Import cancelled{/gray-fg}"),this.closeSnapshotConfirmation(),setTimeout(()=>this.render(),2e3)}),this.screen.render()}closeSnapshotConfirmation(){this.w.snapshotConfirmBox&&(this.w.snapshotConfirmBox.destroy(),delete this.w.snapshotConfirmBox,this.screen.render())}applySnapshot(e){try{let t=Or(this.settings,e.settings);this.settings=t,ge(this.settings),e.settings.theme&&e.settings.theme!==Cr()&&(Ss(e.settings.theme),Zt()),this.recalculateLayout(),this.applyTheme(),this.w.footerText.setContent(`{green-fg}\u2713 Snapshot imported: ${e.name}{/green-fg}`),u.info(`Dashboard snapshot imported: ${e.name}`)}catch(t){this.w.footerText.setContent(`{red-fg}\u2717 Apply failed: ${t.message}{/red-fg}`),u.error(`Failed to apply snapshot: ${t.message}`)}this.screen.render(),setTimeout(()=>this.render(),3e3)}async toggleHelp(){this.w.helpBox?(await Te.transitionOut(this.screen,this.w.helpBox,{duration:150,fade:!0,scale:!0}),this.w.helpBox.destroy(),delete this.w.helpBox,this.w.helpContent.destroy(),delete this.w.helpContent,this.screen.render()):await this.showHelp()}showHelp(){let e=["{center}{bold}CLAW DASHBOARD - KEYBOARD SHORTCUTS{/bold}{/center}",""," {cyan-fg}q{/cyan-fg} or {cyan-fg}Ctrl+C{/cyan-fg} Quit the dashboard"," {cyan-fg}r{/cyan-fg} Force refresh all data"," {cyan-fg}p{/cyan-fg} Toggle performance metrics overlay"," {cyan-fg}P{/cyan-fg} or {cyan-fg}Space{/cyan-fg} Pause/resume auto-refresh"," {cyan-fg}o{/cyan-fg} Cycle session sort (time/tokens/idle/name)"," {cyan-fg}e{/cyan-fg} Export dashboard data (JSON/CSV)"," {cyan-fg}E{/cyan-fg} Cycle export format (JSON/CSV)"," {cyan-fg}Ctrl+S{/cyan-fg} Export config snapshot (shareable)"," {cyan-fg}Ctrl+O{/cyan-fg} Import config snapshot"," {cyan-fg}t{/cyan-fg} Cycle theme (default/dark/high-contrast/ocean)"," {cyan-fg}v{/cyan-fg} Show version info"," {cyan-fg}G{/cyan-fg} Retry gateway connection (when offline)"," {cyan-fg}X{/cyan-fg} Retry failed widgets (error recovery)"," {cyan-fg}[{/cyan-fg} or {cyan-fg}]{/cyan-fg} Previous/next page (when >6 sessions)"," {cyan-fg}?{/cyan-fg} Toggle this help panel"," {cyan-fg}s{/cyan-fg} or {cyan-fg}S{/cyan-fg} Open settings panel",""," {cyan-fg}1-9{/cyan-fg} Toggle widgets (1:CPU 2:MEM 3:GPU 4:NET 5:DISK 6:SYS 7:UP 8:HLTH 9:GATEWAY)"," {cyan-fg}Alt+1-9{/cyan-fg} Pin/unpin widget to favorites row (max 4)",""," {bold}Vi-mode Navigation:{/bold}"," {cyan-fg}h{/cyan-fg}/{cyan-fg}l{/cyan-fg} Previous/next page"," {cyan-fg}j{/cyan-fg}/{cyan-fg}k{/cyan-fg} Select next/previous session"," {cyan-fg}g{/cyan-fg} Go to first page ({cyan-fg}G{/cyan-fg} retries gateway)"," {cyan-fg}Ctrl+B{/cyan-fg}/{cyan-fg}Ctrl+F{/cyan-fg} Page up/down",""," {bold}Widget Navigation:{/bold}"," {cyan-fg}Tab{/cyan-fg} Focus next widget"," {cyan-fg}Shift+Tab{/cyan-fg} Focus previous widget",""," {bold}Favorites:{/bold}"," {cyan-fg}f{/cyan-fg} Toggle favorite on current session"," {cyan-fg}F{/cyan-fg} Show favorites only (filter)","",` {gray-fg}Export Dir: ${this.settings.exportDirectory}{/gray-fg}`,` {gray-fg}Export Format: ${this.settings.exportFormat.toUpperCase()}{/gray-fg}`,` {gray-fg}Theme: ${this.settings.theme}{/gray-fg}`,"","{center}{gray-fg}Press ? to close this help{/gray-fg}{/center}"].join(`
|
|
1716
|
-
`);this.w.helpBox=C.box({parent:this.screen,top:"center",left:"center",width:50,height:21,border:{type:"line"},style:{border:{fg:E.brightCyan},bg:E.black},label:" HELP "}),this.w.helpContent=C.text({parent:this.w.helpBox,top:1,left:1,width:"95%",height:"90%",content:e,style:{fg:E.white},tags:!0}),Te.transitionIn(this.screen,this.w.helpBox,{duration:150,fade:!0,scale:!0}),this.isModalActive=!0}async toggleCommandPalette(){this.w.commandPaletteBox?await this.closeCommandPalette():await this.showCommandPalette()}getCommandPaletteCommands(){return[{name:"Toggle Help",shortcut:"?",action:()=>this.toggleHelp(),category:"Navigation"},{name:"Open Settings",shortcut:"s",action:()=>this.toggleSettings(),category:"Navigation"},{name:"Search Sessions",shortcut:"/",action:()=>this.showSearch(),category:"Navigation"},{name:"Open Command Palette",shortcut:"Ctrl+K",action:()=>this.closeCommandPalette(),category:"Navigation"},{name:"Force Refresh",shortcut:"r",action:()=>this.refresh(),category:"Display"},{name:"Toggle Pause",shortcut:"P / Space",action:()=>this.togglePause(),category:"Display"},{name:"Cycle Theme",shortcut:"t",action:()=>this.cycleTheme(),category:"Display"},{name:"Show Theme Selector",shortcut:"T",action:()=>this.showThemeSelector(),category:"Display"},{name:"Show Version",shortcut:"v",action:()=>this.showVersionInfo(),category:"Display"},{name:"Toggle Performance Metrics",shortcut:"p",action:()=>this.togglePerformanceOverlay(),category:"Display"},{name:"Toggle CPU Widget",shortcut:"1",action:()=>this.toggleWidgetByIndex(0),category:"Widgets"},{name:"Toggle Memory Widget",shortcut:"2",action:()=>this.toggleWidgetByIndex(1),category:"Widgets"},{name:"Toggle GPU Widget",shortcut:"3",action:()=>this.toggleWidgetByIndex(2),category:"Widgets"},{name:"Toggle Network Widget",shortcut:"4",action:()=>this.toggleWidgetByIndex(3),category:"Widgets"},{name:"Toggle Disk Widget",shortcut:"5",action:()=>this.toggleWidgetByIndex(4),category:"Widgets"},{name:"Toggle System Widget",shortcut:"6",action:()=>this.toggleWidgetByIndex(5),category:"Widgets"},{name:"Toggle Uptime Widget",shortcut:"7",action:()=>this.toggleWidgetByIndex(6),category:"Widgets"},{name:"Toggle Health Widget",shortcut:"8",action:()=>this.toggleWidgetByIndex(7),category:"Widgets"},{name:"Toggle Gateway Widget",shortcut:"9",action:()=>this.toggleWidgetByIndex(8),category:"Widgets"},{name:"Toggle Widget Arrange Mode",shortcut:"w",action:()=>this.toggleWidgetArrangeMode(),category:"Widgets"},{name:"Cycle Session Sort",shortcut:"o",action:()=>this.cycleSessionSort(),category:"Sessions"},{name:"Toggle Favorite",shortcut:"f",action:()=>this.toggleFavorite(),category:"Sessions"},{name:"Show Favorites Only",shortcut:"F",action:()=>this.toggleFavoritesFilter(),category:"Sessions"},{name:"Export Dashboard Data",shortcut:"e",action:()=>this.exportDashboard(),category:"Export"},{name:"Cycle Export Format",shortcut:"E",action:()=>this.cycleExportFormat(),category:"Export"},{name:"Export Config Snapshot",shortcut:"Ctrl+S",action:()=>this.exportSnapshot(),category:"Export"},{name:"Import Config Snapshot",shortcut:"Ctrl+O",action:()=>this.importSnapshot(),category:"Export"},{name:"Retry Gateway Connection",shortcut:"G",action:()=>this.retryGatewayConnection(),category:"System"},{name:"Retry Failed Widgets",shortcut:"X",action:()=>this.retryFailedWidgets(),category:"System"},{name:"Quit Dashboard",shortcut:"q / Ctrl+C",action:()=>{clearInterval(this.timer),this.screen.destroy(),process.exit(0)},category:"System"}]}toggleWidgetByIndex(e){let t=["showWidget1","showWidget2","showWidget3","showWidget4","showWidget5","showWidget6","showWidget7","showWidget8","showWidget9"];e>=0&&e<t.length&&(this.settings[t[e]]=!this.settings[t[e]],ge(this.settings),this.recalculateLayout(),this.refresh())}async showCommandPalette(){this.w.commandPaletteBox=C.box({parent:this.screen,top:"center",left:"center",width:60,height:18,border:{type:"line"},style:{border:{fg:E.brightMagenta},bg:E.black},label:" COMMAND PALETTE (Ctrl+K) "}),this.w.commandPaletteInput=C.textbox({parent:this.w.commandPaletteBox,top:1,left:1,width:56,height:1,inputOnFocus:!0,style:{fg:E.brightWhite,bg:E.black,focus:{bg:"blue"}},placeholder:"Type to search commands..."}),this.w.commandPaletteList=C.list({parent:this.w.commandPaletteBox,top:3,left:1,width:56,height:12,style:{fg:E.white,bg:E.black,selected:{fg:E.black,bg:E.brightMagenta,bold:!0},item:{fg:E.white}},keys:!0,vi:!1,mouse:!0,scrollable:!0,scrollbar:{ch:"\u2502",style:{fg:E.brightMagenta}}}),C.text({parent:this.w.commandPaletteBox,bottom:0,left:"center",width:40,content:"{gray-fg}\u2191\u2193 Navigate \xB7 Enter Execute \xB7 Esc Close{/}",tags:!0,style:{fg:E.gray}}),this._allCommands=this.getCommandPaletteCommands(),this._filteredCommands=[...this._allCommands],this._commandPaletteQuery="",this._renderCommandPaletteList(),this.w.commandPaletteInput.on("keypress",(e,t)=>{if(t.name==="escape"){this.closeCommandPalette();return}t.name==="up"||t.name==="down"||t.name==="return"||setTimeout(()=>{this._commandPaletteQuery=this.w.commandPaletteInput.getValue().toLowerCase(),this._filterCommandPalette(),this._renderCommandPaletteList(),this.screen.render()},10)}),this.w.commandPaletteList.on("select",(e,t)=>{this._filteredCommands[t]&&this.executeCommand(this._filteredCommands[t])}),this.w.commandPaletteInput.key("return",()=>{this._filteredCommands.length>0&&this.executeCommand(this._filteredCommands[0])}),this.w.commandPaletteList.key("k",()=>{this.w.commandPaletteList.selected>0&&(this.w.commandPaletteList.up(),this.screen.render())}),this.w.commandPaletteList.key("j",()=>{this.w.commandPaletteList.selected<this.w.commandPaletteList.items.length-1&&(this.w.commandPaletteList.down(),this.screen.render())}),this.w.commandPaletteList.key("g",()=>{this.w.commandPaletteList.select(0),this.screen.render()}),this.w.commandPaletteList.key("G",()=>{this.w.commandPaletteList.select(this.w.commandPaletteList.items.length-1),this.screen.render()}),this.w.commandPaletteList.key("escape",()=>{this.closeCommandPalette()}),await Te.transitionIn(this.screen,this.w.commandPaletteBox,{duration:150,fade:!0,scale:!0}),this.isModalActive=!0,this.w.commandPaletteInput.focus(),this.screen.render()}_filterCommandPalette(){let e=this._commandPaletteQuery;if(!e){this._filteredCommands=[...this._allCommands];return}this._filteredCommands=this._allCommands.filter(t=>{let s=t.name.toLowerCase().includes(e),i=t.shortcut.toLowerCase().includes(e),n=t.category.toLowerCase().includes(e);return s||i||n})}_renderCommandPaletteList(){let e=this._filteredCommands.map(t=>`{cyan-fg}${t.shortcut.padEnd(12)}{/cyan-fg} ${t.name}`);e.length===0&&e.push("{gray-fg}No commands found{/gray-fg}"),this.w.commandPaletteList.setItems(e),this._filteredCommands.length>0&&this.w.commandPaletteList.select(0)}async executeCommand(e){await this.closeCommandPalette(),setTimeout(()=>{e.action&&typeof e.action=="function"&&e.action()},200)}async closeCommandPalette(){if(this.w.commandPaletteBox){this._commandPaletteClosing=!0;try{await Te.transitionOut(this.screen,this.w.commandPaletteBox,{duration:150,fade:!0,scale:!0}),this.w.commandPaletteBox&&(this.w.commandPaletteBox.destroy(),delete this.w.commandPaletteBox,delete this.w.commandPaletteInput,delete this.w.commandPaletteList,this.updateModalState(),this.screen.render())}finally{this._commandPaletteClosing=!1}}}async toggleSettings(){this.w.settingsBox?await this.closeSettings():await this.showSettings()}async closeSettings(){if(this.w.settingsBox){this._settingsClosing=!0;try{await Te.transitionOut(this.screen,this.w.settingsBox,{duration:150,fade:!0,scale:!0}),this.w.settingsBox&&(this.w.settingsBox.destroy(),delete this.w.settingsBox,delete this.w.settingsList,this.updateModalState(),this.screen.render())}finally{this._settingsClosing=!1}}}async showSettings(){let t=this.settings.refreshInterval/1e3;this.w.settingsBox=C.box({parent:this.screen,top:"center",left:"center",width:56,height:19,border:{type:"line"},style:{border:{fg:E.brightGreen},bg:E.black},label:" SETTINGS "}),C.text({parent:this.w.settingsBox,top:1,left:"center",content:"{bold}SETTINGS{/bold}",style:{fg:E.brightWhite},tags:!0}),C.text({parent:this.w.settingsBox,top:3,left:2,content:"\u2191/\u2193 Navigate Enter Toggle s/Esc Close",style:{fg:E.cyan},tags:!0});let s=()=>[`Theme: ${this.settings.theme||"auto"}`,`Refresh Interval: ${Math.round(this.settings.refreshInterval/1e3)}s (1s/2s/5s/10s)`,`1 CPU: ${this.settings.showWidget1?"ON":"OFF"}`,`2 Memory: ${this.settings.showWidget2?"ON":"OFF"}`,`3 GPU: ${this.settings.showWidget3?"ON":"OFF"}`,`4 Network: ${this.settings.showWidget4?"ON":"OFF"}`,`5 Disk: ${this.settings.showWidget5?"ON":"OFF"}`,`6 System: ${this.settings.showWidget6?"ON":"OFF"}`,`7 Uptime: ${this.settings.showWidget7?"ON":"OFF"}`,`8 Data Health: ${this.settings.showWidget8?"ON":"OFF"}`,`Log Level Filter: ${this.settings.logLevelFilter.toUpperCase()}`,`9 Export Dir: ${(this.settings.exportDirectory||"").replace(it.homedir()+"/","~/")}`,`Widget Sizes: ${Object.values(this.settings.widgetSizes||{}).every(i=>i==="small")?"ALL SMALL":Object.values(this.settings.widgetSizes||{}).every(i=>i==="large")?"ALL LARGE":Object.values(this.settings.widgetSizes||{}).every(i=>i==="wide")?"ALL WIDE":"MEDIUM/ MIXED"}`,`Perf Metrics: ${this.settings.showPerformanceMetrics?"ON":"OFF"}`,`Version Check: ${Math.round((this.settings.versionCheckInterval||432e5)/36e5)}h (off/1h/6h/12h/24h)`,`Plugin Config: ${Object.keys(this.settings.plugins||{}).length} plugins`];this.w.settingsList=C.list({parent:this.w.settingsBox,top:5,left:2,width:52,height:10,items:s(),style:{fg:E.white,bg:E.black,selected:{fg:E.black,bg:E.yellow,bold:!0},item:{fg:E.white}},keys:!0,vi:!1,mouse:!1,scrollable:!1}),C.text({parent:this.w.settingsBox,bottom:1,left:"center",content:"Changes auto-saved",style:{fg:E.gray},tags:!0}),this.w.settingsList.on("select",(i,n)=>{this.w.settingsList&&(this.toggleSettingOption(n),this.w.settingsList&&(this.w.settingsList.setItems(s()),this.w.settingsList&&(this.w.settingsList.select(n),this.screen.render())))}),this.w.settingsList.key(["return","enter"," "],()=>{if(!this.w.settingsList)return;let i=this.w.settingsList.selected;this.toggleSettingOption(i),this.w.settingsList&&(this.w.settingsList.setItems(s()),this.w.settingsList&&(this.w.settingsList.select(i),this.screen.render()))}),this.w.settingsList.key(["escape"],()=>{this.closeSettings()}),this.w.settingsList.key("k",()=>{this.w.settingsList&&this.w.settingsList.selected>0&&(this.w.settingsList.up(),this.screen.render())}),this.w.settingsList.key("j",()=>{this.w.settingsList&&this.w.settingsList.selected<this.w.settingsList.items.length-1&&(this.w.settingsList.down(),this.screen.render())}),this.w.settingsList.key("g",()=>{this.w.settingsList&&(this.w.settingsList.select(0),this.screen.render())}),this.w.settingsList.key("G",()=>{this.w.settingsList&&(this.w.settingsList.select(this.w.settingsList.items.length-1),this.screen.render())}),this.w.settingsList.key("C-b",()=>{if(!this.w.settingsList)return;let n=Math.max(0,this.w.settingsList.selected-5);this.w.settingsList.select(n),this.screen.render()}),this.w.settingsList.key("C-f",()=>{if(!this.w.settingsList)return;let n=Math.min(this.w.settingsList.items.length-1,this.w.settingsList.selected+5);this.w.settingsList.select(n),this.screen.render()}),this.w.settingsList.focus(),await Te.transitionIn(this.screen,this.w.settingsBox,{duration:150,fade:!0,scale:!0}),this.isModalActive=!0}updateAlertDisplay(){let e=Ts.getActiveAlerts(),t=Ts.getAlertCounts();if(t.total===0)this.w.alertBox&&this.w.alertBox.hide();else if(this.w.alertBox){this.w.alertBox.show();let s=e.filter(a=>a.level===Ts.AlertLevel.CRITICAL),i=e.filter(a=>a.level===Ts.AlertLevel.WARNING),n="";s.length>0&&(n+="{red-fg}{bold}CRITICAL:{/} ",n+=s.map(a=>`${a.type.toUpperCase()} ${a.value}%`).join(" | ")),i.length>0&&(n&&(n+=`
|
|
1717
|
-
`),n+="{yellow-fg}WARNING:{/} ",n+=i.map(a=>`${a.type.toUpperCase()} ${a.value}%`).join(" | ")),this.w.alertContent.setContent(n),s.length>0?this.w.alertBox.style.border.fg=E.red:i.length>0&&(this.w.alertBox.style.border.fg=E.yellow)}this.w.alertBox&&(t.total>0&&!this.w.alertBox._isVisible?this.recalculateLayout():t.total===0&&this.w.alertBox._isVisible&&this.recalculateLayout())}toggleSettingOption(e){let t=!1;switch(e){case 0:let s=["auto","default","dark","high-contrast","ocean"],i=this.settings.theme||"auto",n=s.indexOf(i);this.settings.theme=s[(n+1)%s.length],Ss(this.settings.theme),Zt();break;case 1:let a=w.REFRESH_INTERVALS.OPTIONS,c=Number(this.settings.refreshInterval)||2e3,d=a.indexOf(c);d===-1&&(d=a.findIndex(I=>I>c)-1,d<0&&(d=a.length-1)),this.settings.refreshInterval=a[(d+1)%a.length],clearInterval(this.timer),this.timer=setInterval(()=>this.refresh(),this.settings.refreshInterval);break;case 2:this.settings.showWidget1=!this.settings.showWidget1,this.recalculateLayout();break;case 3:this.settings.showWidget2=!this.settings.showWidget2,this.recalculateLayout();break;case 4:this.settings.showWidget3=!this.settings.showWidget3,this.recalculateLayout();break;case 5:this.settings.showWidget4=!this.settings.showWidget4,this.recalculateLayout();break;case 6:this.settings.showWidget5=!this.settings.showWidget5,this.recalculateLayout();break;case 7:this.settings.showWidget6=!this.settings.showWidget6,this.recalculateLayout();break;case 8:this.settings.showWidget7=!this.settings.showWidget7,this.recalculateLayout();break;case 9:this.settings.showWidget8=!this.settings.showWidget8,this.recalculateLayout();break;case 10:let g=["all","debug","info","warn","error"],p=g.indexOf(this.settings.logLevelFilter);this.settings.logLevelFilter=g[(p+1)%g.length];break;case 11:let T=[it.homedir()+"/.openclaw/exports",it.homedir()+"/Downloads",it.homedir()+"/Desktop","custom"],b=this.settings.exportDirectory||it.homedir()+"/.openclaw/exports",_=T.indexOf(b);_===-1&&(_=0);let v=(_+1)%T.length;if(v===3){this.w.customPathPrompt=C.prompt({parent:this.screen,top:"center",left:"center",width:50,height:"shrink",border:{type:"line"},style:{border:{fg:E.cyan},bg:E.black},label:" Custom Export Path "}),this.w.customPathPrompt.input("Enter custom export path (~ for home):",b,(I,G)=>{if(!I&&G&&G.trim()){let W=G.trim();W.startsWith("~")&&(W=it.homedir()+W.substring(1));let U=fi(W);U.valid?(this.settings.exportDirectory=U.resolvedPath,ge(this.settings)):u.warn("Invalid custom export path: "+U.error)}this.w.customPathPrompt.destroy(),this.w.settingsList&&(this.w.settingsList.setItems(getSettingsItems()),this.screen.render())}),t=!0;break}else this.settings.exportDirectory=T[v];break;case 12:let S=["small","medium","large","wide"],M=this.settings.widgetSizes?.cpu||"medium",j=S.indexOf(M),k=S[(j+1)%S.length];this.settings.widgetSizes={cpu:k,mem:k,gpu:k,net:k,disk:k,sys:k,uptime:k,health:k,gateway:k},this.recalculateLayout();break;case 13:this.settings.showPerformanceMetrics=!this.settings.showPerformanceMetrics;break;case 14:let F=[0,36e5,216e5,432e5,864e5],ee=this.settings.versionCheckInterval||432e5,D=F.indexOf(ee);D===-1&&(D=3);let O=(D+1)%F.length;this.settings.versionCheckInterval=F[O];break;case 15:this.showPluginConfigEditor(),t=!0;break}t||ge(this.settings),this.screen.render()}async showPluginConfigEditor(){this.settings.plugins||(this.settings.plugins={});let e=Object.keys(this.settings.plugins),t=e.length>0;if(this.w.pluginConfigBox=C.box({parent:this.screen,top:"center",left:"center",width:70,height:20,border:{type:"line"},style:{border:{fg:E.brightMagenta},bg:E.black},label:" PLUGIN CONFIGURATION "}),C.text({parent:this.w.pluginConfigBox,top:1,left:"center",content:"{bold}CONFIGURE PLUGINS{/bold}",style:{fg:E.brightWhite},tags:!0}),!t)C.text({parent:this.w.pluginConfigBox,top:5,left:"center",content:`No plugins configured yet.
|
|
1718
|
-
|
|
1719
|
-
Plugins will appear here when configured.`,style:{fg:E.gray},tags:!0}),C.text({parent:this.w.pluginConfigBox,bottom:2,left:"center",content:"{gray}Press Esc or q to close{/gray}",style:{fg:E.gray},tags:!0}),this.w.pluginConfigBox.key(["escape","q","Q"],()=>{this.closePluginConfigEditor()});else{let s=e.map(i=>{let n=this.settings.plugins[i],a=Object.keys(n||{}).length;return`${i} (${a} settings)`});s.push("{cyan-fg}+ Add new plugin config{/cyan-fg}"),this.w.pluginConfigList=C.list({parent:this.w.pluginConfigBox,top:3,left:2,width:66,height:12,items:s,style:{fg:E.white,bg:E.black,selected:{fg:E.black,bg:E.cyan,bold:!0},item:{fg:E.white}},keys:!0,vi:!1,mouse:!1,scrollable:!0}),C.text({parent:this.w.pluginConfigBox,bottom:2,left:"center",content:"{gray}Enter to edit, d to delete, Esc to close{/gray}",style:{fg:E.gray},tags:!0}),this.w.pluginConfigList.on("select",(i,n)=>{if(n===e.length)this.showAddPluginDialog();else{let a=e[n];this.editPluginConfig(a)}}),this.w.pluginConfigList.key(["d","D"],()=>{let i=this.w.pluginConfigList.selected;if(i<e.length){let n=e[i];this.deletePluginConfig(n)}}),this.w.pluginConfigList.key(["escape","q","Q"],()=>{this.closePluginConfigEditor()}),this.w.pluginConfigList.focus()}await Te.transitionIn(this.screen,this.w.pluginConfigBox,{duration:150,fade:!0,scale:!0}),this.isModalActive=!0}async closePluginConfigEditor(){this.w.pluginConfigBox&&(await Te.transitionOut(this.screen,this.w.pluginConfigBox,{duration:150,fade:!0,scale:!0}),this.w.pluginConfigBox.destroy(),delete this.w.pluginConfigBox,delete this.w.pluginConfigList,this.isModalActive=!1,this.screen.render())}async showAddPluginDialog(){this.w.pluginIdInput=C.prompt({parent:this.screen,top:"center",left:"center",width:50,height:"shrink",border:{type:"line"},style:{border:{fg:E.cyan},bg:E.black},label:" New Plugin ID "}),this.w.pluginIdInput.input("Enter plugin ID (e.g., my-widget):","",(e,t)=>{if(!e&&t&&t.trim()){let s=t.trim();this.settings.plugins||(this.settings.plugins={}),this.settings.plugins[s]={},ge(this.settings),this.closePluginConfigEditor(),setImmediate(()=>{this.showPluginConfigEditor(),setImmediate(()=>this.editPluginConfig(s))})}else this.w.pluginIdInput.destroy(),delete this.w.pluginIdInput,this.screen.render()})}async editPluginConfig(e){let t=this.settings.plugins[e]||{},s=JSON.stringify(t,null,2);this.w.pluginEditBox=C.box({parent:this.screen,top:"center",left:"center",width:70,height:18,border:{type:"line"},style:{border:{fg:E.brightCyan},bg:E.black},label:` EDIT: ${e} `}),C.text({parent:this.w.pluginEditBox,top:1,left:"center",content:"{bold}EDIT PLUGIN CONFIGURATION{/bold}",style:{fg:E.brightWhite},tags:!0}),this.w.pluginTextarea=C.textarea({parent:this.w.pluginEditBox,top:3,left:2,width:66,height:11,content:s,style:{fg:E.white,bg:E.black,focus:{fg:E.white,bg:E.black}},border:{type:"line",fg:E.gray},keys:!0,vi:!0,mouse:!0,scrollable:!0,inputOnFocus:!0}),C.text({parent:this.w.pluginEditBox,bottom:1,left:"center",content:"{gray}Ctrl+S to save, Esc to cancel{/gray}",style:{fg:E.gray},tags:!0}),this.w.pluginTextarea.key(["C-s"],()=>{try{let i=this.w.pluginTextarea.getValue(),n=JSON.parse(i);this.settings.plugins[e]=n,ge(this.settings),this.closePluginEditBox(),this.closePluginConfigEditor(),setImmediate(()=>this.showPluginConfigEditor())}catch(i){this.w.pluginTextarea.setValue(content+`
|
|
1720
|
-
|
|
1721
|
-
/* ERROR: Invalid JSON - `+i.message+" */"),this.screen.render()}}),this.w.pluginTextarea.key(["escape"],()=>{this.closePluginEditBox()}),this.w.pluginTextarea.focus(),this.screen.render(),await Te.transitionIn(this.screen,this.w.pluginEditBox,{duration:150,fade:!0,scale:!0})}async closePluginEditBox(){this.w.pluginEditBox&&(await Te.transitionOut(this.screen,this.w.pluginEditBox,{duration:150,fade:!0,scale:!0}),this.w.pluginEditBox.destroy(),delete this.w.pluginEditBox,delete this.w.pluginTextarea,this.screen.render())}async deletePluginConfig(e){this.w.deleteConfirm=C.question({parent:this.screen,top:"center",left:"center",width:50,height:"shrink",border:{type:"line"},style:{border:{fg:E.red},bg:E.black},label:" Confirm Delete "}),this.w.deleteConfirm.ask(`Delete config for "${e}"?`,(t,s)=>{s&&(delete this.settings.plugins[e],ge(this.settings)),this.w.deleteConfirm.destroy(),delete this.w.deleteConfirm,this.closePluginConfigEditor(),setImmediate(()=>this.showPluginConfigEditor())})}showSessionDetail(){let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.min(6,e?.length||0);if(!e||e.length===0||this.selectedSessionIndex<0||this.selectedSessionIndex>=t)return;let s=this.paginationOffset*6+this.selectedSessionIndex,i=e[s];this.w.detailBox=C.box({parent:this.screen,top:"center",left:"center",width:70,height:14,border:{type:"line"},style:{border:{fg:E.brightCyan},bg:E.black},label:" SESSION DETAIL "});let n=i.updatedAt?Math.floor((Date.now()-i.updatedAt)/1e3/60):0,a=n>0?`${n}m`:"<1m",c=i.sessionId||i.key,g=this.settings.favorites&&this.settings.favorites[c]?"{yellow-fg}\u2605 Favorite{/yellow-fg}":"{gray-fg}\u2606 Not favorite{/gray-fg}",p=[`{bold}Session ID:{/bold} ${i.sessionId||i.key}`,`{bold}Agent:{/bold} ${i.displayName||"unknown"}`,`{bold}Channel:{/bold} ${i.channel||"unknown"}`,`{bold}Model:{/bold} ${i.model||"unknown"}`,`{bold}Kind:{/bold} ${i.kind||"other"}`,`{bold}Tokens:{/bold} ${i.totalTokens||0} total, ${i.contextTokens||0} context`,`{bold}Idle:{/bold} ${a}`,`{bold}Favorite:{/bold} ${g}`,`{bold}Status:{/bold} ${i.abortedLastRun?"{red-fg}Aborted{/red-fg}":"{green-fg}Active{/green-fg}"}`,"","{center}{gray-fg}Press 'q' or 'Esc' to close{/gray-fg}{/center}"].join(`
|
|
1722
|
-
`);C.text({parent:this.w.detailBox,top:1,left:1,width:"95%",height:"90%",content:p,style:{fg:E.white},tags:!0}),this.w.detailBox.key(["escape","q","Q"],()=>{this.closeSessionDetail()}),Te.transitionIn(this.screen,this.w.detailBox,{duration:150,fade:!0,scale:!0}),this.isModalActive=!0}async closeSessionDetail(){this.w.detailBox&&(await Te.transitionOut(this.screen,this.w.detailBox,{duration:150,fade:!0,scale:!0}),this.w.detailBox&&(this.w.detailBox.destroy(),delete this.w.detailBox,this.updateModalState(),this.screen.render()))}updateModalState(){this.isModalActive=!!(this.w.settingsBox||this.w.detailBox||this.w.searchBox||this.w.helpBox||this.w.commandPaletteBox||this.w.snapshotPickerBox||this.w.snapshotConfirmBox||this.w.pluginConfigBox||this.w.pluginEditBox||this.w.deleteConfirm||this.w.customPathPrompt)}resetModalState(){this.isModalActive=!1,this._settingsClosing=!1,this._commandPaletteClosing=!1}toggleFavorite(){let e=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,t=Math.min(6,e?.length||0);if(!e||e.length===0||this.selectedSessionIndex<0||this.selectedSessionIndex>=t)return;let s=this.paginationOffset*6+this.selectedSessionIndex,i=e[s],n=i.sessionId||i.key;this.settings.favorites||(this.settings.favorites={}),this.settings.favorites[n]?delete this.settings.favorites[n]:this.settings.favorites[n]=!0,ge(this.settings),this.render()}toggleFavoritesFilter(){this.showFavoritesOnly=!this.showFavoritesOnly,this.settings.showFavoritesOnly=this.showFavoritesOnly,ge(this.settings),this.showFavoritesOnly?this.filteredSessions=this.data.sessions.filter(e=>{let t=e.sessionId||e.key;return this.settings.favorites&&this.settings.favorites[t]}):this.sessionSearchQuery?this.filterSessions():this.filteredSessions=[],this.selectedSessionIndex=0,this.paginationOffset=0,this.render()}showSearch(){this.isSearchMode||this.w.searchBox||(this.isSearchMode=!0,this.isModalActive=!0,this.w.searchBox=C.box({parent:this.screen,bottom:1,left:0,width:"100%",height:3,border:{type:"line"},style:{border:{fg:E.brightYellow},bg:E.black},label:" SEARCH "}),this.w.searchInput=C.textbox({parent:this.w.searchBox,top:1,left:1,width:"95%",height:1,inputOnFocus:!0,style:{fg:E.brightWhite,bg:E.black}}),this.w.searchInput.on("keypress",(e,t)=>{if(t.name==="escape"){this.closeSearch();return}if(t.name==="return"){this.closeSearch();return}setTimeout(()=>{this.sessionSearchQuery=this.w.searchInput.getValue().toLowerCase(),this.settings.sessionSearchQuery=this.sessionSearchQuery,ge(this.settings),this.filterSessions(),this.screen.render()},10)}),this.sessionSearchQuery&&this.w.searchInput.setValue(this.sessionSearchQuery),this.w.searchInput.focus(),Te.transitionIn(this.screen,this.w.searchBox,{duration:150,fade:!0,slide:!0,slideDirection:"up"}))}async closeSearch(){if(this.w.searchBox){try{await Te.transitionOut(this.screen,this.w.searchBox,{duration:150,fade:!0,slide:!0,slideDirection:"down"})}catch{}this.w.searchBox&&(this.w.searchBox.destroy(),delete this.w.searchBox,delete this.w.searchInput),this.isSearchMode=!1,this.sessionSearchQuery="",this.settings.sessionSearchQuery="",ge(this.settings),this.filteredSessions=[],this.selectedSessionIndex=0,this.paginationOffset=0,this.updateModalState(),this.refresh(),this.screen.render()}}filterSessions(){if(!this.data.sessions||this.data.sessions.length===0){this.filteredSessions=[],this.selectedSessionIndex=0,this.paginationOffset=0;return}if(!this.sessionSearchQuery){this.filteredSessions=[],this.selectedSessionIndex=0,this.paginationOffset=0;return}this.filteredSessions=this.data.sessions.filter(e=>`${e.sessionId||e.key} ${e.displayName||""} ${e.channel||""} ${e.model||""} ${e.kind||""}`.toLowerCase().includes(this.sessionSearchQuery))}async fetchSessions(){try{let{sessions:e,stats:t}=await Pe.fetchAllSessions();return this.data.gatewayStats=t,this.corruptedSessionsCount=0,t.totalEndpoints>0&&t.reachableEndpoints===0&&this.shouldAutoRetryGateway()&&(u.info("All gateways unreachable - triggering auto-retry"),this.triggerAutoRetry()),e}catch(e){return u.warn("Failed to fetch sessions from gateways: "+e.message),this.data.gatewayStats={totalEndpoints:0,reachableEndpoints:0,error:e.message},this.shouldAutoRetryGateway()&&(u.info("Gateway fetch failed - triggering auto-retry"),this.triggerAutoRetry()),[]}}shouldAutoRetryGateway(){let e=this.settings?.autoRetry||{};if(e.enabled===!1)return!1;let t=Date.now(),s=this._lastGatewayAutoRetry||0,i=e.intervalMs||3e4,n=i;if(e.exponentialBackoff!==!1){let a=Pe.getTotalFailCount(),c=e.consecutiveFailureThreshold||3;if(a>=c){let d=e.backoffMultiplier||2,g=e.maxBackoffIntervalMs||3e5,p=Math.max(0,a-c+1);n=Math.min(i*Math.pow(d,p),g)}}return t-s>=n?(this._lastGatewayAutoRetry=t,this._lastAutoRetryInterval=n,!0):!1}async triggerAutoRetry(){try{if(this.w.footerText){let t=this._lastAutoRetryInterval,s=t?` (${Math.round(t/1e3)}s)`:"";this.w.footerText.setContent(`{yellow-fg}\u27F3 Auto-retrying gateways...${s}{/yellow-fg}`),this.screen.render()}let e=await Pe.forceRetry();if(e.successful>0){u.info(`Auto-retry successful: ${e.successful}/${e.attempted} gateways reconnected`);let t=this.settings?.autoRetry||{};t.resetAfterSuccess!==!1&&t.exponentialBackoff!==!1&&(Pe.clearAllFailCounts(),u.debug("Reset gateway failure counts after successful auto-retry")),setTimeout(()=>this.refresh(),500)}else u.debug("Auto-retry completed but no gateways reconnected")}catch(e){u.warn("Auto-retry failed: "+e.message)}}async start(e){let t=e||(()=>{});t(15,"Initializing database..."),await Cs.initDatabase(),t(25,"Cleaning up old data..."),Cs.cleanupOldData(30),t(35,"Initializing gateway..."),Pe.init(this.settings),t(45,"Starting performance monitor..."),St.start(),t(55,"Starting workers..."),Ka(Nt),t(65,"Setting up config watcher..."),this.startConfigWatcher(),we.watch&&(t(75,"Setting up plugin watcher..."),this.startPluginWatcher()),t(85,"Fetching initial data..."),await this.refresh(),t(95,"Starting refresh timer..."),this.timer=setInterval(()=>this.refresh(),this.settings.refreshInterval),this.autoSaveManager.start(),t(100,"Ready!")}startConfigWatcher(){try{this.configWatcher=Ea(Nn,e=>this.handleSettingsHotReload(e),{debounceMs:500}),this.configWatcher&&u.info("ConfigWatcher: Hot-reload enabled for settings")}catch(e){u.warn(`ConfigWatcher: Failed to start watching settings: ${e.message}`)}}stopConfigWatcher(){this.configWatcher&&(this.configWatcher.unwatchAll(),this.configWatcher=null,u.info("ConfigWatcher: Hot-reload disabled"))}handleSettingsHotReload(e){try{u.info("ConfigWatcher: Processing settings hot-reload");let t=Mt.validateSettings(e);if(!t.valid){u.warn(`ConfigWatcher: Invalid settings detected, ignoring reload: ${t.errors?.join(", ")}`);return}let s={...this.settings};this.settings=t.value,s.refreshInterval!==this.settings.refreshInterval&&(clearInterval(this.timer),this.currentRefreshInterval=this.settings.refreshInterval,this.timer=setInterval(()=>this.refresh(),this.settings.refreshInterval),u.info(`ConfigWatcher: Refresh interval updated to ${this.settings.refreshInterval}ms`)),s.theme!==this.settings.theme&&(Bi(this.settings.theme),this.applyTheme(),u.info(`ConfigWatcher: Theme changed to ${this.settings.theme}`)),(s.showWidget1!==this.settings.showWidget1||s.showWidget2!==this.settings.showWidget2||s.showWidget3!==this.settings.showWidget3||s.showWidget4!==this.settings.showWidget4||s.showWidget5!==this.settings.showWidget5||s.showWidget6!==this.settings.showWidget6||s.showWidget7!==this.settings.showWidget7||s.showWidget8!==this.settings.showWidget8)&&(this._previousVisibleState=null,this.recalculateLayout(),u.info("ConfigWatcher: Widget visibility updated, layout recalculated")),s.logLevelFilter!==this.settings.logLevelFilter&&u.info(`ConfigWatcher: Log level filter changed to ${this.settings.logLevelFilter}`),JSON.stringify(s.gatewayEndpoints)!==JSON.stringify(this.settings.gatewayEndpoints)&&(Pe.init(this.settings),u.info("ConfigWatcher: Gateway endpoints updated"));try{this.screen.render()}catch(n){u.warn(`ConfigWatcher: Render error after reload: ${n.message}`)}u.info("ConfigWatcher: Settings hot-reload complete")}catch(t){u.error(`ConfigWatcher: Error handling settings reload: ${t.message}`)}}startPluginWatcher(){try{let e=new Zr;this.pluginReloadManager=new ei({widgetLoader:e,pluginsDir:w.PATHS.PLUGINS_DIR,debounceMs:300,autoReload:!0,showNotifications:!0}),this.pluginReloadManager.addHook("afterReload",({id:s,loadTime:i,isNew:n})=>{let a=n?"loaded":"reloaded";u.info(`Plugin '${s}' ${a} successfully in ${i}ms`),this.showNotification&&this.showNotification(`Plugin '${s}' ${a}`,"info")}),this.pluginReloadManager.addHook("onError",({id:s,error:i,type:n})=>{u.error(`Plugin '${s}' hot-reload error (${n}): ${i.message}`),this.showNotification&&this.showNotification(`Plugin '${s}' reload failed: ${i.message}`,"error")}),this.pluginReloadManager.start()?u.info("PluginWatcher: Hot-reload enabled for plugins"):u.warn("PluginWatcher: Failed to start watching plugins")}catch(e){u.warn(`PluginWatcher: Failed to start plugin watcher: ${e.message}`)}}stopPluginWatcher(){this.pluginReloadManager&&(this.pluginReloadManager.stop(),this.pluginReloadManager=null,u.info("PluginWatcher: Hot-reload disabled"))}updateHistory(e,t){this.history.cpu.push(e),this.history.cpu.shift(),this.history.memory.push(t),this.history.memory.shift()}updateAdaptiveRefresh(){let e=Date.now(),t=0;if(this.data.sessions&&this.data.sessions.length>0)for(let n of this.data.sessions)(n.updatedAt?e-n.updatedAt:ol+1)<ol&&t++;let s=this.activeAgentCount>0;this.activeAgentCount=t;let i=t>0?bf:Sf;this.currentRefreshInterval!==i&&(this.currentRefreshInterval=i,this.timer&&(clearInterval(this.timer),this.timer=setInterval(()=>this.refresh(),this.currentRefreshInterval)),this.lastActivityTime=e)}async refresh(){let e=Date.now(),t=e-this.lastTime,s=e,i={},n=[],a=async(p,T,b=5e3)=>{let _=Date.now();try{let v=await Promise.race([T(),new Promise((M,j)=>setTimeout(()=>j(new Error(`${p} timeout`)),b))]),S=Date.now()-_;return i[p]=S,S>1e3&&n.push(`${p}(${S}ms)`),v}catch(v){let S=Date.now()-_;throw i[p]=S,n.push(`${p}(${S}ms,error:${v.message})`),v}},c=this.getVisibleWidgets(),g=Nt.getStatus().degradation?.level||"none";try{let p=c.cpu&&this.shouldWidgetUpdate("cpu",e),T=c.memory&&this.shouldWidgetUpdate("memory",e);if(p?.shouldUpdate||T?.shouldUpdate)try{let[v,S]=await a("CPU/Memory",()=>Promise.all([xe.getCpuData(),xe.getMemoryData()]),3e3);this.data.cpu=v.cpus.map(j=>j.load),this.data.cpuAvg=v.currentLoad;let M=S.available?S.total-S.available:S.used;this.data.memory={usedGB:(M/1024**3).toFixed(1),totalGB:(S.total/1024**3).toFixed(1),percent:Math.round(M/S.total*100),cachedGB:((S.used-M)/1024**3).toFixed(1)},this.updateHistory(this.data.cpuAvg,this.data.memory.percent),this.dataTimestamps.cpu=e,this.dataTimestamps.memory=e,this.recordWidgetUpdate("cpu",e),this.recordWidgetUpdate("memory",e)}catch(v){u.warn(`CPU/Memory fetch failed: ${v.message}`),this.data.cpu=this.data.cpu||[],this.data.cpuAvg=this.data.cpuAvg||0,this.data.memory=this.data.memory||{usedGB:"0",totalGB:"0",percent:0}}if(c.system||c.uptime)try{let v=await a("System",()=>xe.getSystemData(),2e3),S=v.os,M=v.ver,j=v.time;this.data.system=`${S.distro||"macOS"} ${S.release} (${S.arch}) Node v${M.node}`,this.data.systemUptime=j.uptime,this.dataTimestamps.system=e,this.recordWidgetUpdate("system",e),this.recordWidgetUpdate("uptime",e)}catch(v){u.warn(`System data fetch failed: ${v.message}`),this.data.system=this.data.system||"System unavailable",this.data.systemUptime=this.data.systemUptime||0}if(c.disk)try{let v=await a("Disk",()=>xe.getDiskData(),3e3),S=v.find(M=>M.mount==="/")||v[0];S&&(this.data.disk={usedGB:(S.used/1024**3).toFixed(1),availableGB:(S.available/1024**3).toFixed(1),totalGB:(S.size/1024**3).toFixed(1),percent:Math.round(S.use),mount:S.mount,fs:S.fs},this.dataTimestamps.disk=e,this.recordWidgetUpdate("disk",e))}catch(v){u.warn(`Disk fetch failed: ${v.message}`),this.data.disk=this.data.disk||null}if(c.cpu||c.memory||c.disk)try{let v=Math.round(this.data.cpuAvg||0),S=this.data.memory?.percent||0,M=this.data.disk?.percent||0;Ts.checkAllMetrics({cpu:v,memory:S,disk:M}).length>0&&this.updateAlertDisplay()}catch{}try{this.data.containerEnv=await oi.detectContainerEnv()}catch(v){u.warn(`Container detection failed: ${v.message}`),this.data.containerEnv=this.data.containerEnv||null}if(c.gpu)try{let v=kf(),S;v==="linux"?S=Of():v==="win32"?S=Df():S=Lf(),this.data.gpu=await a("GPU",()=>S,5e3),this.dataTimestamps.gpu=e,this.recordWidgetUpdate("gpu",e)}catch(v){u.warn(`GPU fetch failed: ${v.message}`),this.data.gpu=this.data.gpu||null}if(c.network)try{let v=await a("Network",()=>xe.getNetworkData(),3e3),S=v.find(M=>M.operstate==="up"&&!M.internal)||v[0];if(S){let M=Date.now(),j=this.lastNetStats&&this.data.network&&this.data.network.interface!==S.iface,k=this.lastNetTime&&this.lastNetStats&&(S.rx_bytes<this.lastNetStats.rx_bytes||S.tx_bytes<this.lastNetStats.tx_bytes),F=j||k;if(F&&(j?u.info(`Network interface changed: ${this.data.network.interface} -> ${S.iface}`):k&&u.info("Network counters reset or overflow detected"),this.history.netRx=new Array(w.HISTORY.NETWORK_LENGTH).fill(0),this.history.netTx=new Array(w.HISTORY.NETWORK_LENGTH).fill(0)),this.lastNetTime&&this.lastNetStats&&!F){let ee=(M-this.lastNetTime)/1e3,D=Math.max(0,S.rx_bytes-this.lastNetStats.rx_bytes),O=Math.max(0,S.tx_bytes-this.lastNetStats.tx_bytes);this.data.network={rxSec:D/ee,txSec:O/ee,rxTotal:S.rx_bytes,txTotal:S.tx_bytes,interface:S.iface},this.history.netRx.push(this.data.network.rxSec),this.history.netRx.shift(),this.history.netTx.push(this.data.network.txSec),this.history.netTx.shift()}else this.data.network={rxSec:0,txSec:0,rxTotal:S.rx_bytes,txTotal:S.tx_bytes,interface:S.iface};this.lastNetStats={rx_bytes:S.rx_bytes,tx_bytes:S.tx_bytes},this.lastNetTime=M,this.dataTimestamps.network=M,this.recordWidgetUpdate("network",M)}}catch(v){u.warn(`Network fetch failed: ${v.message}`),this.data.network=this.data.network||null}try{let v=await a("Sessions",()=>this.fetchSessions(),5e3);this.data.sessions=v||[],this.data.openclaw={gateway:{reachable:!0}},this.dataTimestamps.sessions=e;let S=new Set(this.data.sessions.map(M=>M.key));for(let M of Object.keys(this.data.sessionTPS))S.has(M)||delete this.data.sessionTPS[M];for(let M of Object.keys(this.data.sessionLastTPS))S.has(M)||delete this.data.sessionLastTPS[M]}catch(v){u.error("Session fetch error:",v.message),this.data.sessions=this.data.sessions||[],this.data.openclaw={gateway:{reachable:!1}}}if(this.updateAdaptiveRefresh(),this.data.openclaw?.sessions?.recent&&this.prev?.openclaw?.sessions?.recent){for(let S of this.data.openclaw.sessions.recent){let M=this.prev.openclaw.sessions.recent.find(k=>k.key===S.key),j=Nf(S,M,t);if(j!==null)this.data.sessionTPS[S.key]={value:j,active:!0},this.data.sessionLastTPS[S.key]=j;else{let k=this.data.sessionLastTPS?.[S.key];this.data.sessionTPS[S.key]={value:k||null,active:!1}}}let v=new Set(this.data.openclaw.sessions.recent.map(S=>S.key));for(let S of Object.keys(this.data.sessionTPS))v.has(S)||delete this.data.sessionTPS[S];for(let S of Object.keys(this.data.sessionLastTPS))v.has(S)||delete this.data.sessionLastTPS[S]}this.data.gatewayUptime=await Cf();try{let{stdout:v}=await a("Logs",()=>be("openclaw logs --limit 200 --plain 2>/dev/null",{timeout:w.COMMAND_TIMEOUTS.OPENCLAW_LOGS}),w.COMMAND_TIMEOUTS.OPENCLAW_LOGS),S=al(this.settings.logLevelFilter||"all"),M=v.trim().split(`
|
|
1723
|
-
`).filter(k=>!k.includes("plugin CLI register skipped")).filter(k=>S(k)),j=500;M.length>0&&(this.logLines=M.slice(-j))}catch{}this.prev=JSON.parse(JSON.stringify(this.data)),this.lastTime=e;let b=Date.now()-s,_=n.length>0?n.join(", "):null;await St.record(this.settings.refreshInterval,{operationTimings:i,slowOperations:_,totalRefreshTime:b}),this.render(),Cs.storeMetricsSnapshot(this.data)}catch{}}render(){this.diffRenderer.beginBatch();let e=this.getVisibleWidgets();if(e.cpu){let I=Math.round(this.data.cpuAvg||0);this.diffRenderer.setContent("cpuValue",this.w.cpuValue,`${I}%`),this.diffRenderer.setFg("cpuValue",this.w.cpuValue,di(I)),this.diffRenderer.setContent("cpuDetail",this.w.cpuDetail,`${this.data.cpu?.length||0} cores`)}if(e.memory){let I=this.data.memory.percent||0;this.diffRenderer.setContent("memValue",this.w.memValue,`${I}%`),this.diffRenderer.setFg("memValue",this.w.memValue,di(I)),this.diffRenderer.setContent("memDetail",this.w.memDetail,`${this.data.memory.usedGB}/${this.data.memory.totalGB}`)}if(e.gpu)if(this.data.gpu){this.diffRenderer.setContent("gpuValue",this.w.gpuValue,this.data.gpu.short),this.diffRenderer.setFg("gpuValue",this.w.gpuValue,E.brightYellow);let I=[];this.data.gpu.utilization!=null&&I.push(`${Math.round(this.data.gpu.utilization)}% util`),this.data.gpu.frequency&&I.push(`${this.data.gpu.frequency}MHz`),this.diffRenderer.setContent("gpuDetail",this.w.gpuDetail,I.join(" ")||"Apple Silicon"),this.diffRenderer.setFg("gpuDetail",this.w.gpuDetail,E.gray)}else this.diffRenderer.setContent("gpuValue",this.w.gpuValue,"Not Detected"),this.diffRenderer.setFg("gpuValue",this.w.gpuValue,E.gray),this.diffRenderer.setContent("gpuDetail",this.w.gpuDetail,"");if(e.network)if(this.data.network){let I=ll(this.data.network.rxSec),G=ll(this.data.network.txSec),W=`\u25BC${I} \u25B2${G}`;this.diffRenderer.setContent("netValue",this.w.netValue,W),this.diffRenderer.setFg("netValue",this.w.netValue,E.brightCyan),this.diffRenderer.setContent("netDetail",this.w.netDetail,this.data.network.interface||"eth0")}else this.diffRenderer.setContent("netValue",this.w.netValue,"No network"),this.diffRenderer.setFg("netValue",this.w.netValue,E.gray),this.diffRenderer.setContent("netDetail",this.w.netDetail,"");if(this.data.openclaw?.gateway?.reachable?this.diffRenderer.setFg("logo",this.w.logo,E.brightCyan):this.diffRenderer.setFg("logo",this.w.logo,E.red),this.data.sessions.length){let I=this.filteredSessions.length>0?this.filteredSessions:this.data.sessions,G=this.settings.sessionSortMode||"time",W=[...I].sort((le,_e)=>{switch(G){case"time":return(_e.updatedAt||0)-(le.updatedAt||0);case"tokens":return(_e.totalTokens||0)-(le.totalTokens||0);case"idle":let Ht=le.updatedAt?Date.now()-le.updatedAt:0;return(_e.updatedAt?Date.now()-_e.updatedAt:0)-Ht;case"name":return(le.displayName||"").localeCompare(_e.displayName||"");default:return(_e.updatedAt||0)-(le.updatedAt||0)}}),U=6,oe=this.paginationOffset*U,ae=oe+U,K=W.slice(oe,ae);this.selectedSessionIndex>=K.length&&(this.selectedSessionIndex=Math.max(0,K.length-1)),this.selectedSessionIndex<0&&(this.selectedSessionIndex=0);let me=K.map((le,_e)=>{let Ht=_e===this.selectedSessionIndex,Os=Ht?"{inverse}":"",ir=Ht?"{/inverse}":"",pt=le.updatedAt?Date.now()-le.updatedAt:0,Ve;pt<300*1e3?Ve="{green-fg}active{/green-fg}":pt<1800*1e3?Ve="{yellow-fg}idle {/yellow-fg}":Ve="{gray-fg}stale {/gray-fg}";let Gt=le.sessionId||le.key,ds=this.settings.favorites&&this.settings.favorites[Gt]?"{yellow-fg}\u2605{/yellow-fg}":" ",mt=le.displayName||"unknown";mt=mt.replace(/^Cron: /,"").substring(0,45).padEnd(45);let nr=(le.model?.replace("moonshot/","").replace("openrouter/","or/")?.substring(0,15)||"-").padEnd(15),or=le.totalTokens||0,de=le.contextWindow||le.contextTokens||0,Ms=Vt=>Vt>=1e6?(Vt/1e6).toFixed(1)+"M":Vt>=1e3?Math.round(Vt/1e3)+"K":Vt.toString(),Ds=`${Ms(or)}/${Ms(de)}`.padEnd(12),yt;pt<6e4?yt=`${Math.round(pt/1e3)}s`:pt<36e5?yt=`${Math.round(pt/6e4)}m`:yt=`${Math.round(pt/36e5)}h`,yt=yt.padEnd(7);let fs=(le.channel||"-").substring(0,10).padEnd(10);return`${Os}${ds}${Ve} ${mt} ${nr} ${Ds} ${yt} ${fs}${ir}`});this.diffRenderer.setContent("sessList",this.w.sessList,me.join(`
|
|
1724
|
-
`).replace(/\n$/,""));let se=W.length,ue=Math.ceil(se/U),Me=this.paginationOffset+1,nt="";if(se>U){nt=`Page ${Me}/${ue}`;let le=se-(this.paginationOffset+1)*U;le>0?this.diffRenderer.setContent("sessTruncated",this.w.sessTruncated,`... and ${le} more`):this.diffRenderer.setContent("sessTruncated",this.w.sessTruncated,"")}else nt=`${se}`,this.diffRenderer.setContent("sessTruncated",this.w.sessTruncated,"");this.diffRenderer.setContent("sessCount",this.w.sessCount,nt)}else this.diffRenderer.setContent("sessList",this.w.sessList,"No active sessions"),this.diffRenderer.setContent("sessCount",this.w.sessCount,"0 sessions"),this.diffRenderer.setContent("sessTruncated",this.w.sessTruncated,"");if(this.logLines.length){let I=this.settings.logLevelFilter||"all",G=al(I),W=this.logLines.filter(ue=>G(ue)),U=this.w.logBox.height||15,oe=(this.w.logBox.width||80)-4,ae=Math.max(1,U-2),K=0,me=[];for(let ue=W.length-1;ue>=0;ue--){let Me=W[ue],nt=Af(Me,oe);if(K+nt<=ae)me.unshift(Me),K+=nt;else break}let se=me.map(ue=>If(ue));this.diffRenderer.setContent("logContent",this.w.logContent,se.join(`
|
|
1725
|
-
`))}else this.diffRenderer.setContent("logContent",this.w.logContent,"No log output");if(this.data.system){let I=this.data.system.split(" ");if(this.diffRenderer.setContent("sysInfoLine1",this.w.sysInfoLine1,I[0]||"macOS"),this.data.containerEnv?.isContainer){let G=oi.getContainerIndicator(this.data.containerEnv);this.diffRenderer.setContent("sysInfoLine2",this.w.sysInfoLine2,G)}else this.diffRenderer.setContent("sysInfoLine2",this.w.sysInfoLine2,I[1]||"")}else this.diffRenderer.setContent("sysInfoLine1",this.w.sysInfoLine1,"Unknown System"),this.diffRenderer.setContent("sysInfoLine2",this.w.sysInfoLine2,"");let s="openclaw unknown";if(this.data.version){let I=this.data.version.replace(/-\d+$/,""),G=this.data.latest;G&&I!=="unknown"?I===G?s=`openclaw ${I} \u2713`:s=`openclaw ${I} \u2192 ${G}`:s=`openclaw ${I}`}this.diffRenderer.setContent("title",this.w.title,`Dashboard ${pe}, ${s}`);let i=new Date,n=i.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!0}),a=i.toLocaleDateString("en-US",{month:"short",day:"numeric"});if(this.isPaused?this.diffRenderer.setContent("clock",this.w.clock,`${n} ${a} {yellow-fg}[PAUSED]{/yellow-fg}`):this.diffRenderer.setContent("clock",this.w.clock,`${n} ${a}`),e.disk)if(this.data.disk){let I=this.data.disk.percent||0;this.diffRenderer.setContent("diskValue",this.w.diskValue,`${I}%`),this.diffRenderer.setFg("diskValue",this.w.diskValue,di(I)),this.diffRenderer.setContent("diskDetail",this.w.diskDetail,`${this.data.disk.usedGB}/${this.data.disk.totalGB}`),this.diffRenderer.setBorderFg("diskBox",this.w.diskBox,di(I))}else this.diffRenderer.setContent("diskValue",this.w.diskValue,"No disk info"),this.diffRenderer.setFg("diskValue",this.w.diskValue,E.gray),this.diffRenderer.setContent("diskDetail",this.w.diskDetail,"");if(e.uptime){let I=cl(this.data.systemUptime),G=cl(this.data.gatewayUptime);this.diffRenderer.setContent("uptimeSys",this.w.uptimeSys,`Sys: ${I}`),this.diffRenderer.setContent("uptimeClaw",this.w.uptimeClaw,`Claw: ${G}`),this.data.openclaw?.gateway?.reachable?(this.diffRenderer.setFg("uptimeSys",this.w.uptimeSys,E.brightMagenta),this.diffRenderer.setFg("uptimeClaw",this.w.uptimeClaw,E.brightMagenta),this.diffRenderer.setBorderFg("uptimeBox",this.w.uptimeBox,E.brightMagenta)):this.data.systemUptime?(this.diffRenderer.setFg("uptimeSys",this.w.uptimeSys,E.yellow),this.diffRenderer.setFg("uptimeClaw",this.w.uptimeClaw,E.yellow),this.diffRenderer.setBorderFg("uptimeBox",this.w.uptimeBox,E.yellow)):(this.diffRenderer.setFg("uptimeSys",this.w.uptimeSys,E.gray),this.diffRenderer.setFg("uptimeClaw",this.w.uptimeClaw,E.gray),this.diffRenderer.setBorderFg("uptimeBox",this.w.uptimeBox,E.gray))}if(e.health){let I=Date.now(),G=5e3,W=15e3,U=Object.values(this.dataTimestamps).filter(Me=>Me!==null),oe=U.length>0?Math.min(...U):null,ae=oe?I-oe:null,K="Initializing",me=E.gray,se=E.gray,ue="";if(ae!==null){let Me=Math.round(ae/1e3);ae<G?(K="All Fresh",me=E.brightGreen,se=E.green,ue=`Last update: ${Me}s ago`):ae<W?(K="Stale Data",me=E.yellow,se=E.yellow,ue=`${Me}s since last refresh`):(K="Data Delayed",me=E.red,se=E.red,ue=`${Me}s - check system`)}this.diffRenderer.setContent("healthStatus",this.w.healthStatus,K),this.diffRenderer.setFg("healthStatus",this.w.healthStatus,me),this.diffRenderer.setContent("healthDetail",this.w.healthDetail,ue),this.diffRenderer.setBorderFg("healthBox",this.w.healthBox,se)}if(e.gateway){let I=Pe.getEndpointHealth(),G=I.length,W=I.filter(se=>se.enabled&&se.reachable).length,U=I.filter(se=>se.enabled&&!se.reachable).length,oe="Checking...",ae=E.gray,K=E.gray,me="";G===0?(oe="No Endpoints",ae=E.yellow,K=E.yellow):U===0?(oe=`{green-fg}\u2713{/green-fg} All Online (${W}/${G})`,ae=E.brightGreen,K=E.green):W===0?(oe=`{red-fg}\u2717{/red-fg} All Offline (${U}/${G})`,ae=E.brightRed,K=E.red,me="Press [G] to retry"):(oe=`{yellow-fg}\u26A0{/yellow-fg} Partial (${W}/${G})`,ae=E.brightYellow,K=E.yellow,me=`${U} offline - [G] retry`),this.diffRenderer.setContent("gatewayStatus",this.w.gatewayStatus,oe),this.diffRenderer.setFg("gatewayStatus",this.w.gatewayStatus,ae),this.diffRenderer.setContent("gatewayDetail",this.w.gatewayDetail,me),this.diffRenderer.setBorderFg("gatewayBox",this.w.gatewayBox,K)}let c=Math.round(this.settings.refreshInterval/1e3),d=this.isPaused?"\u25B6 running":"p pause",g=this.settings.sessionSortMode,p,T=`v${pe}`,b=Pe.getEndpointHealth(),_=b.filter(I=>I.enabled&&!I.reachable).length,v=b.filter(I=>I.enabled).length,S="";v>0&&(_===0?S="{green-fg}\u25CF gateway{/green-fg} ":_===v?S="{red-fg}\u2717 gateway offline{/red-fg} [G] retry ":S=`{yellow-fg}\u26A0 ${_}/${v} gateways{/yellow-fg} [G] retry `);let M=this.errorBoundaryManager.getAllErrorStates(),k=Object.entries(M).filter(([I,G])=>G?.hasError).length,F="";if(k>0&&(F=`{red-fg}\u2717 ${k} widget(s) failed{/red-fg} [X] retry `),this.settings.showPerformanceMetrics){let I=St.getStatusString();p=`q quit r refresh ${d} o sort:${g} 1-8 toggle ? help s settings \u2022 ${S}${F}${I} \u2022 ${T}`}else p=`q quit r refresh ${d} o sort:${g} 1-8 toggle ? help s settings \u2022 ${S}${F}${c}s refresh \u2022 ${T}`;this.diffRenderer.setContent("footerText",this.w.footerText,p);let ee=g==="time"?"TIME":g==="tokens"?"TOKENS":g==="idle"?"IDLE":"NAME",D=this.showFavoritesOnly?"\u2605 FAVES":"",O=D?` ${D}`:"";this.diffRenderer.setLabel("sessions",this.w.sessBox,` SESSIONS (${ee})${O} `);try{this.diffRenderer.endBatch()}catch(I){if(I.code==="EPIPE"||I.message?.includes("write"))return;throw I}}},Dn=class extends gi{constructor(e={}){super(),this.webPort=e.webPort||w.WEB.DEFAULT_PORT,this.webHost=e.webHost||w.WEB.HOST,this.webServer=null,this.dataCache={metrics:null,sessions:null,agents:null,logs:null,lastUpdate:0}}async init(){this.webServer=new Xa({port:this.webPort,host:this.webHost}),this.webServer.setDataProvider(e=>this.getWebData(e));try{await this.webServer.start(),u.info(`Web dashboard available at http://${this.webHost}:${this.webPort}`),console.log("Claw Dashboard Web Server"),console.log(`Version: ${pe}`),console.log(`Listening on: http://${this.webHost}:${this.webPort}`),console.log(`
|
|
1726
|
-
Available endpoints:`);let e=this.webServer.getInfo().endpoints;for(let[t,s]of Object.entries(e))console.log(` GET ${s} - ${t.charAt(0).toUpperCase()+t.slice(1)}`);console.log(`
|
|
1727
|
-
Press Ctrl+C to stop
|
|
1728
|
-
`)}catch(e){u.error(`Failed to start web server: ${e.message}`),console.error(`Error: ${e.message}`),process.exit(1)}await Cs.initDatabase(),Cs.cleanupOldData(30),Pe.init(this.settings),St.start(),this.startWebRefresh(),process.on("SIGINT",()=>this.shutdown()),process.on("SIGTERM",()=>this.shutdown())}startWebRefresh(){this.refreshWebData(),this.webTimer=setInterval(()=>this.refreshWebData(),this.settings.refreshInterval)}async refreshWebData(){try{await Promise.all([this.fetchMetrics(),this.fetchSessions(),this.fetchAgents(),this.fetchLogs()]),this.dataCache.lastUpdate=Date.now()}catch(e){u.error(`Web data refresh error: ${e.message}`)}}async fetchMetrics(){try{let[e,t,s,i,n,a]=await Promise.all([xe.getCpuData().catch(()=>null),xe.getMemoryData().catch(()=>null),xe.getGpuData().catch(()=>null),xe.getDiskData().catch(()=>null),xe.getNetworkData().catch(()=>null),xe.getSystemData().catch(()=>null)]),c=t?.available?t.total-t.available:t?.used||0;this.dataCache.metrics={cpu:e?{load:e.currentLoad,cores:e.cpus?.map(d=>d.load)||[]}:null,memory:t?{usedGB:(c/1024**3).toFixed(1),totalGB:(t.total/1024**3).toFixed(1),percent:Math.round(c/t.total*100),availableGB:(t.available/1024**3).toFixed(1)}:null,gpu:s?{name:s.name,utilization:s.utilization,memoryUsed:s.memoryUsed,memoryTotal:s.memoryTotal}:null,disk:i?{used:i.used,size:i.size,percent:i.percent,fs:i.fs}:null,network:n?{interface:n.interface,rx:n.rx,tx:n.tx}:null,system:a?{platform:a.os?.platform,distro:a.os?.distro,arch:a.ver?.arch}:null,timestamp:new Date().toISOString()}}catch(e){u.warn(`Metrics fetch failed: ${e.message}`)}}async fetchSessions(){try{this.dataCache.sessions=await Pe.getSessions()}catch(e){u.warn(`Sessions fetch failed: ${e.message}`),this.dataCache.sessions=[]}}async fetchAgents(){try{this.dataCache.agents=await Pe.getAgents()}catch(e){u.warn(`Agents fetch failed: ${e.message}`),this.dataCache.agents=[]}}async fetchLogs(){try{let e=await Wa();this.dataCache.logs=e.logs||[]}catch(e){u.warn(`Logs fetch failed: ${e.message}`),this.dataCache.logs=[]}}getWebData(e){switch(Date.now()-this.dataCache.lastUpdate>w.WEB.REFRESH_CACHE_MS&&this.refreshWebData(),e){case"metrics":return this.dataCache.metrics;case"sessions":return this.dataCache.sessions;case"agents":return this.dataCache.agents;case"logs":return this.dataCache.logs;default:return null}}async shutdown(){console.log(`
|
|
1729
|
-
Shutting down web server...`),this.settings.autoSave?.saveOnExit!==!1&&this.autoSaveManager&&(console.log("Saving dashboard state..."),this.autoSaveManager.saveNow()),this.exportScheduler&&this.exportScheduler.stop(),this.webTimer&&clearInterval(this.webTimer),this.webServer&&await this.webServer.stop(),St.stop(),process.exit(0)}};async function $f(){if(we.command==="create-plugin"){let r=await an(we.commandArgs);process.exit(r)}else if(we.command==="validate-plugin"){let r=await dn(we.commandArgs);process.exit(r)}else if(we.command==="validate-config"){let r=await fn(we.commandArgs);process.exit(r)}else if(we.command==="export-snapshot"){let r=await gn(we.commandArgs);process.exit(r)}else if(we.command==="import-snapshot"){let r=await pn(we.commandArgs);process.exit(r)}else if(we.command==="list-templates"){let r=await mn(we.commandArgs);process.exit(r)}else if(we.command==="export-schedule"){let r=await yn(we.commandArgs);process.exit(r)}we.web?new Dn({webPort:we.webPort,webHost:we.webHost}).init():new gi}$f().catch(r=>{console.error("Fatal error:",r),process.exit(1)});
|