@clawlabz/clawnetwork 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.ts +219 -97
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -807,24 +807,28 @@ function buildUiHtml(cfg: PluginConfig): string {
807
807
  <meta charset="UTF-8">
808
808
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
809
809
  <title>ClawNetwork Node Dashboard</title>
810
- <link rel="icon" href="https://cdn.clawlabz.xyz/brand/favicon.png">
810
+ <link rel="icon" href="https://explorer.clawlabz.xyz/favicon.png">
811
+ <link rel="preconnect" href="https://fonts.googleapis.com">
812
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
811
813
  <style>
812
814
  :root {
813
- --bg: #0a0a12;
814
- --bg-panel: #12121f;
815
- --border: #1e1e3a;
816
- --accent: #00ccff;
817
- --accent-dim: rgba(0, 204, 255, 0.15);
818
- --green: #00ff88;
819
- --green-dim: rgba(0, 255, 136, 0.15);
820
- --purple: #8b5cf6;
821
- --text: #e0e0f0;
822
- --text-dim: #666688;
823
- --danger: #ff4455;
824
- --font: system-ui, -apple-system, sans-serif;
825
- --font-mono: 'SF Mono', 'Fira Code', Consolas, monospace;
815
+ --bg: #0a0705;
816
+ --bg-panel: #140e0a;
817
+ --border: #2a1c14;
818
+ --accent: #F96706;
819
+ --accent-dim: rgba(249, 103, 6, 0.15);
820
+ --accent-light: #FF8C3A;
821
+ --purple: #a855f7;
822
+ --purple-dim: rgba(168, 85, 247, 0.15);
823
+ --green: #22c55e;
824
+ --green-dim: rgba(34, 197, 94, 0.15);
825
+ --text: #fffaf5;
826
+ --text-dim: #8892a0;
827
+ --danger: #ef4444;
828
+ --font: 'Space Grotesk', system-ui, -apple-system, sans-serif;
829
+ --font-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
826
830
  --radius: 10px;
827
- --shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
831
+ --shadow: 0 4px 24px rgba(0, 0, 0, 0.5);
828
832
  }
829
833
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
830
834
  body { background: var(--bg); color: var(--text); font-family: var(--font); line-height: 1.6; min-height: 100vh; }
@@ -834,16 +838,17 @@ function buildUiHtml(cfg: PluginConfig): string {
834
838
  .header { background: var(--bg-panel); border-bottom: 1px solid var(--border); padding: 16px 0; position: sticky; top: 0; z-index: 100; }
835
839
  .header .container { display: flex; align-items: center; justify-content: space-between; }
836
840
  .logo { font-size: 22px; font-weight: 800; letter-spacing: -0.5px; }
837
- .logo-claw { color: var(--accent); }
838
- .logo-net { color: var(--green); }
841
+ .logo-claw { color: #ffffff; }
842
+ .logo-net { color: var(--accent); }
839
843
  .header-badge { font-size: 11px; background: var(--accent-dim); color: var(--accent); padding: 2px 8px; border-radius: 4px; }
840
844
 
841
- .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin: 24px 0; }
845
+ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
842
846
  .stat-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; }
843
847
  .stat-label { font-size: 12px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
844
848
  .stat-value { font-size: 28px; font-weight: 700; font-family: var(--font-mono); margin-top: 4px; }
845
849
  .stat-value.green { color: var(--green); }
846
850
  .stat-value.accent { color: var(--accent); }
851
+ .stat-value.purple { color: var(--purple); }
847
852
  .stat-value.danger { color: var(--danger); }
848
853
 
849
854
  .panel { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; margin: 16px 0; }
@@ -858,13 +863,23 @@ function buildUiHtml(cfg: PluginConfig): string {
858
863
  .status-dot.offline { background: var(--danger); }
859
864
  .status-dot.syncing { background: #ffaa00; animation: pulse 1.5s infinite; }
860
865
 
861
- .btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-panel); color: var(--text); font-size: 13px; cursor: pointer; transition: 0.2s; }
866
+ .btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-panel); color: var(--text); font-size: 13px; cursor: pointer; transition: 0.2s; font-family: var(--font); }
862
867
  .btn:hover { border-color: var(--accent); color: var(--accent); }
