iwa 0.0.1a2__py3-none-any.whl → 0.0.1a4__py3-none-any.whl

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 (67) hide show
  1. iwa/core/chain/interface.py +51 -61
  2. iwa/core/chain/models.py +7 -7
  3. iwa/core/chain/rate_limiter.py +21 -10
  4. iwa/core/cli.py +27 -2
  5. iwa/core/constants.py +6 -5
  6. iwa/core/contracts/abis/erc20.json +930 -0
  7. iwa/core/contracts/abis/multisend.json +24 -0
  8. iwa/core/contracts/abis/multisend_call_only.json +17 -0
  9. iwa/core/contracts/contract.py +16 -4
  10. iwa/core/ipfs.py +149 -0
  11. iwa/core/keys.py +259 -29
  12. iwa/core/mnemonic.py +3 -13
  13. iwa/core/models.py +28 -6
  14. iwa/core/pricing.py +4 -4
  15. iwa/core/secrets.py +77 -0
  16. iwa/core/services/safe.py +3 -3
  17. iwa/core/utils.py +6 -1
  18. iwa/core/wallet.py +4 -0
  19. iwa/plugins/gnosis/safe.py +2 -2
  20. iwa/plugins/gnosis/tests/test_safe.py +1 -1
  21. iwa/plugins/olas/constants.py +8 -0
  22. iwa/plugins/olas/contracts/abis/activity_checker.json +110 -0
  23. iwa/plugins/olas/contracts/abis/mech.json +740 -0
  24. iwa/plugins/olas/contracts/abis/mech_marketplace.json +1293 -0
  25. iwa/plugins/olas/contracts/abis/mech_new.json +954 -0
  26. iwa/plugins/olas/contracts/abis/service_manager.json +1382 -0
  27. iwa/plugins/olas/contracts/abis/service_registry.json +1909 -0
  28. iwa/plugins/olas/contracts/abis/staking.json +1400 -0
  29. iwa/plugins/olas/contracts/abis/staking_token.json +1274 -0
  30. iwa/plugins/olas/contracts/mech.py +30 -2
  31. iwa/plugins/olas/plugin.py +2 -2
  32. iwa/plugins/olas/tests/test_plugin_full.py +3 -3
  33. iwa/plugins/olas/tests/test_staking_integration.py +2 -2
  34. iwa/tools/__init__.py +1 -0
  35. iwa/tools/check_profile.py +6 -5
  36. iwa/tools/list_contracts.py +136 -0
  37. iwa/tools/release.py +9 -3
  38. iwa/tools/reset_env.py +2 -2
  39. iwa/tools/reset_tenderly.py +26 -24
  40. iwa/tools/wallet_check.py +150 -0
  41. iwa/web/dependencies.py +4 -4
  42. iwa/web/routers/state.py +1 -0
  43. iwa/web/static/app.js +3096 -0
  44. iwa/web/static/index.html +543 -0
  45. iwa/web/static/style.css +1443 -0
  46. iwa/web/tests/test_web_endpoints.py +3 -2
  47. iwa/web/tests/test_web_swap_coverage.py +156 -0
  48. {iwa-0.0.1a2.dist-info → iwa-0.0.1a4.dist-info}/METADATA +6 -3
  49. {iwa-0.0.1a2.dist-info → iwa-0.0.1a4.dist-info}/RECORD +64 -44
  50. iwa-0.0.1a4.dist-info/entry_points.txt +6 -0
  51. {iwa-0.0.1a2.dist-info → iwa-0.0.1a4.dist-info}/top_level.txt +0 -1
  52. tests/test_chain.py +1 -1
  53. tests/test_chain_interface_coverage.py +92 -0
  54. tests/test_contract.py +2 -0
  55. tests/test_keys.py +58 -15
  56. tests/test_migration.py +52 -0
  57. tests/test_mnemonic.py +1 -1
  58. tests/test_pricing.py +7 -7
  59. tests/test_safe_coverage.py +1 -1
  60. tests/test_safe_service.py +3 -3
  61. tests/test_staking_router.py +13 -1
  62. tools/verify_drain.py +1 -1
  63. conftest.py +0 -22
  64. iwa/core/settings.py +0 -95
  65. iwa-0.0.1a2.dist-info/entry_points.txt +0 -2
  66. {iwa-0.0.1a2.dist-info → iwa-0.0.1a4.dist-info}/WHEEL +0 -0
  67. {iwa-0.0.1a2.dist-info → iwa-0.0.1a4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,543 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>IWA Terminal</title>
7
+ <link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
8
+ <link rel="stylesheet" href="/static/style.css" />
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&family=JetBrains+Mono:wght@400;500&display=swap"
12
+ rel="stylesheet" />
13
+ </head>
14
+ <body>
15
+ <div class="background-blobs">
16
+ <div class="blob blob-1"></div>
17
+ <div class="blob blob-2"></div>
18
+ <div class="blob blob-3"></div>
19
+ </div>
20
+ <div class="app-container">
21
+ <header>
22
+ <div class="logo">
23
+ <svg width="24"
24
+ height="24"
25
+ viewBox="0 0 24 24"
26
+ fill="none"
27
+ stroke="var(--accent-color)"
28
+ stroke-width="2"
29
+ stroke-linecap="round"
30
+ stroke-linejoin="round"
31
+ class="logo-icon">
32
+ <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
33
+ <polyline points="2 17 12 22 22 17"></polyline>
34
+ <polyline points="2 12 12 17 22 12"></polyline>
35
+ </svg>
36
+ <h1>
37
+ IWA <span>Terminal</span>
38
+ </h1>
39
+ </div>
40
+ <div class="chain-selector">
41
+ <label for="active-chain">Network</label>
42
+ <select id="active-chain">
43
+ <option value="gnosis">Gnosis</option>
44
+ <option value="ethereum">Ethereum</option>
45
+ <option value="base">Base</option>
46
+ </select>
47
+ </div>
48
+ <div class="status-indicator" id="global-status">
49
+ <span class="pulse"></span>
50
+ <span id="status-text">Connected</span>
51
+ </div>
52
+ </header>
53
+ <nav class="tabs">
54
+ <button class="tab-btn active" data-tab="dashboard">Dashboard</button>
55
+ <button class="tab-btn" data-tab="olas">Olas</button>
56
+ <button class="tab-btn" data-tab="cowswap">CowSwap</button>
57
+ <button class="tab-btn" data-tab="rpc">RPC Status</button>
58
+ </nav>
59
+ <main class="tab-content">
60
+ <!-- Dashboard Tab (Merged Wallets & Transactions) -->
61
+ <section id="dashboard" class="tab-pane active">
62
+ <div class="section-header">
63
+ <h2>Accounts</h2>
64
+ <div class="actions">
65
+ <button id="refresh-btn" class="btn-icon" title="Refresh Balances">
66
+ <svg width="16"
67
+ height="16"
68
+ viewBox="0 0 24 24"
69
+ fill="none"
70
+ stroke="currentColor"
71
+ stroke-width="2"
72
+ stroke-linecap="round"
73
+ stroke-linejoin="round">
74
+ <path d="M23 4v6h-6"></path>
75
+ <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
76
+ </svg>
77
+ </button>
78
+ </div>
79
+ </div>
80
+ <!-- Token Selector -->
81
+ <div class="token-selector-row mb-1">
82
+ <span class="label">Track Tokens:</span>
83
+ <div id="token-toggles" class="token-toggles">
84
+ <!-- Dynamic checkboxes -->
85
+ </div>
86
+ </div>
87
+ <div class="table-container glass">
88
+ <table id="accounts-table">
89
+ <thead>
90
+ <tr id="accounts-header-row">
91
+ <th>Tag</th>
92
+ <th>Address</th>
93
+ <th>Type</th>
94
+ <!-- Dynamic token columns -->
95
+ </tr>
96
+ </thead>
97
+ <tbody id="accounts-body">
98
+ <!-- Rows loaded via JS -->
99
+ </tbody>
100
+ </table>
101
+ </div>
102
+ <!-- Buttons below accounts table -->
103
+ <div class="account-actions mt-2">
104
+ <button id="create-eoa-btn" class="btn-primary">Create EOA</button>
105
+ <button id="create-safe-btn" class="btn-warning">Create Safe</button>
106
+ </div>
107
+ <div class="tx-form glass mt-2">
108
+ <h3>Send Transaction</h3>
109
+ <form id="send-tx-form">
110
+ <div class="form-grid form-grid-5">
111
+ <div class="form-group">
112
+ <label>From</label>
113
+ <select id="tx-from" required></select>
114
+ </div>
115
+ <div class="form-group">
116
+ <label>To</label>
117
+ <select id="tx-to" required></select>
118
+ </div>
119
+ <div class="form-group">
120
+ <label>Amount</label>
121
+ <input type="number" id="tx-amount" step="1" placeholder="0.00" required />
122
+ </div>
123
+ <div class="form-group">
124
+ <label>Token</label>
125
+ <select id="tx-token"></select>
126
+ </div>
127
+ <div class="form-group form-group-btn">
128
+ <label>&nbsp;</label>
129
+ <button type="submit" class="btn-send">Send</button>
130
+ </div>
131
+ </div>
132
+ </form>
133
+ </div>
134
+ <div class="section-header mt-2">
135
+ <h2>Recent Activity</h2>
136
+ </div>
137
+ <div class="table-container glass">
138
+ <table id="tx-table">
139
+ <thead>
140
+ <tr>
141
+ <th>Time</th>
142
+ <th>Chain</th>
143
+ <th>From</th>
144
+ <th>To</th>
145
+ <th>Token</th>
146
+ <th class="val">Amount</th>
147
+ <th class="val">Value (€)</th>
148
+ <th>Status</th>
149
+ <th>Hash</th>
150
+ <th>Gas (Wei)</th>
151
+ <th>Gas (€)</th>
152
+ <th>Tags</th>
153
+ </tr>
154
+ </thead>
155
+ <tbody id="tx-body">
156
+ <!-- Rows loaded via JS -->
157
+ </tbody>
158
+ </table>
159
+ </div>
160
+ <div class="mb-3"></div>
161
+ </section>
162
+ <!-- Olas Tab -->
163
+ <section id="olas" class="tab-pane">
164
+ <div class="section-header">
165
+ <h2>Olas Services</h2>
166
+ <div class="actions">
167
+ <button id="refresh-olas-btn" class="btn-icon" title="Refresh All Services">
168
+ <svg xmlns="http://www.w3.org/2000/svg"
169
+ width="16"
170
+ height="16"
171
+ viewBox="0 0 24 24"
172
+ fill="none"
173
+ stroke="currentColor"
174
+ stroke-width="2"
175
+ stroke-linecap="round"
176
+ stroke-linejoin="round">
177
+ <polyline points="23 4 23 10 17 10"></polyline>
178
+ <polyline points="1 20 1 14 7 14"></polyline>
179
+ <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
180
+ </svg>
181
+ </button>
182
+ </div>
183
+ </div>
184
+ <div id="olas-summary-container">
185
+ <!-- Summary header loaded via JS -->
186
+ </div>
187
+ <div id="olas-services-container" class="olas-services-grid">
188
+ <!-- Service cards loaded via JS -->
189
+ <div class="empty-state glass">
190
+ <p>No Olas services found for this chain.</p>
191
+ </div>
192
+ </div>
193
+ <!-- Actions below service cards -->
194
+ <div class="olas-actions mt-2 text-center mb-3">
195
+ <button id="create-service-btn" class="btn-primary">Create Service</button>
196
+ </div>
197
+ </section>
198
+ <!-- CowSwap Tab -->
199
+ <section id="cowswap" class="tab-pane">
200
+ <div class="swap-wrapper">
201
+ <!-- Master Balance Table (CowSwap specific) -->
202
+ <div class="table-container glass">
203
+ <table id="cowswap-master-table">
204
+ <thead>
205
+ <tr id="cowswap-master-header">
206
+ <th>Account</th>
207
+ <!-- Dynamic tokens -->
208
+ </tr>
209
+ </thead>
210
+ <tbody id="cowswap-master-body">
211
+ <!-- Master row -->
212
+ </tbody>
213
+ </table>
214
+ </div>
215
+ <div class="swap-cards-grid">
216
+ <div class="swap-container glass">
217
+ <h3>Token Swap</h3>
218
+ <form id="swap-form">
219
+ <div class="swap-mode-toggle">
220
+ <label class="radio-item">
221
+ <input type="radio" name="swap-mode" value="sell" checked />
222
+ <span>Sell exact amount</span>
223
+ </label>
224
+ <label class="radio-item">
225
+ <input type="radio" name="swap-mode" value="buy" />
226
+ <span>Buy exact amount</span>
227
+ </label>
228
+ </div>
229
+ <div class="swap-cards">
230
+ <!-- Sell Card -->
231
+ <div class="swap-card" id="sell-card">
232
+ <div class="swap-card-header">Sell</div>
233
+ <select id="swap-sell-token" required></select>
234
+ <div class="swap-card-amount">
235
+ <input type="number"
236
+ id="swap-sell-amount"
237
+ step="any"
238
+ min="0"
239
+ placeholder="0.00" />
240
+ <button type="button" id="swap-max-sell" class="btn-max">Max</button>
241
+ </div>
242
+ </div>
243
+ <!-- Arrow (click to swap tokens) -->
244
+ <div class="swap-arrow"
245
+ id="swap-tokens-btn"
246
+ title="Swap tokens"
247
+ style="cursor: pointer">
248
+ <svg width="24"
249
+ height="24"
250
+ viewBox="0 0 24 24"
251
+ fill="none"
252
+ stroke="currentColor"
253
+ stroke-width="2">
254
+ <path d="M5 12h14M13 5l7 7-7 7" />
255
+ </svg>
256
+ </div>
257
+ <!-- Buy Card -->
258
+ <div class="swap-card" id="buy-card">
259
+ <div class="swap-card-header">Buy</div>
260
+ <select id="swap-buy-token" required></select>
261
+ <div class="swap-card-amount">
262
+ <input type="number"
263
+ id="swap-buy-amount"
264
+ class="no-spinners"
265
+ step="any"
266
+ min="0"
267
+ placeholder="0.00"
268
+ readonly />
269
+ <button type="button" id="swap-max-buy" class="btn-max hidden">Max</button>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ <button type="submit" class="btn-swap">Swap Tokens</button>
274
+ </form>
275
+ </div>
276
+ <div class="swap-container glass">
277
+ <h3>Wrap / Unwrap</h3>
278
+ <form id="wrap-form">
279
+ <div class="swap-mode-toggle">
280
+ <label class="radio-item">
281
+ <input type="radio" name="wrap-mode" value="wrap" checked />
282
+ <span>Wrap xDAI → WXDAI</span>
283
+ </label>
284
+ <label class="radio-item">
285
+ <input type="radio" name="wrap-mode" value="unwrap" />
286
+ <span>Unwrap WXDAI → xDAI</span>
287
+ </label>
288
+ </div>
289
+ <div class="form-group mb-1">
290
+ <label>Amount</label>
291
+ <div class="swap-card-amount">
292
+ <input type="number"
293
+ id="wrap-amount"
294
+ step="any"
295
+ min="0"
296
+ placeholder="0.00"
297
+ required />
298
+ <button type="button" id="wrap-max-btn" class="btn-max">Max</button>
299
+ </div>
300
+ </div>
301
+ <button type="submit" class="btn-swap" id="wrap-submit-btn">Wrap xDAI</button>
302
+ </form>
303
+ </div>
304
+ </div>
305
+ <!-- Recent Orders Table -->
306
+ <div class="recent-orders-section mt-2">
307
+ <h3>Recent Orders</h3>
308
+ <div class="table-container glass">
309
+ <table id="recent-orders-table">
310
+ <thead>
311
+ <tr>
312
+ <th>Date</th>
313
+ <th>Order ID</th>
314
+ <th>Status</th>
315
+ <th>Sell</th>
316
+ <th>Buy</th>
317
+ <th>Expiring in</th>
318
+ </tr>
319
+ </thead>
320
+ <tbody id="recent-orders-body">
321
+ <tr>
322
+ <td colspan="6" class="text-center text-muted">Loading orders...</td>
323
+ </tr>
324
+ </tbody>
325
+ </table>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </section>
330
+ <!-- RPC Tab -->
331
+ <section id="rpc" class="tab-pane">
332
+ <div class="section-header">
333
+ <h2>Node Connectivity</h2>
334
+ </div>
335
+ <div class="rpc-grid" id="rpc-cards">
336
+ <!-- Cards loaded via JS -->
337
+ </div>
338
+ </section>
339
+ </main>
340
+ </div>
341
+ <!-- Safe Creation Modal -->
342
+ <div id="safe-modal" class="modal">
343
+ <div class="modal-content glass modal-md">
344
+ <h2>Create Multisig Safe</h2>
345
+ <form id="create-safe-form">
346
+ <div class="form-group mb-1">
347
+ <label>Tag Name</label>
348
+ <input type="text" id="safe-tag" placeholder="e.g. Treasury Safe" required />
349
+ </div>
350
+ <div class="form-group mb-1">
351
+ <label>Threshold (Signatures needed)</label>
352
+ <input type="number" id="safe-threshold" min="1" value="1" required />
353
+ </div>
354
+ <div class="form-group mb-1">
355
+ <label>Select Owners</label>
356
+ <div id="safe-owners-list" class="checkbox-grid">
357
+ <!-- Dynamic account checkboxes -->
358
+ </div>
359
+ </div>
360
+ <div class="form-group mb-1">
361
+ <label>Chains (Select at least one)</label>
362
+ <div id="safe-chains-list" class="checkbox-grid">
363
+ <!-- Dynamic -->
364
+ </div>
365
+ </div>
366
+ <div class="modal-actions mt-2">
367
+ <button type="button" class="btn-secondary" id="close-safe-modal">Cancel</button>
368
+ <button type="submit" class="btn-primary">Deploy Safe</button>
369
+ </div>
370
+ </form>
371
+ </div>
372
+ </div>
373
+ <!-- EOA Creation Modal -->
374
+ <div id="eoa-modal" class="modal">
375
+ <div class="modal-content glass">
376
+ <h2>Create EOA Account</h2>
377
+ <form id="create-eoa-form">
378
+ <div class="form-group mb-1">
379
+ <label>Tag Name (optional)</label>
380
+ <input type="text" id="eoa-tag" placeholder="e.g. Trading Account" />
381
+ </div>
382
+ <div class="modal-actions mt-2">
383
+ <button type="button" class="btn-secondary" id="close-eoa-modal">Cancel</button>
384
+ <button type="submit" class="btn-primary">Create Account</button>
385
+ </div>
386
+ </form>
387
+ </div>
388
+ </div>
389
+ <!-- Confirmation Modal -->
390
+ <div id="confirm-modal" class="modal">
391
+ <div class="modal-content glass modal-md">
392
+ <h2 id="confirm-title">Confirm Action</h2>
393
+ <p id="confirm-message" class="text-muted mb-2"></p>
394
+ <div class="modal-actions">
395
+ <button type="button" class="btn-secondary" id="confirm-cancel">Cancel</button>
396
+ <button type="button" class="btn-primary" id="confirm-ok">Confirm</button>
397
+ </div>
398
+ </div>
399
+ </div>
400
+ <!-- Stake Modal -->
401
+ <div id="stake-modal" class="modal">
402
+ <div class="modal-content glass modal-lg">
403
+ <h2>Stake Service</h2>
404
+ <p class="text-muted mb-1">Select a staking contract for this service:</p>
405
+ <input type="hidden" id="stake-service-key" />
406
+ <div class="form-group mb-1">
407
+ <label>Staking Contract</label>
408
+ <div id="stake-contract-spinner" class="hidden">
409
+ <span class="cell-spinner"></span> Loading contracts...
410
+ </div>
411
+ <select id="stake-contract-select">
412
+ <option value="">Loading contracts...</option>
413
+ </select>
414
+ </div>
415
+ <div class="modal-actions mt-2">
416
+ <button type="button" class="btn-secondary" id="stake-cancel">Cancel</button>
417
+ <button type="button" class="btn-primary" id="stake-confirm">Stake</button>
418
+ </div>
419
+ </div>
420
+ </div>
421
+ <!-- Create Service Modal -->
422
+ <div id="create-service-modal" class="modal">
423
+ <div class="modal-content glass modal-lg">
424
+ <h2>Create Olas Service</h2>
425
+ <form id="create-service-form">
426
+ <div class="form-group mb-1">
427
+ <label>Service Name</label>
428
+ <input type="text"
429
+ id="new-service-name"
430
+ placeholder="e.g. My Trader"
431
+ required />
432
+ </div>
433
+ <div class="form-group mb-1">
434
+ <label>Chain</label>
435
+ <select id="new-service-chain">
436
+ <option value="gnosis" selected>Gnosis</option>
437
+ </select>
438
+ </div>
439
+ <div class="form-group mb-1">
440
+ <label>Agent Type</label>
441
+ <select id="new-service-agent-type">
442
+ <option value="trader" selected>Trader</option>
443
+ </select>
444
+ </div>
445
+ <div class="form-group mb-1">
446
+ <label>Staking Contract</label>
447
+ <div id="staking-contract-spinner" class="hidden">
448
+ <span class="cell-spinner"></span> Loading contracts...
449
+ </div>
450
+ <select id="new-service-staking-contract">
451
+ <option value="">None (don't stake)</option>
452
+ <!-- Populated via JS -->
453
+ </select>
454
+ </div>
455
+ <div class="modal-actions mt-2">
456
+ <button type="button" class="btn-secondary" id="close-create-service-modal">Cancel</button>
457
+ <button type="submit" class="btn-primary">Create Service</button>
458
+ </div>
459
+ </form>
460
+ </div>
461
+ </div>
462
+ <!-- Fund Service Modal -->
463
+ <div id="fund-service-modal" class="modal">
464
+ <div class="modal-content glass modal-lg">
465
+ <h2>Fund Service</h2>
466
+ <p class="text-muted mb-1">Send native tokens from master wallet to service accounts:</p>
467
+ <input type="hidden" id="fund-service-key" />
468
+ <div class="form-group mb-1">
469
+ <label>
470
+ Agent Amount (<span id="fund-native-symbol">xDAI</span>)
471
+ </label>
472
+ <input type="number"
473
+ id="fund-agent-amount"
474
+ step="0.01"
475
+ min="0"
476
+ value="0"
477
+ placeholder="0.00" />
478
+ </div>
479
+ <div class="form-group mb-1">
480
+ <label>
481
+ Safe Amount (<span id="fund-safe-symbol">xDAI</span>)
482
+ </label>
483
+ <input type="number"
484
+ id="fund-safe-amount"
485
+ step="0.01"
486
+ min="0"
487
+ value="0"
488
+ placeholder="0.00" />
489
+ </div>
490
+ <div class="modal-actions mt-2">
491
+ <button type="button" class="btn-secondary" id="close-fund-modal">Cancel</button>
492
+ <button type="button" class="btn-primary" id="fund-confirm">Fund Service</button>
493
+ </div>
494
+ </div>
495
+ </div>
496
+ <!-- Terminate Service Modal -->
497
+ <div id="terminate-modal" class="modal">
498
+ <div class="modal-content glass modal-lg">
499
+ <h2 class="text-error">⚠️ Terminate Service</h2>
500
+ <p class="text-muted mb-1">
501
+ This action will:
502
+ <br />
503
+ • Unstake the service (if staked)
504
+ <br />
505
+ • Terminate the service
506
+ <br />
507
+ • Unbond all operators
508
+ <br />
509
+ <br />
510
+ The service will return to PRE_REGISTRATION state.
511
+ </p>
512
+ <input type="hidden" id="terminate-service-key" />
513
+ <div class="modal-actions mt-2">
514
+ <button type="button" class="btn-secondary" id="terminate-cancel">Cancel</button>
515
+ <button type="button" class="btn-danger" id="terminate-confirm">Terminate</button>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ <!-- Login Modal -->
520
+ <div id="login-modal" class="modal">
521
+ <div class="modal-content glass modal-sm">
522
+ <h2>🔐 Authentication Required</h2>
523
+ <p class="text-muted mb-2">Enter your Web UI password to continue:</p>
524
+ <form id="login-form">
525
+ <div class="form-group mb-1">
526
+ <label>Password</label>
527
+ <input type="password"
528
+ id="login-password"
529
+ placeholder="Enter password"
530
+ required
531
+ autocomplete="current-password" />
532
+ </div>
533
+ <div class="modal-actions mt-2">
534
+ <button type="submit" class="btn-primary w-100">Login</button>
535
+ </div>
536
+ </form>
537
+ </div>
538
+ </div>
539
+ <!-- Modals (minimal implementation for now) -->
540
+ <div id="toast-container" class="toast-container"></div>
541
+ <script src="/static/app.js?v=1.0.4"></script>
542
+ </body>
543
+ </html>