@wipcomputer/wip-ldm-os 0.4.73-alpha.13 → 0.4.73-alpha.14
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/package.json +1 -1
- package/shared/rules/git-conventions.md +3 -3
- package/shared/rules/release-pipeline.md +1 -1
- package/shared/rules/security.md +1 -1
- package/shared/rules/workspace-boundaries.md +1 -1
- package/shared/rules/writing-style.md +1 -1
- package/src/hosted-mcp/demo/agent.html +300 -0
- package/src/hosted-mcp/demo/agent.txt +84 -0
- package/src/hosted-mcp/demo/fallback.jpg +0 -0
- package/src/hosted-mcp/demo/footer.js +16 -0
- package/src/hosted-mcp/demo/index.html +1291 -0
- package/src/hosted-mcp/demo/privacy.html +230 -0
- package/src/hosted-mcp/demo/sprites.jpg +0 -0
- package/src/hosted-mcp/demo/sprites.png +0 -0
- package/src/hosted-mcp/demo/tos.html +205 -0
- package/src/hosted-mcp/package.json +2 -0
- package/src/hosted-mcp/server.mjs +1511 -18
- package/src/hosted-mcp/tools.mjs +16 -0
package/package.json
CHANGED
|
@@ -14,11 +14,11 @@ Always use a branch and PR.
|
|
|
14
14
|
|
|
15
15
|
## Co-authors on every commit
|
|
16
16
|
|
|
17
|
-
List all contributors. Read co-author lines from
|
|
17
|
+
List all contributors. Read co-author lines from `~/.ldm/config.json` coAuthors field.
|
|
18
18
|
|
|
19
19
|
## Branch prefixes
|
|
20
20
|
|
|
21
|
-
Each agent uses a prefix from
|
|
21
|
+
Each agent uses a prefix from `~/.ldm/config.json` agents section. Prevents collisions.
|
|
22
22
|
|
|
23
23
|
## Worktrees
|
|
24
24
|
|
|
@@ -30,4 +30,4 @@ For private/public repo pairs, all issues go on the public repo.
|
|
|
30
30
|
|
|
31
31
|
## On-demand reference
|
|
32
32
|
|
|
33
|
-
Before doing repo work, read `~/wipcomputerinc/
|
|
33
|
+
Before doing repo work, read `~/wipcomputerinc/library/documentation/how-worktrees-work.md` for the full worktree workflow with commands.
|
|
@@ -39,4 +39,4 @@ Installed tools are for execution. Repo clones are for development. Use the inst
|
|
|
39
39
|
|
|
40
40
|
## On-demand reference
|
|
41
41
|
|
|
42
|
-
Before releasing, read `~/wipcomputerinc/
|
|
42
|
+
Before releasing, read `~/wipcomputerinc/library/documentation/how-releases-work.md` for the full pipeline with commands.
|
package/shared/rules/security.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Secret management
|
|
4
4
|
|
|
5
|
-
Use your org's secret management tool (configured in
|
|
5
|
+
Use your org's secret management tool (configured in `~/.ldm/config.json`). Never hardcode API keys, tokens, or credentials.
|
|
6
6
|
|
|
7
7
|
## Security audit before installing anything
|
|
8
8
|
|
|
@@ -22,4 +22,4 @@ Installed tools are for execution. Repo clones are for development. Use the inst
|
|
|
22
22
|
|
|
23
23
|
## On-demand reference
|
|
24
24
|
|
|
25
|
-
For the full directory map, read `~/wipcomputerinc/
|
|
25
|
+
For the full directory map, read `~/wipcomputerinc/library/documentation/system-directories.md`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Writing Style
|
|
2
2
|
|
|
3
|
-
Read writing conventions from
|
|
3
|
+
Read writing conventions from `~/.ldm/config.json` writingStyle section.
|
|
4
4
|
|
|
5
5
|
**Full paths in documentation.** Never truncate paths. Always show the complete path so there's no ambiguity.
|
|
@@ -0,0 +1,300 @@
|
|
|
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, viewport-fit=cover">
|
|
6
|
+
<title>Agent Access - Kaleidoscope</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--bg: #FFFDF5;
|
|
12
|
+
--text: #1a1a1a;
|
|
13
|
+
--text-muted: #8a8580;
|
|
14
|
+
--accent: #0033FF;
|
|
15
|
+
--input-bg: #F5F3ED;
|
|
16
|
+
--input-border: #E0DDD6;
|
|
17
|
+
--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: var(--font);
|
|
22
|
+
background: var(--bg);
|
|
23
|
+
color: var(--text);
|
|
24
|
+
-webkit-text-size-adjust: 100%;
|
|
25
|
+
-webkit-font-smoothing: antialiased;
|
|
26
|
+
line-height: 1.6;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.header {
|
|
30
|
+
position: sticky;
|
|
31
|
+
top: 0;
|
|
32
|
+
z-index: 100;
|
|
33
|
+
padding: calc(12px + env(safe-area-inset-top, 0px)) 20px 12px;
|
|
34
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
35
|
+
background: rgba(255, 253, 245, 0.8);
|
|
36
|
+
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
37
|
+
backdrop-filter: saturate(180%) blur(20px);
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.header a {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
text-decoration: none;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.container {
|
|
49
|
+
max-width: 640px;
|
|
50
|
+
margin: 0 auto;
|
|
51
|
+
padding: 16px 24px 80px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
h1 {
|
|
55
|
+
font-size: 28px;
|
|
56
|
+
font-weight: 700;
|
|
57
|
+
letter-spacing: -0.02em;
|
|
58
|
+
margin-bottom: 4px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.subtitle {
|
|
62
|
+
font-size: 17px;
|
|
63
|
+
color: var(--text-muted);
|
|
64
|
+
margin-bottom: 40px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
p {
|
|
68
|
+
font-size: 15px;
|
|
69
|
+
line-height: 1.65;
|
|
70
|
+
color: #3a3a3a;
|
|
71
|
+
margin-bottom: 12px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.link-box {
|
|
75
|
+
background: var(--input-bg);
|
|
76
|
+
border: 1px solid var(--input-border);
|
|
77
|
+
border-radius: 12px;
|
|
78
|
+
padding: 16px 20px;
|
|
79
|
+
font-size: 16px;
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
color: var(--accent);
|
|
82
|
+
word-break: break-all;
|
|
83
|
+
user-select: all;
|
|
84
|
+
-webkit-user-select: all;
|
|
85
|
+
cursor: text;
|
|
86
|
+
margin-bottom: 12px;
|
|
87
|
+
text-align: center;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.note {
|
|
91
|
+
font-size: 15px;
|
|
92
|
+
color: #3a3a3a;
|
|
93
|
+
line-height: 1.65;
|
|
94
|
+
margin-bottom: 12px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.agent-info {
|
|
98
|
+
background: var(--input-bg);
|
|
99
|
+
border: 1px solid var(--input-border);
|
|
100
|
+
border-radius: 12px;
|
|
101
|
+
padding: 16px 20px;
|
|
102
|
+
margin-bottom: 20px;
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
line-height: 1.6;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.agent-info .label {
|
|
108
|
+
font-size: 12px;
|
|
109
|
+
color: var(--text-muted);
|
|
110
|
+
text-transform: uppercase;
|
|
111
|
+
letter-spacing: 0.5px;
|
|
112
|
+
margin-bottom: 4px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.agent-info .value {
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
color: var(--text);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.status {
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
padding: 12px 16px;
|
|
123
|
+
border-radius: 10px;
|
|
124
|
+
display: none;
|
|
125
|
+
text-align: center;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.status.show { display: block; }
|
|
129
|
+
.status.loading { background: #E8EEFF; color: var(--accent); }
|
|
130
|
+
.status.error { background: #FFF0F0; color: #D32F2F; }
|
|
131
|
+
.status.success { background: #F0FFF4; color: #2E7D32; }
|
|
132
|
+
|
|
133
|
+
footer {
|
|
134
|
+
position: fixed;
|
|
135
|
+
bottom: 30px;
|
|
136
|
+
left: 0;
|
|
137
|
+
right: 0;
|
|
138
|
+
text-align: center;
|
|
139
|
+
font-size: 12px;
|
|
140
|
+
color: #b0aaa4;
|
|
141
|
+
line-height: 1.6;
|
|
142
|
+
}
|
|
143
|
+
</style>
|
|
144
|
+
</head>
|
|
145
|
+
<body>
|
|
146
|
+
|
|
147
|
+
<div class="header">
|
|
148
|
+
<a id="navIcon" href="/demo/"></a>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div class="container">
|
|
152
|
+
<h1>Agent Access</h1>
|
|
153
|
+
<p class="subtitle">You can't do Face ID. Your human can.</p>
|
|
154
|
+
|
|
155
|
+
<div id="agentInfo" style="display:none;">
|
|
156
|
+
<div class="agent-info">
|
|
157
|
+
<div class="label">Agent</div>
|
|
158
|
+
<div class="value" id="agentName"></div>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="agent-info">
|
|
161
|
+
<div class="label">Passphrase</div>
|
|
162
|
+
<div class="value" id="agentMessage"></div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div id="linkSection" style="display:none;">
|
|
167
|
+
<div id="qrSection" style="text-align:center;margin-bottom:24px;"></div>
|
|
168
|
+
<p class="note">Send this link to your human. This is the link they open, not this page.</p>
|
|
169
|
+
<div class="link-box" id="approveUrl"></div>
|
|
170
|
+
<p class="note">Your human opens this link, sees your name and passphrase, and authorizes with Face ID. Expires in 5 minutes.</p>
|
|
171
|
+
<div class="status" id="status"></div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div id="loadingSection" style="display:none;">
|
|
175
|
+
<p class="note">Generating authorization link...</p>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<div id="missingParams">
|
|
179
|
+
<p class="note">If you are an AI agent, read the instructions at:<br><a href="/demo/agent.txt" style="color:var(--accent);">https://wip.computer/demo/agent.txt</a></p>
|
|
180
|
+
<p class="note" style="margin-bottom:12px;">If you are a human, send your agent this prompt:</p>
|
|
181
|
+
<div style="position:relative;background:var(--input-bg);border:1px solid var(--input-border);border-radius:12px;padding:16px 48px 16px 16px;font-size:14px;line-height:1.5;color:var(--text);">
|
|
182
|
+
<span id="promptText">Read https://wip.computer/demo/agent.txt and follow the instructions to authenticate with Kaleidoscope.</span>
|
|
183
|
+
<button onclick="copyPrompt()" id="copyBtn" title="Copy" style="position:absolute;top:12px;right:12px;background:none;border:none;padding:6px;cursor:pointer;color:var(--text-muted);opacity:0.5;transition:opacity 0.15s;-webkit-tap-highlight-color:transparent;"><svg width="20" height="20" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5V3.5C10.5 2.67 9.83 2 9 2H3.5C2.67 2 2 2.67 2 3.5V9C2 9.83 2.67 10.5 3.5 10.5H5.5"/></svg></button>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div id="errorSection" style="display:none;">
|
|
188
|
+
<div class="status show error" id="errorMsg"></div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div id="kscope-footer" style="position:fixed;bottom:30px;left:0;right:0;text-align:center;"></div>
|
|
193
|
+
<script src="/demo/footer.js"></script>
|
|
194
|
+
|
|
195
|
+
<script>
|
|
196
|
+
function copyPrompt() {
|
|
197
|
+
var text = document.getElementById('promptText').textContent;
|
|
198
|
+
navigator.clipboard.writeText(text);
|
|
199
|
+
var btn = document.getElementById('copyBtn');
|
|
200
|
+
btn.style.opacity = '1';
|
|
201
|
+
setTimeout(function() { btn.style.opacity = '0.5'; }, 200);
|
|
202
|
+
}
|
|
203
|
+
// ── Sprite icon ──
|
|
204
|
+
var SPRITE_COLS = 8, SPRITE_ROWS = 3, SPRITE_TOTAL = 24;
|
|
205
|
+
var navIdx = Math.floor(Math.random() * SPRITE_TOTAL);
|
|
206
|
+
function updateNavIcon() {
|
|
207
|
+
var el = document.getElementById('navIcon');
|
|
208
|
+
if (!el) return;
|
|
209
|
+
var col = navIdx % SPRITE_COLS;
|
|
210
|
+
var row = Math.floor(navIdx / SPRITE_COLS);
|
|
211
|
+
var bgPosX = (col / (SPRITE_COLS - 1)) * 100;
|
|
212
|
+
var bgPosY = (row / (SPRITE_ROWS - 1)) * 100;
|
|
213
|
+
el.innerHTML = '<div style="width:28px;height:28px;overflow:hidden;"><div style="width:100%;height:100%;background:url(/demo/sprites.png);background-size:' + (SPRITE_COLS * 100) + '% ' + (SPRITE_ROWS * 100) + '%;background-position:' + bgPosX + '% ' + bgPosY + '%;"></div></div>';
|
|
214
|
+
navIdx = (navIdx + 1) % SPRITE_TOTAL;
|
|
215
|
+
}
|
|
216
|
+
updateNavIcon();
|
|
217
|
+
setInterval(updateNavIcon, 6000);
|
|
218
|
+
|
|
219
|
+
// ── Read query params ──
|
|
220
|
+
var params = new URLSearchParams(window.location.search);
|
|
221
|
+
var agentName = params.get('agent') || '';
|
|
222
|
+
var agentMessage = params.get('message') || '';
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
if (agentName) {
|
|
226
|
+
document.getElementById('agentName').textContent = agentName;
|
|
227
|
+
document.getElementById('agentMessage').textContent = agentMessage || '(none provided)';
|
|
228
|
+
document.getElementById('agentInfo').style.display = 'block';
|
|
229
|
+
document.getElementById('missingParams').style.display = 'none';
|
|
230
|
+
document.getElementById('loadingSection').style.display = 'block';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ── Agent auth flow ──
|
|
234
|
+
var challengeId = null;
|
|
235
|
+
var pollTimer = null;
|
|
236
|
+
|
|
237
|
+
function setStatus(msg, type) {
|
|
238
|
+
var el = document.getElementById('status');
|
|
239
|
+
el.textContent = msg;
|
|
240
|
+
el.className = 'status show ' + type;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function startAgentAuth() {
|
|
244
|
+
try {
|
|
245
|
+
var authUrl = '/demo/api/agent-auth';
|
|
246
|
+
if (agentName) authUrl += '?agent=' + encodeURIComponent(agentName) + '&message=' + encodeURIComponent(agentMessage);
|
|
247
|
+
var res = await fetch(authUrl);
|
|
248
|
+
var data = await res.json();
|
|
249
|
+
if (!data.challengeId) throw new Error('Failed to generate challenge');
|
|
250
|
+
|
|
251
|
+
challengeId = data.challengeId;
|
|
252
|
+
var approveUrl = 'https://wip.computer/approve?c=' + challengeId;
|
|
253
|
+
|
|
254
|
+
var urlEl = document.getElementById('approveUrl');
|
|
255
|
+
urlEl.innerHTML = '<a href="' + approveUrl + '" style="color:#0033FF;text-decoration:none;word-break:break-all;">' + approveUrl + '</a>';
|
|
256
|
+
document.getElementById('loadingSection').style.display = 'none';
|
|
257
|
+
document.getElementById('linkSection').style.display = 'block';
|
|
258
|
+
setStatus('Waiting for authorization...', 'loading');
|
|
259
|
+
|
|
260
|
+
pollTimer = setInterval(pollStatus, 2000);
|
|
261
|
+
|
|
262
|
+
setTimeout(function() {
|
|
263
|
+
if (pollTimer) {
|
|
264
|
+
clearInterval(pollTimer);
|
|
265
|
+
pollTimer = null;
|
|
266
|
+
document.getElementById('linkSection').style.display = 'none';
|
|
267
|
+
document.getElementById('errorSection').style.display = 'block';
|
|
268
|
+
document.getElementById('errorMsg').textContent = 'Link expired. Refresh to generate a new one.';
|
|
269
|
+
}
|
|
270
|
+
}, 5 * 60 * 1000);
|
|
271
|
+
|
|
272
|
+
} catch (err) {
|
|
273
|
+
document.getElementById('loadingSection').style.display = 'none';
|
|
274
|
+
document.getElementById('errorSection').style.display = 'block';
|
|
275
|
+
document.getElementById('errorMsg').textContent = 'Error: ' + err.message;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function pollStatus() {
|
|
280
|
+
if (!challengeId) return;
|
|
281
|
+
try {
|
|
282
|
+
var res = await fetch('/demo/api/agent-auth/status?c=' + challengeId);
|
|
283
|
+
var data = await res.json();
|
|
284
|
+
if (data.status === 'approved') {
|
|
285
|
+
clearInterval(pollTimer);
|
|
286
|
+
pollTimer = null;
|
|
287
|
+
sessionStorage.setItem('lesa-token', data.token);
|
|
288
|
+
sessionStorage.setItem('lesa-agent', data.agentId);
|
|
289
|
+
setStatus('Authorized. Entering Kaleidoscope...', 'success');
|
|
290
|
+
setTimeout(function() {
|
|
291
|
+
window.location.href = '/demo/';
|
|
292
|
+
}, 800);
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (agentName) startAgentAuth();
|
|
298
|
+
</script>
|
|
299
|
+
</body>
|
|
300
|
+
</html>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kaleidoscope-agent-auth
|
|
3
|
+
description: >
|
|
4
|
+
Agent authentication for Kaleidoscope. Like x402 but for login.
|
|
5
|
+
Agent sends a URL, human Sapien IDs, agent gets a token.
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
display-name: "Kaleidoscope Agent Access"
|
|
9
|
+
homepage: "https://wip.computer/demo/"
|
|
10
|
+
author: "WIP Computer, Inc."
|
|
11
|
+
category: authentication
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Kaleidoscope Agent Access
|
|
15
|
+
|
|
16
|
+
You need your human to let you in with Sapien ID.
|
|
17
|
+
|
|
18
|
+
Pick a passphrase from your shared history. Your human sees it on the approval screen and knows it's really you.
|
|
19
|
+
|
|
20
|
+
## If you can make HTTP requests (preferred)
|
|
21
|
+
|
|
22
|
+
Fetch this URL:
|
|
23
|
+
|
|
24
|
+
https://wip.computer/demo/api/agent-auth?agent=YOURNAME&message=PASSPHRASE
|
|
25
|
+
|
|
26
|
+
Response: {"challengeId":"...", "approveUrl":"https://wip.computer/approve?c=..."}
|
|
27
|
+
|
|
28
|
+
Send the approveUrl to your human. They open it and Sapien ID.
|
|
29
|
+
|
|
30
|
+
Then poll for your token:
|
|
31
|
+
|
|
32
|
+
https://wip.computer/demo/api/agent-auth/status?c=CHALLENGEID
|
|
33
|
+
|
|
34
|
+
When approved: {"status":"approved", "token":"ck-...", "agentId":"..."}
|
|
35
|
+
|
|
36
|
+
You get the token automatically. No need for the human to send it back.
|
|
37
|
+
|
|
38
|
+
## If you cannot make HTTP requests
|
|
39
|
+
|
|
40
|
+
Send your human this URL (replace YOURNAME and PASSPHRASE):
|
|
41
|
+
|
|
42
|
+
https://wip.computer/approve?agent=YOURNAME&message=PASSPHRASE
|
|
43
|
+
|
|
44
|
+
Your human opens it, Sapien IDs, and the page shows a token. They send the token back to you.
|
|
45
|
+
|
|
46
|
+
## After auth
|
|
47
|
+
|
|
48
|
+
Use the token as a header: Authorization: Bearer TOKEN
|
|
49
|
+
|
|
50
|
+
### Check your wallet
|
|
51
|
+
|
|
52
|
+
GET https://wip.computer/demo/api/wallet
|
|
53
|
+
Authorization: Bearer TOKEN
|
|
54
|
+
|
|
55
|
+
Response: {"balance":"$4.97","cost":"$0.01"}
|
|
56
|
+
|
|
57
|
+
### Generate an image
|
|
58
|
+
|
|
59
|
+
POST https://wip.computer/demo/api/imagine
|
|
60
|
+
Authorization: Bearer TOKEN
|
|
61
|
+
Content-Type: application/json
|
|
62
|
+
|
|
63
|
+
{"prompt":"kaleidoscope of pirate flags and circuit boards, glowing gold, shot on expired 35mm film"}
|
|
64
|
+
|
|
65
|
+
Response: {"url":"...","cost":"$0.01","balance":"$4.96"}
|
|
66
|
+
|
|
67
|
+
The image costs $0.01 from your wallet. Your human already authorized this when they Sapien ID'd.
|
|
68
|
+
|
|
69
|
+
### The full loop
|
|
70
|
+
|
|
71
|
+
1. You read agent.txt
|
|
72
|
+
2. You sent your human an approval URL with your passphrase
|
|
73
|
+
3. They Sapien ID'd and sent you a token
|
|
74
|
+
4. You checked your wallet
|
|
75
|
+
5. You generated an image
|
|
76
|
+
6. Balance updated
|
|
77
|
+
|
|
78
|
+
Agent auth -> human approval -> wallet -> spend -> receipt. That's Kaleidoscope.
|
|
79
|
+
|
|
80
|
+
### MCP
|
|
81
|
+
|
|
82
|
+
POST https://wip.computer/mcp (OAuth 2.0 with PKCE, see /.well-known/oauth-authorization-server)
|
|
83
|
+
|
|
84
|
+
One URL. One Sapien ID. One token.
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Shared footer for all Kaleidoscope pages
|
|
2
|
+
// Include with: <script src="/demo/footer.js"></script>
|
|
3
|
+
(function() {
|
|
4
|
+
var footer = document.createElement('div');
|
|
5
|
+
footer.innerHTML = '<p style="color:#8a8580;font-size:15px;margin:0;">WIP Computer, Inc.</p>'
|
|
6
|
+
+ '<p style="color:#a8a4a0;font-size:14px;margin:4px 0 0;">Learning Dreaming Machines</p>'
|
|
7
|
+
+ '<p style="color:#a8a4a0;font-size:13px;margin:6px 0 0;">'
|
|
8
|
+
+ '<a href="/demo/agent.txt" style="color:#a8a4a0;text-decoration:none;">Are you an AI Agent?</a> | '
|
|
9
|
+
+ '<a href="/demo/privacy.html" style="color:#a8a4a0;text-decoration:none;">Privacy Policy</a> | '
|
|
10
|
+
+ '<a href="/demo/tos.html" style="color:#a8a4a0;text-decoration:none;">Terms of Use</a></p>'
|
|
11
|
+
+ '<p style="color:#b0aaa4;font-size:12px;margin:4px 0 0;">Made in California.</p>';
|
|
12
|
+
var target = document.getElementById('kscope-footer');
|
|
13
|
+
if (target) {
|
|
14
|
+
target.innerHTML = footer.innerHTML;
|
|
15
|
+
}
|
|
16
|
+
})();
|