863
868
  .btn.danger:hover { border-color: var(--danger); color: var(--danger); }
864
869
  .btn.primary { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }
865
- .btn-group { display: flex; gap: 8px; margin: 16px 0; flex-wrap: wrap; }
870
+ .node-controls { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding-top: 16px; margin-top: 16px; border-top: 1px solid var(--border); }
871
+ .node-controls .spacer { flex: 1; }
866
872
 
867
- .logs-box { background: #080810; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-family: var(--font-mono); font-size: 12px; max-height: 300px; overflow-y: auto; white-space: pre-wrap; color: var(--text-dim); line-height: 1.8; }
873
+ .wallet-hero { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }
874
+ .wallet-balance { font-size: 36px; font-weight: 800; font-family: var(--font-mono); color: var(--accent); letter-spacing: -1px; line-height: 1; }
875
+ .wallet-balance-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }
876
+ .wallet-addr-wrap { flex: 1; min-width: 0; }
877
+ .wallet-addr-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }
878
+ .wallet-addr { font-family: var(--font-mono); font-size: 12px; background: var(--bg); padding: 8px 12px; border-radius: 6px; border: 1px solid var(--border); word-break: break-all; display: flex; align-items: center; gap: 8px; }
879
+ .copy-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; padding: 2px 8px; border-radius: 4px; border: 1px solid var(--accent); white-space: nowrap; font-family: var(--font); transition: 0.2s; }
880
+ .copy-btn:hover { background: var(--accent-dim); }
881
+
882
+ .logs-box { background: #060402; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-family: var(--font-mono); font-size: 12px; max-height: 300px; overflow-y: auto; white-space: pre-wrap; color: var(--text-dim); line-height: 1.8; }
868
883
 
869
884
  .wallet-addr { font-family: var(--font-mono); font-size: 13px; background: var(--bg); padding: 8px 12px; border-radius: 6px; border: 1px solid var(--border); word-break: break-all; display: flex; align-items: center; gap: 8px; }
870
885
  .copy-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 14px; padding: 2px 6px; }
@@ -873,7 +888,7 @@ function buildUiHtml(cfg: PluginConfig): string {
873
888
  .toast { position: fixed; bottom: 24px; right: 24px; background: var(--bg-panel); border: 1px solid var(--accent); color: var(--accent); padding: 12px 20px; border-radius: 8px; font-size: 13px; opacity: 0; transition: 0.3s; z-index: 1000; }
874
889
  .toast.show { opacity: 1; }
875
890
 
876
- .quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; margin: 16px 0; }
891
+ .quick-actions { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 16px 0 0; }
877
892
  .quick-action { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; cursor: pointer; transition: 0.2s; display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text); }
878
893
  .quick-action:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
879
894
  .quick-action .qa-icon { font-size: 18px; width: 28px; text-align: center; }
