@wipcomputer/wip-ldm-os 0.4.85-alpha.8 → 0.4.86
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 +22 -2
- package/SKILL.md +137 -15
- package/bin/ldm.js +608 -75
- package/lib/deploy.mjs +90 -12
- package/lib/registry-migrations.mjs +296 -0
- package/package.json +21 -3
- package/scripts/test-boot-dir-truth.mjs +158 -0
- package/scripts/test-boot-hook-registration.mjs +136 -0
- package/scripts/test-boot-payload-trim.mjs +200 -0
- package/scripts/test-crc-agentid-tenant-boundary.mjs +2 -2
- package/scripts/test-crc-e2ee-key-persistence.mjs +150 -0
- package/scripts/test-crc-e2ee-session-route.mjs +9 -2
- package/scripts/test-crc-pair-login-flow.mjs +76 -1
- package/scripts/test-crc-pair-relink-audit-and-rotation.mjs +164 -0
- package/scripts/test-crc-websocket-abuse-limits.mjs +128 -0
- package/scripts/test-deploy-hook-ownership.mjs +160 -0
- package/scripts/test-doctor-hook-dedupe.mjs +188 -0
- package/scripts/test-install-prompt-policy.mjs +84 -0
- package/scripts/test-installer-skill-dry-run-destinations.mjs +100 -0
- package/scripts/test-installer-target-self-update.mjs +131 -0
- package/scripts/test-kaleidoscope-onboarding-copy.mjs +170 -0
- package/scripts/test-kaleidoscope-public-stats-baseline.mjs +129 -0
- package/scripts/test-kaleidoscope-qr-authenticator-confirmation.mjs +89 -0
- package/scripts/test-ldm-status-concurrency.mjs +118 -0
- package/scripts/test-ldm-status-timeout.mjs +96 -0
- package/scripts/test-legacy-npm-sources-migration.mjs +460 -0
- package/scripts/test-readme-install-prompt.mjs +66 -0
- package/shared/boot/boot-config.json +18 -8
- package/shared/docs/dev-guide-wipcomputerinc.md.tmpl +5 -4
- package/shared/rules/security.md +4 -0
- package/shared/templates/install-prompt.md +20 -2
- package/src/boot/README.md +24 -1
- package/src/boot/boot-config.json +18 -8
- package/src/boot/boot-hook.mjs +118 -28
- package/src/boot/installer.mjs +33 -10
- package/src/hosted-mcp/.env.example +4 -0
- package/src/hosted-mcp/README.md +37 -0
- package/src/hosted-mcp/app/footer.js +2 -2
- package/src/hosted-mcp/app/kaleidoscope-login.html +489 -42
- package/src/hosted-mcp/app/pair.html +21 -3
- package/src/hosted-mcp/app/wip-logo.png +0 -0
- package/src/hosted-mcp/codex-relay-e2ee-registry.mjs +208 -0
- package/src/hosted-mcp/codex-relay-ws-abuse-limits.mjs +140 -0
- package/src/hosted-mcp/demo/footer.js +2 -2
- package/src/hosted-mcp/demo/index.html +166 -44
- package/src/hosted-mcp/demo/login.html +87 -23
- package/src/hosted-mcp/demo/privacy.html +4 -214
- package/src/hosted-mcp/demo/tos.html +4 -189
- package/src/hosted-mcp/deploy.sh +2 -0
- package/src/hosted-mcp/docs/self-host.md +268 -0
- package/src/hosted-mcp/legal/internet-services/kaleidoscope/index.html +257 -0
- package/src/hosted-mcp/legal/internet-services/terms/site.html +224 -168
- package/src/hosted-mcp/legal/legal-footer.js +75 -0
- package/src/hosted-mcp/legal/legal.css +166 -0
- package/src/hosted-mcp/legal/privacy/en-ww/index.html +4 -221
- package/src/hosted-mcp/legal/privacy/index.html +253 -0
- package/src/hosted-mcp/server.mjs +920 -74
|
@@ -3,221 +3,11 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
body {
|
|
11
|
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
|
|
12
|
-
background: #FFFDF5;
|
|
13
|
-
color: #1a1a1a;
|
|
14
|
-
-webkit-font-smoothing: antialiased;
|
|
15
|
-
-webkit-text-size-adjust: 100%;
|
|
16
|
-
line-height: 1.6;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.container {
|
|
20
|
-
max-width: 980px;
|
|
21
|
-
margin: 0 auto;
|
|
22
|
-
padding: 16px 24px 80px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.header {
|
|
26
|
-
position: sticky;
|
|
27
|
-
top: 0;
|
|
28
|
-
z-index: 100;
|
|
29
|
-
padding: calc(12px + env(safe-area-inset-top, 0px)) 20px 12px;
|
|
30
|
-
background: rgba(255, 253, 245, 0.8);
|
|
31
|
-
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
32
|
-
backdrop-filter: saturate(180%) blur(20px);
|
|
33
|
-
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
34
|
-
display: flex;
|
|
35
|
-
align-items: center;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.header a {
|
|
39
|
-
display: flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
text-decoration: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
h1 {
|
|
45
|
-
font-size: 28px;
|
|
46
|
-
font-weight: 700;
|
|
47
|
-
letter-spacing: -0.02em;
|
|
48
|
-
margin-bottom: 4px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.subtitle {
|
|
52
|
-
font-size: 17px;
|
|
53
|
-
color: #8a8580;
|
|
54
|
-
margin-bottom: 8px;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.updated {
|
|
58
|
-
font-size: 13px;
|
|
59
|
-
color: #b0aaa4;
|
|
60
|
-
margin-bottom: 40px;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
section {
|
|
64
|
-
padding: 28px 0;
|
|
65
|
-
border-top: 1px solid #e8e5de;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
section:last-of-type {
|
|
69
|
-
border-bottom: 1px solid #e8e5de;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
h2 {
|
|
73
|
-
font-size: 16px;
|
|
74
|
-
font-weight: 600;
|
|
75
|
-
letter-spacing: -0.01em;
|
|
76
|
-
margin-bottom: 12px;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
p {
|
|
80
|
-
font-size: 15px;
|
|
81
|
-
line-height: 1.65;
|
|
82
|
-
color: #3a3a3a;
|
|
83
|
-
margin-bottom: 12px;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
p:last-child {
|
|
87
|
-
margin-bottom: 0;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
ul {
|
|
91
|
-
list-style: none;
|
|
92
|
-
padding: 0;
|
|
93
|
-
margin-bottom: 12px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
ul li {
|
|
97
|
-
font-size: 15px;
|
|
98
|
-
line-height: 1.65;
|
|
99
|
-
color: #3a3a3a;
|
|
100
|
-
padding-left: 16px;
|
|
101
|
-
position: relative;
|
|
102
|
-
margin-bottom: 4px;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
ul li::before {
|
|
106
|
-
content: "\2022";
|
|
107
|
-
position: absolute;
|
|
108
|
-
left: 0;
|
|
109
|
-
color: #b0aaa4;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
a {
|
|
113
|
-
color: #1a1a1a;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
footer {
|
|
117
|
-
margin-top: 48px;
|
|
118
|
-
padding-bottom: 160px;
|
|
119
|
-
}
|
|
120
|
-
</style>
|
|
6
|
+
<meta http-equiv="refresh" content="0; url=/legal/privacy/">
|
|
7
|
+
<link rel="canonical" href="/legal/privacy/">
|
|
8
|
+
<title>Privacy Policy - WIP Computer</title>
|
|
121
9
|
</head>
|
|
122
10
|
<body>
|
|
123
|
-
<
|
|
124
|
-
<a id="navIcon" href="/demo/"></a>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="container">
|
|
127
|
-
|
|
128
|
-
<h1>Privacy Policy</h1>
|
|
129
|
-
<p class="subtitle">Kaleidoscope Demo</p>
|
|
130
|
-
<p class="updated">Last updated: April 2, 2026</p>
|
|
131
|
-
|
|
132
|
-
<section>
|
|
133
|
-
<p>WIP Computer, Inc. ("we", "us") operates the Kaleidoscope demo at wip.computer/demo.</p>
|
|
134
|
-
</section>
|
|
135
|
-
|
|
136
|
-
<section>
|
|
137
|
-
<h2>What We Collect</h2>
|
|
138
|
-
<ul>
|
|
139
|
-
<li>Passkey credential ID and public key (for authentication)</li>
|
|
140
|
-
<li>Username (optional, if you provide one)</li>
|
|
141
|
-
<li>Wallet balance (simulated, for demo purposes)</li>
|
|
142
|
-
</ul>
|
|
143
|
-
</section>
|
|
144
|
-
|
|
145
|
-
<section>
|
|
146
|
-
<h2>What We Do NOT Collect</h2>
|
|
147
|
-
<ul>
|
|
148
|
-
<li>Email addresses (unless voluntarily provided later)</li>
|
|
149
|
-
<li>Passwords (passkeys only, no passwords exist)</li>
|
|
150
|
-
<li>Biometric data (Face ID / fingerprint verification happens on your device, we never receive biometric data)</li>
|
|
151
|
-
<li>Photos (camera captures are processed in your browser, never uploaded)</li>
|
|
152
|
-
<li>Browsing history or tracking data</li>
|
|
153
|
-
<li>Cookies (we use sessionStorage only, cleared when you close the browser)</li>
|
|
154
|
-
</ul>
|
|
155
|
-
</section>
|
|
156
|
-
|
|
157
|
-
<section>
|
|
158
|
-
<h2>How We Use Your Data</h2>
|
|
159
|
-
<ul>
|
|
160
|
-
<li>Authentication: verifying your passkey when you sign in</li>
|
|
161
|
-
<li>Demo functionality: tracking simulated wallet balance</li>
|
|
162
|
-
<li>Product improvement: aggregate usage patterns (no personal data)</li>
|
|
163
|
-
</ul>
|
|
164
|
-
</section>
|
|
165
|
-
|
|
166
|
-
<section>
|
|
167
|
-
<h2>Third-Party Services</h2>
|
|
168
|
-
<ul>
|
|
169
|
-
<li>xAI (Grok Imagine API): receives text prompts for image generation. Does not receive your photos or personal data.</li>
|
|
170
|
-
<li>No analytics services</li>
|
|
171
|
-
<li>No advertising networks</li>
|
|
172
|
-
<li>No data brokers</li>
|
|
173
|
-
</ul>
|
|
174
|
-
</section>
|
|
175
|
-
|
|
176
|
-
<section>
|
|
177
|
-
<h2>Data Storage</h2>
|
|
178
|
-
<p>Your passkey data is stored on our server at wip.computer. It is not encrypted at rest in this demo version. Production versions will implement end-to-end encryption where we architecturally cannot read your data.</p>
|
|
179
|
-
</section>
|
|
180
|
-
|
|
181
|
-
<section>
|
|
182
|
-
<h2>Data Deletion</h2>
|
|
183
|
-
<p>Contact <a href="mailto:hello@wip.computer">hello@wip.computer</a> to request deletion of your passkey data.</p>
|
|
184
|
-
</section>
|
|
185
|
-
|
|
186
|
-
<section>
|
|
187
|
-
<h2>Your Rights</h2>
|
|
188
|
-
<p>You can delete your passkey from your device at any time through your device settings (Settings > Passwords on iOS, chrome://settings/passwords on Chrome).</p>
|
|
189
|
-
</section>
|
|
190
|
-
|
|
191
|
-
<section>
|
|
192
|
-
<h2>Changes</h2>
|
|
193
|
-
<p>We may update this policy. Changes will be reflected in the "Last updated" date.</p>
|
|
194
|
-
</section>
|
|
195
|
-
|
|
196
|
-
<section>
|
|
197
|
-
<h2>Contact</h2>
|
|
198
|
-
<p><a href="mailto:hello@wip.computer">hello@wip.computer</a></p>
|
|
199
|
-
</section>
|
|
200
|
-
|
|
201
|
-
<footer>
|
|
202
|
-
<div id="kscope-footer"></div>
|
|
203
|
-
</footer>
|
|
204
|
-
<script src="/demo/footer.js"></script>
|
|
205
|
-
</div>
|
|
206
|
-
<script>
|
|
207
|
-
var SPRITE_COLS = 8, SPRITE_ROWS = 3, SPRITE_TOTAL = 24;
|
|
208
|
-
var navIdx = Math.floor(Math.random() * SPRITE_TOTAL);
|
|
209
|
-
function updateNavIcon() {
|
|
210
|
-
var el = document.getElementById('navIcon');
|
|
211
|
-
if (!el) return;
|
|
212
|
-
var col = navIdx % SPRITE_COLS;
|
|
213
|
-
var row = Math.floor(navIdx / SPRITE_COLS);
|
|
214
|
-
var bgPosX = (col / (SPRITE_COLS - 1)) * 100;
|
|
215
|
-
var bgPosY = (row / (SPRITE_ROWS - 1)) * 100;
|
|
216
|
-
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>';
|
|
217
|
-
navIdx = (navIdx + 1) % SPRITE_TOTAL;
|
|
218
|
-
}
|
|
219
|
-
updateNavIcon();
|
|
220
|
-
setInterval(updateNavIcon, 6000);
|
|
221
|
-
</script>
|
|
11
|
+
<p>The WIP Computer Privacy Policy has moved to <a href="/legal/privacy/">/legal/privacy/</a>.</p>
|
|
222
12
|
</body>
|
|
223
13
|
</html>
|
|
@@ -3,196 +3,11 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
body {
|
|
11
|
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
|
|
12
|
-
background: #FFFDF5;
|
|
13
|
-
color: #1a1a1a;
|
|
14
|
-
-webkit-font-smoothing: antialiased;
|
|
15
|
-
-webkit-text-size-adjust: 100%;
|
|
16
|
-
line-height: 1.6;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.container {
|
|
20
|
-
max-width: 980px;
|
|
21
|
-
margin: 0 auto;
|
|
22
|
-
padding: 16px 24px 80px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.header {
|
|
26
|
-
position: sticky;
|
|
27
|
-
top: 0;
|
|
28
|
-
z-index: 100;
|
|
29
|
-
padding: calc(12px + env(safe-area-inset-top, 0px)) 20px 12px;
|
|
30
|
-
background: rgba(255, 253, 245, 0.8);
|
|
31
|
-
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
32
|
-
backdrop-filter: saturate(180%) blur(20px);
|
|
33
|
-
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
34
|
-
display: flex;
|
|
35
|
-
align-items: center;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.header a {
|
|
39
|
-
display: flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
text-decoration: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
h1 {
|
|
45
|
-
font-size: 28px;
|
|
46
|
-
font-weight: 700;
|
|
47
|
-
letter-spacing: -0.02em;
|
|
48
|
-
margin-bottom: 4px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.subtitle {
|
|
52
|
-
font-size: 17px;
|
|
53
|
-
color: #8a8580;
|
|
54
|
-
margin-bottom: 8px;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.updated {
|
|
58
|
-
font-size: 13px;
|
|
59
|
-
color: #b0aaa4;
|
|
60
|
-
margin-bottom: 40px;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
section {
|
|
64
|
-
padding: 28px 0;
|
|
65
|
-
border-top: 1px solid #e8e5de;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
section:last-of-type {
|
|
69
|
-
border-bottom: 1px solid #e8e5de;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
h2 {
|
|
73
|
-
font-size: 16px;
|
|
74
|
-
font-weight: 600;
|
|
75
|
-
letter-spacing: -0.01em;
|
|
76
|
-
margin-bottom: 12px;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
p {
|
|
80
|
-
font-size: 15px;
|
|
81
|
-
line-height: 1.65;
|
|
82
|
-
color: #3a3a3a;
|
|
83
|
-
margin-bottom: 12px;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
p:last-child {
|
|
87
|
-
margin-bottom: 0;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
ul {
|
|
91
|
-
list-style: none;
|
|
92
|
-
padding: 0;
|
|
93
|
-
margin-bottom: 12px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
ul li {
|
|
97
|
-
font-size: 15px;
|
|
98
|
-
line-height: 1.65;
|
|
99
|
-
color: #3a3a3a;
|
|
100
|
-
padding-left: 16px;
|
|
101
|
-
position: relative;
|
|
102
|
-
margin-bottom: 4px;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
ul li::before {
|
|
106
|
-
content: "\2022";
|
|
107
|
-
position: absolute;
|
|
108
|
-
left: 0;
|
|
109
|
-
color: #b0aaa4;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
a {
|
|
113
|
-
color: #1a1a1a;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
footer {
|
|
117
|
-
margin-top: 48px;
|
|
118
|
-
padding-bottom: 160px;
|
|
119
|
-
}
|
|
120
|
-
</style>
|
|
6
|
+
<meta http-equiv="refresh" content="0; url=/legal/internet-services/kaleidoscope/">
|
|
7
|
+
<link rel="canonical" href="/legal/internet-services/kaleidoscope/">
|
|
8
|
+
<title>Kaleidoscope Terms of Service - WIP Computer</title>
|
|
121
9
|
</head>
|
|
122
10
|
<body>
|
|
123
|
-
<
|
|
124
|
-
<a id="navIcon" href="/demo/"></a>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="container">
|
|
127
|
-
|
|
128
|
-
<h1>Terms of Service</h1>
|
|
129
|
-
<p class="subtitle">Kaleidoscope Demo</p>
|
|
130
|
-
<p class="updated">Last updated: April 2, 2026</p>
|
|
131
|
-
|
|
132
|
-
<section>
|
|
133
|
-
<p>This is a technology demonstration by WIP Computer, Inc.</p>
|
|
134
|
-
</section>
|
|
135
|
-
|
|
136
|
-
<section>
|
|
137
|
-
<h2>The Demo</h2>
|
|
138
|
-
<p>This demo showcases passkey authentication, biometric permission, and AI image generation. It is not a production service.</p>
|
|
139
|
-
</section>
|
|
140
|
-
|
|
141
|
-
<section>
|
|
142
|
-
<h2>Your Account</h2>
|
|
143
|
-
<p>Your account is created with a passkey. No email or password is stored. Your passkey lives on your device.</p>
|
|
144
|
-
</section>
|
|
145
|
-
|
|
146
|
-
<section>
|
|
147
|
-
<h2>Your Wallet</h2>
|
|
148
|
-
<p>The demo wallet starts with $5.00 in simulated credits. No real money is charged. The wallet balance is for demonstration purposes only.</p>
|
|
149
|
-
</section>
|
|
150
|
-
|
|
151
|
-
<section>
|
|
152
|
-
<h2>Generated Content</h2>
|
|
153
|
-
<p>Images generated through this demo are created using third-party AI APIs (xAI Grok Imagine). Generated content is dual-licensed:</p>
|
|
154
|
-
<ul>
|
|
155
|
-
<li>MIT License for personal, non-commercial use</li>
|
|
156
|
-
<li>Apache 2.0 License for commercial use</li>
|
|
157
|
-
</ul>
|
|
158
|
-
<p>Both you and WIP Computer, Inc. retain rights to generated content. We may use generated images for product development, marketing, and research.</p>
|
|
159
|
-
</section>
|
|
160
|
-
|
|
161
|
-
<section>
|
|
162
|
-
<h2>Uploaded Media</h2>
|
|
163
|
-
<p>Photos taken through the camera feature are processed locally in your browser. They are not uploaded to or stored on our servers. Camera access is optional and can be denied.</p>
|
|
164
|
-
</section>
|
|
165
|
-
|
|
166
|
-
<section>
|
|
167
|
-
<h2>No Warranty</h2>
|
|
168
|
-
<p>This demo is provided "as is" without warranty of any kind. WIP Computer, Inc. is not liable for any damages arising from use of this demo.</p>
|
|
169
|
-
</section>
|
|
170
|
-
|
|
171
|
-
<section>
|
|
172
|
-
<h2>Contact</h2>
|
|
173
|
-
<p><a href="mailto:hello@wip.computer">hello@wip.computer</a></p>
|
|
174
|
-
</section>
|
|
175
|
-
|
|
176
|
-
<footer>
|
|
177
|
-
<div id="kscope-footer"></div>
|
|
178
|
-
</footer>
|
|
179
|
-
<script src="/demo/footer.js"></script>
|
|
180
|
-
</div>
|
|
181
|
-
<script>
|
|
182
|
-
var SPRITE_COLS = 8, SPRITE_ROWS = 3, SPRITE_TOTAL = 24;
|
|
183
|
-
var navIdx = Math.floor(Math.random() * SPRITE_TOTAL);
|
|
184
|
-
function updateNavIcon() {
|
|
185
|
-
var el = document.getElementById('navIcon');
|
|
186
|
-
if (!el) return;
|
|
187
|
-
var col = navIdx % SPRITE_COLS;
|
|
188
|
-
var row = Math.floor(navIdx / SPRITE_COLS);
|
|
189
|
-
var bgPosX = (col / (SPRITE_COLS - 1)) * 100;
|
|
190
|
-
var bgPosY = (row / (SPRITE_ROWS - 1)) * 100;
|
|
191
|
-
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>';
|
|
192
|
-
navIdx = (navIdx + 1) % SPRITE_TOTAL;
|
|
193
|
-
}
|
|
194
|
-
updateNavIcon();
|
|
195
|
-
setInterval(updateNavIcon, 6000);
|
|
196
|
-
</script>
|
|
11
|
+
<p>The Kaleidoscope Terms of Service have moved to <a href="/legal/internet-services/kaleidoscope/">/legal/internet-services/kaleidoscope/</a>.</p>
|
|
197
12
|
</body>
|
|
198
13
|
</html>
|
package/src/hosted-mcp/deploy.sh
CHANGED
|
@@ -116,6 +116,8 @@ if [ "$SKIP_APP" -ne 1 ]; then
|
|
|
116
116
|
add_file "server.mjs" "${APP_REMOTE_DIR}/server.mjs"
|
|
117
117
|
add_file "inbox.mjs" "${APP_REMOTE_DIR}/inbox.mjs"
|
|
118
118
|
add_file "tools.mjs" "${APP_REMOTE_DIR}/tools.mjs"
|
|
119
|
+
add_file "codex-relay-e2ee-registry.mjs" "${APP_REMOTE_DIR}/codex-relay-e2ee-registry.mjs"
|
|
120
|
+
add_file "codex-relay-ws-abuse-limits.mjs" "${APP_REMOTE_DIR}/codex-relay-ws-abuse-limits.mjs"
|
|
119
121
|
add_file "package.json" "${APP_REMOTE_DIR}/package.json"
|
|
120
122
|
# Phone app static files (codex-remote-control, login).
|
|
121
123
|
if [ -d "${SCRIPT_DIR}/app" ]; then
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Hosted Relay Self-Host Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to inspect and run the hosted relay source that backs WIP-hosted services such as Codex Remote Control.
|
|
4
|
+
|
|
5
|
+
The public source lives here:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
src/hosted-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
WIP's production relay runs at `wip.computer`. Self-hosting means running the same relay source on your own domain, with your own database, TLS certificate, process manager, and secrets.
|
|
12
|
+
|
|
13
|
+
## What The Hosted Relay Does
|
|
14
|
+
|
|
15
|
+
The hosted relay is a Node server with several surfaces:
|
|
16
|
+
|
|
17
|
+
- hosted MCP over HTTP at `/mcp`;
|
|
18
|
+
- OAuth and passkey login routes;
|
|
19
|
+
- demo routes under `/demo`;
|
|
20
|
+
- Codex Remote Control pairing and relay routes under `/api/codex-relay/*`;
|
|
21
|
+
- health reporting at `/health`.
|
|
22
|
+
|
|
23
|
+
For Codex Remote Control, the relay lets a local `codex-daemon` dial out to a public server. Browser and phone clients connect to that same public server. After E2EE setup, prompt text, assistant output, command output, and errors are carried as encrypted frames. The relay routes and authorizes frames, but it is not the place where Codex runs.
|
|
24
|
+
|
|
25
|
+
## Current Self-Host Status
|
|
26
|
+
|
|
27
|
+
The relay source is inspectable and runnable, but the non-WIP self-host story is not yet a one-command installer.
|
|
28
|
+
|
|
29
|
+
Important current constraints:
|
|
30
|
+
|
|
31
|
+
- `server.mjs` currently defaults `ISSUER_URL`, `MCP_RESOURCE_URL`, `RP_ID`, and `RP_ORIGIN` to `wip.computer`;
|
|
32
|
+
- the nginx examples are written for the WIP production domain and filesystem layout;
|
|
33
|
+
- the Codex Remote Control browser surface at `/codex-remote-control/<threadId>` is served by the WIP web app, not by the hosted-mcp Node process itself;
|
|
34
|
+
- `codex-daemon` can point at a custom relay with environment variables, but a complete non-WIP phone/web UI deployment must also point at that same relay.
|
|
35
|
+
|
|
36
|
+
That means a production self-host should treat this guide as the infrastructure map. Before broad use, parameterize or patch the WIP domain constants for your domain.
|
|
37
|
+
|
|
38
|
+
## Prerequisites
|
|
39
|
+
|
|
40
|
+
You need:
|
|
41
|
+
|
|
42
|
+
- Node.js 20 or newer;
|
|
43
|
+
- npm;
|
|
44
|
+
- Postgres;
|
|
45
|
+
- nginx or another reverse proxy that supports WebSocket upgrades;
|
|
46
|
+
- TLS for your domain;
|
|
47
|
+
- PM2 or another process manager;
|
|
48
|
+
- a public domain such as `relay.example.com`.
|
|
49
|
+
|
|
50
|
+
Optional demo surfaces may also need:
|
|
51
|
+
|
|
52
|
+
- `OPENAI_API_KEY`;
|
|
53
|
+
- `XAI_API_KEY`.
|
|
54
|
+
|
|
55
|
+
Codex Remote Control relay operation does not require those demo keys.
|
|
56
|
+
|
|
57
|
+
## Environment
|
|
58
|
+
|
|
59
|
+
Start from:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd src/hosted-mcp
|
|
63
|
+
cp .env.example .env
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Required:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
DATABASE_URL=postgresql://kaleidoscope:YOUR_PASSWORD@localhost:5432/kaleidoscope
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Common optional variables:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
MCP_PORT=18800
|
|
76
|
+
LDM_HOSTED_MCP_WS_ORIGIN_ALLOWLIST=https://relay.example.com
|
|
77
|
+
LDM_HOSTED_MCP_RL_MINT=30
|
|
78
|
+
LDM_HOSTED_MCP_RL_VALIDATE=60
|
|
79
|
+
LDM_HOSTED_MCP_RL_STATUS=120
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Development-only variables:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
LDM_HOSTED_MCP_DEV_MODE=1
|
|
86
|
+
LDM_HOSTED_MCP_ALLOW_WS_URL_TOKEN=1
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Do not enable those development flags in production. Production should use Postgres and bearer or ticket authentication, not JSON fallback files or URL token fallback.
|
|
90
|
+
|
|
91
|
+
## Database Setup
|
|
92
|
+
|
|
93
|
+
Create a Postgres database and user for the relay. Then run Prisma from `src/hosted-mcp`:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install
|
|
97
|
+
npx prisma generate
|
|
98
|
+
npx prisma migrate deploy
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The Prisma schema stores:
|
|
102
|
+
|
|
103
|
+
- users;
|
|
104
|
+
- WebAuthn credentials;
|
|
105
|
+
- device tokens;
|
|
106
|
+
- wallets;
|
|
107
|
+
- API keys.
|
|
108
|
+
|
|
109
|
+
Production should use Postgres. If Prisma cannot connect and `LDM_HOSTED_MCP_DEV_MODE` is not set, the server fails closed.
|
|
110
|
+
|
|
111
|
+
## Local Smoke Test
|
|
112
|
+
|
|
113
|
+
From `src/hosted-mcp`:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm install
|
|
117
|
+
node server.mjs
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
In another shell:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
curl -fsS http://127.0.0.1:18800/health
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Expected result: JSON health output from the Node process.
|
|
127
|
+
|
|
128
|
+
## Process Management
|
|
129
|
+
|
|
130
|
+
WIP production uses PM2 with:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
src/hosted-mcp/ecosystem.config.cjs
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For a self-host:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cd src/hosted-mcp
|
|
140
|
+
pm2 start ecosystem.config.cjs --update-env
|
|
141
|
+
pm2 save
|
|
142
|
+
pm2 status mcp-server
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If you use another process manager, preserve the same contract:
|
|
146
|
+
|
|
147
|
+
- run `server.mjs` from `src/hosted-mcp`;
|
|
148
|
+
- provide `DATABASE_URL`;
|
|
149
|
+
- keep the process alive across restarts;
|
|
150
|
+
- preserve environment variables on reload;
|
|
151
|
+
- verify `/health` after restart.
|
|
152
|
+
|
|
153
|
+
## Deploy Helper
|
|
154
|
+
|
|
155
|
+
WIP's production deploy helper is:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
src/hosted-mcp/deploy.sh
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
It copies `server.mjs`, supporting modules, static app/demo files, nginx snippets, and package metadata to WIP's VPS, then reloads nginx, reloads PM2, and writes a deploy manifest.
|
|
162
|
+
|
|
163
|
+
For self-hosting, read it as an example of the file inventory and verification sequence. Do not run it unmodified unless your SSH host, remote directories, nginx layout, PM2 process name, and deploy-manifest path intentionally match the WIP production layout.
|
|
164
|
+
|
|
165
|
+
## nginx, TLS, And Domain
|
|
166
|
+
|
|
167
|
+
The production nginx examples live in:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
src/hosted-mcp/nginx
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Key files:
|
|
174
|
+
|
|
175
|
+
- `codex-relay.conf` contains the `/api/codex-relay/*`, `/pair`, and WebSocket proxy routes;
|
|
176
|
+
- `mcp-oauth.conf` and `mcp-server.conf` contain hosted MCP and OAuth routes;
|
|
177
|
+
- `wip.computer.conf` shows how WIP includes those snippets inside the public site config;
|
|
178
|
+
- `conf.d/redact-logs.conf` defines the redacted access-log format.
|
|
179
|
+
|
|
180
|
+
For self-hosting:
|
|
181
|
+
|
|
182
|
+
1. Put TLS in front of your relay domain.
|
|
183
|
+
2. Proxy HTTP routes to `http://127.0.0.1:18800`.
|
|
184
|
+
3. Preserve WebSocket upgrade headers for `/api/codex-relay/web/` and `/api/codex-relay/daemon`.
|
|
185
|
+
4. Use redacted logs so bearer tokens, relay tickets, and API keys do not land in access logs.
|
|
186
|
+
5. Replace WIP paths and domains with your own.
|
|
187
|
+
|
|
188
|
+
Minimum verification:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
sudo nginx -t
|
|
192
|
+
sudo systemctl reload nginx
|
|
193
|
+
curl -fsS https://relay.example.com/health
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Pointing Codex Remote Control At A Custom Relay
|
|
197
|
+
|
|
198
|
+
`codex-daemon` defaults to WIP's hosted relay. For a custom relay, set the relay endpoints before pairing and starting the daemon:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
export CODEX_DAEMON_RELAY_HTTP=https://relay.example.com
|
|
202
|
+
export CODEX_DAEMON_RELAY_WS=wss://relay.example.com/api/codex-relay/daemon
|
|
203
|
+
codex-daemon link
|
|
204
|
+
codex-daemon start
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The MCP tool that creates browser links also defaults to WIP's hosted origin. Set this for sessions that should generate links for your relay domain:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
export CODEX_REMOTE_CONTROL_ORIGIN=https://relay.example.com
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
A full non-WIP deployment also needs a browser or phone UI that serves `/codex-remote-control/<threadId>` and talks to the same relay routes. In WIP production, that UI is part of the Kaleidoscope web app.
|
|
214
|
+
|
|
215
|
+
## Verify The Relay
|
|
216
|
+
|
|
217
|
+
Use these checks after any deploy:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
curl -fsS https://relay.example.com/health
|
|
221
|
+
curl -fsS https://relay.example.com/api/codex-relay/state
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
For WIP production deploys, `scripts/verify-deploy.sh` verifies a deploy manifest against live remote file hashes:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
bash src/hosted-mcp/scripts/verify-deploy.sh latest
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
That script assumes the WIP deploy-manifest layout unless you pass a different manifest and remote.
|
|
231
|
+
|
|
232
|
+
## What Not To Copy From WIP Production
|
|
233
|
+
|
|
234
|
+
Do not copy:
|
|
235
|
+
|
|
236
|
+
- WIP `.env` files;
|
|
237
|
+
- WIP Postgres credentials;
|
|
238
|
+
- WIP API keys or `ck-` tokens;
|
|
239
|
+
- WIP passkey, device, wallet, or user rows;
|
|
240
|
+
- WIP PM2 process state;
|
|
241
|
+
- WIP nginx certificate paths;
|
|
242
|
+
- WIP domain constants without changing them for your domain;
|
|
243
|
+
- WIP deploy manifests as proof of your deploy.
|
|
244
|
+
|
|
245
|
+
Use the source shape, not WIP's production secrets or account data.
|
|
246
|
+
|
|
247
|
+
## Production Checklist
|
|
248
|
+
|
|
249
|
+
- Domain and TLS are live.
|
|
250
|
+
- `DATABASE_URL` points at your Postgres database.
|
|
251
|
+
- Prisma migrations have run.
|
|
252
|
+
- `server.mjs` starts without `LDM_HOSTED_MCP_DEV_MODE`.
|
|
253
|
+
- nginx proxies `/health`, `/mcp`, `/oauth/*`, `/api/codex-relay/*`, `/pair`, and WebSocket upgrades.
|
|
254
|
+
- WebSocket origins are restricted with `LDM_HOSTED_MCP_WS_ORIGIN_ALLOWLIST`.
|
|
255
|
+
- URL token fallback is disabled.
|
|
256
|
+
- Access logs redact bearer tokens, relay tickets, and `ck-` values.
|
|
257
|
+
- `codex-daemon link` completes against your domain.
|
|
258
|
+
- `codex-daemon start` reports relay paired.
|
|
259
|
+
- Browser links are generated for your domain, not `wip.computer`.
|
|
260
|
+
|
|
261
|
+
## Open Work
|
|
262
|
+
|
|
263
|
+
The remaining product work is to turn this infrastructure map into a first-class self-host installer:
|
|
264
|
+
|
|
265
|
+
- parameterize issuer and WebAuthn relying party settings;
|
|
266
|
+
- package the phone/web Remote Control UI for non-WIP domains;
|
|
267
|
+
- add a guided `ldm` self-host profile;
|
|
268
|
+
- add an end-to-end self-host smoke test that pairs a daemon and browser through a non-WIP domain.
|