@conversionpros/aiva 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/auto-deploy.js +190 -0
- package/bin/aiva.js +81 -0
- package/cli-sync.js +126 -0
- package/d2a-prompt-template.txt +106 -0
- package/diagnostics-api.js +304 -0
- package/docs/ara-dedup-fix-scope.md +112 -0
- package/docs/ara-fix-round2-scope.md +61 -0
- package/docs/ara-greeting-fix-scope.md +70 -0
- package/docs/calendar-date-fix-scope.md +28 -0
- package/docs/getting-started.md +115 -0
- package/docs/network-architecture-rollout-scope.md +43 -0
- package/docs/scope-google-oauth-integration.md +351 -0
- package/docs/settings-page-scope.md +50 -0
- package/docs/xai-imagine-scope.md +116 -0
- package/docs/xai-voice-integration-scope.md +115 -0
- package/docs/xai-voice-tools-scope.md +165 -0
- package/email-router.js +512 -0
- package/follow-up-handler.js +606 -0
- package/gateway-monitor.js +158 -0
- package/google-email.js +379 -0
- package/google-oauth.js +310 -0
- package/grok-imagine.js +97 -0
- package/health-reporter.js +287 -0
- package/invisible-prefix-base.txt +206 -0
- package/invisible-prefix-owner.txt +26 -0
- package/invisible-prefix-slim.txt +10 -0
- package/invisible-prefix.txt +43 -0
- package/knowledge-base.js +472 -0
- package/lib/cli.js +19 -0
- package/lib/config.js +124 -0
- package/lib/health.js +57 -0
- package/lib/process.js +207 -0
- package/lib/server.js +42 -0
- package/lib/setup.js +472 -0
- package/meta-capi.js +206 -0
- package/meta-leads.js +411 -0
- package/notion-oauth.js +323 -0
- package/package.json +61 -0
- package/public/agent-config.html +241 -0
- package/public/aiva-avatar-anime.png +0 -0
- package/public/css/docs.css.bak +688 -0
- package/public/css/onboarding.css +543 -0
- package/public/diagrams/claude-subscription-pool.html +329 -0
- package/public/diagrams/claude-subscription-pool.png +0 -0
- package/public/docs-icon.png +0 -0
- package/public/escalation.html +237 -0
- package/public/group-config.html +300 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icons/agents.svg +1 -0
- package/public/icons/attach.svg +1 -0
- package/public/icons/characters.svg +1 -0
- package/public/icons/chat.svg +1 -0
- package/public/icons/docs.svg +1 -0
- package/public/icons/heartbeat.svg +1 -0
- package/public/icons/messages.svg +1 -0
- package/public/icons/mic.svg +1 -0
- package/public/icons/notes.svg +1 -0
- package/public/icons/settings.svg +1 -0
- package/public/icons/tasks.svg +1 -0
- package/public/images/onboarding/p0-communication-layer.png +0 -0
- package/public/images/onboarding/p0-infinite-surface.png +0 -0
- package/public/images/onboarding/p0-learning-model.png +0 -0
- package/public/images/onboarding/p0-meet-aiva.png +0 -0
- package/public/images/onboarding/p4-contact-intelligence.png +0 -0
- package/public/images/onboarding/p4-context-compounds.png +0 -0
- package/public/images/onboarding/p4-message-router.png +0 -0
- package/public/images/onboarding/p4-per-contact-rules.png +0 -0
- package/public/images/onboarding/p4-send-messages.png +0 -0
- package/public/images/onboarding/p6-be-precise.png +0 -0
- package/public/images/onboarding/p6-review-escalations.png +0 -0
- package/public/images/onboarding/p6-voice-input.png +0 -0
- package/public/images/onboarding/p7-completion.png +0 -0
- package/public/index.html +11594 -0
- package/public/js/onboarding.js +699 -0
- package/public/manifest.json +24 -0
- package/public/messages-v2.html +2824 -0
- package/public/permission-approve.html.bak +107 -0
- package/public/permissions.html +150 -0
- package/public/styles/design-system.css +68 -0
- package/router-db.js +604 -0
- package/router-utils.js +28 -0
- package/router-v2/adapters/imessage.js +191 -0
- package/router-v2/adapters/quo.js +82 -0
- package/router-v2/adapters/whatsapp.js +192 -0
- package/router-v2/contact-manager.js +234 -0
- package/router-v2/conversation-engine.js +498 -0
- package/router-v2/data/knowledge-base.json +176 -0
- package/router-v2/data/router-v2.db +0 -0
- package/router-v2/data/router-v2.db-shm +0 -0
- package/router-v2/data/router-v2.db-wal +0 -0
- package/router-v2/data/router.db +0 -0
- package/router-v2/db.js +457 -0
- package/router-v2/escalation-bridge.js +540 -0
- package/router-v2/follow-up-engine.js +347 -0
- package/router-v2/index.js +441 -0
- package/router-v2/ingestion.js +213 -0
- package/router-v2/knowledge-base.js +231 -0
- package/router-v2/lead-qualifier.js +152 -0
- package/router-v2/learning-loop.js +202 -0
- package/router-v2/outbound-sender.js +160 -0
- package/router-v2/package.json +13 -0
- package/router-v2/permission-gate.js +86 -0
- package/router-v2/playbook.js +177 -0
- package/router-v2/prompts/base.js +52 -0
- package/router-v2/prompts/first-contact.js +38 -0
- package/router-v2/prompts/lead-qualification.js +37 -0
- package/router-v2/prompts/scheduling.js +72 -0
- package/router-v2/prompts/style-overrides.js +22 -0
- package/router-v2/scheduler.js +301 -0
- package/router-v2/scripts/migrate-v1-to-v2.js +215 -0
- package/router-v2/scripts/seed-faq.js +67 -0
- package/router-v2/seed-knowledge-base.js +39 -0
- package/router-v2/utils/ai.js +129 -0
- package/router-v2/utils/phone.js +52 -0
- package/router-v2/utils/response-validator.js +98 -0
- package/router-v2/utils/sanitize.js +222 -0
- package/router.js +5005 -0
- package/routes/google-calendar.js +186 -0
- package/scripts/deploy.sh +62 -0
- package/scripts/macos-calendar.sh +232 -0
- package/scripts/onboard-device.sh +466 -0
- package/server.js +5131 -0
- package/start.sh +24 -0
- package/templates/AGENTS.md +548 -0
- package/templates/IDENTITY.md +15 -0
- package/templates/docs-agents.html +132 -0
- package/templates/docs-app.html +130 -0
- package/templates/docs-home.html +83 -0
- package/templates/docs-imessage.html +121 -0
- package/templates/docs-tasks.html +123 -0
- package/templates/docs-tips.html +175 -0
- package/templates/getting-started.html +809 -0
- package/templates/invisible-prefix-base.txt +171 -0
- package/templates/invisible-prefix-owner.txt +282 -0
- package/templates/invisible-prefix.txt +338 -0
- package/templates/manifest.json +61 -0
- package/templates/memory-org/clients.md +7 -0
- package/templates/memory-org/credentials.md +9 -0
- package/templates/memory-org/devices.md +7 -0
- package/templates/updates.html +464 -0
- package/templates/workspace/AGENTS.md.tmpl +161 -0
- package/templates/workspace/HEARTBEAT.md.tmpl +17 -0
- package/templates/workspace/IDENTITY.md.tmpl +15 -0
- package/templates/workspace/MEMORY.md.tmpl +16 -0
- package/templates/workspace/SOUL.md.tmpl +51 -0
- package/templates/workspace/USER.md.tmpl +25 -0
- package/tts-proxy.js +96 -0
- package/voice-call-local.js +731 -0
- package/voice-call.js +732 -0
- package/wa-listener.js +354 -0
|
@@ -0,0 +1,329 @@
|
|
|
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>Claude Subscription Pool Architecture</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: #0f0f1a;
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
align-items: center;
|
|
15
|
+
min-height: 100vh;
|
|
16
|
+
color: #fff;
|
|
17
|
+
}
|
|
18
|
+
.container {
|
|
19
|
+
width: 1200px;
|
|
20
|
+
height: 800px;
|
|
21
|
+
position: relative;
|
|
22
|
+
background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 100%);
|
|
23
|
+
border-radius: 24px;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
padding: 40px;
|
|
26
|
+
}
|
|
27
|
+
.title {
|
|
28
|
+
text-align: center;
|
|
29
|
+
font-size: 28px;
|
|
30
|
+
font-weight: 700;
|
|
31
|
+
color: #fff;
|
|
32
|
+
margin-bottom: 8px;
|
|
33
|
+
letter-spacing: -0.5px;
|
|
34
|
+
}
|
|
35
|
+
.subtitle {
|
|
36
|
+
text-align: center;
|
|
37
|
+
font-size: 14px;
|
|
38
|
+
color: #8b8ba3;
|
|
39
|
+
margin-bottom: 40px;
|
|
40
|
+
}
|
|
41
|
+
.cloud {
|
|
42
|
+
width: 460px;
|
|
43
|
+
margin: 0 auto 50px;
|
|
44
|
+
background: linear-gradient(135deg, #d4a574 0%, #c4956a 50%, #b8845c 100%);
|
|
45
|
+
border-radius: 32px;
|
|
46
|
+
padding: 28px;
|
|
47
|
+
position: relative;
|
|
48
|
+
box-shadow: 0 8px 40px rgba(212, 165, 116, 0.25);
|
|
49
|
+
}
|
|
50
|
+
.cloud-label {
|
|
51
|
+
text-align: center;
|
|
52
|
+
font-size: 13px;
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
color: rgba(255,255,255,0.9);
|
|
55
|
+
text-transform: uppercase;
|
|
56
|
+
letter-spacing: 2px;
|
|
57
|
+
margin-bottom: 16px;
|
|
58
|
+
}
|
|
59
|
+
.keys-grid {
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: 1fr 1fr;
|
|
62
|
+
gap: 10px;
|
|
63
|
+
}
|
|
64
|
+
.key-card {
|
|
65
|
+
background: rgba(0,0,0,0.25);
|
|
66
|
+
border-radius: 14px;
|
|
67
|
+
padding: 14px 16px;
|
|
68
|
+
text-align: center;
|
|
69
|
+
backdrop-filter: blur(8px);
|
|
70
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
71
|
+
}
|
|
72
|
+
.key-num {
|
|
73
|
+
font-size: 24px;
|
|
74
|
+
font-weight: 800;
|
|
75
|
+
color: #fff;
|
|
76
|
+
}
|
|
77
|
+
.key-name {
|
|
78
|
+
font-size: 10px;
|
|
79
|
+
color: rgba(255,255,255,0.7);
|
|
80
|
+
margin-top: 2px;
|
|
81
|
+
font-family: 'SF Mono', monospace;
|
|
82
|
+
}
|
|
83
|
+
.key-badge {
|
|
84
|
+
display: inline-block;
|
|
85
|
+
font-size: 9px;
|
|
86
|
+
padding: 2px 8px;
|
|
87
|
+
border-radius: 6px;
|
|
88
|
+
margin-top: 6px;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
}
|
|
91
|
+
.badge-token { background: rgba(99, 179, 237, 0.3); color: #63b3ed; }
|
|
92
|
+
.badge-api { background: rgba(154, 230, 180, 0.3); color: #9ae6b4; }
|
|
93
|
+
|
|
94
|
+
.flow-section {
|
|
95
|
+
display: flex;
|
|
96
|
+
justify-content: center;
|
|
97
|
+
align-items: flex-start;
|
|
98
|
+
gap: 0;
|
|
99
|
+
position: relative;
|
|
100
|
+
margin-top: 10px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* SVG lines */
|
|
104
|
+
.lines-svg {
|
|
105
|
+
position: absolute;
|
|
106
|
+
top: -50px;
|
|
107
|
+
left: 0;
|
|
108
|
+
width: 100%;
|
|
109
|
+
height: 120px;
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.machines {
|
|
114
|
+
display: flex;
|
|
115
|
+
justify-content: center;
|
|
116
|
+
gap: 40px;
|
|
117
|
+
width: 100%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.machine {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
align-items: center;
|
|
124
|
+
gap: 10px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.machine-icon {
|
|
128
|
+
width: 80px;
|
|
129
|
+
height: 80px;
|
|
130
|
+
border-radius: 20px;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
align-items: center;
|
|
134
|
+
justify-content: center;
|
|
135
|
+
position: relative;
|
|
136
|
+
}
|
|
137
|
+
.machine-big {
|
|
138
|
+
width: 110px;
|
|
139
|
+
height: 110px;
|
|
140
|
+
border-radius: 24px;
|
|
141
|
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
142
|
+
box-shadow: 0 6px 30px rgba(102, 126, 234, 0.35);
|
|
143
|
+
}
|
|
144
|
+
.machine-small {
|
|
145
|
+
background: linear-gradient(135deg, #2d3748, #4a5568);
|
|
146
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
147
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
148
|
+
}
|
|
149
|
+
.machine-emoji {
|
|
150
|
+
font-size: 32px;
|
|
151
|
+
}
|
|
152
|
+
.machine-big .machine-emoji {
|
|
153
|
+
font-size: 42px;
|
|
154
|
+
}
|
|
155
|
+
.machine-name {
|
|
156
|
+
font-size: 13px;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
color: #e2e8f0;
|
|
159
|
+
}
|
|
160
|
+
.machine-detail {
|
|
161
|
+
font-size: 10px;
|
|
162
|
+
color: #718096;
|
|
163
|
+
text-align: center;
|
|
164
|
+
line-height: 1.4;
|
|
165
|
+
}
|
|
166
|
+
.machine-keys {
|
|
167
|
+
font-size: 10px;
|
|
168
|
+
color: #d4a574;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
}
|
|
171
|
+
.big-label {
|
|
172
|
+
position: absolute;
|
|
173
|
+
bottom: -8px;
|
|
174
|
+
right: -8px;
|
|
175
|
+
background: #e53e3e;
|
|
176
|
+
color: #fff;
|
|
177
|
+
font-size: 9px;
|
|
178
|
+
font-weight: 700;
|
|
179
|
+
padding: 2px 8px;
|
|
180
|
+
border-radius: 8px;
|
|
181
|
+
text-transform: uppercase;
|
|
182
|
+
letter-spacing: 1px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.arrow-label {
|
|
186
|
+
text-align: center;
|
|
187
|
+
color: #d4a574;
|
|
188
|
+
font-size: 12px;
|
|
189
|
+
font-weight: 600;
|
|
190
|
+
margin-bottom: 6px;
|
|
191
|
+
letter-spacing: 1px;
|
|
192
|
+
}
|
|
193
|
+
.arrows-down {
|
|
194
|
+
text-align: center;
|
|
195
|
+
color: #d4a574;
|
|
196
|
+
font-size: 24px;
|
|
197
|
+
margin-bottom: 14px;
|
|
198
|
+
letter-spacing: 20px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.fallback-section {
|
|
202
|
+
margin-top: 36px;
|
|
203
|
+
text-align: center;
|
|
204
|
+
}
|
|
205
|
+
.fallback-label {
|
|
206
|
+
font-size: 11px;
|
|
207
|
+
color: #718096;
|
|
208
|
+
text-transform: uppercase;
|
|
209
|
+
letter-spacing: 2px;
|
|
210
|
+
margin-bottom: 12px;
|
|
211
|
+
}
|
|
212
|
+
.fallback-chain {
|
|
213
|
+
display: flex;
|
|
214
|
+
justify-content: center;
|
|
215
|
+
align-items: center;
|
|
216
|
+
gap: 12px;
|
|
217
|
+
}
|
|
218
|
+
.fallback-box {
|
|
219
|
+
padding: 10px 20px;
|
|
220
|
+
border-radius: 12px;
|
|
221
|
+
font-size: 12px;
|
|
222
|
+
font-weight: 600;
|
|
223
|
+
}
|
|
224
|
+
.fb-openai {
|
|
225
|
+
background: rgba(16, 163, 127, 0.15);
|
|
226
|
+
color: #10a37f;
|
|
227
|
+
border: 1px solid rgba(16, 163, 127, 0.3);
|
|
228
|
+
}
|
|
229
|
+
.fb-google {
|
|
230
|
+
background: rgba(66, 133, 244, 0.15);
|
|
231
|
+
color: #4285f4;
|
|
232
|
+
border: 1px solid rgba(66, 133, 244, 0.3);
|
|
233
|
+
opacity: 0.5;
|
|
234
|
+
}
|
|
235
|
+
.fallback-arrow {
|
|
236
|
+
color: #4a5568;
|
|
237
|
+
font-size: 18px;
|
|
238
|
+
}
|
|
239
|
+
.fb-future {
|
|
240
|
+
font-size: 9px;
|
|
241
|
+
color: #718096;
|
|
242
|
+
margin-top: 4px;
|
|
243
|
+
}
|
|
244
|
+
</style>
|
|
245
|
+
</head>
|
|
246
|
+
<body>
|
|
247
|
+
<div class="container">
|
|
248
|
+
<div class="title">🔑 Claude Subscription Pool</div>
|
|
249
|
+
<div class="subtitle">All machines share all keys — rotate through before falling back to other providers</div>
|
|
250
|
+
|
|
251
|
+
<div class="cloud">
|
|
252
|
+
<div class="cloud-label">☁️ Shared Anthropic Key Pool</div>
|
|
253
|
+
<div class="keys-grid">
|
|
254
|
+
<div class="key-card">
|
|
255
|
+
<div class="key-num">$1</div>
|
|
256
|
+
<div class="key-name">anthropic:secondary</div>
|
|
257
|
+
<div class="key-badge badge-token">OAuth Token</div>
|
|
258
|
+
</div>
|
|
259
|
+
<div class="key-card">
|
|
260
|
+
<div class="key-num">$2</div>
|
|
261
|
+
<div class="key-name">anthropic:openclaw</div>
|
|
262
|
+
<div class="key-badge badge-token">OAuth Token</div>
|
|
263
|
+
</div>
|
|
264
|
+
<div class="key-card">
|
|
265
|
+
<div class="key-num">$3</div>
|
|
266
|
+
<div class="key-name">anthropic:api</div>
|
|
267
|
+
<div class="key-badge badge-api">API Key</div>
|
|
268
|
+
</div>
|
|
269
|
+
<div class="key-card">
|
|
270
|
+
<div class="key-num">$4</div>
|
|
271
|
+
<div class="key-name">anthropic:secondary2</div>
|
|
272
|
+
<div class="key-badge badge-api">API Key</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
<div class="arrow-label">EVERY AGENT ON EVERY MACHINE</div>
|
|
278
|
+
<div class="arrows-down">↓ ↓ ↓</div>
|
|
279
|
+
|
|
280
|
+
<div class="machines">
|
|
281
|
+
<div class="machine">
|
|
282
|
+
<div class="machine-icon machine-big">
|
|
283
|
+
<div class="machine-emoji">🖥️</div>
|
|
284
|
+
<div class="big-label">HQ</div>
|
|
285
|
+
</div>
|
|
286
|
+
<div class="machine-name">Mac Studio</div>
|
|
287
|
+
<div class="machine-detail">Brandon's Machine<br>7 agents (incl. coder)</div>
|
|
288
|
+
<div class="machine-keys">4 shared keys</div>
|
|
289
|
+
</div>
|
|
290
|
+
<div class="machine">
|
|
291
|
+
<div class="machine-icon machine-small">
|
|
292
|
+
<div class="machine-emoji">💻</div>
|
|
293
|
+
</div>
|
|
294
|
+
<div class="machine-name">Nate's Mini</div>
|
|
295
|
+
<div class="machine-detail">CMP Sales Ops<br>6 agents</div>
|
|
296
|
+
<div class="machine-keys">2 local + 4 shared = 6 keys</div>
|
|
297
|
+
</div>
|
|
298
|
+
<div class="machine">
|
|
299
|
+
<div class="machine-icon machine-small">
|
|
300
|
+
<div class="machine-emoji">💻</div>
|
|
301
|
+
</div>
|
|
302
|
+
<div class="machine-name">James's Mini</div>
|
|
303
|
+
<div class="machine-detail">Starr Benefits<br>6 agents</div>
|
|
304
|
+
<div class="machine-keys">1 local + 4 shared = 5 keys</div>
|
|
305
|
+
</div>
|
|
306
|
+
<div class="machine">
|
|
307
|
+
<div class="machine-icon machine-small" style="border: 1px dashed rgba(255,255,255,0.2); background: transparent;">
|
|
308
|
+
<div class="machine-emoji" style="opacity:0.4;">💻</div>
|
|
309
|
+
</div>
|
|
310
|
+
<div class="machine-name" style="opacity:0.4;">Future Node</div>
|
|
311
|
+
<div class="machine-detail" style="opacity:0.4;">Auto-synced<br>on connect</div>
|
|
312
|
+
<div class="machine-keys" style="opacity:0.4;">+ 4 shared keys</div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
<div class="fallback-section">
|
|
317
|
+
<div class="fallback-label">If all Anthropic keys exhausted → Provider Fallback</div>
|
|
318
|
+
<div class="fallback-chain">
|
|
319
|
+
<div class="fallback-box fb-openai">OpenAI Codex<br><span style="font-size:10px;opacity:0.7;">GPT-5.4 → GPT-5.3</span></div>
|
|
320
|
+
<div class="fallback-arrow">→</div>
|
|
321
|
+
<div class="fallback-box fb-google">
|
|
322
|
+
Google Gemini
|
|
323
|
+
<div class="fb-future">Coming Soon</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</body>
|
|
329
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,237 @@
|
|
|
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
|
+
<link rel="stylesheet" href="/styles/design-system.css">
|
|
7
|
+
<title>AIVA - Escalation Response</title>
|
|
8
|
+
<style>
|
|
9
|
+
body{font-family:var(--font-sans);background:var(--bg-secondary);color:var(--text);min-height:100vh;display:flex;flex-direction:column;align-items:center;padding:20px}
|
|
10
|
+
.container{max-width:480px;width:100%}
|
|
11
|
+
.header{text-align:center;margin-bottom:24px;padding:16px 0;border-bottom:1px solid var(--border-dim)}
|
|
12
|
+
.header h1{font-size:18px;color:var(--text-dim);font-weight:500;letter-spacing:1px}
|
|
13
|
+
.contact-info{background:var(--surface-glass);border:1px solid var(--border-dim);border-radius:var(--radius-lg);padding:var(--space-lg);margin-bottom:var(--space-lg)}
|
|
14
|
+
.contact-name{font-size:20px;font-weight:600;color:var(--text)}
|
|
15
|
+
.contact-phone{font-size:14px;color:var(--text-dim);margin-top:var(--space-xs)}
|
|
16
|
+
.situation{background:var(--surface-glass);border:1px solid var(--border);border-radius:var(--radius-lg);padding:var(--space-lg);margin-bottom:var(--space-2xl)}
|
|
17
|
+
.situation-label{font-size:12px;color:var(--yellow-border);text-transform:uppercase;letter-spacing:1px;font-weight:600;margin-bottom:var(--space-sm)}
|
|
18
|
+
.situation-text{font-size:16px;line-height:1.5;color:var(--text-secondary)}
|
|
19
|
+
.decision-section{margin-bottom:24px}
|
|
20
|
+
.decision-label{font-size:12px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.5px;margin-bottom:12px}
|
|
21
|
+
.decision-btn{width:100%;padding:14px 16px;border:2px solid var(--border);border-radius:var(--radius-lg);font-size:15px;font-weight:600;cursor:pointer;margin-bottom:var(--space-sm);transition:all .2s;background:var(--surface-glass);color:var(--text-secondary);text-align:left;display:flex;align-items:center;gap:10px}
|
|
22
|
+
.decision-btn:hover{border-color:var(--blue);background:#1c2333}
|
|
23
|
+
.decision-btn.selected{border-color:var(--blue);background:#1c2333}
|
|
24
|
+
.decision-btn.approve.selected{border-color:var(--green-border);background:var(--green-bg)}
|
|
25
|
+
.decision-btn.always.selected{border-color:var(--yellow-border);background:var(--yellow-bg)}
|
|
26
|
+
.decision-btn.deny.selected{border-color:var(--red-border);background:var(--red-bg)}
|
|
27
|
+
.decision-icon{font-size:20px;flex-shrink:0}
|
|
28
|
+
.decision-text{flex:1}
|
|
29
|
+
.decision-title{font-size:15px;font-weight:600}
|
|
30
|
+
.decision-desc{font-size:12px;color:var(--text-dim);margin-top:2px;font-weight:400}
|
|
31
|
+
textarea{width:100%;background:var(--surface-glass);border:1px solid var(--border);border-radius:var(--radius-lg);padding:14px;font-size:15px;color:var(--text);resize:none;font-family:inherit;min-height:80px;transition:border-color .2s}
|
|
32
|
+
textarea:focus{outline:none;border-color:var(--blue)}
|
|
33
|
+
select{width:100%;background:var(--surface-glass);border:1px solid var(--border);border-radius:var(--radius-lg);padding:14px;font-size:15px;color:var(--text);font-family:inherit;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238b949e' fill='none' stroke-width='2'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center}
|
|
34
|
+
select:focus{outline:none;border-color:var(--blue)}
|
|
35
|
+
.section-label{display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;text-transform:uppercase;letter-spacing:.5px}
|
|
36
|
+
.instructions-section{margin-bottom:var(--space-lg);max-height:0;overflow:hidden;opacity:0;transition:max-height .3s ease,opacity .3s ease}
|
|
37
|
+
.instructions-section.visible{max-height:300px;opacity:1}
|
|
38
|
+
.notes-section{margin-bottom:var(--space-lg)}
|
|
39
|
+
.advanced-toggle{color:var(--blue);font-size:13px;cursor:pointer;margin-bottom:var(--space-md);display:inline-block;border:none;background:none;font-family:inherit;padding:0}
|
|
40
|
+
.advanced-toggle:hover{text-decoration:underline}
|
|
41
|
+
.advanced-section{display:none;margin-bottom:var(--space-lg)}
|
|
42
|
+
.advanced-section.open{display:block}
|
|
43
|
+
.btn{width:100%;padding:14px;background:var(--green-border);color:#fff;border:none;border-radius:var(--radius-lg);font-size:16px;font-weight:600;cursor:pointer;margin-top:var(--space-md);transition:all .2s}
|
|
44
|
+
.btn:hover{background:#2ea043}
|
|
45
|
+
.btn:disabled{background:var(--border-dim);color:var(--text-muted);cursor:not-allowed}
|
|
46
|
+
.btn.deny-btn{background:var(--red-border)}
|
|
47
|
+
.btn.deny-btn:hover{background:#f85149}
|
|
48
|
+
.status{text-align:center;padding:var(--space-lg);border-radius:var(--radius-lg);margin-top:var(--space-lg);font-size:15px}
|
|
49
|
+
.status.success{background:var(--green-bg);border:1px solid var(--green-border);color:var(--green)}
|
|
50
|
+
.status.error{background:var(--red-bg);border:1px solid var(--red-border);color:var(--red)}
|
|
51
|
+
.expired{text-align:center;padding:40px 20px}
|
|
52
|
+
.expired h2{color:var(--red);margin-bottom:var(--space-md)}
|
|
53
|
+
.expired p{color:var(--text-dim)}
|
|
54
|
+
.loading{text-align:center;padding:60px;color:var(--text-dim)}
|
|
55
|
+
</style>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<div class="container" id="app">
|
|
59
|
+
<div class="loading" id="loading">Loading escalation...</div>
|
|
60
|
+
</div>
|
|
61
|
+
<script>
|
|
62
|
+
let currentDecision = null;
|
|
63
|
+
let escalationData = null;
|
|
64
|
+
|
|
65
|
+
function esc(s){const d=document.createElement('div');d.textContent=s||'';return d.innerHTML}
|
|
66
|
+
const scopeLabels={'messages.read':'Read Messages','messages.send':'Send Messages','messages.auto-reply':'Auto-Reply','calendar.view':'View Calendar','calendar.book':'Book Appointments','calendar.modify':'Modify Calendar','tasks.create':'Create Tasks','tasks.view':'View Tasks','info.business':'Business Info','info.personal':'Personal Info','reminders.create':'Create Reminders','files.send':'Send Files','payments.request':'Payment Requests','support.technical':'Technical Support'};
|
|
67
|
+
function scopeLabel(s){return scopeLabels[s]||s}
|
|
68
|
+
function parseCategory(msg){
|
|
69
|
+
const m=(msg||'').match(/^\[([^\]]+)\]\s*([^:]+):\s*(.*)/s);
|
|
70
|
+
if(m) return {category:m[1],label:m[2].trim(),details:m[3].trim()};
|
|
71
|
+
return {category:'other',label:'Escalation',details:msg||'Needs your attention'};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(async()=>{
|
|
75
|
+
const app=document.getElementById('app');
|
|
76
|
+
const pathParts=window.location.pathname.split('/');
|
|
77
|
+
const code=pathParts[pathParts.length-1];
|
|
78
|
+
const token=new URLSearchParams(window.location.search).get('token');
|
|
79
|
+
if(!code||!token){app.innerHTML='<div class="expired"><h2>Invalid Link</h2><p>This link is missing required parameters.</p></div>';return}
|
|
80
|
+
try{
|
|
81
|
+
const res=await fetch(`/api/escalation/${code}?token=${encodeURIComponent(token)}`);
|
|
82
|
+
if(!res.ok){app.innerHTML='<div class="expired"><h2>Link Expired</h2><p>This link has expired or has already been used.</p></div>';return}
|
|
83
|
+
const d=await res.json();
|
|
84
|
+
escalationData=d;
|
|
85
|
+
app.innerHTML=`
|
|
86
|
+
<div class="header"><h1>AIVA ESCALATION</h1></div>
|
|
87
|
+
<div class="contact-info">
|
|
88
|
+
<div class="contact-name">${esc(d.contactName)}</div>
|
|
89
|
+
<div class="contact-phone">${esc(d.phone)}</div>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="situation">
|
|
92
|
+
<div class="situation-label">${esc(parseCategory(d.message).label)}</div>
|
|
93
|
+
<div class="situation-text">${esc(parseCategory(d.message).details)}</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
${d.requiredScopes.length ? '<div class="situation" style="border-color:var(--blue-border,#388bfd44)"><div class="situation-label" style="color:var(--blue,#58a6ff)">Scope Summary</div><div style="font-size:14px;line-height:1.8;color:var(--text-secondary)"><div><strong>Required:</strong> '+d.requiredScopes.map(s=>'<code style="background:#1c2333;padding:2px 6px;border-radius:4px;font-size:12px">'+esc(scopeLabel(s))+'</code>').join(' ')+'</div><div style="margin-top:6px"><strong>Granted:</strong> '+(d.grantedScopes.length ? d.grantedScopes.map(s=>'<code style="background:#1c2333;padding:2px 6px;border-radius:4px;font-size:12px;'+(d.requiredScopes.includes(s)?'color:#3fb950':'')+'">'+esc(scopeLabel(s))+'</code>').join(' ') : '<span style="color:var(--text-dim)">none</span>')+'</div><div style="margin-top:6px"><strong>Missing:</strong> '+(d.missingScopes.length ? d.missingScopes.map(s=>'<code style="background:#f8514922;padding:2px 6px;border-radius:4px;font-size:12px;color:#f85149">'+esc(scopeLabel(s))+'</code>').join(' ') : '<span style="color:#3fb950">✓ all granted</span>')+'</div></div></div>' : '<div class="situation" style="border-color:var(--yellow-border,#d29922)"><div style="font-size:15px;line-height:1.6;color:var(--text-secondary);padding:4px 0">⚡ This request requires your direct input — no automatic permissions apply.</div></div>'}
|
|
97
|
+
|
|
98
|
+
<div class="decision-section">
|
|
99
|
+
<div class="decision-label">What do you want to do?</div>
|
|
100
|
+
<button class="decision-btn approve" onclick="selectDecision('approve',this)" style="">
|
|
101
|
+
<span class="decision-icon">✅</span>
|
|
102
|
+
<span class="decision-text">
|
|
103
|
+
<div class="decision-title">Approve (One-time)</div>
|
|
104
|
+
<div class="decision-desc">${!d.requiredScopes.length ? 'Use your judgment to handle this request' : 'Handle this request without granting permissions'}</div>
|
|
105
|
+
</span>
|
|
106
|
+
</button>
|
|
107
|
+
${d.requiredScopes.length ? '<button class="decision-btn always" onclick="selectDecision(\'always-approve\',this)"><span class="decision-icon">🔑</span><span class="decision-text"><div class="decision-title">Grant Requested Scopes</div><div class="decision-desc">Grant: '+d.requiredScopes.join(', ')+'</div></span></button>' : ''}
|
|
108
|
+
<button class="decision-btn always" onclick="selectDecision('grant-business',this)">
|
|
109
|
+
<span class="decision-icon">💼</span>
|
|
110
|
+
<span class="decision-text">
|
|
111
|
+
<div class="decision-title">Grant Business Standard</div>
|
|
112
|
+
<div class="decision-desc">${d.businessScopes.join(', ')}</div>
|
|
113
|
+
</span>
|
|
114
|
+
</button>
|
|
115
|
+
<button class="decision-btn always" onclick="selectDecision('grant-full',this)">
|
|
116
|
+
<span class="decision-icon">⭐</span>
|
|
117
|
+
<span class="decision-text">
|
|
118
|
+
<div class="decision-title">Grant Full Access</div>
|
|
119
|
+
<div class="decision-desc">All ${d.allScopesCount} permissions: ${d.allScopes.join(', ')}</div>
|
|
120
|
+
</span>
|
|
121
|
+
</button>
|
|
122
|
+
<button class="decision-btn deny" onclick="selectDecision('deny',this)">
|
|
123
|
+
<span class="decision-icon">🚫</span>
|
|
124
|
+
<span class="decision-text">
|
|
125
|
+
<div class="decision-title">Deny</div>
|
|
126
|
+
<div class="decision-desc">Ignore this request</div>
|
|
127
|
+
</span>
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="instructions-section" id="instructionsSection">
|
|
132
|
+
<label class="section-label">Instructions for AIVA</label>
|
|
133
|
+
<textarea id="instructions" placeholder="How should I handle this?"></textarea>
|
|
134
|
+
<label style="display:flex;align-items:center;gap:8px;margin-top:10px;font-size:14px;color:#8b949e;cursor:pointer">
|
|
135
|
+
<input type="checkbox" id="rememberCheckbox" checked style="width:18px;height:18px;accent-color:#58a6ff;cursor:pointer">
|
|
136
|
+
Remember this for future requests from ${esc(d.contactName)}
|
|
137
|
+
</label>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<button class="advanced-toggle" onclick="toggleAdvanced()">Advanced options</button>
|
|
141
|
+
<div class="advanced-section" id="advancedSection">
|
|
142
|
+
<label class="section-label">Response Mode</label>
|
|
143
|
+
<select id="responseMode">
|
|
144
|
+
<option value="">Keep Current</option>
|
|
145
|
+
<option value="auto-respond"${d.currentMode==='auto-respond'?' selected':''}>Auto-Respond</option>
|
|
146
|
+
<option value="passive-helper"${d.currentMode==='passive-helper'?' selected':''}>Passive Helper</option>
|
|
147
|
+
<option value="escalate"${d.currentMode==='escalate'?' selected':''}>Escalate Only</option>
|
|
148
|
+
<option value="block"${d.currentMode==='block'?' selected':''}>Block</option>
|
|
149
|
+
<option value="monitor"${d.currentMode==='monitor'?' selected':''}>Monitor Only</option>
|
|
150
|
+
<option value="direct-to-agent"${d.currentMode==='direct-to-agent'?' selected':''}>Direct-to-Agent</option>
|
|
151
|
+
</select>
|
|
152
|
+
<label class="section-label" style="margin-top:12px">Category</label>
|
|
153
|
+
<select id="contactCategory">
|
|
154
|
+
<option value="">Keep Current</option>
|
|
155
|
+
<optgroup label="Relationship">
|
|
156
|
+
<option value="acquaintance"${d.currentCategory==='acquaintance'?' selected':''}>Acquaintance</option>
|
|
157
|
+
<option value="distant-friend"${d.currentCategory==='distant-friend'?' selected':''}>Distant Friend</option>
|
|
158
|
+
<option value="casual-friend"${d.currentCategory==='casual-friend'?' selected':''}>Casual Friend</option>
|
|
159
|
+
<option value="close-friend"${d.currentCategory==='close-friend'?' selected':''}>Close Friend</option>
|
|
160
|
+
<option value="family"${d.currentCategory==='family'?' selected':''}>Family</option>
|
|
161
|
+
<option value="spouse-partner"${d.currentCategory==='spouse-partner'?' selected':''}>Spouse/Partner</option>
|
|
162
|
+
</optgroup>
|
|
163
|
+
<optgroup label="Professional">
|
|
164
|
+
<option value="client"${d.currentCategory==='client'?' selected':''}>Client</option>
|
|
165
|
+
<option value="lead-prospect"${d.currentCategory==='lead-prospect'?' selected':''}>Lead/Prospect</option>
|
|
166
|
+
<option value="business-partner"${d.currentCategory==='business-partner'?' selected':''}>Business Partner</option>
|
|
167
|
+
<option value="vendor-contractor"${d.currentCategory==='vendor-contractor'?' selected':''}>Vendor/Contractor</option>
|
|
168
|
+
<option value="employee-team"${d.currentCategory==='employee-team'?' selected':''}>Employee/Team</option>
|
|
169
|
+
<option value="mentor-advisor"${d.currentCategory==='mentor-advisor'?' selected':''}>Mentor/Advisor</option>
|
|
170
|
+
</optgroup>
|
|
171
|
+
<optgroup label="Other">
|
|
172
|
+
${(!d.currentCategory || d.currentCategory==='unknown') ? '<option value="unknown" selected>Unknown</option>' : ''}
|
|
173
|
+
<option value="service-automated"${d.currentCategory==='service-automated'?' selected':''}>Service/Automated</option>
|
|
174
|
+
</optgroup>
|
|
175
|
+
</select>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<button class="btn" id="send" onclick="respond()" disabled>Select a decision above</button>
|
|
179
|
+
<div id="status"></div>`;
|
|
180
|
+
}catch(e){console.error('Escalation load error:',e);app.innerHTML='<div class="expired"><h2>Error</h2><p>Could not load escalation.</p></div>'}
|
|
181
|
+
|
|
182
|
+
window.selectDecision=function(decision,btn){
|
|
183
|
+
currentDecision=decision;
|
|
184
|
+
document.querySelectorAll('.decision-btn').forEach(b=>b.classList.remove('selected'));
|
|
185
|
+
btn.classList.add('selected');
|
|
186
|
+
const instrSection=document.getElementById('instructionsSection');
|
|
187
|
+
const sendBtn=document.getElementById('send');
|
|
188
|
+
if(decision==='approve'||decision==='always-approve'||decision==='grant-business'||decision==='grant-full'){
|
|
189
|
+
instrSection.classList.add('visible');
|
|
190
|
+
const labels={'approve':'Approve & Send','always-approve':'Grant Scopes & Send','grant-business':'Grant Business & Send','grant-full':'Grant Full Access & Send'};
|
|
191
|
+
sendBtn.textContent=labels[decision]||'Send';
|
|
192
|
+
sendBtn.className='btn';
|
|
193
|
+
}else{
|
|
194
|
+
instrSection.classList.remove('visible');
|
|
195
|
+
sendBtn.textContent='Deny Request';
|
|
196
|
+
sendBtn.className='btn deny-btn';
|
|
197
|
+
}
|
|
198
|
+
sendBtn.disabled=false;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
window.toggleAdvanced=function(){
|
|
202
|
+
document.getElementById('advancedSection').classList.toggle('open');
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
window.respond=async()=>{
|
|
206
|
+
if(!currentDecision)return;
|
|
207
|
+
const btn=document.getElementById('send');
|
|
208
|
+
const instructions=document.getElementById('instructions')?.value.trim();
|
|
209
|
+
const remember=document.getElementById('rememberCheckbox')?.checked;
|
|
210
|
+
const notes=remember?instructions:undefined;
|
|
211
|
+
const responseMode=document.getElementById('responseMode')?.value;
|
|
212
|
+
const category=document.getElementById('contactCategory')?.value;
|
|
213
|
+
btn.disabled=true;btn.textContent='Sending...';
|
|
214
|
+
try{
|
|
215
|
+
const r=await fetch(`/api/escalation/${code}/respond`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token,decision:currentDecision,instructions:instructions||undefined,notes:notes||undefined,responseMode:responseMode||undefined,category:category||undefined})});
|
|
216
|
+
const d=await r.json();
|
|
217
|
+
if(r.ok){
|
|
218
|
+
document.getElementById('status').className='status success';
|
|
219
|
+
document.getElementById('status').textContent=currentDecision==='deny'?'Request denied.':'Response sent!';
|
|
220
|
+
btn.style.display='none';
|
|
221
|
+
document.querySelectorAll('textarea').forEach(t=>t.disabled=true);
|
|
222
|
+
document.querySelectorAll('.decision-btn').forEach(b=>{b.style.pointerEvents='none';b.style.opacity='0.5'});
|
|
223
|
+
}else{
|
|
224
|
+
document.getElementById('status').className='status error';
|
|
225
|
+
document.getElementById('status').textContent=d.error||'Failed';
|
|
226
|
+
btn.disabled=false;btn.textContent='Retry';
|
|
227
|
+
}
|
|
228
|
+
}catch(e){
|
|
229
|
+
document.getElementById('status').className='status error';
|
|
230
|
+
document.getElementById('status').textContent='Network error';
|
|
231
|
+
btn.disabled=false;btn.textContent='Retry';
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
})();
|
|
235
|
+
</script>
|
|
236
|
+
</body>
|
|
237
|
+
</html>
|