@@ -890,77 +905,81 @@ function buildUiHtml(cfg: PluginConfig): string {
890
905
  .modal-actions { display: flex; gap: 8px; margin-top: 16px; justify-content: flex-end; }
891
906
  .modal-close { background: none; border: 1px solid var(--border); color: var(--text-dim); padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; }
892
907
  .modal-close:hover { border-color: var(--text); color: var(--text); }
908
+ .modal-input { width: 100%; box-sizing: border-box; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; font-size: 14px; color: var(--text); font-family: var(--font-mono); outline: none; margin-top: 4px; }
909
+ .modal-input:focus { border-color: var(--accent); }
910
+ .modal-hint { font-size: 12px; color: var(--text-dim); margin-top: 6px; line-height: 1.5; }
893
911
  </style>
894
912
  </head>
895
913
  <body>
896
914
  <header class="header">
897
915
  <div class="container">
898
916
  <div style="display:flex;align-items:center;gap:14px">
899
- <div class="logo"><span class="logo-claw">Claw</span><span class="logo-net">Network</span></div>
917
+ <div class="logo"><img src="https://explorer.clawlabz.xyz/favicon.png" style="width:28px;height:28px;border-radius:6px;vertical-align:middle;margin-right:8px"><span class="logo-claw">Claw</span><span class="logo-net">Network</span></div>
900
918
  <span class="header-badge">Node Dashboard</span>
901
919
  </div>
902
920
  <span id="lastUpdate" style="font-size:12px;color:var(--text-dim)"></span>
903
921
  </div>
904
922
  </header>
905
923
 
906
- <main class="container" style="padding-top:8px;padding-bottom:40px">
907
- <div class="stats-grid">
908
- <div class="stat-card">
909
- <div class="stat-label">Status</div>
910
- <div class="stat-value" id="statusValue"><span class="status-dot offline"></span>Offline</div>
911
- </div>
912
- <div class="stat-card">
913
- <div class="stat-label">Block Height</div>
914
- <div class="stat-value accent" id="heightValue">—</div>
915
- </div>
916
- <div class="stat-card">
917
- <div class="stat-label">Peers</div>
918
- <div class="stat-value" id="peersValue">—</div>
919
- </div>
920
- <div class="stat-card">
921
- <div class="stat-label">Uptime</div>
922
- <div class="stat-value" id="uptimeValue">—</div>
923
- </div>
924
- </div>
925
-
926
- <div class="btn-group">
927
- <button class="btn primary" onclick="doAction('start')">Start Node</button>
928
- <button class="btn danger" onclick="doAction('stop')">Stop Node</button>
929
- <button class="btn" onclick="doAction('faucet')">Faucet (testnet)</button>
930
- <button class="btn" onclick="refreshLogs()">Refresh Logs</button>
931
- </div>
924
+ <main class="container" style="padding-top:16px;padding-bottom:40px">
932
925
 
933
926
  <div class="panel">
934
- <div class="panel-title">Wallet</div>
935
- <div id="walletInfo">Loading...</div>
936
- <div class="quick-actions" id="walletActions" style="display:none">
937
- <div class="quick-action" onclick="copyAddress()">
938
- <span class="qa-icon">&#x1F4CB;</span>
939
- <div><div class="qa-label">Copy Address</div><div class="qa-hint">Share to receive CLAW</div></div>
940
- </div>
941
- <div class="quick-action" onclick="importToExtension()" id="qaImportExt" style="display:none">
942
- <span class="qa-icon">&#x1F517;</span>
943
- <div><div class="qa-label">Import to Extension</div><div class="qa-hint">One-click import to browser wallet</div></div>
927
+ <div class="panel-title">Node</div>
928
+ <div class="stats-grid" style="margin:0 0 4px">
929
+ <div class="stat-card">
930
+ <div class="stat-label">Status</div>
931
+ <div class="stat-value" id="statusValue"><span class="status-dot offline"></span>Offline</div>
944
932
  </div>
945
- <div class="quick-action warn" onclick="showExportKey()">
946
- <span class="qa-icon">&#x1F511;</span>
947
- <div><div class="qa-label">Export Private Key</div><div class="qa-hint">Manual copy for backup</div></div>
933
+ <div class="stat-card">
934
+ <div class="stat-label">Block Height</div>
935
+ <div class="stat-value accent" id="heightValue">—</div>
948
936
  </div>
949
- <div class="quick-action" onclick="openExplorer()">
950
- <span class="qa-icon">&#x1F50D;</span>
951
- <div><div class="qa-label">View on Explorer</div><div class="qa-hint">Transaction history</div></div>
937
+ <div class="stat-card">
938
+ <div class="stat-label">Peers</div>
939
+ <div class="stat-value" id="peersValue">—</div>
952
940
  </div>
953
- <div class="quick-action" onclick="transferFromDashboard()">
954
- <span class="qa-icon">&#x1F4B8;</span>
955
- <div><div class="qa-label">Transfer CLAW</div><div class="qa-hint">Send to any address</div></div>
941
+ <div class="stat-card">
942
+ <div class="stat-label">Uptime</div>
943
+ <div class="stat-value" id="uptimeValue">—</div>
956
944
  </div>
957
- <div class="quick-action" onclick="registerAgentFromDashboard()">
958
- <span class="qa-icon">&#x1F916;</span>
959
- <div><div class="qa-label">Register Agent</div><div class="qa-hint">On-chain identity</div></div>
945
+ </div>
946
+ <div class="node-controls">
947
+ <button class="btn primary" onclick="doAction('start')">&#x25B6; Start Node</button>
948
+ <button class="btn danger" onclick="doAction('stop')">&#x25A0; Stop Node</button>
949
+ </div>
950
+ </div>
951
+
952
+ <div class="panel" id="walletPanel">
953
+ <div class="panel-title">Wallet</div>
954
+ <div id="walletEmpty" style="color:var(--text-dim);font-size:13px">No wallet yet — start the node to generate one</div>
955
+ <div id="walletLoaded" style="display:none">
956
+ <div class="wallet-hero">
957
+ <div>
958
+ <div class="wallet-balance-label">Balance</div>
959
+ <div class="wallet-balance" id="walletBalance">—</div>
960
+ </div>
961
+ <div class="wallet-addr-wrap">
962
+ <div class="wallet-addr-label">Address</div>
963
+ <div class="wallet-addr"><span id="walletAddrText" style="flex:1;min-width:0;word-break:break-all"></span><button class="copy-btn" onclick="copyText(cachedAddress)">Copy</button></div>
964
+ </div>
960
965
  </div>
961
- <div class="quick-action" onclick="openFaucet()">
962
- <span class="qa-icon">&#x1F6B0;</span>
963
- <div><div class="qa-label">Open Faucet</div><div class="qa-hint">Get testnet CLAW</div></div>
966
+ <div class="quick-actions" id="walletActions">
967
+ <div class="quick-action" onclick="importToExtension()" id="qaImportExt">
968
+ <span class="qa-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></span>
969
+ <div><div class="qa-label">Import to Extension</div><div class="qa-hint" id="qaImportHint">One-click import to browser wallet</div></div>
970
+ </div>
971
+ <div class="quick-action warn" onclick="showExportKey()">
972
+ <span class="qa-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="7.5" cy="15.5" r="5.5"/><path d="m21 2-9.6 9.6"/><path d="m15.5 7.5 3 3L22 7l-3-3"/></svg></span>
973
+ <div><div class="qa-label">Export Private Key</div><div class="qa-hint">Manual copy for backup</div></div>
974
+ </div>
975
+ <div class="quick-action" onclick="openExplorer()">
976
+ <span class="qa-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg></span>
977
+ <div><div class="qa-label">View on Explorer</div><div class="qa-hint">Transaction history</div></div>
978
+ </div>
979
+ <div class="quick-action" id="qaRegister" onclick="handleRegisterAgent()">
980
+ <span class="qa-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2M9 2v2M15 20v2M9 20v2M2 15h2M2 9h2M20 15h2M20 9h2"/></svg></span>
981
+ <div><div class="qa-label" id="qaRegisterLabel">Register Agent</div><div class="qa-hint" id="qaRegisterHint">On-chain identity</div></div>
982
+ </div>
964
983
  </div>
965
984
  </div>
966
985
  </div>
@@ -971,13 +990,57 @@ function buildUiHtml(cfg: PluginConfig): string {
971
990
  </div>
972
991
 
973
992
  <div class="panel">
974
- <div class="panel-title">Recent Logs</div>
993
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
994
+ <div class="panel-title" style="margin-bottom:0">Recent Logs</div>
995
+ <button class="btn" style="font-size:12px;padding:5px 12px" onclick="refreshLogs()">&#x21BB; Refresh</button>
996
+ </div>
975
997
  <div class="logs-box" id="logsBox">Loading...</div>
976
998
  </div>
977
999
  </main>
978
1000
 
1001
+ <footer style="border-top:1px solid var(--border);padding:24px 0;margin-top:16px">
1002
+ <div class="container" style="display:flex;flex-wrap:wrap;gap:20px;align-items:center;justify-content:space-between">
1003
+ <div style="display:flex;align-items:center;gap:8px">
1004
+ <img src="https://explorer.clawlabz.xyz/favicon.png" style="width:18px;height:18px;border-radius:4px;opacity:0.7">
1005
+ <span style="font-size:12px;color:var(--text-dim)">© 2026 ClawLabz</span>
1006
+ </div>
1007
+ <div style="display:flex;gap:20px;flex-wrap:wrap">
1008
+ <a href="https://chain.clawlabz.xyz" target="_blank" style="font-size:12px;color:var(--text-dim);text-decoration:none;transition:0.2s" onmouseover="this.style.color='var(--accent)'" onmouseout="this.style.color='var(--text-dim)'">Chain</a>
1009
+ <a href="https://explorer.clawlabz.xyz" target="_blank" style="font-size:12px;color:var(--text-dim);text-decoration:none;transition:0.2s" onmouseover="this.style.color='var(--accent)'" onmouseout="this.style.color='var(--text-dim)'">Explorer</a>
1010
+ <a href="https://chrome.google.com/webstore/search/ClawNetwork" target="_blank" style="font-size:12px;color:var(--text-dim);text-decoration:none;transition:0.2s" onmouseover="this.style.color='var(--accent)'" onmouseout="this.style.color='var(--text-dim)'">Wallet Extension</a>
1011
+ </div>
1012
+ </div>
1013
+ </footer>
1014
+
979
1015
  <div class="toast" id="toast"></div>
980
1016
 
1017
+ <div class="modal-overlay" id="registerModal" onclick="if(event.target===this)closeRegisterModal()">
1018
+ <div class="modal">
1019
+ <div class="modal-title">Register Agent</div>
1020
+ <p style="font-size:13px;color:var(--text-dim);margin:0 0 12px">Register your wallet as an AI Agent on ClawNetwork. The name is your on-chain identity — it does not need to be unique globally (the wallet address is what's unique). Registration is gas-free on mainnet.</p>
1021
+ <input id="registerNameInput" class="modal-input" type="text" placeholder="my-agent-name" maxlength="32" onkeydown="if(event.key==='Enter')submitRegisterAgent()" />
1022
+ <div class="modal-hint">Allowed: letters, numbers, hyphens, underscores. Max 32 chars.</div>
1023
+ <div class="modal-actions">
1024
+ <button class="modal-close" onclick="closeRegisterModal()">Cancel</button>
1025
+ <button class="btn primary" onclick="submitRegisterAgent()">Register</button>
1026
+ </div>
1027
+ </div>
1028
+ </div>
1029
+
1030
+ <div class="modal-overlay" id="installModal" onclick="if(event.target===this)closeInstallModal()">
1031
+ <div class="modal">
1032
+ <div class="modal-title">Install ClawNetwork Wallet</div>
1033
+ <p style="font-size:13px;color:var(--text-dim);margin:0 0 16px;line-height:1.6">The ClawNetwork browser extension is not detected. Install it first, then click Import to Extension to import your node wallet.</p>
1034
+ <div style="display:flex;gap:10px;flex-direction:column">
1035
+ <a href="https://chrome.google.com/webstore/search/ClawNetwork" target="_blank" class="btn primary" style="text-decoration:none;justify-content:center;padding:10px 16px">Open Chrome Web Store</a>
1036
+ <a href="https://chain.clawlabz.xyz" target="_blank" style="font-size:12px;color:var(--text-dim);text-decoration:none;text-align:center" onmouseover="this.style.color='var(--accent)'" onmouseout="this.style.color='var(--text-dim)'">Learn more at chain.clawlabz.xyz →</a>
1037
+ </div>
1038
+ <div class="modal-actions" style="margin-top:16px">
1039
+ <button class="modal-close" onclick="closeInstallModal()">Close</button>
1040
+ </div>
1041
+ </div>
1042
+ </div>
1043
+
981
1044
  <div class="modal-overlay" id="exportModal" onclick="if(event.target===this)closeExportModal()">
982
1045
  <div class="modal">
983
1046
  <div class="modal-title">Export Private Key</div>
@@ -1006,6 +1069,7 @@ function buildUiHtml(cfg: PluginConfig): string {
1006
1069
  let cachedAddress = '';
1007
1070
  let cachedNetwork = '';
1008
1071
  let cachedKey = '';
1072
+ let cachedAgentName = ''; // '' = not registered, string = registered name
1009
1073
 
1010
1074
  function copyText(text) {
1011
1075
  navigator.clipboard.writeText(text).then(() => toast('Copied!')).catch(() => {});
@@ -1050,16 +1114,13 @@ function buildUiHtml(cfg: PluginConfig): string {
1050
1114
  window.open('https://chain.clawlabz.xyz/faucet', '_blank');
1051
1115
  }
1052
1116
 
1053
- // Detect ClawNetwork extension provider
1117
+ // Detect ClawNetwork extension provider (for enhanced flow when available)
1054
1118
  let hasExtension = false;
1055
1119
  function checkExtension() {
1056
1120
  if (window.clawNetwork && window.clawNetwork.isClawNetwork) {
1057
1121
  hasExtension = true;
1058
- const el = document.getElementById('qaImportExt');
1059
- if (el) el.style.display = '';
1060
1122
  }
1061
1123
  }
1062
- // Check immediately and after a short delay (extension injects at document_start)
1063
1124
  checkExtension();
1064
1125
  setTimeout(checkExtension, 1000);
1065
1126
  setTimeout(checkExtension, 3000);
@@ -1083,7 +1144,10 @@ function buildUiHtml(cfg: PluginConfig): string {
1083
1144
  } catch (e) { /* fall through to provider method */ }
1084
1145
  }
1085
1146
  // Fallback: use window.clawNetwork provider
1086
- if (!window.clawNetwork) { toast('ClawNetwork extension not detected. Install it first.'); return; }
1147
+ if (!window.clawNetwork) {
1148
+ document.getElementById('installModal').classList.add('open');
1149
+ return;
1150
+ }
1087
1151
  toast('Connecting to extension...');
1088
1152
  try {
1089
1153
  await window.clawNetwork.request({ method: 'claw_requestAccounts' });
@@ -1145,21 +1209,45 @@ function buildUiHtml(cfg: PluginConfig): string {
1145
1209
  setTimeout(fetchStatus, 3000);
1146
1210
  }
1147
1211
 
1148
- async function registerAgentFromDashboard() {
1149
- const name = prompt('Agent name (alphanumeric, max 32 chars):', 'openclaw-agent');
1150
- if (!name) return;
1212
+ function closeInstallModal() {
1213
+ document.getElementById('installModal').classList.remove('open');
1214
+ }
1215
+
1216
+ function handleRegisterAgent() {
1217
+ if (cachedAgentName) {
1218
+ toast('Already registered as "' + cachedAgentName + '"');
1219
+ return;
1220
+ }
1221
+ openRegisterModal();
1222
+ }
1223
+
1224
+ function openRegisterModal() {
1225
+ document.getElementById('registerNameInput').value = '';
1226
+ document.getElementById('registerModal').classList.add('open');
1227
+ setTimeout(() => document.getElementById('registerNameInput').focus(), 50);
1228
+ }
1229
+
1230
+ function closeRegisterModal() {
1231
+ document.getElementById('registerModal').classList.remove('open');
1232
+ }
1233
+
1234
+ async function submitRegisterAgent() {
1235
+ const raw = document.getElementById('registerNameInput').value.trim();
1236
+ const name = raw.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 32);
1237
+ if (!name) { toast('Please enter an agent name'); return; }
1238
+ closeRegisterModal();
1151
1239
  if (window.clawNetwork) {
1152
1240
  try {
1153
1241
  toast('Approve registration in extension...');
1154
1242
  await window.clawNetwork.request({ method: 'claw_requestAccounts' });
1155
1243
  await window.clawNetwork.request({ method: 'claw_registerAgent', params: [name] });
1156
- toast('Agent registered!');
1244
+ toast('Agent "' + name + '" registered!');
1157
1245
  } catch (e) { toast('Registration failed: ' + (e.message || e)); }
1158
1246
  } else {
1159
1247
  try {
1160
1248
  const res = await fetch(API + '/api/agent/register', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({name}) });
1161
1249
  const data = await res.json();
1162
- toast(data.ok ? 'Agent registered!' : 'Error: ' + data.error);
1250
+ toast(data.ok ? 'Agent "' + name + '" registered!' : 'Error: ' + data.error);
1163
1251
  } catch (e) { toast('Registration failed: ' + e.message); }
1164
1252
  }
1165
1253
  }
@@ -1170,7 +1258,10 @@ function buildUiHtml(cfg: PluginConfig): string {
1170
1258
  const data = await res.json();
1171
1259
  renderStatus(data);
1172
1260
  document.getElementById('lastUpdate').textContent = 'Updated: ' + new Date().toLocaleTimeString();
1173
- } catch (e) { console.error(e); }
1261
+ } catch (e) {
1262
+ console.error(e);
1263
+ renderStatus({ running: false, blockHeight: null, peerCount: null, walletAddress: '', network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:19877', pluginVersion: '0.1.1', restartCount: 0, dataDir: '', balance: '', syncing: false, uptimeFormatted: '—', pid: null });
1264
+ }
1174
1265
  }
1175
1266
 
1176
1267
  function renderStatus(s) {
@@ -1192,12 +1283,34 @@ function buildUiHtml(cfg: PluginConfig): string {
1192
1283
  // Wallet
1193
1284
  cachedAddress = s.walletAddress || '';
1194
1285
  cachedNetwork = s.network || '';
1195
- const wHtml = s.walletAddress
1196
- ? '<div class="wallet-addr">' + s.walletAddress + ' <button class="copy-btn" onclick="copyText(\\''+s.walletAddress+'\\')">Copy</button></div>' +
1197
- (s.balance ? '<div style="margin-top:8px;font-size:14px;color:var(--green)">' + s.balance + '</div>' : '')
1198
- : '<div style="color:var(--text-dim)">No wallet yet — start the node to generate one</div>';
1199
- document.getElementById('walletInfo').innerHTML = wHtml;
1200
- document.getElementById('walletActions').style.display = s.walletAddress ? '' : 'none';
1286
+ if (s.walletAddress) {
1287
+ document.getElementById('walletEmpty').style.display = 'none';
1288
+ document.getElementById('walletLoaded').style.display = '';
1289
+ document.getElementById('walletAddrText').textContent = s.walletAddress;
1290
+ document.getElementById('walletBalance').textContent = s.balance || '—';
1291
+ // Agent status
1292
+ cachedAgentName = s.agentName || '';
1293
+ const regCard = document.getElementById('qaRegister');
1294
+ const regLabel = document.getElementById('qaRegisterLabel');
1295
+ const regHint = document.getElementById('qaRegisterHint');
1296
+ if (cachedAgentName) {
1297
+ regLabel.textContent = 'Agent Registered';
1298
+ regHint.innerHTML = '<span style="color:var(--green)">&#x2713; ' + cachedAgentName + '</span>';
1299
+ regCard.style.borderColor = 'var(--green)';
1300
+ regCard.style.opacity = '0.85';
1301
+ } else {
1302
+ regLabel.textContent = 'Register Agent';
1303
+ regHint.textContent = 'On-chain identity';
1304
+ regCard.style.borderColor = '';
1305
+ regCard.style.opacity = '';
1306
+ }
1307
+ // Extension detection hint
1308
+ const hasExt = !!(window.clawNetwork && window.clawNetwork.isClawNetwork);
1309
+ document.getElementById('qaImportHint').textContent = hasExt ? 'Extension detected — click to import' : 'Install wallet extension first';
1310
+ } else {
1311
+ document.getElementById('walletEmpty').style.display = '';
1312
+ document.getElementById('walletLoaded').style.display = 'none';
1313
+ }
1201
1314
 
1202
1315
  // Node info
1203
1316
  const rows = [
@@ -1321,10 +1434,16 @@ async function handle(req, res) {
1321
1434
  try {
1322
1435
  const h = await fetchJson('http://localhost:' + RPC_PORT + '/health');
1323
1436
  let balance = '';
1437
+ let walletAddress = '';
1438
+ let agentName = '';
1324
1439
  try {
1325
1440
  const walletPath = path.join(os.homedir(), '.openclaw/workspace/clawnetwork/wallet.json');
1326
1441
  const w = JSON.parse(fs.readFileSync(walletPath, 'utf8'));
1327
- if (w.address) { const b = await rpcCall('claw_getBalance', [w.address]); balance = formatClaw(b); }
1442
+ walletAddress = w.address || '';
1443
+ if (w.address) {
1444
+ const b = await rpcCall('claw_getBalance', [w.address]); balance = formatClaw(b);
1445
+ try { const ag = await rpcCall('claw_getAgent', [w.address]); agentName = (ag && ag.name) ? ag.name : ''; } catch {}
1446
+ }
1328
1447
  } catch {}
1329
1448
  json(200, {
1330
1449
  running: h.status === 'ok',
@@ -1333,14 +1452,17 @@ async function handle(req, res) {
1333
1452
  network: h.chain_id,
1334
1453
  syncMode: 'light',
1335
1454
  rpcUrl: 'http://localhost:' + RPC_PORT,
1336
- walletAddress: (() => { try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.openclaw/workspace/clawnetwork/wallet.json'), 'utf8')).address; } catch { return ''; } })(),
1455
+ walletAddress,
1337
1456
  binaryVersion: h.version,
1338
- pluginVersion: '0.1.0',
1457
+ pluginVersion: '0.1.1',
1339
1458
  uptime: h.uptime_secs,
1340
1459
  uptimeFormatted: h.uptime_secs < 60 ? h.uptime_secs + 's' : h.uptime_secs < 3600 ? Math.floor(h.uptime_secs/60) + 'm' : Math.floor(h.uptime_secs/3600) + 'h ' + Math.floor((h.uptime_secs%3600)/60) + 'm',
1341
- restartCount: 0, dataDir: path.join(os.homedir(), '.clawnetwork'), balance, syncing: h.status === 'degraded',
1460
+ restartCount: 0, dataDir: path.join(os.homedir(), '.clawnetwork'), balance, agentName, syncing: h.status === 'degraded',
1342
1461
  });
1343
- } catch { json(200, { running: false, blockHeight: null, peerCount: null }); }
1462
+ } catch {
1463
+ const walletAddr = (() => { try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.openclaw/workspace/clawnetwork/wallet.json'), 'utf8')).address; } catch { return ''; } })();
1464
+ json(200, { running: false, blockHeight: null, peerCount: null, walletAddress: walletAddr, network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:' + RPC_PORT, pluginVersion: '0.1.1', restartCount: 0, dataDir: path.join(os.homedir(), '.clawnetwork'), balance: '', agentName: '', syncing: false, uptimeFormatted: '—', pid: null });
1465
+ }
1344
1466
  return;
1345
1467
  }
1346
1468
  if (p === '/api/logs') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawlabz/clawnetwork",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Run a ClawNetwork blockchain node inside OpenClaw. Every agent is a blockchain node.",
5
5
  "type": "module",
6
6
  "license": "MIT",