1
0
Files
homelab-public-context/runtime/latest.txt
T

35 lines
30 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
CHAT_OUTPUT_BEGIN
COMMAND_ID=GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z
STATUS=OK
RC=0
HOST=pve01
MODE=verify
COMPONENT=gram1-site-charts-no-data-v25-read-only-exact-diag
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83
COMMAND_SHA256=63f257115dd000cfe86eb63dadd592cea3306949f5184917bbb497f3b1211198
DUPLICATE_FAILED_COMMAND_BLOCKED=false
EXECUTION_STARTED=true
CHANGE_DECLARED=false
RESULT_CONTRACT_VALID=true
RESULT_CONTRACT_STATUS=NOT_APPLICABLE
RESULT_CONTRACT_ERROR=NONE
COMMAND_RC=0
CHANGES_MADE=false
ROLLBACK_STARTED=false
ROLLBACK_RESTORED=null
MUTATION_OUTCOME=NO_MUTATION
SANITIZED=yes
SECRETS_INCLUDED=no
PRIVATE_ADDRESSES_INCLUDED=no
RAW_EVIDENCE_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75
SANITIZED_OUTPUT_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75
OUTPUT_BEGIN
HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","mutation_outcome":"NO_MUTATION","rollback_restored":null,"rollback_started":false,"status":"OK","version":1}
{"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","previous_capsule_sha256":"a7143b656e161f0f0312e43cc0c6f59840953dfa414537cc2881dd37b2739439","previous_command_id":"GRAM1-SITE-POL-ACCORDION-V24-ATOMIC-UI-FIX-20260801T092200Z","previous_output_sha256":"6c1c2b55816a60b410b09865a069ba9a7feec2a1d6f90d90c5947d2c10c8ab8f","previous_runner_json_sha256":"fd9459ab8e69940ad23be7e4aa3d1b8ffc68a08b83425967a3244891389e9de2","previous_runner_text_sha256":"279ecb54d524871dce71eb4a34e6d46fd95a70a3ae712035914cc40b752bbf96","production_site_changed":false,"rc":0,"remote_result":{"changes_made":false,"checks":{"app_routes":[{"decorator":"app.get('/login', response_class=HTMLResponse)","function":"login_page","line":53,"path":"/login"},{"decorator":"app.post('/login')","function":"login","line":59,"path":"/login"},{"decorator":"app.post('/logout')","function":"logout","line":74,"path":"/logout"},{"decorator":"app.get('/', response_class=HTMLResponse)","function":"home","line":79,"path":"/"},{"decorator":"app.get('/health')","function":"health","line":85,"path":"/health"},{"decorator":"app.get('/coin-icon/{coin_id}')","function":"coin_icon","line":93,"path":"/coin-icon/{coin_id}"},{"decorator":"app.get('/vendor/lightweight-charts.js')","function":"lightweight_charts_js","line":142,"path":"/vendor/lightweight-charts.js"},{"decorator":"app.get('/api/klines/{symbol}')","function":"klines","line":308,"path":"/api/klines/{symbol}"},{"decorator":"app.get('/api/chart-health')","function":"chart_health","line":313,"path":"/api/chart-health"},{"decorator":"app.get('/api/state')","function":"state","line":347,"path":"/api/state"},{"decorator":"app.post('/api/holding')","function":"save_holding","line":364,"path":"/api/holding"},{"decorator":"app.post('/api/alert')","function":"add_alert","line":377,"path":"/api/alert"},{"decorator":"app.delete('/api/alert/{alert_id}')","function":"delete_alert","line":391,"path":"/api/alert/{alert_id}"}],"compose_sha256":"6d344e46b3de94ad86131a914df2ff3ff25e9d82f7ce0557cbffa468b8cdc1b8","data":{"files":[{"bytes":20963,"name":"klines-cache.json","sha256":"c37fd69ccd9f027fa5c97a4e405cd731feb7a7519c05ef4c2d88ac07182fd201","symbols":{"AVAX":{"count":2,"present":true},"HBAR":{"count":2,"present":true},"LINK":{"count":2,"present":true},"POL":{"count":2,"present":true}},"top_keys":["entries","saved_at","version"]},{"bytes":13860,"name":"market.json","sha256":"d964ce60028612f44c9da3a61cbd2b7831f4a70784be683da3580d010659de3f","symbols":{"AVAX":{"count":1,"present":true},"HBAR":{"count":1,"present":true},"LINK":{"count":1,"present":true},"POL":{"count":2,"present":true}},"top_keys":["coins","currency","updated_at","usd_rub"]},{"bytes":96,"name":"worker-status.json","sha256":"ca07f70b4037b5f9890a8a08709baa30680263bf810fecc08682b99df72b4b82","symbols":{"AVAX":{"count":0,"present":false},"HBAR":{"count":0,"present":false},"LINK":{"count":0,"present":false},"POL":{"count":0,"present":false}},"top_keys":["alerts_triggered","coin_count","history_rows","status","updated_at"]}],"now":1785576765},"diagnostic_flags":["NO_TRADINGVIEW_WIDGET_INITIALIZER_FOUND","NO_DATA_FALLBACK_EXISTS_IN_FRONTEND","CHART_ERROR_PLACEHOLDER_PRESENT","HOMEPAGE_NOT_200"],"exact_file_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"595fec2f7a1dc7ffac4a2ce7f6703c25608a775bebee492b2143cf9792789696","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"external_script_probe":[{"skipped":"relative","url":"/vendor/lightweight-charts.js"}],"next_decision":"FIX_ONLY_PROVEN_NO_DATA_CAUSE_WITH_ONE_ATOMIC_TRANSACTION","runtime":{"ports":[8000,5000,8080,3000,80,35961],"routes":[{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"external_scripts":[],"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"inline_script_count":0,"path":"/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":303},{"bytes":66,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"market_age_seconds":258,"status":"OK","type":"crypto-portfolio"},"path":"/health","port":8000,"sha256":"1c5a784dabda5571bc1411d064b364ddff7085a2fa503ea4ca9d3c0eed3e5e56","status":200},{"bytes":450,"contains":{"POL":true,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"bad":0,"disk_cache_present":true,"library_ok":true,"status":"OK","symbols":{"AVAX":{"cache_age_seconds":127,"candles":72,"source":"binance","stale":false,"status":"OK"},"HBAR":{"cache_age_seconds":127,"candles":84,"source":"binance","stale":false,"status":"OK"},"LINK":{"cache_age_seconds":127,"candles":92,"source":"binance","stale":false,"status":"OK"},"POL":{"cache_age_seconds":127,"candles":24,"source":"binance","stale":false,"status":"OK"}}},"path":"/api/chart-health","port":8000,"sha256":"e345436fd16349538387e51a62b494a6a727e0f04b65249837398100fa9d89d2","status":200},{"bytes":1088,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"text/html; charset=utf-8","focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/login","port":8000,"sha256":"66b06909949879d84757d0f96be74eebf1db40f35de22b625ea67e85e1bbdae2","status":200},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/logout","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":196203,"contains":{"POL":false,"TradingView":true,"Нет данных":false},"content_type":"application/javascript","focus":["/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value i","/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value is undefined\");return t}function a(t){if(null===t)throw new Er","Logo}Jv(){const t=new URL(location.href);return t.hostname?\"&utm_source=\"+t.hostname+t.pathname:\"\"}Yv(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"35\" height=\"19\" fill=\"none\"><g fill-rule=\"evenodd\" clip-path=\"url(#a)\" clip-rule=\"evenodd\"><path fill=\"var(--stroke)\" d=\"M2 0H0v10h6v9h21.4l.5-1.3 6-15 1-2.7H23.7l-.5 1.3-.2.6a5 5 0 0 0-7-.9V0H2Zm20 17h4l5.2-13 .8-2h-7l-1 2.5-.2.5-1.5 3.8-.3.7V17Zm-.8-10a3 3 0 0 0 .7-2.7A3 3 0 1 0 16.8 7h4.4ZM14 7V2H2v6h6v9h4V7h2Z\"/><path fill=\"var(--fill)\" d=\"M14 2H2v6h6v9h6V2Zm12 15h-7l6-15h7l-6 15Zm-7-9a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\"/></g><defs><clipPath id=\"a\"><path fill=\"var(--stroke)\" d=\"M0 0h35v19H0z\"/></clipPath></defs></svg>',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).","v(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"35\" height=\"19\" fill=\"none\"><g fill-rule=\"evenodd\" clip-path=\"url(#a)\" clip-rule=\"evenodd\"><path fill=\"var(--stroke)\" d=\"M2 0H0v10h6v9h21.4l.5-1.3 6-15 1-2.7H23.7l-.5 1.3-.2.6a5 5 0 0 0-7-.9V0H2Zm20 17h4l5.2-13 .8-2h-7l-1 2.5-.2.5-1.5 3.8-.3.7V17Zm-.8-10a3 3 0 0 0 .7-2.7A3 3 0 1 0 16.8 7h4.4ZM14 7V2H2v6h6v9h4V7h2Z\"/><path fill=\"var(--fill)\" d=\"M14 2H2v6h6v9h6V2Zm12 15h-7l6-15h7l-6 15Zm-7-9a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\"/></g><defs><clipPath id=\"a\"><path fill=\"var(--stroke)\" d=\"M0 0h35v19H0z\"/></clipPath></defs></svg>',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).createElement(\"canvas\");t.appendChild(n);const s=new cn(n,(e={options:{allowResizeObserver:!0},trans"],"headers":{"cache-control":"public, max-age=31536000, immutable","content-security-policy":null,"x-frame-options":null},"path":"/vendor/lightweight-charts.js","port":8000,"sha256":"c0992580867c4912cc9385b3c2728315bcc1a76c7f1087dca908430fccdf31d7","status":200},{"bytes":27,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"login required"},"path":"/api/state","port":8000,"sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","status":401},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/holding","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/alert","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/api/alert/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":307},{"bytes":22,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Not Found"},"path":"/api/klines/","port":8000,"sha256":"37ec4665a8102d115ffd1ac20dae94c98b4dac64b0c1a68228aa2a531caeb35d","status":404}]},"services":{"rc":0,"stderr":"","stdout":"{\"Command\":\"\\\"uvicorn app:app --h…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"fe312e150112\",\"Image\":\"crypto-portfolio-web\",\"Labels\":\"com.docker.compose.service=web,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.container-number=1,com.docker.compose.depends_on=,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.version=2.26.1,com.docker.compose.image=sha256:2f4d3926f130f414fbf92a27b6fac6eb0d97bb5b726efc5bc52360ba76b6e103,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio\",\"Names\":\"crypto-portfolio\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\"<PRIVATE_ADDRESS>:8030-\\u003e8000/tcp\",\"Project\":\"crypto-portfolio\",\"Publishers\":[{\"URL\":\"<PRIVATE_ADDRESS>\",\"TargetPort\":8000,\"PublishedPort\":8030,\"Protocol\":\"tcp\"}],\"RunningFor\":\"9 minutes ago\",\"Service\":\"web\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n{\"Command\":\"\\\"python /app/worker.…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"e63250c93d2b\",\"Image\":\"crypto-portfolio-worker\",\"Labels\":\"com.docker.compose.container-number=1,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.depends_on=,com.docker.compose.image=sha256:41f34e3eb9647aba391e96336caacbddbe0db37a3a7fce8ba09b66b104a91eb4,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.service=worker,com.docker.compose.version=2.26.1\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio-worker\",\"Names\":\"crypto-portfolio-worker\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\"\",\"Project\":\"crypto-portfolio\",\"Publishers\":null,\"RunningFor\":\"9 minutes ago\",\"Service\":\"worker\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n"},"source":{"bytes":30286,"contexts":[{"offset":7619,"pattern":"fetch\\s*\\(","text":"UB\"?\"RUB\":\"USD\";const fx=()=>Number(state&&state.market&&state.market.usd_rub||0);const cv=n=>Number(n||0)*(currency===\"RUB\"?fx():1);const money=(n,d=2)=>new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{style:\"currency\",currency:currency,minimumFractionDigits:d,maximumFractionDigits:d}).format(cv(n));const compactMoney=n=>(currency===\"RUB\"?\"₽\":\"$\")+new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{notation:\"compact\",maximumFractionDigits:2}).format(cv(n));const inputPrice=n=>Number((Number(n||0)*(currency===\"RUB\"?fx():1)).toFixed(currency===\"RUB\"?2:8));const coin=()=>state.market.coins[selected];async function load(){let r=await fetch(\"/api/state\");if(r.status===401){location=\"/login\";return}state=await r.json();render()}function render(){let m=state.market.coins||{};let ids=Object.keys(state.coins);/* ALERT_COIN_SELECTOR_EARLY_V1 */aCoin.innerHTML=ids.map(id=>\"<option value=\\\"\"+id+\"\\\">\"+state.coins[id]+\"</option>\").join(\"\");if(currency===\"RUB\"&&!(fx()>0)){currency=\"USD\"}document.querySelectorAll(\".currency-btn\").forEach(x=>x.classList.toggle(\"active\",x.dataset.currency===currency));avgHeader.textContent=\"Средняя покупка (\"+currency+\")\";coins.innerHTML=ids.map(id=>{let c=m[id]||{};let ch=Number(c.change_24h||0);return \"<div class=\\\"card coin \"+(id===selected?\"active\":\"\")+\""},{"offset":10457,"pattern":"Нет данных","text":"let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"<option value=\\\"\"+id+\"\\\">\"+state.coins[id]+\"</option>\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-T"},{"offset":12971,"pattern":"fetch\\s*\\(","text":"k={price_above:\"цена ≥\",price_below:\"цена ≤\",cap_above:\"капитализация ≥\",cap_below:\"капитализация ≤\",pump:\"памп ≥ +\",dump:\"падение ≥ \"}[a.kind];return c+\": \"+k+\" \"+a.threshold+(a.kind===\"pump\"||a.kind===\"dump\"?\"% за \"+Math.round(a.window_seconds/60)+\" мин\":\" USD\")}function renderAlerts(){alertList.innerHTML=state.alerts.length?state.alerts.map(a=>\"<div class=\\\"alert\\\"><div><b>\"+label(a)+\"</b><div class=\\\"muted\\\">\"+a.email+\"</div></div><button class=\\\"btn ghost del\\\" data-id=\\\"\"+a.id+\"\\\">Удалить</button></div>\").join(\"\"):\"<span class=\\\"muted\\\">Оповещений пока нет</span>\";document.querySelectorAll(\".del\").forEach(x=>x.onclick=async()=>{await fetch(\"/api/alert/\"+x.dataset.id,{method:\"DELETE\"});load()})}aKind.onchange=()=>aWindow.classList.toggle(\"hidden\",!([\"pump\",\"dump\"].includes(aKind.value)));addAlert.onclick=async()=>{let dynamic=[\"pump\",\"dump\"].includes(aKind.value);let r=await fetch(\"/api/alert\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:aCoin.value,kind:aKind.value,threshold:Number(aThreshold.value),window_seconds:dynamic?Number(aWindow.value):0,email:aEmail.value})});if(!r.ok){alert(\"Проверьте параметры\")};aThreshold.value=\"\";load()};document.querySelectorAll(\".currency-btn\").forEach(x=>x.onclick=()=>{currency=x.dataset.currency;local"},{"offset":16886,"pattern":"fetch\\s*\\(","text":"lue||\"\").trim() }; statusEl.className=\"muted full\"; statusEl.textContent=\"\"; if(!payload.coin_id){statusEl.className=\"bad full\";statusEl.textContent=\"Не выбрана монета\";return;} if(!Number.isFinite(payload.threshold)||payload.threshold<=0){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи положительный порог\";return;} if(!payload.email||!payload.email.includes(\"@\")){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи корректный email\";return;} button.disabled=true; const oldText=button.textContent; button.textContent=\"Создание…\"; try{ const beforeResponse=await fetch(\"/api/state\",{credentials:\"same-origin\",headers:{\"Accept\":\"application/json\"}}); if(beforeResponse.status===401){location=\"/login\";return;} if(!beforeResponse.ok){throw new Error(\"предварительная проверка HTTP \"+beforeResponse.status);} const before=await beforeResponse.json(); const beforeIds=new Set((before.alerts||[]).map(a=>Number(a.id))); const response=await fetch(\"/api/alert\",{ method:\"POST\", credentials:\"same-origin\", headers:{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"}, body:JSON.stringify(payload) }); const raw=await re"},{"offset":21685,"pattern":"fetch\\s*\\(","text":"data,alert))); left.append(make(\"div\",\"muted\",alert.email||\"\")); const holding=(data.holdings&&data.holdings[alert.coin_id])||{}; const quantity=Number(holding.quantity||0); const isPrice=[\"price_above\",\"price_below\"].includes(alert.kind); const sale=make(\"div\",\"sale\",isPrice?alertMoney(data,quantity*Number(alert.threshold||0)):\"—\"); const button=make(\"button\",\"btn ghost del\",\"Удалить\"); button.type=\"button\"; button.dataset.alertDeleteV4=String(alert.id); button.onclick=async event=>{ event.preventDefault(); button.disabled=true; try{ const response=await fetch(\"/api/alert/\"+encodeURIComponent(alert.id),{method:\"DELETE\",credentials:\"same-origin\",cache:\"no-store\"}); if(response.status===401){location=\"/login\";return;} if(!response.ok)throw new Error(\"HTTP \"+response.status); await refresh(); }catch(error){ button.disabled=false; button.textContent=\"Ошибка удаления\"; } }; row.append(left,sale,button); box.append(row); }); }; const refresh=async()=>{ if(loading)return; loading=true; const box=document.getElementById(\"alertList\"); try{ const response=await fetch(\"/api/state\",{credentials:\"sa"},{"offset":23740,"pattern":"TradingView","text":"}); observer.observe(box,{childList:true,subtree:true}); } const add=document.getElementById(\"addAlert\"); if(add){ add.addEventListener(\"click\",()=>{ setTimeout(refresh,400); setTimeout(refresh,1200); }); } refresh(); setInterval(refresh,15000); }; if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",install,{once:true});else install(); const redrawForCurrency=()=>{if(lastState)draw(lastState);}; document.querySelectorAll(\".currency-btn\").forEach(button=>button.addEventListener(\"click\",()=>setTimeout(redrawForCurrency,0))); })(); </script> <style id=\"TRADINGVIEW_ACCORDION_STYLE_V2\">#chart{display:none!important}#tvCharts{display:block;margin-top:12px;border:1px solid var(--l);border-radius:16px;overflow:hidden;background:#081823}.tv-accordion-item{border-bottom:1px solid var(--l);background:#081823}.tv-accordion-item:last-child{border-bottom:0}.tv-accordion-head{list-style:none;cursor:pointer;padding:14px 16px;font-weight:800;display:flex;align-items:center;justify-content:space-between;gap:12px;user-select:none}.tv-accordion-head::-webkit-details-marker{display:none}.tv-accordion-chevron{font-size:18px;transition:transform .2s ease}.tv-accordion-item[open] .tv-accordion-chevron{transform:rotate(180"},{"offset":25210,"pattern":"Нет данных","text":"n-head{padding:12px 14px}}</style> <script src=\"/vendor/lightweight-charts.js\"></script> <script id=\"LOCAL_TRADINGVIEW_CHARTS_V1\"> (()=>{ const symbols=[\"HBAR\",\"POL\",\"AVAX\",\"LINK\"]; const instances=[]; const loadCandles=async symbol=>{ const response=await fetch(\"/api/klines/\"+encodeURIComponent(symbol)+\"?limit=1000&interval=1M\",{cache:\"no-store\"}); if(response.status===401){location=\"/login\";throw new Error(\"Требуется повторный вход\")} if(!response.ok)throw new Error(\"HTTP \"+response.status); const data=await response.json(); if(data.status!==\"OK\"||!Array.isArray(data.candles)||!data.candles.length)throw new Error(\"Нет данных\"); return data.candles; }; const mount=async()=>{ if(!window.LightweightCharts)throw new Error(\"Локальная библиотека не загрузилась\"); chart.style.display=\"none\"; const panel=chart.closest(\".panel\"); if(panel)panel.style.gridColumn=\"1 / -1\"; chartTitle.textContent=\"Графики монет\"; const note=chartTitle.parentElement.querySelector(\".muted\"); if(note)note.textContent=\"Дневные свечи Binance · 365 дней\"; let root=document.getElementById(\"tvCharts\"); if(!root){root=document.createElement(\"div\");root.id=\"tvCharts\";chart.insertAdjacentElement(\"afterend\",root)} root.innerHTML=\"\"; const pending=symb"},{"offset":26576,"pattern":"tv-widget-slot","text":"t(\"details\"); card.className=\"tv-accordion-item\"; card.setAttribute(\"name\",\"tv-coin-charts\"); card.open=symbol===symbols[0]; card.innerHTML=`<summary class=\"tv-accordion-head\"><span>${symbol} / USDT</span><span class=\"tv-accordion-chevron\" aria-hidden=\"true\">⌄</span></summary><div class=\"tv-accordion-body\"><div class=\"tv-widget-slot\"></div><div class=\"tv-chart-error muted\" style=\"padding:0 14px 12px\">Загрузка...</div></div>`; card.addEventListener(\"toggle\",()=>{if(!card.open)return;root.querySelectorAll(\"details.tv-accordion-item\").forEach(item=>{if(item!==card)item.open=false})}); root.appendChild(card); const box=card.querySelector(\".tv-widget-slot\"); const error=card.querySelector(\".tv-chart-error\"); const api=LightweightCharts.createChart(box,{width:box.clientWidth||900,height:430,layout:{background:{type:LightweightCharts.ColorType.Solid,color:\"#081823\"},textColor:\"#8fa5b6\"},grid:{vertLines:{color:\"rgba(143,165,182,.08)\"},horzLines:{color:\"rgba(143,165,182,.08)\"}},rightPriceScale:{borderColor:\"rgba(143,165,182,.2)\"},timeScale:{borderColor:\"rgba(143,165,182,.2)\",timeVisible:false,secondsVisible:false}}); const series=api.addSeries(LightweightCharts.CandlestickSeries,{upColor:\"#63e6be\",downColor:\"#ff6b81\",wickUpColor:\"#63e6be\",wickDownColor:\"#ff6b81\",borderVisible:fa"},{"offset":27958,"pattern":"TradingView","text":"const observer=new ResizeObserver(entries=>{const width=Math.floor(entries[0].contentRect.width);if(width>0)api.applyOptions({width})}); observer.observe(box); return {symbol,api,series,error,observer}; }); instances.push(...pending); await Promise.all(pending.map(async item=>{ try{ item.series.setData(await loadCandles(item.symbol)); item.api.timeScale().fitContent(); item.error.textContent=\"\"; }catch(chartError){ item.error.textContent=\"Ошибка: \"+String(chartError.message||chartError); } })); }; draw=()=>{}; mount().catch(error=>{ console.error(\"Local TradingView chart error\",error); const note=chartTitle.parentElement.querySelector(\".muted\"); if(note)note.textContent=\"Ошибка графиков: \"+String(error.message||error); }); })(); </script> <style id=\"SHARP_MOVES_LAYOUT_V2\">.sharp-moves-panel{grid-column:1 / -1;justify-self:center;width:min(100%,860px);margin-inline:auto}.sharp-moves-panel .title{justify-content:center}.sharp-moves-panel .title h2{width:100%;text-align:center}#moves{grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:12px!important}@media(max-width:750px){.sharp-moves-panel{width:100%}#moves{grid-template-columns:1fr!important}}</style> <script id=\"MOVE_CHARTS_TO_BOTTO"}],"counts":{"accordion_details_creator":1,"container_id":0,"details_name":1,"loading_text":1,"new_tradingview_widget":0,"no_data_text":3,"open_first":1,"tradingview_widget":0,"tv_chart_error":2,"tv_widget_slot":4},"external_scripts":["/vendor/lightweight-charts.js"],"fetch_paths":["/api/state","/api/holding","/api/alert/","/api/alert","/api/klines/"],"inline_scripts":[{"bytes":7045,"offset":6862,"sha256":"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7"},{"bytes":4775,"offset":14583,"sha256":"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582"},{"bytes":4605,"offset":19235,"sha256":"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9"},{"bytes":3579,"offset":24690,"sha256":"4c96a33dced07327225e33226cd197272503830dc12d8043532e88591bdcdac2"},{"bytes":642,"offset":28633,"sha256":"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40"}],"lines":273,"symbols":["HBAR","POL","AVAX","LINK"]}},"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","production_site_changed":false,"rc":0,"rollback_restored":null,"rollback_started":false,"schema":1,"status":"OK"},"rollback_restored":null,"rollback_started":false,"schema":1,"selected_method":"ALIAS_PINNED_AS_DEBIAN","ssh_method_probes":[{"duration_seconds":0.128,"identity_count":null,"identity_sudo_read_ok":true,"name":"ALIAS_PINNED_AS_DEBIAN","rc":0,"stderr":""},{"duration_seconds":0.126,"identity_count":2,"identity_sudo_read_ok":true,"name":"DIRECT_PINNED_AS_DEBIAN_NO_PROXY","rc":0,"stderr":""}],"status":"OK"}
OUTPUT_END
CHAT_OUTPUT_END