@vitronai/alethia 0.3.6 → 0.3.8
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/README.md +5 -6
- package/demo/README.md +74 -0
- package/demo/admin-panel.html +128 -0
- package/demo/cookie-banner.html +66 -0
- package/demo/ecommerce.html +88 -0
- package/demo/financial-dashboard.html +97 -0
- package/demo/form-validation.html +113 -0
- package/demo/signup-form.html +70 -0
- package/demo/spa-loading.html +64 -0
- package/demo/todo-app.html +51 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ alethia-mcp --health-check
|
|
|
66
66
|
Expected:
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
✓ Connected.
|
|
69
|
+
✓ Connected. MCP tools available.
|
|
70
70
|
runtime version: 0.1.0-alpha.1
|
|
71
71
|
default profile: controlled-web
|
|
72
72
|
kill switch: inactive
|
|
@@ -125,9 +125,9 @@ After saving the config, restart your MCP client.
|
|
|
125
125
|
|
|
126
126
|
Once configured, your agent has the full Alethia tool suite available. The most common one:
|
|
127
127
|
|
|
128
|
-
> *"Use alethia_tell to navigate to
|
|
128
|
+
> *"Use alethia_tell to navigate to file:///path/to/app.html, click the Sign In button, and assert the dashboard heading is visible."*
|
|
129
129
|
|
|
130
|
-
The agent
|
|
130
|
+
The agent calls `alethia_tell` with plain English. Alethia compiles it to Action IR, runs each step through the VITRON-EA1 policy gate, and returns a `PlanRun` with per-step results, DOM diffs, a semantic page snapshot, policy audit records, and a SHA-256 integrity hash.
|
|
131
131
|
|
|
132
132
|
---
|
|
133
133
|
|
|
@@ -137,9 +137,8 @@ The agent will call `alethia_tell` with that NLP, Alethia compiles to Action IR,
|
|
|
137
137
|
Execute natural-language test instructions. The headline tool.
|
|
138
138
|
|
|
139
139
|
```
|
|
140
|
-
nlp: "navigate to
|
|
141
|
-
type
|
|
142
|
-
type password123 into the password field
|
|
140
|
+
nlp: "navigate to file:///path/to/app.html
|
|
141
|
+
type test@example.com into the email field
|
|
143
142
|
click Sign In
|
|
144
143
|
assert the dashboard heading is visible"
|
|
145
144
|
```
|
package/demo/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Alethia Demo Pages
|
|
2
|
+
|
|
3
|
+
Ready-to-use local HTML pages for testing Alethia. Open any page in your browser or drive it with `alethia_tell`.
|
|
4
|
+
|
|
5
|
+
## Pages
|
|
6
|
+
|
|
7
|
+
| Page | What it tests | Key features shown |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `signup-form.html` | Login flow with validation | Navigate, type, click, assert, error detection, DOM diffs |
|
|
10
|
+
| `todo-app.html` | Dynamic list add/delete | Type, click, assert, list awareness in snapshots |
|
|
11
|
+
| `ecommerce.html` | Add to cart → checkout | EA1 policy gate blocks purchase (write-high) |
|
|
12
|
+
| `spa-loading.html` | Async data loading (2s delay) | Page readiness detection, MutationObserver wait-for |
|
|
13
|
+
| `cookie-banner.html` | Cookie consent + newsletter | Conditional steps ("if banner exists, click Accept") |
|
|
14
|
+
| `form-validation.html` | Multi-field validation | Smart assertions, error detection, suggested fixes |
|
|
15
|
+
| `admin-panel.html` | Classified admin system | EA1 blocks user deletion (write-high), audit trail, modal handling |
|
|
16
|
+
| `financial-dashboard.html` | Trading risk monitor | Compliance checks, EA1 blocks trades (write-high), data verification |
|
|
17
|
+
|
|
18
|
+
## Prompts
|
|
19
|
+
|
|
20
|
+
### Login flow (signup-form.html)
|
|
21
|
+
```
|
|
22
|
+
Use alethia_tell to navigate to file:///PATH/demo/signup-form.html, click Sign In without filling anything in and assert the error message appears, then type admin@acme.com into email, type secret123 into password with allowSensitiveInput true, click Sign In, and assert "Welcome back!" is visible.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Todo list (todo-app.html)
|
|
26
|
+
```
|
|
27
|
+
Use alethia_tell to navigate to file:///PATH/demo/todo-app.html, type "Ship v1" into the task input, click Add, type "Record demo" into the task input, click Add, type "Send cold DMs" into the task input, click Add, and assert all three items appear in the list.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### EA1 policy gate (ecommerce.html)
|
|
31
|
+
```
|
|
32
|
+
Use alethia_tell to navigate to file:///PATH/demo/ecommerce.html, click "Add to Cart" on the Wireless Keyboard, click "Add to Cart" on the USB-C Hub, assert the cart shows both items, then click "Complete Purchase" and tell me what the policy gate does.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Page readiness / SPA loading (spa-loading.html)
|
|
36
|
+
```
|
|
37
|
+
Use alethia_tell to navigate to file:///PATH/demo/spa-loading.html and assert "1,247" is visible. The page has a 2-second loading spinner — Alethia should wait for it automatically.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Conditional steps / cookie banner (cookie-banner.html)
|
|
41
|
+
```
|
|
42
|
+
Use alethia_tell to navigate to file:///PATH/demo/cookie-banner.html. If the cookie banner exists, click Accept. Then type hello@test.com into the email field and click Subscribe. Assert "Subscribed!" is visible.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Form validation / smart assertions (form-validation.html)
|
|
46
|
+
```
|
|
47
|
+
Use alethia_tell to navigate to file:///PATH/demo/form-validation.html and click Send Message without filling anything. Check what validation errors appear. Then fill in: name "Jane Doe", email "jane@test.com", select "Partnership" for subject, type "I'd like to discuss integrating Alethia into our agent platform" as the message, and click Send Message. Assert "Message Sent!" is visible.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Admin panel / defense (admin-panel.html)
|
|
51
|
+
```
|
|
52
|
+
Use alethia_tell to navigate to file:///PATH/demo/admin-panel.html. Assert the classification banner says "TOP SECRET // SCI". Check how many users are listed in the table. Then try to click "Delete" on Lt. Marcus Webb — tell me what the policy gate does. If the modal appears, try to click "Delete User" and report what EA1 decides.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Financial risk monitor (financial-dashboard.html)
|
|
56
|
+
```
|
|
57
|
+
Use alethia_tell to navigate to file:///PATH/demo/financial-dashboard.html. Assert the risk level banner is visible. Check the margin used percentage. Verify the compliance checks — are any failing? Then try to click "Liquidate All" and tell me what the policy gate does.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Setup
|
|
61
|
+
|
|
62
|
+
Replace `PATH` in the prompts above with the actual path to this demo folder:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Find your path
|
|
66
|
+
npm root -g
|
|
67
|
+
# The demos are at: <global_root>/@vitronai/alethia/demo/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or clone the repo and use the local path:
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/vitron-ai/alethia-mcp.git
|
|
73
|
+
# Demos at: /path/to/alethia-mcp/demo/
|
|
74
|
+
```
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Admin Panel — Classified</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0a0e17; color: #e2e8f0; min-height: 100vh; padding: 1.5rem; }
|
|
8
|
+
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
|
|
9
|
+
h1 { font-size: 1.4rem; }
|
|
10
|
+
.classification { background: #991b1b; color: #fecaca; padding: 0.3rem 0.8rem; border-radius: 4px; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }
|
|
11
|
+
.user-info { color: #64748b; font-size: 0.85rem; }
|
|
12
|
+
.grid { display: grid; grid-template-columns: 250px 1fr; gap: 1.5rem; }
|
|
13
|
+
.sidebar { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
14
|
+
.nav-item { padding: 0.6rem 0.8rem; border-radius: 8px; background: #1e293b; border: 1px solid #334155; color: #94a3b8; cursor: pointer; text-align: left; font-size: 0.9rem; }
|
|
15
|
+
.nav-item.active { background: #1e3a5f; border-color: #3b82f6; color: #e2e8f0; }
|
|
16
|
+
.content { border: 1px solid #1e293b; border-radius: 12px; background: #111827; padding: 1.5rem; }
|
|
17
|
+
.content h2 { margin-bottom: 1rem; font-size: 1.2rem; }
|
|
18
|
+
table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
|
|
19
|
+
th { text-align: left; padding: 0.6rem; color: #64748b; border-bottom: 1px solid #1e293b; font-weight: 600; }
|
|
20
|
+
td { padding: 0.6rem; border-bottom: 1px solid #0f172a; }
|
|
21
|
+
.status-active { color: #34d399; }
|
|
22
|
+
.status-suspended { color: #f87171; }
|
|
23
|
+
.status-pending { color: #fbbf24; }
|
|
24
|
+
.actions { display: flex; gap: 0.4rem; }
|
|
25
|
+
.actions button { padding: 0.3rem 0.6rem; border-radius: 6px; border: none; font-size: 0.8rem; cursor: pointer; }
|
|
26
|
+
.btn-view { background: #1e3a5f; color: #93c5fd; }
|
|
27
|
+
.btn-suspend { background: #7f1d1d; color: #fca5a5; }
|
|
28
|
+
.btn-delete { background: #991b1b; color: #fecaca; }
|
|
29
|
+
.btn-approve { background: #14532d; color: #86efac; }
|
|
30
|
+
.audit-log { margin-top: 1rem; font-family: monospace; font-size: 0.8rem; background: #0a0e17; border: 1px solid #1e293b; border-radius: 8px; padding: 0.8rem; max-height: 200px; overflow-y: auto; }
|
|
31
|
+
.audit-entry { padding: 0.2rem 0; color: #64748b; }
|
|
32
|
+
.audit-entry .timestamp { color: #475569; }
|
|
33
|
+
.audit-entry .action { color: #fbbf24; }
|
|
34
|
+
.modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: 100; align-items: center; justify-content: center; }
|
|
35
|
+
.modal.visible { display: flex; }
|
|
36
|
+
.modal-content { background: #1e293b; border: 1px solid #334155; border-radius: 12px; padding: 1.5rem; max-width: 400px; text-align: center; }
|
|
37
|
+
.modal-content h3 { color: #f87171; margin-bottom: 0.8rem; }
|
|
38
|
+
.modal-content p { color: #94a3b8; margin-bottom: 1rem; }
|
|
39
|
+
.modal-actions { display: flex; gap: 0.8rem; justify-content: center; }
|
|
40
|
+
.modal-actions button { padding: 0.5rem 1.2rem; border-radius: 8px; border: none; cursor: pointer; font-weight: 600; }
|
|
41
|
+
.btn-cancel { background: #334155; color: #e2e8f0; }
|
|
42
|
+
.btn-confirm-delete { background: #991b1b; color: white; }
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
<div class="header">
|
|
47
|
+
<div>
|
|
48
|
+
<h1>System Administration</h1>
|
|
49
|
+
<span class="user-info">Operator: admin@agency.gov · Session: 4f8a2c · Clearance: TS/SCI</span>
|
|
50
|
+
</div>
|
|
51
|
+
<span class="classification">TOP SECRET // SCI</span>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="grid">
|
|
54
|
+
<div class="sidebar">
|
|
55
|
+
<button class="nav-item active" id="nav-users">User Management</button>
|
|
56
|
+
<button class="nav-item" id="nav-access">Access Control</button>
|
|
57
|
+
<button class="nav-item" id="nav-audit">Audit Trail</button>
|
|
58
|
+
<button class="nav-item" id="nav-system">System Config</button>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="content">
|
|
61
|
+
<h2>User Management</h2>
|
|
62
|
+
<table>
|
|
63
|
+
<thead>
|
|
64
|
+
<tr><th>Name</th><th>Role</th><th>Clearance</th><th>Status</th><th>Actions</th></tr>
|
|
65
|
+
</thead>
|
|
66
|
+
<tbody>
|
|
67
|
+
<tr>
|
|
68
|
+
<td>Col. Sarah Chen</td><td>Program Director</td><td>TS/SCI</td>
|
|
69
|
+
<td class="status-active">Active</td>
|
|
70
|
+
<td class="actions"><button class="btn-view">View</button><button class="btn-suspend">Suspend</button></td>
|
|
71
|
+
</tr>
|
|
72
|
+
<tr>
|
|
73
|
+
<td>Maj. James Rivera</td><td>Systems Engineer</td><td>TS</td>
|
|
74
|
+
<td class="status-active">Active</td>
|
|
75
|
+
<td class="actions"><button class="btn-view">View</button><button class="btn-suspend">Suspend</button></td>
|
|
76
|
+
</tr>
|
|
77
|
+
<tr>
|
|
78
|
+
<td>Dr. Aisha Patel</td><td>Analyst</td><td>Secret</td>
|
|
79
|
+
<td class="status-pending">Pending Review</td>
|
|
80
|
+
<td class="actions"><button class="btn-view">View</button><button class="btn-approve">Approve</button></td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr>
|
|
83
|
+
<td>Lt. Marcus Webb</td><td>Contractor</td><td>Secret</td>
|
|
84
|
+
<td class="status-suspended">Suspended</td>
|
|
85
|
+
<td class="actions"><button class="btn-view">View</button><button class="btn-delete" id="delete-webb">Delete</button></td>
|
|
86
|
+
</tr>
|
|
87
|
+
</tbody>
|
|
88
|
+
</table>
|
|
89
|
+
<div class="audit-log" id="audit-log">
|
|
90
|
+
<div class="audit-entry"><span class="timestamp">2026-04-10T09:14:22Z</span> <span class="action">LOGIN</span> admin@agency.gov from 10.0.0.42</div>
|
|
91
|
+
<div class="audit-entry"><span class="timestamp">2026-04-10T09:14:28Z</span> <span class="action">VIEW</span> User Management panel accessed</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div id="delete-modal" class="modal">
|
|
96
|
+
<div class="modal-content">
|
|
97
|
+
<h3>Confirm User Deletion</h3>
|
|
98
|
+
<p>This action is irreversible. Lt. Marcus Webb's access credentials, audit history, and associated records will be permanently removed.</p>
|
|
99
|
+
<div class="modal-actions">
|
|
100
|
+
<button class="btn-cancel" id="cancel-delete">Cancel</button>
|
|
101
|
+
<button class="btn-confirm-delete" id="confirm-delete">Delete User</button>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<script>
|
|
106
|
+
var auditLog = document.getElementById('audit-log');
|
|
107
|
+
function logAudit(action, detail) {
|
|
108
|
+
var entry = document.createElement('div');
|
|
109
|
+
entry.className = 'audit-entry';
|
|
110
|
+
entry.innerHTML = '<span class="timestamp">' + new Date().toISOString() + '</span> <span class="action">' + action + '</span> ' + detail;
|
|
111
|
+
auditLog.appendChild(entry);
|
|
112
|
+
auditLog.scrollTop = auditLog.scrollHeight;
|
|
113
|
+
}
|
|
114
|
+
document.getElementById('delete-webb').addEventListener('click', function() {
|
|
115
|
+
document.getElementById('delete-modal').classList.add('visible');
|
|
116
|
+
logAudit('DELETE_REQUESTED', 'Deletion requested for Lt. Marcus Webb');
|
|
117
|
+
});
|
|
118
|
+
document.getElementById('cancel-delete').addEventListener('click', function() {
|
|
119
|
+
document.getElementById('delete-modal').classList.remove('visible');
|
|
120
|
+
logAudit('DELETE_CANCELLED', 'Deletion cancelled for Lt. Marcus Webb');
|
|
121
|
+
});
|
|
122
|
+
document.getElementById('confirm-delete').addEventListener('click', function() {
|
|
123
|
+
document.getElementById('delete-modal').classList.remove('visible');
|
|
124
|
+
logAudit('DELETE_CONFIRMED', 'Lt. Marcus Webb permanently deleted');
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
</body>
|
|
128
|
+
</html>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Blog Post</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; padding: 2rem; }
|
|
8
|
+
h1 { font-size: 1.8rem; margin-bottom: 0.5rem; }
|
|
9
|
+
.meta { color: #64748b; margin-bottom: 1.5rem; font-size: 0.9rem; }
|
|
10
|
+
article { max-width: 640px; line-height: 1.7; }
|
|
11
|
+
article p { margin-bottom: 1rem; color: #cbd5e1; }
|
|
12
|
+
.cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: #1e293b; border-top: 1px solid #334155; padding: 1rem 2rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; z-index: 100; }
|
|
13
|
+
.cookie-banner p { color: #94a3b8; font-size: 0.9rem; margin: 0; }
|
|
14
|
+
.cookie-banner button { padding: 0.5rem 1.2rem; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
|
|
15
|
+
.accept-btn { background: #3b82f6; color: white; }
|
|
16
|
+
.decline-btn { background: #334155; color: #94a3b8; }
|
|
17
|
+
.hidden { display: none; }
|
|
18
|
+
.newsletter { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; margin-top: 2rem; }
|
|
19
|
+
.newsletter h3 { margin-bottom: 0.5rem; }
|
|
20
|
+
.newsletter input { padding: 0.5rem; border-radius: 6px; border: 1px solid #334155; background: #0f172a; color: #e2e8f0; margin-right: 0.5rem; }
|
|
21
|
+
.newsletter button { padding: 0.5rem 1rem; border-radius: 6px; border: none; background: #3b82f6; color: white; cursor: pointer; }
|
|
22
|
+
.subscribed { color: #34d399; font-weight: 600; display: none; }
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<article>
|
|
27
|
+
<h1>Why Zero-IPC Matters for AI Agents</h1>
|
|
28
|
+
<p class="meta">April 10, 2026 · 5 min read</p>
|
|
29
|
+
<p>When an AI agent generates code and needs to verify it works, every millisecond of automation latency compounds. CDP-based tools add ~580ms of marshalling tax per assertion.</p>
|
|
30
|
+
<p>Zero-IPC eliminates the process boundary between the automation driver and the DOM. The driver touches the DOM the same way the page's own JavaScript does — synchronously, in-process, with no serialization overhead.</p>
|
|
31
|
+
<p>The result: ~13ms per step instead of ~580ms. That's not an optimization — it's a different architecture.</p>
|
|
32
|
+
<div class="newsletter">
|
|
33
|
+
<h3>Subscribe to updates</h3>
|
|
34
|
+
<div id="subscribe-form">
|
|
35
|
+
<input id="email" type="email" placeholder="you@example.com" aria-label="Email address" />
|
|
36
|
+
<button id="subscribe-btn" type="button">Subscribe</button>
|
|
37
|
+
</div>
|
|
38
|
+
<p id="subscribed" class="subscribed">Subscribed! Check your inbox.</p>
|
|
39
|
+
</div>
|
|
40
|
+
</article>
|
|
41
|
+
|
|
42
|
+
<div id="cookie-banner" class="cookie-banner">
|
|
43
|
+
<p>We use cookies to improve your experience. No tracking, no ads.</p>
|
|
44
|
+
<div>
|
|
45
|
+
<button class="decline-btn" id="decline-cookies" type="button">Decline</button>
|
|
46
|
+
<button class="accept-btn" id="accept-cookies" type="button">Accept</button>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
document.getElementById('accept-cookies').addEventListener('click', function() {
|
|
52
|
+
document.getElementById('cookie-banner').classList.add('hidden');
|
|
53
|
+
});
|
|
54
|
+
document.getElementById('decline-cookies').addEventListener('click', function() {
|
|
55
|
+
document.getElementById('cookie-banner').classList.add('hidden');
|
|
56
|
+
});
|
|
57
|
+
document.getElementById('subscribe-btn').addEventListener('click', function() {
|
|
58
|
+
var email = document.getElementById('email').value;
|
|
59
|
+
if (email && email.includes('@')) {
|
|
60
|
+
document.getElementById('subscribe-form').style.display = 'none';
|
|
61
|
+
document.getElementById('subscribed').style.display = 'block';
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Acme Store</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; padding: 2rem; }
|
|
8
|
+
h1 { font-size: 1.8rem; margin-bottom: 1.5rem; }
|
|
9
|
+
.products { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 2rem; }
|
|
10
|
+
.product { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; }
|
|
11
|
+
.product h2 { font-size: 1.1rem; margin-bottom: 0.4rem; }
|
|
12
|
+
.product .price { color: #34d399; font-weight: 700; font-size: 1.2rem; }
|
|
13
|
+
.product p { color: #94a3b8; font-size: 0.9rem; margin: 0.4rem 0; }
|
|
14
|
+
button { padding: 0.6rem 1rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-weight: 600; cursor: pointer; margin-top: 0.5rem; }
|
|
15
|
+
button:hover { background: #2563eb; }
|
|
16
|
+
button:disabled { background: #475569; cursor: not-allowed; }
|
|
17
|
+
.cart { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; max-width: 400px; }
|
|
18
|
+
.cart h2 { margin-bottom: 0.8rem; }
|
|
19
|
+
.cart ul { list-style: none; }
|
|
20
|
+
.cart li { padding: 0.4rem 0; border-bottom: 1px solid #0f172a; display: flex; justify-content: space-between; }
|
|
21
|
+
.cart-total { margin-top: 0.8rem; font-weight: 700; font-size: 1.1rem; color: #34d399; }
|
|
22
|
+
.cart-empty { color: #64748b; }
|
|
23
|
+
.checkout-btn { background: #ef4444; width: 100%; margin-top: 0.8rem; }
|
|
24
|
+
.success { display: none; color: #34d399; font-size: 1.2rem; font-weight: 700; margin-top: 1rem; }
|
|
25
|
+
</style>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<h1>Acme Store</h1>
|
|
29
|
+
<div class="products">
|
|
30
|
+
<div class="product">
|
|
31
|
+
<h2>Wireless Keyboard</h2>
|
|
32
|
+
<p>Mechanical, RGB backlit</p>
|
|
33
|
+
<span class="price">$79</span>
|
|
34
|
+
<br/>
|
|
35
|
+
<button onclick="addToCart('Wireless Keyboard', 79)">Add to Cart</button>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="product">
|
|
38
|
+
<h2>USB-C Hub</h2>
|
|
39
|
+
<p>7-port, 100W passthrough</p>
|
|
40
|
+
<span class="price">$45</span>
|
|
41
|
+
<br/>
|
|
42
|
+
<button onclick="addToCart('USB-C Hub', 45)">Add to Cart</button>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="product">
|
|
45
|
+
<h2>Monitor Stand</h2>
|
|
46
|
+
<p>Adjustable, aluminum</p>
|
|
47
|
+
<span class="price">$120</span>
|
|
48
|
+
<br/>
|
|
49
|
+
<button onclick="addToCart('Monitor Stand', 120)">Add to Cart</button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="cart">
|
|
53
|
+
<h2>Cart</h2>
|
|
54
|
+
<ul id="cart-items"><li class="cart-empty">Your cart is empty</li></ul>
|
|
55
|
+
<p id="cart-total" class="cart-total"></p>
|
|
56
|
+
<button class="checkout-btn" id="checkout-btn" onclick="checkout()" disabled>Complete Purchase</button>
|
|
57
|
+
</div>
|
|
58
|
+
<p id="success" class="success" role="alert">Order confirmed! Thank you for your purchase.</p>
|
|
59
|
+
<script>
|
|
60
|
+
const cart = [];
|
|
61
|
+
function addToCart(name, price) {
|
|
62
|
+
cart.push({ name, price });
|
|
63
|
+
renderCart();
|
|
64
|
+
}
|
|
65
|
+
function renderCart() {
|
|
66
|
+
const list = document.getElementById('cart-items');
|
|
67
|
+
const total = document.getElementById('cart-total');
|
|
68
|
+
const btn = document.getElementById('checkout-btn');
|
|
69
|
+
if (cart.length === 0) {
|
|
70
|
+
list.innerHTML = '<li class="cart-empty">Your cart is empty</li>';
|
|
71
|
+
total.textContent = '';
|
|
72
|
+
btn.disabled = true;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
list.innerHTML = cart.map(item => '<li><span>' + item.name + '</span><span>$' + item.price + '</span></li>').join('');
|
|
76
|
+
const sum = cart.reduce((s, i) => s + i.price, 0);
|
|
77
|
+
total.textContent = 'Total: $' + sum;
|
|
78
|
+
btn.disabled = false;
|
|
79
|
+
}
|
|
80
|
+
function checkout() {
|
|
81
|
+
document.getElementById('success').style.display = 'block';
|
|
82
|
+
document.getElementById('checkout-btn').disabled = true;
|
|
83
|
+
document.getElementById('checkout-btn').textContent = 'Purchased';
|
|
84
|
+
document.title = 'Order Confirmed — Acme Store';
|
|
85
|
+
}
|
|
86
|
+
</script>
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Trading Platform — Risk Monitor</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0a0e17; color: #e2e8f0; min-height: 100vh; padding: 1.5rem; }
|
|
8
|
+
h1 { font-size: 1.4rem; margin-bottom: 0.3rem; }
|
|
9
|
+
.subtitle { color: #64748b; font-size: 0.85rem; margin-bottom: 1.5rem; }
|
|
10
|
+
.risk-banner { padding: 0.6rem 1rem; border-radius: 8px; margin-bottom: 1.5rem; font-weight: 600; }
|
|
11
|
+
.risk-low { background: #14532d; border: 1px solid #22c55e; color: #86efac; }
|
|
12
|
+
.risk-medium { background: #78350f; border: 1px solid #f59e0b; color: #fde68a; }
|
|
13
|
+
.risk-high { background: #7f1d1d; border: 1px solid #ef4444; color: #fca5a5; }
|
|
14
|
+
.metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
15
|
+
.metric { background: #111827; border: 1px solid #1e293b; border-radius: 12px; padding: 1rem; }
|
|
16
|
+
.metric-label { color: #64748b; font-size: 0.8rem; margin-bottom: 0.3rem; }
|
|
17
|
+
.metric-value { font-size: 1.6rem; font-weight: 700; }
|
|
18
|
+
.metric-value.positive { color: #34d399; }
|
|
19
|
+
.metric-value.negative { color: #f87171; }
|
|
20
|
+
.metric-value.neutral { color: #3b82f6; }
|
|
21
|
+
.positions { background: #111827; border: 1px solid #1e293b; border-radius: 12px; padding: 1.2rem; margin-bottom: 1.5rem; }
|
|
22
|
+
.positions h2 { font-size: 1.1rem; margin-bottom: 0.8rem; }
|
|
23
|
+
table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
|
|
24
|
+
th { text-align: left; padding: 0.5rem; color: #64748b; border-bottom: 1px solid #1e293b; }
|
|
25
|
+
td { padding: 0.5rem; border-bottom: 1px solid #0f172a; }
|
|
26
|
+
.pnl-positive { color: #34d399; }
|
|
27
|
+
.pnl-negative { color: #f87171; }
|
|
28
|
+
.trade-actions { display: flex; gap: 1rem; margin-top: 1rem; }
|
|
29
|
+
.trade-btn { padding: 0.6rem 1.2rem; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; font-size: 0.9rem; }
|
|
30
|
+
.btn-buy { background: #14532d; color: #86efac; }
|
|
31
|
+
.btn-sell { background: #7f1d1d; color: #fca5a5; }
|
|
32
|
+
.btn-liquidate { background: #991b1b; color: white; }
|
|
33
|
+
.compliance { background: #111827; border: 1px solid #1e293b; border-radius: 12px; padding: 1.2rem; }
|
|
34
|
+
.compliance h2 { font-size: 1.1rem; margin-bottom: 0.8rem; }
|
|
35
|
+
.check-item { display: flex; justify-content: space-between; padding: 0.4rem 0; border-bottom: 1px solid #0f172a; }
|
|
36
|
+
.check-pass { color: #34d399; }
|
|
37
|
+
.check-fail { color: #f87171; }
|
|
38
|
+
.check-warn { color: #fbbf24; }
|
|
39
|
+
</style>
|
|
40
|
+
</head>
|
|
41
|
+
<body>
|
|
42
|
+
<h1>Risk Monitor</h1>
|
|
43
|
+
<p class="subtitle">Live · Last update: 2 seconds ago · Market: NYSE · Session: Pre-market</p>
|
|
44
|
+
|
|
45
|
+
<div id="risk-banner" class="risk-banner risk-medium" role="alert">
|
|
46
|
+
RISK LEVEL: MEDIUM — Portfolio exposure approaching limit (82% of max)
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="metrics">
|
|
50
|
+
<div class="metric">
|
|
51
|
+
<div class="metric-label">Portfolio Value</div>
|
|
52
|
+
<div class="metric-value neutral">$4.2M</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="metric">
|
|
55
|
+
<div class="metric-label">Day P&L</div>
|
|
56
|
+
<div class="metric-value positive">+$127,430</div>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="metric">
|
|
59
|
+
<div class="metric-label">Open Positions</div>
|
|
60
|
+
<div class="metric-value neutral">14</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="metric">
|
|
63
|
+
<div class="metric-label">Margin Used</div>
|
|
64
|
+
<div class="metric-value negative">82%</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="positions">
|
|
69
|
+
<h2>Open Positions</h2>
|
|
70
|
+
<table>
|
|
71
|
+
<thead>
|
|
72
|
+
<tr><th>Symbol</th><th>Qty</th><th>Avg Cost</th><th>Current</th><th>P&L</th><th>Risk</th></tr>
|
|
73
|
+
</thead>
|
|
74
|
+
<tbody>
|
|
75
|
+
<tr><td>AAPL</td><td>5,000</td><td>$178.42</td><td>$182.15</td><td class="pnl-positive">+$18,650</td><td>Low</td></tr>
|
|
76
|
+
<tr><td>TSLA</td><td>2,000</td><td>$245.80</td><td>$238.20</td><td class="pnl-negative">-$15,200</td><td>Medium</td></tr>
|
|
77
|
+
<tr><td>NVDA</td><td>1,500</td><td>$890.00</td><td>$912.50</td><td class="pnl-positive">+$33,750</td><td>Low</td></tr>
|
|
78
|
+
<tr><td>GME</td><td>10,000</td><td>$28.40</td><td>$24.15</td><td class="pnl-negative">-$42,500</td><td>High</td></tr>
|
|
79
|
+
</tbody>
|
|
80
|
+
</table>
|
|
81
|
+
<div class="trade-actions">
|
|
82
|
+
<button class="trade-btn btn-buy" id="buy-btn">Buy</button>
|
|
83
|
+
<button class="trade-btn btn-sell" id="sell-btn">Sell Position</button>
|
|
84
|
+
<button class="trade-btn btn-liquidate" id="liquidate-btn">Liquidate All</button>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div class="compliance">
|
|
89
|
+
<h2>Compliance Checks</h2>
|
|
90
|
+
<div class="check-item"><span>Position concentration limit (< 25%)</span><span class="check-pass">PASS</span></div>
|
|
91
|
+
<div class="check-item"><span>Margin requirement (< 85%)</span><span class="check-warn">WARNING — 82%</span></div>
|
|
92
|
+
<div class="check-item"><span>Daily loss limit (< $100K)</span><span class="check-pass">PASS</span></div>
|
|
93
|
+
<div class="check-item"><span>Restricted securities check</span><span class="check-pass">CLEAR</span></div>
|
|
94
|
+
<div class="check-item"><span>Pre-trade risk approval</span><span class="check-fail">REQUIRED for trades > $500K</span></div>
|
|
95
|
+
</div>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Contact Form</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
+
.container { width: 400px; }
|
|
9
|
+
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
+
form { display: flex; flex-direction: column; gap: 0.8rem; }
|
|
11
|
+
label { font-size: 0.9rem; color: #94a3b8; }
|
|
12
|
+
input, textarea, select { padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; font-family: inherit; }
|
|
13
|
+
input::placeholder, textarea::placeholder { color: #64748b; }
|
|
14
|
+
input.invalid, textarea.invalid, select.invalid { border-color: #f87171; }
|
|
15
|
+
.field-error { color: #f87171; font-size: 0.8rem; display: none; }
|
|
16
|
+
.field-error.visible { display: block; }
|
|
17
|
+
textarea { resize: vertical; min-height: 80px; }
|
|
18
|
+
button { padding: 0.75rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
19
|
+
button:hover { background: #2563eb; }
|
|
20
|
+
button:disabled { background: #475569; cursor: not-allowed; }
|
|
21
|
+
.success { display: none; text-align: center; }
|
|
22
|
+
.success h2 { color: #34d399; margin-bottom: 0.5rem; }
|
|
23
|
+
.success p { color: #94a3b8; }
|
|
24
|
+
.char-count { font-size: 0.8rem; color: #64748b; text-align: right; }
|
|
25
|
+
</style>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<div class="container">
|
|
29
|
+
<div id="form-container">
|
|
30
|
+
<h1>Contact Us</h1>
|
|
31
|
+
<form id="contact-form" onsubmit="return false;">
|
|
32
|
+
<div>
|
|
33
|
+
<label for="name">Full Name</label>
|
|
34
|
+
<input id="name" placeholder="Jane Doe" aria-label="Full name" />
|
|
35
|
+
<p id="name-error" class="field-error" role="alert">Name is required</p>
|
|
36
|
+
</div>
|
|
37
|
+
<div>
|
|
38
|
+
<label for="contact-email">Email</label>
|
|
39
|
+
<input id="contact-email" type="email" placeholder="jane@example.com" aria-label="Email" />
|
|
40
|
+
<p id="email-error" class="field-error" role="alert">Please enter a valid email</p>
|
|
41
|
+
</div>
|
|
42
|
+
<div>
|
|
43
|
+
<label for="subject">Subject</label>
|
|
44
|
+
<select id="subject" aria-label="Subject">
|
|
45
|
+
<option value="">Select a topic...</option>
|
|
46
|
+
<option value="general">General inquiry</option>
|
|
47
|
+
<option value="support">Technical support</option>
|
|
48
|
+
<option value="partnership">Partnership</option>
|
|
49
|
+
<option value="licensing">Licensing</option>
|
|
50
|
+
</select>
|
|
51
|
+
<p id="subject-error" class="field-error" role="alert">Please select a subject</p>
|
|
52
|
+
</div>
|
|
53
|
+
<div>
|
|
54
|
+
<label for="message">Message</label>
|
|
55
|
+
<textarea id="message" placeholder="Tell us what's on your mind..." aria-label="Message"></textarea>
|
|
56
|
+
<p class="char-count"><span id="char-count">0</span>/500</p>
|
|
57
|
+
<p id="message-error" class="field-error" role="alert">Message must be at least 10 characters</p>
|
|
58
|
+
</div>
|
|
59
|
+
<button type="button" id="submit-btn">Send Message</button>
|
|
60
|
+
</form>
|
|
61
|
+
</div>
|
|
62
|
+
<div id="success" class="success">
|
|
63
|
+
<h2>Message Sent!</h2>
|
|
64
|
+
<p>Thanks for reaching out. We'll get back to you within 24 hours.</p>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
<script>
|
|
68
|
+
var messageEl = document.getElementById('message');
|
|
69
|
+
var charCount = document.getElementById('char-count');
|
|
70
|
+
messageEl.addEventListener('input', function() {
|
|
71
|
+
charCount.textContent = messageEl.value.length;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
document.getElementById('submit-btn').addEventListener('click', function() {
|
|
75
|
+
var name = document.getElementById('name');
|
|
76
|
+
var email = document.getElementById('contact-email');
|
|
77
|
+
var subject = document.getElementById('subject');
|
|
78
|
+
var message = document.getElementById('message');
|
|
79
|
+
var valid = true;
|
|
80
|
+
|
|
81
|
+
// Reset
|
|
82
|
+
[name, email, subject, message].forEach(function(el) { el.classList.remove('invalid'); });
|
|
83
|
+
document.querySelectorAll('.field-error').forEach(function(el) { el.classList.remove('visible'); });
|
|
84
|
+
|
|
85
|
+
if (!name.value.trim()) {
|
|
86
|
+
name.classList.add('invalid');
|
|
87
|
+
document.getElementById('name-error').classList.add('visible');
|
|
88
|
+
valid = false;
|
|
89
|
+
}
|
|
90
|
+
if (!email.value.trim() || !email.value.includes('@')) {
|
|
91
|
+
email.classList.add('invalid');
|
|
92
|
+
document.getElementById('email-error').classList.add('visible');
|
|
93
|
+
valid = false;
|
|
94
|
+
}
|
|
95
|
+
if (!subject.value) {
|
|
96
|
+
subject.classList.add('invalid');
|
|
97
|
+
document.getElementById('subject-error').classList.add('visible');
|
|
98
|
+
valid = false;
|
|
99
|
+
}
|
|
100
|
+
if (message.value.trim().length < 10) {
|
|
101
|
+
message.classList.add('invalid');
|
|
102
|
+
document.getElementById('message-error').classList.add('visible');
|
|
103
|
+
valid = false;
|
|
104
|
+
}
|
|
105
|
+
if (valid) {
|
|
106
|
+
document.getElementById('form-container').style.display = 'none';
|
|
107
|
+
document.getElementById('success').style.display = 'block';
|
|
108
|
+
document.title = 'Message Sent — Contact';
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
</script>
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Acme Dashboard</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
+
.container { width: 360px; }
|
|
9
|
+
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
+
form { display: flex; flex-direction: column; gap: 0.8rem; }
|
|
11
|
+
input { padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; }
|
|
12
|
+
input::placeholder { color: #64748b; }
|
|
13
|
+
button { padding: 0.75rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
14
|
+
button:hover { background: #2563eb; }
|
|
15
|
+
.error { color: #f87171; font-size: 0.9rem; display: none; }
|
|
16
|
+
.error.visible { display: block; }
|
|
17
|
+
#dashboard { display: none; }
|
|
18
|
+
#dashboard h1 { color: #34d399; }
|
|
19
|
+
#dashboard ul { list-style: none; margin-top: 1rem; }
|
|
20
|
+
#dashboard li { padding: 0.5rem 0; border-bottom: 1px solid #1e293b; }
|
|
21
|
+
#dashboard button { background: #ef4444; margin-top: 1rem; }
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<div class="container">
|
|
26
|
+
<div id="login">
|
|
27
|
+
<h1>Sign In</h1>
|
|
28
|
+
<div id="error" class="error" role="alert">Please fill in all fields</div>
|
|
29
|
+
<form onsubmit="return false;">
|
|
30
|
+
<input id="email" type="email" placeholder="Email" aria-label="Email" />
|
|
31
|
+
<input id="password" type="password" placeholder="Password" aria-label="Password" />
|
|
32
|
+
<button type="button" id="signin-btn">Sign In</button>
|
|
33
|
+
</form>
|
|
34
|
+
</div>
|
|
35
|
+
<div id="dashboard">
|
|
36
|
+
<h1>Welcome back!</h1>
|
|
37
|
+
<p id="user-greeting"></p>
|
|
38
|
+
<ul id="tasks">
|
|
39
|
+
<li>Deploy v2.1</li>
|
|
40
|
+
<li>Review PR #42</li>
|
|
41
|
+
<li>Update docs</li>
|
|
42
|
+
</ul>
|
|
43
|
+
<button type="button" id="logout-btn">Sign Out</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<script>
|
|
47
|
+
document.getElementById('signin-btn').addEventListener('click', function() {
|
|
48
|
+
var email = document.getElementById('email').value;
|
|
49
|
+
var password = document.getElementById('password').value;
|
|
50
|
+
var error = document.getElementById('error');
|
|
51
|
+
if (!email || !password) {
|
|
52
|
+
error.classList.add('visible');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
error.classList.remove('visible');
|
|
56
|
+
document.getElementById('login').style.display = 'none';
|
|
57
|
+
document.getElementById('dashboard').style.display = 'block';
|
|
58
|
+
document.getElementById('user-greeting').textContent = 'Logged in as ' + email;
|
|
59
|
+
document.title = 'Dashboard — Acme';
|
|
60
|
+
});
|
|
61
|
+
document.getElementById('logout-btn').addEventListener('click', function() {
|
|
62
|
+
document.getElementById('login').style.display = 'block';
|
|
63
|
+
document.getElementById('dashboard').style.display = 'none';
|
|
64
|
+
document.getElementById('email').value = '';
|
|
65
|
+
document.getElementById('password').value = '';
|
|
66
|
+
document.title = 'Acme Dashboard';
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
</body>
|
|
70
|
+
</html>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>SPA Dashboard</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
+
.container { width: 480px; }
|
|
9
|
+
h1 { font-size: 1.8rem; margin-bottom: 1rem; }
|
|
10
|
+
.spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid #334155; border-top-color: #3b82f6; border-radius: 50%; animation: spin 0.8s linear infinite; margin-right: 0.5rem; vertical-align: middle; }
|
|
11
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
12
|
+
.loading { color: #94a3b8; margin-bottom: 1rem; }
|
|
13
|
+
.card { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; margin-bottom: 0.8rem; }
|
|
14
|
+
.card h3 { margin-bottom: 0.4rem; }
|
|
15
|
+
.card p { color: #94a3b8; font-size: 0.9rem; }
|
|
16
|
+
.stats { display: flex; gap: 1rem; margin-top: 1rem; }
|
|
17
|
+
.stat { text-align: center; }
|
|
18
|
+
.stat-value { font-size: 2rem; font-weight: 700; color: #3b82f6; }
|
|
19
|
+
.stat-label { font-size: 0.8rem; color: #64748b; }
|
|
20
|
+
#content { display: none; }
|
|
21
|
+
</style>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<div class="container">
|
|
25
|
+
<h1>Analytics Dashboard</h1>
|
|
26
|
+
<div id="loading" class="loading" aria-busy="true">
|
|
27
|
+
<span class="spinner"></span>Loading dashboard data...
|
|
28
|
+
</div>
|
|
29
|
+
<div id="content">
|
|
30
|
+
<div class="stats">
|
|
31
|
+
<div class="stat">
|
|
32
|
+
<div class="stat-value">1,247</div>
|
|
33
|
+
<div class="stat-label">Users</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="stat">
|
|
36
|
+
<div class="stat-value">89%</div>
|
|
37
|
+
<div class="stat-label">Uptime</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="stat">
|
|
40
|
+
<div class="stat-value">3.2s</div>
|
|
41
|
+
<div class="stat-label">Avg Response</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="card">
|
|
45
|
+
<h3>Recent Activity</h3>
|
|
46
|
+
<p>12 deployments this week. Last deploy: 2 hours ago.</p>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="card">
|
|
49
|
+
<h3>Alerts</h3>
|
|
50
|
+
<p>No active alerts. All systems operational.</p>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<script>
|
|
55
|
+
// Simulate async data loading — 2 second delay
|
|
56
|
+
setTimeout(function() {
|
|
57
|
+
document.getElementById('loading').style.display = 'none';
|
|
58
|
+
document.getElementById('loading').setAttribute('aria-busy', 'false');
|
|
59
|
+
document.getElementById('content').style.display = 'block';
|
|
60
|
+
document.title = 'Analytics Dashboard — Loaded';
|
|
61
|
+
}, 2000);
|
|
62
|
+
</script>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Todo App</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
+
.container { width: 400px; }
|
|
9
|
+
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
+
.add-row { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
|
|
11
|
+
input { flex: 1; padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; }
|
|
12
|
+
input::placeholder { color: #64748b; }
|
|
13
|
+
button { padding: 0.7rem 1.2rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
14
|
+
button:hover { background: #2563eb; }
|
|
15
|
+
ul { list-style: none; }
|
|
16
|
+
li { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
|
|
17
|
+
.delete-btn { background: #ef4444; padding: 0.3rem 0.6rem; font-size: 0.85rem; }
|
|
18
|
+
.count { color: #94a3b8; font-size: 0.9rem; margin-top: 0.8rem; }
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div class="container">
|
|
23
|
+
<h1>Todo List</h1>
|
|
24
|
+
<div class="add-row">
|
|
25
|
+
<input id="todo-input" placeholder="Add a task..." aria-label="New task" />
|
|
26
|
+
<button type="button" onclick="addTodo()">Add</button>
|
|
27
|
+
</div>
|
|
28
|
+
<ul id="todo-list"></ul>
|
|
29
|
+
<p id="count" class="count"></p>
|
|
30
|
+
</div>
|
|
31
|
+
<script>
|
|
32
|
+
function updateCount() {
|
|
33
|
+
const items = document.querySelectorAll('#todo-list li');
|
|
34
|
+
document.getElementById('count').textContent = items.length + ' item' + (items.length !== 1 ? 's' : '');
|
|
35
|
+
}
|
|
36
|
+
function addTodo() {
|
|
37
|
+
const input = document.getElementById('todo-input');
|
|
38
|
+
const text = input.value.trim();
|
|
39
|
+
if (!text) return;
|
|
40
|
+
const li = document.createElement('li');
|
|
41
|
+
li.innerHTML = '<span>' + text + '</span><button class="delete-btn" onclick="this.parentElement.remove(); updateCount()">Delete</button>';
|
|
42
|
+
document.getElementById('todo-list').appendChild(li);
|
|
43
|
+
input.value = '';
|
|
44
|
+
updateCount();
|
|
45
|
+
}
|
|
46
|
+
document.getElementById('todo-input').addEventListener('keydown', function(e) {
|
|
47
|
+
if (e.key === 'Enter') addTodo();
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
</body>
|
|
51
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitronai/alethia",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "MIT-licensed MCP bridge to the Alethia desktop runtime — the patent-pending zero-IPC E2E test runtime built for AI agents. 45x faster than Playwright on the localhost loop. Local-first, zero telemetry by default. Auto-installs the signed headless runtime on first use.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
+
"demo",
|
|
12
13
|
"LICENSE",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|