@wipcomputer/wip-ldm-os 0.4.73-alpha.13 → 0.4.73-alpha.15
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/docs/doc-pipeline/README.md +74 -0
- package/docs/doc-pipeline/TECHNICAL.md +79 -0
- 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
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Documentation Pipeline
|
|
2
|
+
|
|
3
|
+
Documentation lives in three places. They stay in sync through the installer. This is not optional.
|
|
4
|
+
|
|
5
|
+
## The Three Levels
|
|
6
|
+
|
|
7
|
+
### 1. Repo Docs (source of truth)
|
|
8
|
+
|
|
9
|
+
Every repo has documentation at its root and in `docs/` for features:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
repo/
|
|
13
|
+
├── README.md What this repo is
|
|
14
|
+
├── TECHNICAL.md How it works
|
|
15
|
+
├── SKILL.md Agent instructions
|
|
16
|
+
├── CLAUDE.md Agent context for Claude Code
|
|
17
|
+
├── docs/
|
|
18
|
+
│ └── <feature>/
|
|
19
|
+
│ ├── README.md What this feature is
|
|
20
|
+
│ └── TECHNICAL.md How this feature works
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
When a feature gets absorbed into a repo, its README and TECHNICAL move into `docs/<feature>/`.
|
|
24
|
+
|
|
25
|
+
Repo docs are the source of truth. Everything else is derived from them.
|
|
26
|
+
|
|
27
|
+
### 2. Home Docs (human readable, personalized)
|
|
28
|
+
|
|
29
|
+
Location: `~/wipcomputerinc/library/documentation/`
|
|
30
|
+
|
|
31
|
+
These are personalized for YOUR system. "Here's how releases work on YOUR machine." Generated by the installer from repo doc templates + your `~/.ldm/config.json`.
|
|
32
|
+
|
|
33
|
+
The human reads these. They describe how the system is set up on this specific machine, with this specific configuration.
|
|
34
|
+
|
|
35
|
+
### 3. Agent Docs (OS reference)
|
|
36
|
+
|
|
37
|
+
Location: `~/.ldm/shared/`
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
~/.ldm/shared/
|
|
41
|
+
├── rules/ Thin rules deployed to ~/.claude/rules/
|
|
42
|
+
├── dev-guide-*.md Org-specific dev conventions
|
|
43
|
+
├── boot/ Boot sequence config
|
|
44
|
+
└── prompts/ Cron prompts
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
These are what agents reference. Rules, dev guide, boot config. The installer deploys them so agents always have current instructions.
|
|
48
|
+
|
|
49
|
+
### 4. ai/ (development process)
|
|
50
|
+
|
|
51
|
+
Location: `<repo>/ai/`
|
|
52
|
+
|
|
53
|
+
Plans, bugs, research, dev updates. Private repo only. Never ships to public. Updated by the dev team (humans + AI agents) during development.
|
|
54
|
+
|
|
55
|
+
## The Update Flow
|
|
56
|
+
|
|
57
|
+
### On merge to private main
|
|
58
|
+
|
|
59
|
+
1. **Repo docs** updated. README, TECHNICAL, docs/<feature>/, SKILL.md, CLAUDE.md. Part of the PR. Code and docs ship together.
|
|
60
|
+
2. **ai/** updated. Plan archived, bugs closed, dev update written. Notes the version is on alpha.
|
|
61
|
+
|
|
62
|
+
### On `ldm install`
|
|
63
|
+
|
|
64
|
+
3. **Home docs** regenerated. Installer reads repo doc templates + config.json, generates personalized `library/documentation/` files.
|
|
65
|
+
4. **Agent docs** deployed. Installer copies rules, dev guide, boot config from the installed package to `~/.ldm/shared/` and `~/.claude/rules/`.
|
|
66
|
+
|
|
67
|
+
### On deploy to public
|
|
68
|
+
|
|
69
|
+
5. **Public repo** updated. `deploy-public.sh` syncs everything except `ai/`.
|
|
70
|
+
6. **ai/** dev update notes the version moved from alpha to release.
|
|
71
|
+
|
|
72
|
+
## The Rule
|
|
73
|
+
|
|
74
|
+
Three places, one update, never out of sync. The installer is the bridge between "code landed" and "docs are current everywhere." Developers write repo docs. The installer propagates them. Nobody manually updates home docs or agent docs.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Documentation Pipeline: Technical Details
|
|
2
|
+
|
|
3
|
+
## File Paths
|
|
4
|
+
|
|
5
|
+
### Repo doc templates (in the LDM OS repo)
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
shared/docs/*.md.tmpl Templates for home docs
|
|
9
|
+
shared/rules/*.md Source for agent rules
|
|
10
|
+
shared/boot/ Boot sequence config
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Templates use placeholders from `~/.ldm/config.json` (workspace path, agent names, org name, etc.).
|
|
14
|
+
|
|
15
|
+
### Installed locations
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
~/.ldm/config.json Org config (agents, paths, co-authors)
|
|
19
|
+
~/.ldm/shared/rules/*.md Agent rules (source for ~/.claude/rules/)
|
|
20
|
+
~/.ldm/shared/dev-guide-*.md Org dev guide
|
|
21
|
+
~/.ldm/shared/boot/ Boot sequence config
|
|
22
|
+
~/.ldm/shared/prompts/ Cron prompts
|
|
23
|
+
~/.ldm/templates/ CLAUDE.md templates, install prompt, etc.
|
|
24
|
+
~/wipcomputerinc/library/documentation/ Personalized human docs (from templates)
|
|
25
|
+
~/.claude/rules/ Deployed rules (copied from ~/.ldm/shared/rules/)
|
|
26
|
+
~/.claude/CLAUDE.md Level 1 global (generated from template + config)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### What ldm install deploys
|
|
30
|
+
|
|
31
|
+
| Source | Destination | When |
|
|
32
|
+
|--------|------------|------|
|
|
33
|
+
| `shared/rules/*.md` | `~/.ldm/shared/rules/` then `~/.claude/rules/` | Every install |
|
|
34
|
+
| `shared/docs/*.md.tmpl` | `~/wipcomputerinc/library/documentation/` | Every install |
|
|
35
|
+
| `shared/boot/` | `~/.ldm/shared/boot/` | Every install |
|
|
36
|
+
| `shared/prompts/` | `~/.ldm/shared/prompts/` | Every install |
|
|
37
|
+
| `shared/templates/` | `~/.ldm/templates/` | Every install |
|
|
38
|
+
|
|
39
|
+
**Known bug (April 2026):** The installer currently deploys shared rules on `ldm init` (first install) but not on every `ldm install`. This means rule updates in new versions don't propagate until the user re-initializes. This needs to be fixed so rules deploy on every install.
|
|
40
|
+
|
|
41
|
+
**Known bug (April 2026):** The installer previously deployed home docs to `settings/docs/`. This path was renamed to `library/documentation/` on March 28, 2026. The installer must deploy to the correct path.
|
|
42
|
+
|
|
43
|
+
## How templates work
|
|
44
|
+
|
|
45
|
+
Home doc templates at `shared/docs/*.md.tmpl` contain placeholders:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Workspace: {{workspace}}
|
|
49
|
+
Agents: {{agents}}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The installer reads `~/.ldm/config.json`, substitutes the placeholders, and writes the personalized docs to `~/wipcomputerinc/library/documentation/`.
|
|
53
|
+
|
|
54
|
+
## CLAUDE.md cascade
|
|
55
|
+
|
|
56
|
+
Three levels. Claude Code reads all of them, walking up from CWD:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Level 1: ~/.claude/CLAUDE.md Global. ~30 lines. Universal rules.
|
|
60
|
+
Level 2: ~/wipcomputerinc/CLAUDE.md Workspace. ~150 lines. Org context.
|
|
61
|
+
Level 3: <repo>/CLAUDE.md Per-repo. ~50-86 lines. Repo-specific.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
After context compaction, CWD may shift to a repo. Without Level 3, all context is lost. Every repo must have a CLAUDE.md.
|
|
65
|
+
|
|
66
|
+
## Config paths (correct as of April 2026)
|
|
67
|
+
|
|
68
|
+
References in CLAUDE.md and rules must use absolute paths:
|
|
69
|
+
|
|
70
|
+
| Reference | Correct path |
|
|
71
|
+
|-----------|-------------|
|
|
72
|
+
| Org config | `~/.ldm/config.json` |
|
|
73
|
+
| Dev guide | `~/.ldm/shared/dev-guide-wipcomputerinc.md` |
|
|
74
|
+
| Human docs | `~/wipcomputerinc/library/documentation/` |
|
|
75
|
+
| Agent rules | `~/.ldm/shared/rules/` (source) or `~/.claude/rules/` (deployed) |
|
|
76
|
+
| Workspace CLAUDE.md | `~/wipcomputerinc/CLAUDE.md` |
|
|
77
|
+
| Global CLAUDE.md | `~/.claude/CLAUDE.md` |
|
|
78
|
+
|
|
79
|
+
NOT `settings/config.json`. NOT `settings/docs/`. Those paths are from before the March 28 rename.
|
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
|
+
})();
|