@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.73-alpha.13",
3
+ "version": "0.4.73-alpha.14",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {
@@ -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 `settings/config.json` in your workspace.
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 `settings/config.json` agents section. Prevents collisions.
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/settings/docs/how-worktrees-work.md` for the full worktree workflow with commands.
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/settings/docs/how-releases-work.md` for the full pipeline with commands.
42
+ Before releasing, read `~/wipcomputerinc/library/documentation/how-releases-work.md` for the full pipeline with commands.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Secret management
4
4
 
5
- Use your org's secret management tool (configured in settings/config.json). Never hardcode API keys, tokens, or credentials.
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/settings/docs/system-directories.md`.
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 your org's `settings/config.json` writingStyle section.
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
+ })();