@crowdedkingdoms/crowdyjs 15.12.1 → 16.0.0-dev.1
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/MIGRATION.md +55 -0
- package/README.md +67 -41
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -0
- package/dist/crowdy-client.d.ts +2 -3
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +9 -11
- package/dist/crowdy-dsh/bridge.d.ts +156 -0
- package/dist/crowdy-dsh/bridge.d.ts.map +1 -0
- package/dist/crowdy-dsh/bridge.js +523 -0
- package/dist/crowdy-dsh/index.d.ts +11 -0
- package/dist/crowdy-dsh/index.d.ts.map +1 -0
- package/dist/crowdy-dsh/index.js +10 -0
- package/dist/crowdy-dsh/pane.d.ts +64 -0
- package/dist/crowdy-dsh/pane.d.ts.map +1 -0
- package/dist/crowdy-dsh/pane.js +247 -0
- package/dist/crowdy-dsh/protocol.d.ts +249 -0
- package/dist/crowdy-dsh/protocol.d.ts.map +1 -0
- package/dist/crowdy-dsh/protocol.js +39 -0
- package/dist/crowdy-dsh/transport.d.ts +66 -0
- package/dist/crowdy-dsh/transport.d.ts.map +1 -0
- package/dist/crowdy-dsh/transport.js +88 -0
- package/dist/crowdy-studio/controller.d.ts +8 -0
- package/dist/crowdy-studio/controller.d.ts.map +1 -1
- package/dist/crowdy-studio/controller.js +33 -1
- package/dist/crowdy-studio/dom-shell.d.ts +21 -4
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.js +32 -17
- package/dist/crowdy-studio/embed/index.d.ts +1 -1
- package/dist/crowdy-studio/embed/index.d.ts.map +1 -1
- package/dist/crowdy-studio/embed/panel.d.ts +18 -18
- package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
- package/dist/crowdy-studio/embed/panel.js +7 -21
- package/dist/crowdy-studio/index.d.ts +2 -3
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/crowdy-studio/index.js +1 -2
- package/dist/crowdy-studio/mount.d.ts +29 -14
- package/dist/crowdy-studio/mount.d.ts.map +1 -1
- package/dist/crowdy-studio/mount.js +39 -126
- package/dist/crowdy-studio/styles.d.ts +1 -1
- package/dist/crowdy-studio/styles.d.ts.map +1 -1
- package/dist/crowdy-studio/styles.js +5 -0
- package/dist/default-origin.d.ts +6 -6
- package/dist/default-origin.d.ts.map +1 -1
- package/dist/default-origin.js +6 -6
- package/dist/generated/graphql.d.ts +76 -2438
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +0 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/{crowdy-agent/errors.d.ts → player-host/agent-errors.d.ts} +1 -1
- package/dist/player-host/agent-errors.d.ts.map +1 -0
- package/dist/player-host/agent-types.d.ts +18 -0
- package/dist/player-host/agent-types.d.ts.map +1 -0
- package/dist/player-host/agent-types.js +7 -0
- package/dist/player-host/index.d.ts +12 -4
- package/dist/player-host/index.d.ts.map +1 -1
- package/dist/player-host/index.js +11 -4
- package/dist/{crowdy-agent/schema.d.ts → player-host/json-schema.d.ts} +1 -1
- package/dist/player-host/json-schema.d.ts.map +1 -0
- package/dist/{crowdy-agent/schema.js → player-host/json-schema.js} +1 -1
- package/dist/player-host/schemas.d.ts +1 -1
- package/dist/player-host/schemas.d.ts.map +1 -1
- package/dist/player-host/schemas.js +2 -2
- package/dist/player-host/types.d.ts +2 -2
- package/dist/player-host/types.d.ts.map +1 -1
- package/package.json +5 -7
- package/dist/crowdy-agent/browser-dispatcher.d.ts +0 -41
- package/dist/crowdy-agent/browser-dispatcher.d.ts.map +0 -1
- package/dist/crowdy-agent/browser-dispatcher.js +0 -264
- package/dist/crowdy-agent/controller.d.ts +0 -152
- package/dist/crowdy-agent/controller.d.ts.map +0 -1
- package/dist/crowdy-agent/controller.js +0 -1289
- package/dist/crowdy-agent/errors.d.ts.map +0 -1
- package/dist/crowdy-agent/graphql-transport.d.ts +0 -154
- package/dist/crowdy-agent/graphql-transport.d.ts.map +0 -1
- package/dist/crowdy-agent/graphql-transport.js +0 -854
- package/dist/crowdy-agent/index.d.ts +0 -17
- package/dist/crowdy-agent/index.d.ts.map +0 -1
- package/dist/crowdy-agent/index.js +0 -16
- package/dist/crowdy-agent/registry.d.ts +0 -29
- package/dist/crowdy-agent/registry.d.ts.map +0 -1
- package/dist/crowdy-agent/registry.js +0 -281
- package/dist/crowdy-agent/schema.d.ts.map +0 -1
- package/dist/crowdy-agent/session-resume.d.ts +0 -24
- package/dist/crowdy-agent/session-resume.d.ts.map +0 -1
- package/dist/crowdy-agent/session-resume.js +0 -76
- package/dist/crowdy-agent/studio-tools.d.ts +0 -15
- package/dist/crowdy-agent/studio-tools.d.ts.map +0 -1
- package/dist/crowdy-agent/studio-tools.js +0 -280
- package/dist/crowdy-agent/tool-descriptors.d.ts +0 -4
- package/dist/crowdy-agent/tool-descriptors.d.ts.map +0 -1
- package/dist/crowdy-agent/tool-descriptors.js +0 -1049
- package/dist/crowdy-agent/transport.d.ts +0 -152
- package/dist/crowdy-agent/transport.d.ts.map +0 -1
- package/dist/crowdy-agent/transport.js +0 -27
- package/dist/crowdy-agent/types.d.ts +0 -328
- package/dist/crowdy-agent/types.d.ts.map +0 -1
- package/dist/crowdy-agent/types.js +0 -37
- package/dist/crowdy-studio/agent-dom-shell.d.ts +0 -68
- package/dist/crowdy-studio/agent-dom-shell.d.ts.map +0 -1
- package/dist/crowdy-studio/agent-dom-shell.js +0 -418
- package/dist/player-host/control-banner.d.ts +0 -40
- package/dist/player-host/control-banner.d.ts.map +0 -1
- package/dist/player-host/control-banner.js +0 -252
- package/dist/player-host/control-gate.d.ts +0 -77
- package/dist/player-host/control-gate.d.ts.map +0 -1
- package/dist/player-host/control-gate.js +0 -197
- package/dist/player-host/lease-manager.d.ts +0 -66
- package/dist/player-host/lease-manager.d.ts.map +0 -1
- package/dist/player-host/lease-manager.js +0 -428
- package/dist/player-host/tools.d.ts +0 -13
- package/dist/player-host/tools.d.ts.map +0 -1
- package/dist/player-host/tools.js +0 -79
- /package/dist/{crowdy-agent/errors.js → player-host/agent-errors.js} +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Studio agent pane: a same-origin iframe hosting the DeepSeek Harness
|
|
3
|
+
* web UI (running in a Web Worker) plus the Crowdy chrome around it — the
|
|
4
|
+
* provider-data notice the player accepts once, a Screenshot button, the
|
|
5
|
+
* payer / spend line, and the bridge status.
|
|
6
|
+
*
|
|
7
|
+
* The harness owns the conversation UI (chat, diffs, plan mode, approvals);
|
|
8
|
+
* this pane owns what the game knows: who pays, whether the player consented,
|
|
9
|
+
* and the capture button that pushes a frame into the model's `captures/`.
|
|
10
|
+
*/
|
|
11
|
+
import { StudioDshBridge } from './bridge.js';
|
|
12
|
+
const USAGE_REFRESH_MS = 30000;
|
|
13
|
+
export class CrowdyStudioDshPane {
|
|
14
|
+
constructor(parent, options) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
this.usageTimer = null;
|
|
17
|
+
this.started = false;
|
|
18
|
+
this.disposed = false;
|
|
19
|
+
this.root = el('section', 'ck-crowdy-studio-dsh');
|
|
20
|
+
this.root.setAttribute('aria-label', 'Crowdy Studio agent');
|
|
21
|
+
const header = el('header');
|
|
22
|
+
const title = el('h2');
|
|
23
|
+
title.textContent = 'Agent';
|
|
24
|
+
this.status = el('span', 'ck-crowdy-studio-dsh-status');
|
|
25
|
+
this.status.textContent = 'Starting…';
|
|
26
|
+
this.captureButton = el('button', 'ck-crowdy-studio-dsh-capture');
|
|
27
|
+
this.captureButton.type = 'button';
|
|
28
|
+
this.captureButton.textContent = 'Screenshot';
|
|
29
|
+
this.captureButton.title = 'Share what you see with the agent (saved under captures/)';
|
|
30
|
+
this.captureButton.disabled = true;
|
|
31
|
+
this.captureButton.addEventListener('click', () => {
|
|
32
|
+
void this.run(async () => {
|
|
33
|
+
const shot = await this.bridge.shareCapture('player capture');
|
|
34
|
+
this.say(`Shared ${shot.name} (${shot.width}x${shot.height}) with the agent.`);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
header.append(title, this.status, this.captureButton);
|
|
38
|
+
this.notice = el('div', 'ck-crowdy-studio-dsh-notice');
|
|
39
|
+
this.notice.hidden = true;
|
|
40
|
+
this.frame = document.createElement('iframe');
|
|
41
|
+
this.frame.className = 'ck-crowdy-studio-dsh-frame';
|
|
42
|
+
this.frame.title = 'Crowdy Studio agent';
|
|
43
|
+
this.frame.setAttribute('allow', 'clipboard-write');
|
|
44
|
+
// The harness is served from the game's own origin: `BroadcastChannel`
|
|
45
|
+
// and OPFS are origin-scoped, so it cannot live anywhere else today.
|
|
46
|
+
// `allow-same-origin` is therefore required and `allow-scripts` runs the
|
|
47
|
+
// worker. With both set the sandbox does NOT isolate the frame from this
|
|
48
|
+
// page (the browser says as much in its console); what it still removes is
|
|
49
|
+
// top-level navigation, popups, forms, downloads and modals. The real
|
|
50
|
+
// control is the CSP the host serves on `/dsh/*`.
|
|
51
|
+
this.frame.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
52
|
+
this.spend = el('div', 'ck-crowdy-studio-dsh-spend');
|
|
53
|
+
this.message = el('div', 'ck-crowdy-studio-dsh-message');
|
|
54
|
+
this.message.hidden = true;
|
|
55
|
+
this.root.append(header, this.notice, this.frame, this.spend, this.message);
|
|
56
|
+
parent.appendChild(this.root);
|
|
57
|
+
this.bridge = new StudioDshBridge({
|
|
58
|
+
controller: options.controller,
|
|
59
|
+
transport: options.transport,
|
|
60
|
+
appId: options.appId,
|
|
61
|
+
persistScope: options.persistScope,
|
|
62
|
+
getToken: options.getToken,
|
|
63
|
+
graphqlUrl: options.graphqlUrl,
|
|
64
|
+
host: options.host,
|
|
65
|
+
confirmLiveDeploy: (summary) => this.confirmLiveDeploy(summary.projectName),
|
|
66
|
+
onWarning: (text) => {
|
|
67
|
+
this.say(text);
|
|
68
|
+
options.onWarning?.(text);
|
|
69
|
+
},
|
|
70
|
+
onStatus: (status) => this.renderStatus(status),
|
|
71
|
+
onFileChanged: (change) => this.say(`Agent updated ${change.target.toLowerCase()}/${change.path}.`),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The page-side gate on a live deploy. The harness UI has its own approval
|
|
76
|
+
* inside the iframe, but the page cannot see it and the channel is open to
|
|
77
|
+
* any same-origin script, so the player confirms here too. Auto-declines
|
|
78
|
+
* after a minute so a stale prompt cannot be accepted by accident later.
|
|
79
|
+
*/
|
|
80
|
+
confirmLiveDeploy(projectName) {
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
this.message.hidden = false;
|
|
83
|
+
this.message.replaceChildren();
|
|
84
|
+
const text = el('span');
|
|
85
|
+
text.textContent = `The agent wants to deploy ${projectName} live to everyone in this grid. `;
|
|
86
|
+
const approve = el('button', 'ck-crowdy-studio-dsh-confirm');
|
|
87
|
+
approve.type = 'button';
|
|
88
|
+
approve.textContent = 'Deploy live';
|
|
89
|
+
const decline = el('button', 'ck-crowdy-studio-dsh-decline');
|
|
90
|
+
decline.type = 'button';
|
|
91
|
+
decline.textContent = 'Not now';
|
|
92
|
+
let settled = false;
|
|
93
|
+
const finish = (answer) => {
|
|
94
|
+
if (settled)
|
|
95
|
+
return;
|
|
96
|
+
settled = true;
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
this.message.replaceChildren();
|
|
99
|
+
this.message.hidden = true;
|
|
100
|
+
resolve(answer);
|
|
101
|
+
};
|
|
102
|
+
const timer = setTimeout(() => finish(false), 60000);
|
|
103
|
+
approve.addEventListener('click', () => finish(true));
|
|
104
|
+
decline.addEventListener('click', () => finish(false));
|
|
105
|
+
this.message.append(text, approve, ' ', decline);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/** Boot once the pane is visible; the notice gates the first boot on consent. */
|
|
109
|
+
async start() {
|
|
110
|
+
if (this.started || this.disposed)
|
|
111
|
+
return;
|
|
112
|
+
this.started = true;
|
|
113
|
+
try {
|
|
114
|
+
const consent = await this.options.transport.consent(this.options.appId);
|
|
115
|
+
if (!consent.consented) {
|
|
116
|
+
this.started = false;
|
|
117
|
+
this.renderNotice();
|
|
118
|
+
this.status.textContent = 'Waiting for your OK';
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
await this.boot();
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
this.started = false;
|
|
125
|
+
this.renderStatus({ phase: 'failed', message: error instanceof Error ? error.message : String(error) });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
dispose() {
|
|
129
|
+
this.disposed = true;
|
|
130
|
+
if (this.usageTimer)
|
|
131
|
+
clearInterval(this.usageTimer);
|
|
132
|
+
this.bridge.detach();
|
|
133
|
+
this.root.remove();
|
|
134
|
+
}
|
|
135
|
+
async boot() {
|
|
136
|
+
const base = this.options.webBase.endsWith('/') ? this.options.webBase : `${this.options.webBase}/`;
|
|
137
|
+
this.frame.src = `${base}index.html`;
|
|
138
|
+
await this.bridge.attach(this.frame);
|
|
139
|
+
this.captureButton.disabled = !this.options.host?.captureFrame;
|
|
140
|
+
await this.refreshUsage();
|
|
141
|
+
this.usageTimer = setInterval(() => void this.refreshUsage(), USAGE_REFRESH_MS);
|
|
142
|
+
}
|
|
143
|
+
renderNotice() {
|
|
144
|
+
this.notice.hidden = false;
|
|
145
|
+
this.notice.replaceChildren();
|
|
146
|
+
const text = el('p');
|
|
147
|
+
text.textContent =
|
|
148
|
+
'The agent sends your project source, your messages and any screenshots you share to a model provider through Crowded Kingdoms (zero data retention, no training). ' +
|
|
149
|
+
'Model usage is charged to your wallet at the app\'s rates unless the app pays for it.';
|
|
150
|
+
const actions = el('div', 'ck-crowdy-studio-dsh-notice-actions');
|
|
151
|
+
const accept = el('button');
|
|
152
|
+
accept.type = 'button';
|
|
153
|
+
accept.textContent = 'I understand, start the agent';
|
|
154
|
+
accept.addEventListener('click', () => {
|
|
155
|
+
void this.run(async () => {
|
|
156
|
+
await this.options.transport.setConsent(this.options.appId, true);
|
|
157
|
+
this.notice.hidden = true;
|
|
158
|
+
this.started = true;
|
|
159
|
+
await this.boot();
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
actions.append(accept);
|
|
163
|
+
this.notice.append(text, actions);
|
|
164
|
+
}
|
|
165
|
+
renderStatus(status) {
|
|
166
|
+
this.root.dataset.phase = status.phase;
|
|
167
|
+
switch (status.phase) {
|
|
168
|
+
case 'idle':
|
|
169
|
+
this.status.textContent = '';
|
|
170
|
+
break;
|
|
171
|
+
case 'waiting-for-frame':
|
|
172
|
+
case 'booting':
|
|
173
|
+
this.status.textContent = 'Starting…';
|
|
174
|
+
break;
|
|
175
|
+
case 'ready':
|
|
176
|
+
this.status.textContent = status.store ? 'Ready · GitHub' : 'Ready';
|
|
177
|
+
this.status.title = status.store ?? '';
|
|
178
|
+
break;
|
|
179
|
+
case 'failed':
|
|
180
|
+
this.status.textContent = 'Unavailable';
|
|
181
|
+
this.say(status.message);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async refreshUsage() {
|
|
186
|
+
if (this.disposed)
|
|
187
|
+
return;
|
|
188
|
+
try {
|
|
189
|
+
const usage = await this.options.transport.usage(this.options.appId, 1);
|
|
190
|
+
this.renderSpend(usage);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Usage is informational; the endpoint enforces the budget.
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
renderSpend(usage) {
|
|
197
|
+
const spent = Number(usage.todayChargeMicrousd) / 1000000;
|
|
198
|
+
const limit = Number(usage.dayLimitMicrousd) / 1000000;
|
|
199
|
+
const payer = usage.payerKind === 'PLAYER' ? 'your wallet' : usage.payerKind === 'ORG' ? "the app's wallet" : 'the platform';
|
|
200
|
+
this.spend.replaceChildren();
|
|
201
|
+
const text = el('span');
|
|
202
|
+
text.textContent = `Today: $${spent.toFixed(2)} of $${limit.toFixed(2)} · ${usage.todayRequests} requests · paid by ${payer}`;
|
|
203
|
+
this.spend.append(text);
|
|
204
|
+
if (usage.payerKind === 'PLAYER' && this.options.studioOrigin) {
|
|
205
|
+
const link = el('a');
|
|
206
|
+
link.href = `${this.options.studioOrigin.replace(/\/+$/, '')}/account/wallet`;
|
|
207
|
+
link.target = '_blank';
|
|
208
|
+
link.rel = 'noopener';
|
|
209
|
+
link.textContent = 'Add funds';
|
|
210
|
+
this.spend.append(' · ', link);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
say(text) {
|
|
214
|
+
this.message.hidden = false;
|
|
215
|
+
this.message.textContent = text;
|
|
216
|
+
}
|
|
217
|
+
async run(work) {
|
|
218
|
+
try {
|
|
219
|
+
await work();
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
this.say(error instanceof Error ? error.message : String(error));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function el(tag, className) {
|
|
227
|
+
const node = document.createElement(tag);
|
|
228
|
+
if (className)
|
|
229
|
+
node.className = className;
|
|
230
|
+
return node;
|
|
231
|
+
}
|
|
232
|
+
export const CROWDY_STUDIO_DSH_STYLES = `
|
|
233
|
+
.ck-crowdy-studio-dsh{flex:none;display:flex;flex-direction:column;min-width:0;min-height:0;border-left:1px solid var(--ck-line);background:#0b1220}
|
|
234
|
+
.ck-crowdy-studio-dsh>header{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--ck-line)}
|
|
235
|
+
.ck-crowdy-studio-dsh>header h2{margin:0;font-size:13px;flex:none}
|
|
236
|
+
.ck-crowdy-studio-dsh-status{flex:1;min-width:0;color:var(--ck-muted);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
237
|
+
.ck-crowdy-studio-dsh[data-phase=failed] .ck-crowdy-studio-dsh-status{color:#fca5a5}
|
|
238
|
+
.ck-crowdy-studio-dsh-frame{flex:1;min-height:0;width:100%;border:0;background:#fff}
|
|
239
|
+
.ck-crowdy-studio-dsh-notice{padding:10px;font-size:12px;color:var(--ck-text);border-bottom:1px solid var(--ck-line)}
|
|
240
|
+
.ck-crowdy-studio-dsh-notice p{margin:0 0 8px}
|
|
241
|
+
.ck-crowdy-studio-dsh-notice-actions{display:flex;gap:6px}
|
|
242
|
+
.ck-crowdy-studio-dsh-spend{padding:4px 10px;font-size:11px;color:var(--ck-muted);border-top:1px solid var(--ck-line)}
|
|
243
|
+
.ck-crowdy-studio-dsh-spend a{color:#bae6fd}
|
|
244
|
+
.ck-crowdy-studio-dsh-message{padding:4px 10px;font-size:11px;color:#fde68a;border-top:1px solid var(--ck-line)}
|
|
245
|
+
.ck-crowdy-studio-dsh-message button{font-size:11px;padding:2px 8px;margin-left:4px}
|
|
246
|
+
.ck-crowdy-studio-dsh-confirm{background:#b91c1c;color:#fff;border:0;border-radius:3px}
|
|
247
|
+
`;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire protocol between the Crowdy Studio page and the DeepSeek Harness that
|
|
3
|
+
* runs in a Web Worker inside the Studio agent pane.
|
|
4
|
+
*
|
|
5
|
+
* The harness side lives in the published `@crowdedkingdoms/crowdy-dsh`
|
|
6
|
+
* package (`bridge-protocol` export); this file mirrors it so the SDK stays
|
|
7
|
+
* dependency-free. Keep the two in step.
|
|
8
|
+
*
|
|
9
|
+
* Two channels exist:
|
|
10
|
+
*
|
|
11
|
+
* - `postMessage` between the page and the harness iframe: the iframe says
|
|
12
|
+
* `crowdy-dsh:ready`, the page answers `crowdy-dsh:boot` with the home
|
|
13
|
+
* files to seed and a one-time `nonce`, and the iframe reports
|
|
14
|
+
* `crowdy-dsh:booted` or `:failed`.
|
|
15
|
+
* - one `BroadcastChannel` (name chosen by the page) between the page and
|
|
16
|
+
* the worker: the worker asks the page to do what only the page can
|
|
17
|
+
* (draft tests, screenshots, project switching, game observation) and the
|
|
18
|
+
* page pushes token, project and context updates.
|
|
19
|
+
*
|
|
20
|
+
* A `BroadcastChannel` is open to every same-origin script, so the channel
|
|
21
|
+
* name is unguessable and every frame carries the boot nonce; a frame without
|
|
22
|
+
* the right nonce is dropped. The page still confirms a live deploy with the
|
|
23
|
+
* player before running it, because the harness UI's approval is inside the
|
|
24
|
+
* iframe and the page cannot see it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const CROWDY_DSH_PROTOCOL_VERSION: 2;
|
|
27
|
+
export type DshBridgeSide = 'page' | 'worker';
|
|
28
|
+
export type DshBridgeFrame = {
|
|
29
|
+
v: 2;
|
|
30
|
+
n: string;
|
|
31
|
+
from: DshBridgeSide;
|
|
32
|
+
t: 'req';
|
|
33
|
+
id: string;
|
|
34
|
+
method: string;
|
|
35
|
+
params: unknown;
|
|
36
|
+
} | {
|
|
37
|
+
v: 2;
|
|
38
|
+
n: string;
|
|
39
|
+
from: DshBridgeSide;
|
|
40
|
+
t: 'res';
|
|
41
|
+
id: string;
|
|
42
|
+
result: unknown;
|
|
43
|
+
} | {
|
|
44
|
+
v: 2;
|
|
45
|
+
n: string;
|
|
46
|
+
from: DshBridgeSide;
|
|
47
|
+
t: 'err';
|
|
48
|
+
id: string;
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
} | {
|
|
52
|
+
v: 2;
|
|
53
|
+
n: string;
|
|
54
|
+
from: DshBridgeSide;
|
|
55
|
+
t: 'event';
|
|
56
|
+
event: string;
|
|
57
|
+
payload: unknown;
|
|
58
|
+
};
|
|
59
|
+
export interface DshScreenshotResult {
|
|
60
|
+
name: string;
|
|
61
|
+
mediaType: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
62
|
+
bytes: ArrayBuffer;
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
caption?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface DshDiagnostic {
|
|
68
|
+
target: 'SERVER' | 'CLIENT';
|
|
69
|
+
path: string;
|
|
70
|
+
line?: number;
|
|
71
|
+
column?: number;
|
|
72
|
+
severity: 'error' | 'warning' | 'info';
|
|
73
|
+
message: string;
|
|
74
|
+
}
|
|
75
|
+
export interface DshRuntimeStatus {
|
|
76
|
+
target: 'SERVER' | 'CLIENT';
|
|
77
|
+
phase: string;
|
|
78
|
+
moduleName?: string;
|
|
79
|
+
runningRevision?: string;
|
|
80
|
+
savedRevision?: string;
|
|
81
|
+
message?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface DshBuildResult {
|
|
84
|
+
ok: boolean;
|
|
85
|
+
mode: 'draft' | 'live';
|
|
86
|
+
summary: string;
|
|
87
|
+
diagnostics: DshDiagnostic[];
|
|
88
|
+
buildLog: string;
|
|
89
|
+
runtime: DshRuntimeStatus[];
|
|
90
|
+
screenshot?: DshScreenshotResult;
|
|
91
|
+
}
|
|
92
|
+
export interface DshProjectSummary {
|
|
93
|
+
projectId: string;
|
|
94
|
+
name: string;
|
|
95
|
+
kind: string;
|
|
96
|
+
updatedAt: string;
|
|
97
|
+
github?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface DshBridgeRequestMap {
|
|
100
|
+
'studio.screenshot': {
|
|
101
|
+
params: {
|
|
102
|
+
label?: string;
|
|
103
|
+
};
|
|
104
|
+
result: DshScreenshotResult;
|
|
105
|
+
};
|
|
106
|
+
'studio.draftTest': {
|
|
107
|
+
params: Record<string, never>;
|
|
108
|
+
result: DshBuildResult;
|
|
109
|
+
};
|
|
110
|
+
'studio.deployLive': {
|
|
111
|
+
params: Record<string, never>;
|
|
112
|
+
result: DshBuildResult;
|
|
113
|
+
};
|
|
114
|
+
'studio.runtimeStatus': {
|
|
115
|
+
params: Record<string, never>;
|
|
116
|
+
result: {
|
|
117
|
+
runtime: DshRuntimeStatus[];
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
'studio.runtimeLogs': {
|
|
121
|
+
params: {
|
|
122
|
+
limit?: number;
|
|
123
|
+
};
|
|
124
|
+
result: {
|
|
125
|
+
lines: string[];
|
|
126
|
+
truncated: boolean;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
'studio.clientLogs': {
|
|
130
|
+
params: {
|
|
131
|
+
limit?: number;
|
|
132
|
+
};
|
|
133
|
+
result: {
|
|
134
|
+
lines: string[];
|
|
135
|
+
truncated: boolean;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
'studio.projectList': {
|
|
139
|
+
params: Record<string, never>;
|
|
140
|
+
result: {
|
|
141
|
+
projects: DshProjectSummary[];
|
|
142
|
+
currentProjectId: string | null;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
'studio.projectOpen': {
|
|
146
|
+
params: {
|
|
147
|
+
projectId: string;
|
|
148
|
+
};
|
|
149
|
+
result: {
|
|
150
|
+
project: DshProjectSummary;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
'studio.projectCreate': {
|
|
154
|
+
params: {
|
|
155
|
+
name: string;
|
|
156
|
+
template?: string;
|
|
157
|
+
};
|
|
158
|
+
result: {
|
|
159
|
+
project: DshProjectSummary;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
'game.observe': {
|
|
163
|
+
params: Record<string, never>;
|
|
164
|
+
result: {
|
|
165
|
+
observation: unknown;
|
|
166
|
+
capturedAt: string;
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export type DshBridgeMethod = keyof DshBridgeRequestMap;
|
|
171
|
+
export interface DshPageEventMap {
|
|
172
|
+
'page.hello': {
|
|
173
|
+
appId: string;
|
|
174
|
+
projectId: string | null;
|
|
175
|
+
appToken?: string;
|
|
176
|
+
};
|
|
177
|
+
'page.token': {
|
|
178
|
+
appToken: string;
|
|
179
|
+
};
|
|
180
|
+
'page.project': {
|
|
181
|
+
projectId: string | null;
|
|
182
|
+
};
|
|
183
|
+
'page.saved': {
|
|
184
|
+
revision?: string;
|
|
185
|
+
};
|
|
186
|
+
'page.context': {
|
|
187
|
+
observation?: unknown;
|
|
188
|
+
clientLogs?: string[];
|
|
189
|
+
diagnostics?: DshDiagnostic[];
|
|
190
|
+
runtime?: DshRuntimeStatus[];
|
|
191
|
+
note?: string;
|
|
192
|
+
};
|
|
193
|
+
'page.capture': DshScreenshotResult;
|
|
194
|
+
/** Text for the agent, queued into the latest live session (or a new one). */
|
|
195
|
+
'page.prompt': {
|
|
196
|
+
text: string;
|
|
197
|
+
mode?: 'queue' | 'steer';
|
|
198
|
+
};
|
|
199
|
+
'page.bye': Record<string, never>;
|
|
200
|
+
}
|
|
201
|
+
export interface DshWorkerEventMap {
|
|
202
|
+
'worker.ready': {
|
|
203
|
+
root: string;
|
|
204
|
+
store?: string;
|
|
205
|
+
};
|
|
206
|
+
'worker.fileChanged': {
|
|
207
|
+
target: 'SERVER' | 'CLIENT';
|
|
208
|
+
path: string;
|
|
209
|
+
};
|
|
210
|
+
'worker.warning': {
|
|
211
|
+
message: string;
|
|
212
|
+
};
|
|
213
|
+
'worker.openFile': {
|
|
214
|
+
target: 'SERVER' | 'CLIENT';
|
|
215
|
+
path: string;
|
|
216
|
+
line?: number;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/** Messages the harness iframe posts to its parent (`source: 'crowdy-dsh'`). */
|
|
220
|
+
export type DshFrameMessage = {
|
|
221
|
+
source: 'crowdy-dsh';
|
|
222
|
+
type: 'crowdy-dsh:ready';
|
|
223
|
+
} | {
|
|
224
|
+
source: 'crowdy-dsh';
|
|
225
|
+
type: 'crowdy-dsh:booted';
|
|
226
|
+
mount: string;
|
|
227
|
+
} | {
|
|
228
|
+
source: 'crowdy-dsh';
|
|
229
|
+
type: 'crowdy-dsh:failed';
|
|
230
|
+
message: string;
|
|
231
|
+
};
|
|
232
|
+
/** The page's answer to `crowdy-dsh:ready`. */
|
|
233
|
+
export interface DshBootMessage {
|
|
234
|
+
type: 'crowdy-dsh:boot';
|
|
235
|
+
/**
|
|
236
|
+
* Home-relative files to seed (`crowdy.json`, `settings.yaml`). Never the
|
|
237
|
+
* app token: that travels over the channel (`page.hello` / `page.token`) and
|
|
238
|
+
* lives only in the worker's memory.
|
|
239
|
+
*/
|
|
240
|
+
files: Record<string, string>;
|
|
241
|
+
/** One-time secret every bridge frame must carry; also in `crowdy.json`. */
|
|
242
|
+
nonce: string;
|
|
243
|
+
/** OPFS scope for restored sessions; omit to start fresh. */
|
|
244
|
+
persistScope?: string;
|
|
245
|
+
mount?: string;
|
|
246
|
+
}
|
|
247
|
+
export declare function isDshBridgeFrame(value: unknown, nonce?: string): value is DshBridgeFrame;
|
|
248
|
+
export declare function isDshFrameMessage(value: unknown): value is DshFrameMessage;
|
|
249
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/crowdy-dsh/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire protocol between the Crowdy Studio page and the DeepSeek Harness that
|
|
3
|
+
* runs in a Web Worker inside the Studio agent pane.
|
|
4
|
+
*
|
|
5
|
+
* The harness side lives in the published `@crowdedkingdoms/crowdy-dsh`
|
|
6
|
+
* package (`bridge-protocol` export); this file mirrors it so the SDK stays
|
|
7
|
+
* dependency-free. Keep the two in step.
|
|
8
|
+
*
|
|
9
|
+
* Two channels exist:
|
|
10
|
+
*
|
|
11
|
+
* - `postMessage` between the page and the harness iframe: the iframe says
|
|
12
|
+
* `crowdy-dsh:ready`, the page answers `crowdy-dsh:boot` with the home
|
|
13
|
+
* files to seed and a one-time `nonce`, and the iframe reports
|
|
14
|
+
* `crowdy-dsh:booted` or `:failed`.
|
|
15
|
+
* - one `BroadcastChannel` (name chosen by the page) between the page and
|
|
16
|
+
* the worker: the worker asks the page to do what only the page can
|
|
17
|
+
* (draft tests, screenshots, project switching, game observation) and the
|
|
18
|
+
* page pushes token, project and context updates.
|
|
19
|
+
*
|
|
20
|
+
* A `BroadcastChannel` is open to every same-origin script, so the channel
|
|
21
|
+
* name is unguessable and every frame carries the boot nonce; a frame without
|
|
22
|
+
* the right nonce is dropped. The page still confirms a live deploy with the
|
|
23
|
+
* player before running it, because the harness UI's approval is inside the
|
|
24
|
+
* iframe and the page cannot see it.
|
|
25
|
+
*/
|
|
26
|
+
export const CROWDY_DSH_PROTOCOL_VERSION = 2;
|
|
27
|
+
export function isDshBridgeFrame(value, nonce) {
|
|
28
|
+
if (!value || typeof value !== 'object')
|
|
29
|
+
return false;
|
|
30
|
+
const frame = value;
|
|
31
|
+
if (frame.v !== CROWDY_DSH_PROTOCOL_VERSION || typeof frame.n !== 'string' || typeof frame.t !== 'string')
|
|
32
|
+
return false;
|
|
33
|
+
if (frame.from !== 'page' && frame.from !== 'worker')
|
|
34
|
+
return false;
|
|
35
|
+
return nonce === undefined || frame.n === nonce;
|
|
36
|
+
}
|
|
37
|
+
export function isDshFrameMessage(value) {
|
|
38
|
+
return !!value && typeof value === 'object' && value.source === 'crowdy-dsh';
|
|
39
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game-API surface the Studio agent pane needs beyond project files:
|
|
3
|
+
* the provider-data consent, the player's own model usage, and the list of
|
|
4
|
+
* models the metered endpoint will serve for this app.
|
|
5
|
+
*
|
|
6
|
+
* Every call carries the app-scoped token the game already holds; there is no
|
|
7
|
+
* second credential. The model list is REST (`GET /v1/model/models`, the
|
|
8
|
+
* OpenAI shape the harness reads) and the rest is GraphQL.
|
|
9
|
+
*/
|
|
10
|
+
import type { GraphQLClient } from '../client.js';
|
|
11
|
+
export interface CrowdyStudioProviderConsent {
|
|
12
|
+
appId: string;
|
|
13
|
+
consented: boolean;
|
|
14
|
+
consentedAt: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface CrowdyStudioModelUsageEntry {
|
|
17
|
+
usageId: string;
|
|
18
|
+
payerKind: string;
|
|
19
|
+
status: string;
|
|
20
|
+
requestedModel: string;
|
|
21
|
+
resolvedModel: string | null;
|
|
22
|
+
promptTokens: string;
|
|
23
|
+
completionTokens: string;
|
|
24
|
+
reasoningTokens: string;
|
|
25
|
+
chargeMicrousd: string;
|
|
26
|
+
occurredAt: string;
|
|
27
|
+
client: string;
|
|
28
|
+
}
|
|
29
|
+
export interface CrowdyStudioModelUsage {
|
|
30
|
+
appId: string;
|
|
31
|
+
/** `PLAYER` (the caller's wallet), `ORG` (the app's org wallet) or `PLATFORM`. */
|
|
32
|
+
payerKind: string;
|
|
33
|
+
todayRequests: string;
|
|
34
|
+
todayChargeMicrousd: string;
|
|
35
|
+
dayLimitMicrousd: string;
|
|
36
|
+
recent: CrowdyStudioModelUsageEntry[];
|
|
37
|
+
}
|
|
38
|
+
export interface CrowdyStudioModelCatalogEntry {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
contextWindow: number | null;
|
|
42
|
+
inputModalities: string[];
|
|
43
|
+
pricingMicrousdPerMillion: {
|
|
44
|
+
input: number;
|
|
45
|
+
output: number;
|
|
46
|
+
reasoning: number;
|
|
47
|
+
cachedInput: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare class CrowdyStudioDshTransport {
|
|
51
|
+
private readonly graphql;
|
|
52
|
+
private readonly options;
|
|
53
|
+
constructor(graphql: GraphQLClient, options: {
|
|
54
|
+
/** Origin of the game API, e.g. `https://ck-or.dev.crowdedkingdoms.com` or the page origin behind a proxy. */
|
|
55
|
+
apiOrigin: string;
|
|
56
|
+
getToken(): string | null;
|
|
57
|
+
});
|
|
58
|
+
/** Base URL the harness posts completions to (`<origin>/v1/model`). */
|
|
59
|
+
get modelBaseUrl(): string;
|
|
60
|
+
consent(appId: string): Promise<CrowdyStudioProviderConsent>;
|
|
61
|
+
setConsent(appId: string, consented: boolean): Promise<CrowdyStudioProviderConsent>;
|
|
62
|
+
usage(appId: string, limit?: number): Promise<CrowdyStudioModelUsage>;
|
|
63
|
+
/** Models the metered endpoint offers this caller; empty when the agent is disabled for the app. */
|
|
64
|
+
models(appId: string): Promise<CrowdyStudioModelCatalogEntry[]>;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/crowdy-dsh/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,2BAA2B,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,yBAAyB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CACtG;AAuBD,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE;QACxB,8GAA8G;QAC9G,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC;KAC3B;IAGH,uEAAuE;IACvE,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEK,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAO5D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAQnF,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAQvE,oGAAoG;IAC9F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC;CAsCtE"}
|