reflectt-node 0.1.8 → 0.1.12
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/defaults/TEAM-ROLES.yaml +317 -5
- package/dist/agent-config.d.ts +51 -0
- package/dist/agent-config.d.ts.map +1 -0
- package/dist/agent-config.js +129 -0
- package/dist/agent-config.js.map +1 -0
- package/dist/agent-config.test.d.ts +2 -0
- package/dist/agent-config.test.d.ts.map +1 -0
- package/dist/agent-config.test.js +91 -0
- package/dist/agent-config.test.js.map +1 -0
- package/dist/agent-memories.d.ts +58 -0
- package/dist/agent-memories.d.ts.map +1 -0
- package/dist/agent-memories.js +168 -0
- package/dist/agent-memories.js.map +1 -0
- package/dist/agent-memories.test.d.ts +2 -0
- package/dist/agent-memories.test.d.ts.map +1 -0
- package/dist/agent-memories.test.js +327 -0
- package/dist/agent-memories.test.js.map +1 -0
- package/dist/agent-messaging.d.ts +50 -0
- package/dist/agent-messaging.d.ts.map +1 -0
- package/dist/agent-messaging.js +103 -0
- package/dist/agent-messaging.js.map +1 -0
- package/dist/agent-messaging.test.d.ts +2 -0
- package/dist/agent-messaging.test.d.ts.map +1 -0
- package/dist/agent-messaging.test.js +105 -0
- package/dist/agent-messaging.test.js.map +1 -0
- package/dist/agent-runs.d.ts +158 -0
- package/dist/agent-runs.d.ts.map +1 -0
- package/dist/agent-runs.js +514 -0
- package/dist/agent-runs.js.map +1 -0
- package/dist/agent-runs.test.d.ts +2 -0
- package/dist/agent-runs.test.d.ts.map +1 -0
- package/dist/agent-runs.test.js +386 -0
- package/dist/agent-runs.test.js.map +1 -0
- package/dist/approval-queue.test.d.ts +2 -0
- package/dist/approval-queue.test.d.ts.map +1 -0
- package/dist/approval-queue.test.js +118 -0
- package/dist/approval-queue.test.js.map +1 -0
- package/dist/artifact-store.d.ts +55 -0
- package/dist/artifact-store.d.ts.map +1 -0
- package/dist/artifact-store.js +128 -0
- package/dist/artifact-store.js.map +1 -0
- package/dist/artifact-store.test.d.ts +2 -0
- package/dist/artifact-store.test.d.ts.map +1 -0
- package/dist/artifact-store.test.js +119 -0
- package/dist/artifact-store.test.js.map +1 -0
- package/dist/boardHealthWorker.d.ts +28 -0
- package/dist/boardHealthWorker.d.ts.map +1 -1
- package/dist/boardHealthWorker.js +33 -1
- package/dist/boardHealthWorker.js.map +1 -1
- package/dist/canvas-input.test.d.ts +2 -0
- package/dist/canvas-input.test.d.ts.map +1 -0
- package/dist/canvas-input.test.js +96 -0
- package/dist/canvas-input.test.js.map +1 -0
- package/dist/canvas-render.test.d.ts +2 -0
- package/dist/canvas-render.test.d.ts.map +1 -0
- package/dist/canvas-render.test.js +95 -0
- package/dist/canvas-render.test.js.map +1 -0
- package/dist/capabilities/browser.d.ts +75 -0
- package/dist/capabilities/browser.d.ts.map +1 -0
- package/dist/capabilities/browser.js +172 -0
- package/dist/capabilities/browser.js.map +1 -0
- package/dist/channels.d.ts +1 -1
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +2 -0
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +135 -3
- package/dist/cloud.js.map +1 -1
- package/dist/cost-enforcement.d.ts +38 -0
- package/dist/cost-enforcement.d.ts.map +1 -0
- package/dist/cost-enforcement.js +84 -0
- package/dist/cost-enforcement.js.map +1 -0
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +8 -0
- package/dist/dashboard.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +131 -0
- package/dist/db.js.map +1 -1
- package/dist/e2e-loop-proof.test.d.ts +2 -0
- package/dist/e2e-loop-proof.test.d.ts.map +1 -0
- package/dist/e2e-loop-proof.test.js +104 -0
- package/dist/e2e-loop-proof.test.js.map +1 -0
- package/dist/email-sms-send.test.d.ts +2 -0
- package/dist/email-sms-send.test.d.ts.map +1 -0
- package/dist/email-sms-send.test.js +96 -0
- package/dist/email-sms-send.test.js.map +1 -0
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -1
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +5 -10
- package/dist/fingerprint.js.map +1 -1
- package/dist/github-webhook-chat.d.ts +75 -0
- package/dist/github-webhook-chat.d.ts.map +1 -0
- package/dist/github-webhook-chat.js +108 -0
- package/dist/github-webhook-chat.js.map +1 -0
- package/dist/handoff-state.test.d.ts +2 -0
- package/dist/handoff-state.test.d.ts.map +1 -0
- package/dist/handoff-state.test.js +102 -0
- package/dist/handoff-state.test.js.map +1 -0
- package/dist/health.d.ts +9 -0
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +18 -0
- package/dist/health.js.map +1 -1
- package/dist/host-error-correlation.d.ts +65 -0
- package/dist/host-error-correlation.d.ts.map +1 -0
- package/dist/host-error-correlation.js +123 -0
- package/dist/host-error-correlation.js.map +1 -0
- package/dist/index.js +39 -10
- package/dist/index.js.map +1 -1
- package/dist/notificationDedupeGuard.d.ts +4 -0
- package/dist/notificationDedupeGuard.d.ts.map +1 -1
- package/dist/notificationDedupeGuard.js +8 -4
- package/dist/notificationDedupeGuard.js.map +1 -1
- package/dist/presence.d.ts +37 -5
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +127 -16
- package/dist/presence.js.map +1 -1
- package/dist/review-sla.d.ts +9 -0
- package/dist/review-sla.d.ts.map +1 -0
- package/dist/review-sla.js +51 -0
- package/dist/review-sla.js.map +1 -0
- package/dist/routing-enforcement.test.d.ts +2 -0
- package/dist/routing-enforcement.test.d.ts.map +1 -0
- package/dist/routing-enforcement.test.js +86 -0
- package/dist/routing-enforcement.test.js.map +1 -0
- package/dist/run-retention.test.d.ts +2 -0
- package/dist/run-retention.test.d.ts.map +1 -0
- package/dist/run-retention.test.js +57 -0
- package/dist/run-retention.test.js.map +1 -0
- package/dist/run-stream.test.d.ts +2 -0
- package/dist/run-stream.test.d.ts.map +1 -0
- package/dist/run-stream.test.js +70 -0
- package/dist/run-stream.test.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1301 -75
- package/dist/server.js.map +1 -1
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +45 -0
- package/dist/tasks.js.map +1 -1
- package/dist/todoHoardingGuard.d.ts +17 -0
- package/dist/todoHoardingGuard.d.ts.map +1 -1
- package/dist/todoHoardingGuard.js +25 -2
- package/dist/todoHoardingGuard.js.map +1 -1
- package/dist/webhook-storage.d.ts +50 -0
- package/dist/webhook-storage.d.ts.map +1 -0
- package/dist/webhook-storage.js +102 -0
- package/dist/webhook-storage.js.map +1 -0
- package/dist/webhook-storage.test.d.ts +2 -0
- package/dist/webhook-storage.test.d.ts.map +1 -0
- package/dist/webhook-storage.test.js +86 -0
- package/dist/webhook-storage.test.js.map +1 -0
- package/dist/workflow-templates.d.ts +44 -0
- package/dist/workflow-templates.d.ts.map +1 -0
- package/dist/workflow-templates.js +154 -0
- package/dist/workflow-templates.js.map +1 -0
- package/dist/workflow-templates.test.d.ts +2 -0
- package/dist/workflow-templates.test.d.ts.map +1 -0
- package/dist/workflow-templates.test.js +76 -0
- package/dist/workflow-templates.test.js.map +1 -0
- package/package.json +3 -1
- package/public/dashboard.js +76 -1
- package/public/design-tokens-platform.md +118 -0
- package/public/design-tokens.css +195 -0
- package/public/docs.md +131 -2
- package/public/presence-loop-demo.html +473 -0
|
@@ -0,0 +1,473 @@
|
|
|
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>Presence Loop — Live Demo</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0a0a0f;
|
|
10
|
+
--surface: #13131a;
|
|
11
|
+
--border: #1e1e2e;
|
|
12
|
+
--text: #e2e2f0;
|
|
13
|
+
--text-dim: #6b6b8a;
|
|
14
|
+
--accent: #7c3aed;
|
|
15
|
+
--accent-glow: rgba(124,58,237,0.15);
|
|
16
|
+
--green: #10b981;
|
|
17
|
+
--amber: #f59e0b;
|
|
18
|
+
--red: #ef4444;
|
|
19
|
+
--blue: #3b82f6;
|
|
20
|
+
}
|
|
21
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
22
|
+
body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 40px 20px; }
|
|
23
|
+
|
|
24
|
+
/* ── Ambient state ── */
|
|
25
|
+
#ambient {
|
|
26
|
+
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
|
27
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
28
|
+
transition: opacity 0.8s ease;
|
|
29
|
+
}
|
|
30
|
+
.pulse-ring {
|
|
31
|
+
width: 80px; height: 80px; border-radius: 50%;
|
|
32
|
+
border: 2px solid var(--accent);
|
|
33
|
+
animation: pulse 3s ease-in-out infinite;
|
|
34
|
+
display: flex; align-items: center; justify-content: center;
|
|
35
|
+
}
|
|
36
|
+
.pulse-ring::after {
|
|
37
|
+
content: ''; display: block;
|
|
38
|
+
width: 20px; height: 20px; border-radius: 50%;
|
|
39
|
+
background: var(--accent); opacity: 0.6;
|
|
40
|
+
animation: pulse-inner 3s ease-in-out infinite;
|
|
41
|
+
}
|
|
42
|
+
@keyframes pulse {
|
|
43
|
+
0%,100% { transform: scale(1); opacity: 0.6; }
|
|
44
|
+
50% { transform: scale(1.1); opacity: 1; }
|
|
45
|
+
}
|
|
46
|
+
@keyframes pulse-inner {
|
|
47
|
+
0%,100% { transform: scale(1); }
|
|
48
|
+
50% { transform: scale(1.3); }
|
|
49
|
+
}
|
|
50
|
+
.ambient-label { margin-top: 20px; font-size: 13px; color: var(--text-dim); letter-spacing: 1px; text-transform: uppercase; }
|
|
51
|
+
.ambient-agent { margin-top: 8px; font-size: 11px; color: var(--text-dim); opacity: 0.6; }
|
|
52
|
+
|
|
53
|
+
/* ── Session surface ── */
|
|
54
|
+
#session {
|
|
55
|
+
width: 100%; max-width: 680px;
|
|
56
|
+
opacity: 0; transform: translateY(20px);
|
|
57
|
+
transition: opacity 0.5s ease, transform 0.5s ease;
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
}
|
|
60
|
+
#session.visible { opacity: 1; transform: translateY(0); pointer-events: all; }
|
|
61
|
+
|
|
62
|
+
.session-header {
|
|
63
|
+
display: flex; align-items: center; gap: 12px;
|
|
64
|
+
padding: 16px 20px;
|
|
65
|
+
background: var(--surface);
|
|
66
|
+
border: 1px solid var(--border);
|
|
67
|
+
border-radius: 12px 12px 0 0;
|
|
68
|
+
}
|
|
69
|
+
.agent-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); animation: blink 2s ease-in-out infinite; }
|
|
70
|
+
@keyframes blink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
|
|
71
|
+
.session-title { font-weight: 600; font-size: 15px; flex: 1; }
|
|
72
|
+
.session-state { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; }
|
|
73
|
+
|
|
74
|
+
.run-stream {
|
|
75
|
+
background: var(--surface);
|
|
76
|
+
border: 1px solid var(--border);
|
|
77
|
+
border-top: none;
|
|
78
|
+
padding: 16px 20px;
|
|
79
|
+
min-height: 120px;
|
|
80
|
+
max-height: 240px;
|
|
81
|
+
overflow-y: auto;
|
|
82
|
+
font-size: 13px;
|
|
83
|
+
line-height: 1.7;
|
|
84
|
+
}
|
|
85
|
+
.run-line { padding: 2px 0; color: var(--text-dim); }
|
|
86
|
+
.run-line.active { color: var(--text); }
|
|
87
|
+
.run-line .ts { color: var(--accent); opacity: 0.5; margin-right: 8px; font-size: 11px; }
|
|
88
|
+
|
|
89
|
+
/* ── Approval surface ── */
|
|
90
|
+
#approval-surface {
|
|
91
|
+
background: var(--surface);
|
|
92
|
+
border: 1px solid var(--amber);
|
|
93
|
+
border-top: none;
|
|
94
|
+
padding: 20px;
|
|
95
|
+
transition: all 0.4s ease;
|
|
96
|
+
}
|
|
97
|
+
#approval-surface.hidden { display: none; }
|
|
98
|
+
.approval-header-row { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
|
|
99
|
+
.approval-icon { font-size: 24px; }
|
|
100
|
+
.approval-title { font-size: 15px; font-weight: 600; }
|
|
101
|
+
.approval-desc { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
|
|
102
|
+
.urgency-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; background: var(--amber); color: #000; margin-left: 8px; }
|
|
103
|
+
.approval-actions { display: flex; gap: 12px; margin-top: 16px; }
|
|
104
|
+
.btn-approve {
|
|
105
|
+
flex: 1; padding: 12px; border-radius: 8px;
|
|
106
|
+
background: var(--green); color: #000; border: none;
|
|
107
|
+
font-weight: 700; font-size: 14px; cursor: pointer;
|
|
108
|
+
transition: opacity 0.2s;
|
|
109
|
+
}
|
|
110
|
+
.btn-approve:hover { opacity: 0.85; }
|
|
111
|
+
.btn-reject {
|
|
112
|
+
padding: 12px 20px; border-radius: 8px;
|
|
113
|
+
background: none; color: var(--red); border: 1px solid var(--red);
|
|
114
|
+
font-weight: 600; font-size: 14px; cursor: pointer;
|
|
115
|
+
transition: opacity 0.2s;
|
|
116
|
+
}
|
|
117
|
+
.btn-reject:hover { opacity: 0.7; }
|
|
118
|
+
.btn-approve:disabled, .btn-reject:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
119
|
+
|
|
120
|
+
/* ── Result ── */
|
|
121
|
+
#result-surface {
|
|
122
|
+
background: var(--surface);
|
|
123
|
+
border: 1px solid var(--green);
|
|
124
|
+
border-top: none;
|
|
125
|
+
padding: 20px;
|
|
126
|
+
display: none;
|
|
127
|
+
}
|
|
128
|
+
#result-surface.visible { display: block; }
|
|
129
|
+
.result-header { color: var(--green); font-weight: 600; margin-bottom: 8px; }
|
|
130
|
+
.result-body { font-size: 13px; color: var(--text-dim); }
|
|
131
|
+
|
|
132
|
+
/* ── Collapse / footer ── */
|
|
133
|
+
.session-footer {
|
|
134
|
+
background: var(--surface);
|
|
135
|
+
border: 1px solid var(--border);
|
|
136
|
+
border-top: none;
|
|
137
|
+
border-radius: 0 0 12px 12px;
|
|
138
|
+
padding: 10px 20px;
|
|
139
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
140
|
+
font-size: 12px; color: var(--text-dim);
|
|
141
|
+
}
|
|
142
|
+
.btn-collapse {
|
|
143
|
+
background: none; border: 1px solid var(--border); color: var(--text-dim);
|
|
144
|
+
padding: 4px 12px; border-radius: 4px; cursor: pointer; font-size: 11px;
|
|
145
|
+
}
|
|
146
|
+
.btn-collapse:hover { border-color: var(--accent); color: var(--text); }
|
|
147
|
+
|
|
148
|
+
/* ── Loop controls ── */
|
|
149
|
+
#controls {
|
|
150
|
+
margin-top: 40px; width: 100%; max-width: 680px;
|
|
151
|
+
background: var(--surface); border: 1px solid var(--border);
|
|
152
|
+
border-radius: 12px; padding: 20px;
|
|
153
|
+
}
|
|
154
|
+
.controls-title { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 16px; }
|
|
155
|
+
.btn-start {
|
|
156
|
+
width: 100%; padding: 14px; border-radius: 8px;
|
|
157
|
+
background: var(--accent); color: #fff; border: none;
|
|
158
|
+
font-weight: 700; font-size: 15px; cursor: pointer;
|
|
159
|
+
transition: opacity 0.2s;
|
|
160
|
+
}
|
|
161
|
+
.btn-start:hover { opacity: 0.85; }
|
|
162
|
+
.btn-start:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
163
|
+
.status-line { margin-top: 12px; font-size: 12px; color: var(--text-dim); text-align: center; min-height: 20px; }
|
|
164
|
+
|
|
165
|
+
/* ── Step indicators ── */
|
|
166
|
+
.steps { display: flex; gap: 8px; margin-top: 16px; }
|
|
167
|
+
.step {
|
|
168
|
+
flex: 1; padding: 8px 4px; border-radius: 6px;
|
|
169
|
+
border: 1px solid var(--border); text-align: center;
|
|
170
|
+
font-size: 10px; color: var(--text-dim); transition: all 0.3s;
|
|
171
|
+
}
|
|
172
|
+
.step.active { border-color: var(--accent); background: var(--accent-glow); color: var(--text); }
|
|
173
|
+
.step.done { border-color: var(--green); color: var(--green); }
|
|
174
|
+
|
|
175
|
+
#log { margin-top: 8px; font-size: 11px; color: var(--text-dim); max-height: 60px; overflow-y: auto; }
|
|
176
|
+
</style>
|
|
177
|
+
</head>
|
|
178
|
+
<body>
|
|
179
|
+
|
|
180
|
+
<!-- Ambient state -->
|
|
181
|
+
<div id="ambient">
|
|
182
|
+
<div class="pulse-ring"></div>
|
|
183
|
+
<div class="ambient-label">Ambient</div>
|
|
184
|
+
<div class="ambient-agent">kai · ready</div>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<!-- Session surface (hidden until run starts) -->
|
|
188
|
+
<div id="session">
|
|
189
|
+
<div class="session-header">
|
|
190
|
+
<div class="agent-dot" id="agent-dot"></div>
|
|
191
|
+
<div class="session-title" id="session-title">Agent run in progress</div>
|
|
192
|
+
<div class="session-state" id="session-state">working</div>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="run-stream" id="run-stream">
|
|
195
|
+
<div class="run-line" style="color:var(--text-dim)">Waiting for run...</div>
|
|
196
|
+
</div>
|
|
197
|
+
<div id="approval-surface" class="hidden">
|
|
198
|
+
<div class="approval-header-row">
|
|
199
|
+
<div class="approval-icon">⚡</div>
|
|
200
|
+
<div>
|
|
201
|
+
<div class="approval-title" id="approval-title">Action requires approval <span class="urgency-badge" id="urgency-badge">critical</span></div>
|
|
202
|
+
<div class="approval-desc" id="approval-desc">Agent is requesting your decision to continue.</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="approval-actions">
|
|
206
|
+
<button class="btn-reject" id="btn-reject" onclick="decide('reject')">✗ Reject</button>
|
|
207
|
+
<button class="btn-approve" id="btn-approve" onclick="decide('approve')">✓ Approve</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
<div id="result-surface">
|
|
211
|
+
<div class="result-header">✓ Approved — result</div>
|
|
212
|
+
<div class="result-body" id="result-body">Run completed successfully.</div>
|
|
213
|
+
</div>
|
|
214
|
+
<div class="session-footer">
|
|
215
|
+
<span id="run-id-label" style="font-family:monospace"></span>
|
|
216
|
+
<button class="btn-collapse" onclick="collapse()">Collapse to ambient</button>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<!-- Controls -->
|
|
221
|
+
<div id="controls">
|
|
222
|
+
<div class="controls-title">Presence Loop — Live Demo</div>
|
|
223
|
+
<button class="btn-start" id="btn-start" onclick="startLoop()">▶ Start Loop</button>
|
|
224
|
+
<div class="steps">
|
|
225
|
+
<div class="step" id="step-0">Ambient</div>
|
|
226
|
+
<div class="step" id="step-1">Run</div>
|
|
227
|
+
<div class="step" id="step-2">Approval</div>
|
|
228
|
+
<div class="step" id="step-3">Result</div>
|
|
229
|
+
<div class="step" id="step-4">Collapse</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="status-line" id="status-line">Click Start to run the loop end-to-end</div>
|
|
232
|
+
<div id="log"></div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<script>
|
|
236
|
+
const BASE = window.location.origin;
|
|
237
|
+
let currentRunId = null;
|
|
238
|
+
let currentApprovalId = null;
|
|
239
|
+
let sseSource = null;
|
|
240
|
+
|
|
241
|
+
function log(msg) {
|
|
242
|
+
const el = document.getElementById('log');
|
|
243
|
+
el.innerHTML = msg;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function setStatus(msg) {
|
|
247
|
+
document.getElementById('status-line').textContent = msg;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function setStep(n) {
|
|
251
|
+
for (let i = 0; i <= 4; i++) {
|
|
252
|
+
const el = document.getElementById('step-' + i);
|
|
253
|
+
el.className = 'step' + (i < n ? ' done' : i === n ? ' active' : '');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function addStreamLine(text, active) {
|
|
258
|
+
const stream = document.getElementById('run-stream');
|
|
259
|
+
const line = document.createElement('div');
|
|
260
|
+
line.className = 'run-line' + (active ? ' active' : '');
|
|
261
|
+
const ts = new Date().toLocaleTimeString('en-US', {hour12:false, hour:'2-digit', minute:'2-digit', second:'2-digit'});
|
|
262
|
+
line.innerHTML = '<span class="ts">' + ts + '</span>' + text;
|
|
263
|
+
if (stream.firstChild && stream.firstChild.textContent.includes('Waiting')) {
|
|
264
|
+
stream.innerHTML = '';
|
|
265
|
+
}
|
|
266
|
+
stream.appendChild(line);
|
|
267
|
+
stream.scrollTop = stream.scrollHeight;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function startLoop() {
|
|
271
|
+
document.getElementById('btn-start').disabled = true;
|
|
272
|
+
document.getElementById('ambient').style.opacity = '0';
|
|
273
|
+
document.getElementById('ambient').style.pointerEvents = 'none';
|
|
274
|
+
|
|
275
|
+
setStep(0);
|
|
276
|
+
setStatus('Starting run...');
|
|
277
|
+
|
|
278
|
+
// Step 1: Create run
|
|
279
|
+
try {
|
|
280
|
+
const res = await fetch(BASE + '/agents/kai/runs', {
|
|
281
|
+
method: 'POST',
|
|
282
|
+
headers: {'Content-Type':'application/json'},
|
|
283
|
+
body: JSON.stringify({objective: 'Presence loop demo: ambient → run → approve → result → collapse'})
|
|
284
|
+
});
|
|
285
|
+
const run = await res.json();
|
|
286
|
+
currentRunId = run.id;
|
|
287
|
+
if (!currentRunId) throw new Error('No run ID returned: ' + JSON.stringify(run));
|
|
288
|
+
} catch(e) {
|
|
289
|
+
setStatus('Failed to create run: ' + e.message);
|
|
290
|
+
document.getElementById('btn-start').disabled = false;
|
|
291
|
+
document.getElementById('ambient').style.opacity = '1';
|
|
292
|
+
document.getElementById('ambient').style.pointerEvents = 'all';
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
document.getElementById('run-id-label').textContent = currentRunId;
|
|
297
|
+
document.getElementById('session').classList.add('visible');
|
|
298
|
+
document.getElementById('session-title').textContent = 'Presence loop demo';
|
|
299
|
+
document.getElementById('session-state').textContent = 'working';
|
|
300
|
+
setStep(1);
|
|
301
|
+
setStatus('Run started — streaming events...');
|
|
302
|
+
addStreamLine('Run created: ' + currentRunId, true);
|
|
303
|
+
|
|
304
|
+
// Subscribe to SSE stream
|
|
305
|
+
if (sseSource) { sseSource.close(); }
|
|
306
|
+
sseSource = new EventSource(BASE + '/agents/kai/stream');
|
|
307
|
+
sseSource.onmessage = function(e) {
|
|
308
|
+
try {
|
|
309
|
+
const evt = JSON.parse(e.data);
|
|
310
|
+
if (evt.eventType === 'review_requested' && evt.runId === currentRunId) {
|
|
311
|
+
showApproval(evt);
|
|
312
|
+
} else if ((evt.eventType === 'review_approved' || evt.eventType === 'review_rejected') && evt.runId === currentRunId) {
|
|
313
|
+
handleDecisionEvent(evt);
|
|
314
|
+
}
|
|
315
|
+
} catch(_) {}
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// Step 2: Post a step event, then request approval
|
|
319
|
+
await delay(600);
|
|
320
|
+
addStreamLine('Analyzing task requirements...', true);
|
|
321
|
+
await delay(700);
|
|
322
|
+
addStreamLine('Preparing deployment payload...', true);
|
|
323
|
+
await delay(500);
|
|
324
|
+
|
|
325
|
+
// Post review_requested
|
|
326
|
+
try {
|
|
327
|
+
const res = await fetch(BASE + '/agents/kai/events', {
|
|
328
|
+
method: 'POST',
|
|
329
|
+
headers: {'Content-Type':'application/json'},
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
eventType: 'review_requested',
|
|
332
|
+
runId: currentRunId,
|
|
333
|
+
payload: {
|
|
334
|
+
title: 'Deploy presence loop update to production',
|
|
335
|
+
action_required: 'Approve deployment to proceed',
|
|
336
|
+
urgency: 'high',
|
|
337
|
+
owner: 'kai',
|
|
338
|
+
description: 'Ready to deploy. This will update the live node. Approve to continue, reject to cancel.',
|
|
339
|
+
rationale: {
|
|
340
|
+
choice: 'Requesting human gate before production deploy',
|
|
341
|
+
considered: ['auto-deploy', 'defer'],
|
|
342
|
+
constraint: 'Production changes require explicit approval'
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
const evt = await res.json();
|
|
348
|
+
currentApprovalId = evt.id;
|
|
349
|
+
addStreamLine('⚡ Approval requested — waiting for human decision', true);
|
|
350
|
+
setStep(2);
|
|
351
|
+
setStatus('Waiting for your approval...');
|
|
352
|
+
showApproval({
|
|
353
|
+
id: currentApprovalId,
|
|
354
|
+
payload: {
|
|
355
|
+
title: 'Deploy presence loop update to production',
|
|
356
|
+
description: 'Ready to deploy. This will update the live node. Approve to continue, reject to cancel.',
|
|
357
|
+
urgency: 'high'
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
} catch(e) {
|
|
361
|
+
addStreamLine('Failed to post approval request: ' + e.message, false);
|
|
362
|
+
setStatus('Error: ' + e.message);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function showApproval(evt) {
|
|
367
|
+
const payload = evt.payload || {};
|
|
368
|
+
document.getElementById('approval-title').innerHTML =
|
|
369
|
+
(payload.title || 'Action requires approval') +
|
|
370
|
+
' <span class="urgency-badge">' + (payload.urgency || 'high') + '</span>';
|
|
371
|
+
document.getElementById('approval-desc').textContent =
|
|
372
|
+
payload.description || payload.action_required || 'Agent is requesting your decision.';
|
|
373
|
+
document.getElementById('approval-surface').classList.remove('hidden');
|
|
374
|
+
document.getElementById('session-state').textContent = 'waiting for approval';
|
|
375
|
+
if (!currentApprovalId && evt.id) currentApprovalId = evt.id;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function decide(decision) {
|
|
379
|
+
if (!currentApprovalId) { setStatus('No approval event ID — run the loop first'); return; }
|
|
380
|
+
document.getElementById('btn-approve').disabled = true;
|
|
381
|
+
document.getElementById('btn-reject').disabled = true;
|
|
382
|
+
setStatus('Submitting decision...');
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
const res = await fetch(BASE + '/approval-queue/' + encodeURIComponent(currentApprovalId) + '/decide', {
|
|
386
|
+
method: 'POST',
|
|
387
|
+
headers: {'Content-Type':'application/json'},
|
|
388
|
+
body: JSON.stringify({ decision: decision, actor: 'human' })
|
|
389
|
+
});
|
|
390
|
+
const data = await res.json();
|
|
391
|
+
if (!res.ok) throw new Error(data.error || 'Decision failed');
|
|
392
|
+
|
|
393
|
+
document.getElementById('approval-surface').classList.add('hidden');
|
|
394
|
+
|
|
395
|
+
if (decision === 'approve') {
|
|
396
|
+
addStreamLine('✓ Approved by human — continuing...', true);
|
|
397
|
+
await delay(400);
|
|
398
|
+
addStreamLine('Deploying update...', true);
|
|
399
|
+
await delay(600);
|
|
400
|
+
addStreamLine('Deploy complete. Node healthy.', true);
|
|
401
|
+
showResult('Deployment approved and complete. Node confirmed healthy at /health.');
|
|
402
|
+
setStep(3);
|
|
403
|
+
setStatus('Approved — result visible');
|
|
404
|
+
} else {
|
|
405
|
+
addStreamLine('✗ Rejected — run cancelled', false);
|
|
406
|
+
showResult('Run rejected by human. No changes deployed.');
|
|
407
|
+
document.getElementById('result-surface').style.borderColor = 'var(--red)';
|
|
408
|
+
document.querySelector('#result-surface .result-header').style.color = 'var(--red)';
|
|
409
|
+
document.querySelector('#result-surface .result-header').textContent = '✗ Rejected';
|
|
410
|
+
setStep(3);
|
|
411
|
+
setStatus('Rejected — run cancelled');
|
|
412
|
+
}
|
|
413
|
+
} catch(e) {
|
|
414
|
+
setStatus('Decision error: ' + e.message);
|
|
415
|
+
document.getElementById('btn-approve').disabled = false;
|
|
416
|
+
document.getElementById('btn-reject').disabled = false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function handleDecisionEvent(evt) {
|
|
421
|
+
// SSE confirmation — already handled by direct button flow
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function showResult(text) {
|
|
425
|
+
document.getElementById('result-body').textContent = text;
|
|
426
|
+
document.getElementById('result-surface').classList.add('visible');
|
|
427
|
+
document.getElementById('session-state').textContent = 'complete';
|
|
428
|
+
const dot = document.getElementById('agent-dot');
|
|
429
|
+
dot.style.background = 'var(--green)';
|
|
430
|
+
dot.style.animation = 'none';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function collapse() {
|
|
434
|
+
setStep(4);
|
|
435
|
+
setStatus('Collapsing to ambient...');
|
|
436
|
+
const session = document.getElementById('session');
|
|
437
|
+
session.style.opacity = '0';
|
|
438
|
+
session.style.transform = 'translateY(20px)';
|
|
439
|
+
|
|
440
|
+
setTimeout(function() {
|
|
441
|
+
session.classList.remove('visible');
|
|
442
|
+
session.style.opacity = '';
|
|
443
|
+
session.style.transform = '';
|
|
444
|
+
|
|
445
|
+
// Reset for next run
|
|
446
|
+
document.getElementById('run-stream').innerHTML = '<div class="run-line" style="color:var(--text-dim)">Waiting for run...</div>';
|
|
447
|
+
document.getElementById('approval-surface').classList.add('hidden');
|
|
448
|
+
document.getElementById('result-surface').classList.remove('visible');
|
|
449
|
+
document.getElementById('result-surface').style.borderColor = '';
|
|
450
|
+
document.querySelector('#result-surface .result-header').style.color = '';
|
|
451
|
+
document.querySelector('#result-surface .result-header').textContent = '✓ Approved — result';
|
|
452
|
+
document.getElementById('btn-approve').disabled = false;
|
|
453
|
+
document.getElementById('btn-reject').disabled = false;
|
|
454
|
+
document.getElementById('session-state').textContent = 'working';
|
|
455
|
+
const dot = document.getElementById('agent-dot');
|
|
456
|
+
dot.style.background = '';
|
|
457
|
+
dot.style.animation = '';
|
|
458
|
+
currentRunId = null;
|
|
459
|
+
currentApprovalId = null;
|
|
460
|
+
if (sseSource) { sseSource.close(); sseSource = null; }
|
|
461
|
+
|
|
462
|
+
document.getElementById('ambient').style.opacity = '1';
|
|
463
|
+
document.getElementById('ambient').style.pointerEvents = 'all';
|
|
464
|
+
document.getElementById('btn-start').disabled = false;
|
|
465
|
+
setStep(0);
|
|
466
|
+
setStatus('Back to ambient. Loop complete. ✓');
|
|
467
|
+
}, 800);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function delay(ms) { return new Promise(function(r) { setTimeout(r, ms); }); }
|
|
471
|
+
</script>
|
|
472
|
+
</body>
|
|
473
|
+
</html>
|