@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
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
const PLAY_SCOPES = [
|
|
2
|
-
'observe',
|
|
3
|
-
'locomotion',
|
|
4
|
-
'interact',
|
|
5
|
-
'craft',
|
|
6
|
-
'combat',
|
|
7
|
-
'communicate',
|
|
8
|
-
'travel',
|
|
9
|
-
];
|
|
10
|
-
/**
|
|
11
|
-
* Accessible, text-only rendering for the integrated durable agent dock.
|
|
12
|
-
*
|
|
13
|
-
* The conversation is the primary surface. Play-control, activity, and
|
|
14
|
-
* change-tracking sections are collapsible disclosures so the dock stays
|
|
15
|
-
* minimal, with one deliberate exception: pending exact approvals and the
|
|
16
|
-
* active Play lease countdown always render prominently.
|
|
17
|
-
*/
|
|
18
|
-
export class CrowdyStudioAgentDomShell {
|
|
19
|
-
constructor(host, controller, options = {}) {
|
|
20
|
-
this.controller = controller;
|
|
21
|
-
this.options = options;
|
|
22
|
-
this.modeButtons = new Map();
|
|
23
|
-
this.scopeInputs = new Map();
|
|
24
|
-
this.lastPendingApprovals = 0;
|
|
25
|
-
this.lastPlayLeaseActive = false;
|
|
26
|
-
this.disposed = false;
|
|
27
|
-
this.lastState = controller.getState();
|
|
28
|
-
this.root = document.createElement('aside');
|
|
29
|
-
this.root.className = 'ck-crowdy-studio-agent-dock';
|
|
30
|
-
this.root.setAttribute('aria-label', 'Crowdy Studio agent');
|
|
31
|
-
const header = document.createElement('header');
|
|
32
|
-
const title = document.createElement('h2');
|
|
33
|
-
title.textContent = 'Crowdy Agent';
|
|
34
|
-
this.status = document.createElement('span');
|
|
35
|
-
this.status.className = 'ck-crowdy-studio-agent-status';
|
|
36
|
-
this.status.setAttribute('role', 'status');
|
|
37
|
-
this.status.setAttribute('aria-live', 'polite');
|
|
38
|
-
header.append(title, this.status);
|
|
39
|
-
const controlsRow = document.createElement('div');
|
|
40
|
-
controlsRow.className = 'ck-crowdy-studio-agent-controls-row';
|
|
41
|
-
const modeGroup = document.createElement('div');
|
|
42
|
-
modeGroup.className = 'ck-crowdy-studio-agent-modes';
|
|
43
|
-
modeGroup.setAttribute('role', 'group');
|
|
44
|
-
modeGroup.setAttribute('aria-label', 'Agent mode');
|
|
45
|
-
for (const mode of ['ASK', 'BUILD', 'PLAY']) {
|
|
46
|
-
const control = button(titleCase(mode));
|
|
47
|
-
control.addEventListener('click', () => {
|
|
48
|
-
void this.run(() => this.controller.setMode(mode));
|
|
49
|
-
});
|
|
50
|
-
control.setAttribute('aria-pressed', 'false');
|
|
51
|
-
this.modeButtons.set(mode, control);
|
|
52
|
-
modeGroup.append(control);
|
|
53
|
-
}
|
|
54
|
-
const controls = document.createElement('div');
|
|
55
|
-
controls.className = 'ck-crowdy-studio-agent-controls';
|
|
56
|
-
const pause = button('Pause');
|
|
57
|
-
pause.addEventListener('click', () => void this.run(() => this.controller.pause()));
|
|
58
|
-
const resume = button('Resume');
|
|
59
|
-
resume.addEventListener('click', () => void this.run(() => this.controller.resume()));
|
|
60
|
-
const stop = button('Stop');
|
|
61
|
-
stop.className = 'ck-crowdy-studio-agent-stop';
|
|
62
|
-
stop.addEventListener('click', () => void this.run(() => this.controller.stop()));
|
|
63
|
-
controls.append(pause, resume, stop);
|
|
64
|
-
controlsRow.append(modeGroup, controls);
|
|
65
|
-
// Safety surfaces: approvals and the active Play lease stay prominent and
|
|
66
|
-
// are never hidden behind a disclosure.
|
|
67
|
-
this.approvals = document.createElement('section');
|
|
68
|
-
this.approvals.className = 'ck-crowdy-studio-agent-approvals';
|
|
69
|
-
this.approvals.setAttribute('aria-label', 'Pending exact approvals');
|
|
70
|
-
this.lease = document.createElement('div');
|
|
71
|
-
this.lease.className = 'ck-crowdy-studio-agent-lease';
|
|
72
|
-
this.lease.setAttribute('role', 'status');
|
|
73
|
-
this.lease.setAttribute('aria-label', 'Agent control lease');
|
|
74
|
-
this.messages = document.createElement('div');
|
|
75
|
-
this.messages.className = 'ck-crowdy-studio-agent-messages';
|
|
76
|
-
this.messages.setAttribute('role', 'log');
|
|
77
|
-
this.messages.setAttribute('aria-live', 'polite');
|
|
78
|
-
this.messages.setAttribute('aria-relevant', 'additions text');
|
|
79
|
-
this.stream = document.createElement('div');
|
|
80
|
-
this.stream.className = 'ck-crowdy-studio-agent-stream';
|
|
81
|
-
this.stream.setAttribute('aria-label', 'Streaming assistant response');
|
|
82
|
-
this.messages.append(this.stream);
|
|
83
|
-
const form = document.createElement('form');
|
|
84
|
-
form.className = 'ck-crowdy-studio-agent-composer';
|
|
85
|
-
this.composer = document.createElement('textarea');
|
|
86
|
-
this.composer.maxLength = 32768;
|
|
87
|
-
this.composer.rows = 3;
|
|
88
|
-
this.composer.placeholder = 'Ask, build, or play…';
|
|
89
|
-
this.composer.setAttribute('aria-label', 'Message Crowdy Agent');
|
|
90
|
-
this.send = button('Send', 'submit');
|
|
91
|
-
form.append(this.composer, this.send);
|
|
92
|
-
form.addEventListener('submit', (event) => {
|
|
93
|
-
event.preventDefault();
|
|
94
|
-
const content = this.composer.value;
|
|
95
|
-
if (!content.trim())
|
|
96
|
-
return;
|
|
97
|
-
void this.run(async () => {
|
|
98
|
-
await this.controller.sendMessage(content);
|
|
99
|
-
this.composer.value = '';
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
this.composer.addEventListener('keydown', (event) => {
|
|
103
|
-
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
104
|
-
event.preventDefault();
|
|
105
|
-
form.requestSubmit();
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
// Collapsible secondary sections.
|
|
109
|
-
const playBody = document.createElement('div');
|
|
110
|
-
const leaseControls = document.createElement('fieldset');
|
|
111
|
-
leaseControls.className = 'ck-crowdy-studio-agent-lease-controls';
|
|
112
|
-
const leaseLegend = document.createElement('legend');
|
|
113
|
-
leaseLegend.textContent = 'Play lease scopes';
|
|
114
|
-
leaseControls.append(leaseLegend);
|
|
115
|
-
for (const scope of PLAY_SCOPES) {
|
|
116
|
-
const label = document.createElement('label');
|
|
117
|
-
const input = document.createElement('input');
|
|
118
|
-
input.type = 'checkbox';
|
|
119
|
-
input.value = scope;
|
|
120
|
-
input.checked = scope === 'observe';
|
|
121
|
-
this.scopeInputs.set(scope, input);
|
|
122
|
-
const text = document.createElement('span');
|
|
123
|
-
text.textContent = scope.replace('_', ' ');
|
|
124
|
-
label.append(input, text);
|
|
125
|
-
leaseControls.append(label);
|
|
126
|
-
}
|
|
127
|
-
const grant = button('Grant 60 second Play lease');
|
|
128
|
-
grant.addEventListener('click', () => {
|
|
129
|
-
const context = this.options.getPlayLeaseContext?.();
|
|
130
|
-
if (!context) {
|
|
131
|
-
this.status.textContent =
|
|
132
|
-
'The game host must advertise a controlled entity before Play.';
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const scopes = [...this.scopeInputs]
|
|
136
|
-
.filter(([, input]) => input.checked)
|
|
137
|
-
.map(([scope]) => scope);
|
|
138
|
-
void this.run(() => this.controller.grantPlayLease({
|
|
139
|
-
scopes,
|
|
140
|
-
durationSeconds: 60,
|
|
141
|
-
...context,
|
|
142
|
-
}));
|
|
143
|
-
});
|
|
144
|
-
leaseControls.append(grant);
|
|
145
|
-
playBody.append(leaseControls);
|
|
146
|
-
[this.playDisclosure, this.playSummary] = disclosure('Play control', playBody);
|
|
147
|
-
this.timeline = document.createElement('ol');
|
|
148
|
-
this.timeline.className = 'ck-crowdy-studio-agent-timeline';
|
|
149
|
-
this.timeline.setAttribute('aria-label', 'Agent plan and tool timeline');
|
|
150
|
-
[this.activityDisclosure, this.activitySummary] = disclosure('Activity', this.timeline);
|
|
151
|
-
this.checkpoints = document.createElement('section');
|
|
152
|
-
this.checkpoints.className = 'ck-crowdy-studio-agent-checkpoints';
|
|
153
|
-
this.checkpoints.setAttribute('aria-label', 'Agent diffs and checkpoints');
|
|
154
|
-
[this.changesDisclosure, this.changesSummary] = disclosure('Changes', this.checkpoints);
|
|
155
|
-
this.budget = document.createElement('div');
|
|
156
|
-
this.budget.className = 'ck-crowdy-studio-agent-budget';
|
|
157
|
-
this.budget.setAttribute('aria-label', 'Agent budget');
|
|
158
|
-
this.root.append(header, controlsRow, this.approvals, this.lease, this.messages, form, this.playDisclosure, this.activityDisclosure, this.changesDisclosure, this.budget);
|
|
159
|
-
host.dataset.agent = 'true';
|
|
160
|
-
host.append(this.root);
|
|
161
|
-
this.unsubscribe = controller.subscribe((state) => this.render(state));
|
|
162
|
-
this.countdownTimer = setInterval(() => this.renderLease(this.lastState), 1000);
|
|
163
|
-
this.render(this.lastState);
|
|
164
|
-
}
|
|
165
|
-
render(state) {
|
|
166
|
-
if (this.disposed)
|
|
167
|
-
return;
|
|
168
|
-
this.lastState = state;
|
|
169
|
-
this.status.textContent = state.lastError
|
|
170
|
-
? `${state.connection} · ${state.lastError.code}: ${state.lastError.message}`
|
|
171
|
-
: state.reconnectRequired
|
|
172
|
-
? `${state.connection} · explicit resume required`
|
|
173
|
-
: state.connection;
|
|
174
|
-
const mode = state.session?.mode;
|
|
175
|
-
for (const [candidate, control] of this.modeButtons) {
|
|
176
|
-
control.setAttribute('aria-pressed', String(candidate === mode));
|
|
177
|
-
control.dataset.active = String(candidate === mode);
|
|
178
|
-
control.disabled = state.connection !== 'CONNECTED';
|
|
179
|
-
}
|
|
180
|
-
this.send.disabled =
|
|
181
|
-
state.connection !== 'CONNECTED' ||
|
|
182
|
-
state.session?.status !== 'ACTIVE';
|
|
183
|
-
this.renderBudget(state);
|
|
184
|
-
this.renderLease(state);
|
|
185
|
-
this.renderMessages(state);
|
|
186
|
-
this.renderTimeline(state);
|
|
187
|
-
this.renderApprovals(state);
|
|
188
|
-
this.renderCheckpoints(state);
|
|
189
|
-
this.autoReveal(state);
|
|
190
|
-
}
|
|
191
|
-
dispose() {
|
|
192
|
-
if (this.disposed)
|
|
193
|
-
return;
|
|
194
|
-
this.disposed = true;
|
|
195
|
-
clearInterval(this.countdownTimer);
|
|
196
|
-
this.unsubscribe();
|
|
197
|
-
this.root.remove();
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Safety-critical auto-reveal: a newly pending exact approval or a Play
|
|
201
|
-
* lease activation opens the dock and the Play disclosure so the human is
|
|
202
|
-
* always shown what needs their decision or is acting on their behalf.
|
|
203
|
-
*/
|
|
204
|
-
autoReveal(state) {
|
|
205
|
-
const pending = state.approvals.filter((approval) => approval.status === 'PENDING').length;
|
|
206
|
-
const playLeaseActive = state.leases.some((lease) => lease.kind === 'PLAY' && lease.status === 'ACTIVE');
|
|
207
|
-
if (pending > this.lastPendingApprovals) {
|
|
208
|
-
this.options.layout?.setVisible('agent', true);
|
|
209
|
-
}
|
|
210
|
-
if (playLeaseActive && !this.lastPlayLeaseActive) {
|
|
211
|
-
this.options.layout?.setVisible('agent', true);
|
|
212
|
-
this.playDisclosure.open = true;
|
|
213
|
-
}
|
|
214
|
-
if (state.session?.mode === 'PLAY' && !playLeaseActive) {
|
|
215
|
-
this.playDisclosure.open = true;
|
|
216
|
-
}
|
|
217
|
-
this.lastPendingApprovals = pending;
|
|
218
|
-
this.lastPlayLeaseActive = playLeaseActive;
|
|
219
|
-
}
|
|
220
|
-
renderBudget(state) {
|
|
221
|
-
if (!state.budget) {
|
|
222
|
-
this.budget.textContent = 'Budget unavailable';
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const dimensions = state.budget.dimensions.map((dimension) => `${dimension.name.toLowerCase().replace(/_/gu, ' ')} ${dimension.consumed}/${dimension.limit} ${dimension.unit}`);
|
|
226
|
-
this.budget.textContent = [
|
|
227
|
-
state.budget.platformFunded ? 'Platform-funded pilot' : state.budget.payer,
|
|
228
|
-
...dimensions,
|
|
229
|
-
].join(' · ');
|
|
230
|
-
}
|
|
231
|
-
renderLease(state) {
|
|
232
|
-
const lease = state.leases.find((entry) => entry.kind === 'PLAY' && entry.status === 'ACTIVE');
|
|
233
|
-
if (!lease) {
|
|
234
|
-
this.lease.textContent = 'No active Play lease';
|
|
235
|
-
this.lease.dataset.active = 'false';
|
|
236
|
-
this.playSummary.textContent = 'Play control';
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
const remaining = Math.max(0, Math.ceil((Date.parse(lease.expiresAt) - Date.now()) / 1000));
|
|
240
|
-
this.lease.dataset.active = 'true';
|
|
241
|
-
this.lease.textContent = [
|
|
242
|
-
`Play lease: ${remaining}s`,
|
|
243
|
-
`holder ${lease.holder}`,
|
|
244
|
-
`entity ${lease.controlledEntityId ?? 'none'}`,
|
|
245
|
-
`scopes ${lease.scopes.join(', ')}`,
|
|
246
|
-
].join(' · ');
|
|
247
|
-
this.playSummary.textContent = `Play control · lease ${remaining}s`;
|
|
248
|
-
}
|
|
249
|
-
renderMessages(state) {
|
|
250
|
-
const rows = state.messages.map((message) => {
|
|
251
|
-
const article = document.createElement('article');
|
|
252
|
-
article.className = 'ck-crowdy-studio-agent-message';
|
|
253
|
-
article.dataset.role = message.role;
|
|
254
|
-
const author = document.createElement('strong');
|
|
255
|
-
author.textContent = message.role === 'USER' ? 'You' : 'Crowdy Agent';
|
|
256
|
-
const content = document.createElement('p');
|
|
257
|
-
content.textContent = message.content;
|
|
258
|
-
article.append(author, content);
|
|
259
|
-
return article;
|
|
260
|
-
});
|
|
261
|
-
this.messages.replaceChildren(...rows, this.stream);
|
|
262
|
-
this.stream.textContent = state.streamingText;
|
|
263
|
-
this.stream.hidden = state.streamingText.length === 0;
|
|
264
|
-
}
|
|
265
|
-
renderTimeline(state) {
|
|
266
|
-
const runItems = state.events
|
|
267
|
-
.filter((event) => event.type.startsWith('RUN_'))
|
|
268
|
-
.map((event) => {
|
|
269
|
-
const item = document.createElement('li');
|
|
270
|
-
item.dataset.status = event.type;
|
|
271
|
-
const title = document.createElement('strong');
|
|
272
|
-
title.textContent = event.type.replace(/_/gu, ' ').toLowerCase();
|
|
273
|
-
const timestamp = document.createElement('span');
|
|
274
|
-
timestamp.textContent = event.createdAt;
|
|
275
|
-
item.append(title, timestamp);
|
|
276
|
-
const payload = event.payload;
|
|
277
|
-
if (payload.code || payload.reason || payload.error) {
|
|
278
|
-
const detail = document.createElement('p');
|
|
279
|
-
detail.textContent = [
|
|
280
|
-
payload.code,
|
|
281
|
-
payload.reason,
|
|
282
|
-
payload.error
|
|
283
|
-
? `${payload.error.code}: ${payload.error.message}`
|
|
284
|
-
: '',
|
|
285
|
-
]
|
|
286
|
-
.filter(Boolean)
|
|
287
|
-
.join(' · ');
|
|
288
|
-
item.append(detail);
|
|
289
|
-
}
|
|
290
|
-
return item;
|
|
291
|
-
});
|
|
292
|
-
const toolItems = state.tools.map((tool) => {
|
|
293
|
-
const item = document.createElement('li');
|
|
294
|
-
item.dataset.status = tool.status;
|
|
295
|
-
const title = document.createElement('strong');
|
|
296
|
-
title.textContent = `${tool.name} ${tool.version}`;
|
|
297
|
-
const status = document.createElement('span');
|
|
298
|
-
status.textContent = tool.status.replace(/_/gu, ' ').toLowerCase();
|
|
299
|
-
item.append(title, status);
|
|
300
|
-
if (tool.safeSummary) {
|
|
301
|
-
const summary = document.createElement('p');
|
|
302
|
-
summary.textContent = tool.safeSummary;
|
|
303
|
-
item.append(summary);
|
|
304
|
-
}
|
|
305
|
-
if (tool.error) {
|
|
306
|
-
const error = document.createElement('p');
|
|
307
|
-
error.textContent = `${tool.error.code}: ${tool.error.message}`;
|
|
308
|
-
item.append(error);
|
|
309
|
-
}
|
|
310
|
-
return item;
|
|
311
|
-
});
|
|
312
|
-
const items = [...runItems, ...toolItems];
|
|
313
|
-
this.timeline.replaceChildren(...items);
|
|
314
|
-
this.activitySummary.textContent =
|
|
315
|
-
items.length > 0 ? `Activity (${items.length})` : 'Activity';
|
|
316
|
-
if (items.length === 0) {
|
|
317
|
-
const empty = document.createElement('li');
|
|
318
|
-
empty.textContent = 'No tool activity.';
|
|
319
|
-
this.timeline.append(empty);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
renderApprovals(state) {
|
|
323
|
-
const pending = state.approvals.filter((approval) => approval.status === 'PENDING');
|
|
324
|
-
const cards = pending.map((approval) => {
|
|
325
|
-
const card = document.createElement('article');
|
|
326
|
-
card.className = 'ck-crowdy-studio-agent-approval';
|
|
327
|
-
const tool = state.tools.find((entry) => entry.toolCallId === approval.toolCallId);
|
|
328
|
-
const title = heading(tool
|
|
329
|
-
? `Exact approval: ${tool.name} ${tool.version}`
|
|
330
|
-
: 'Exact approval required', 3);
|
|
331
|
-
const summary = document.createElement('p');
|
|
332
|
-
summary.textContent = `Server-verified execution plan: ${approval.safeSummary}`;
|
|
333
|
-
const call = document.createElement('p');
|
|
334
|
-
call.textContent = `Tool call ${approval.toolCallId}`;
|
|
335
|
-
const reasons = document.createElement('p');
|
|
336
|
-
reasons.textContent = approval.reasons.join(' · ');
|
|
337
|
-
const hash = document.createElement('code');
|
|
338
|
-
hash.textContent = approval.argumentHash;
|
|
339
|
-
const expiry = document.createElement('p');
|
|
340
|
-
expiry.textContent = `Expires ${approval.expiresAt}`;
|
|
341
|
-
const actions = document.createElement('div');
|
|
342
|
-
const approve = button('Approve exact call');
|
|
343
|
-
approve.addEventListener('click', () => void this.run(() => this.controller.approveTool(approval.toolCallId, approval.argumentHash)));
|
|
344
|
-
const deny = button('Deny');
|
|
345
|
-
deny.addEventListener('click', () => void this.run(() => this.controller.rejectTool(approval.toolCallId)));
|
|
346
|
-
actions.append(approve, deny);
|
|
347
|
-
card.append(title, call, summary, reasons, hash, expiry, actions);
|
|
348
|
-
return card;
|
|
349
|
-
});
|
|
350
|
-
this.approvals.replaceChildren(...cards);
|
|
351
|
-
this.approvals.hidden = cards.length === 0;
|
|
352
|
-
}
|
|
353
|
-
renderCheckpoints(state) {
|
|
354
|
-
const diffTools = state.tools.filter((tool) => tool.name === 'workspace.file.patch' ||
|
|
355
|
-
tool.name === 'workspace.conflict.resolve');
|
|
356
|
-
const cards = diffTools.map((tool) => {
|
|
357
|
-
const card = document.createElement('article');
|
|
358
|
-
card.className = 'ck-crowdy-studio-agent-diff';
|
|
359
|
-
const title = heading('Project diff', 3);
|
|
360
|
-
const summary = document.createElement('p');
|
|
361
|
-
summary.textContent =
|
|
362
|
-
tool.safeSummary ?? `${tool.name} · ${tool.status.toLowerCase()}`;
|
|
363
|
-
card.append(title, summary);
|
|
364
|
-
return card;
|
|
365
|
-
});
|
|
366
|
-
for (const checkpoint of state.checkpoints) {
|
|
367
|
-
const card = document.createElement('article');
|
|
368
|
-
card.className = 'ck-crowdy-studio-agent-checkpoint';
|
|
369
|
-
const title = heading('Checkpoint', 3);
|
|
370
|
-
const detail = document.createElement('p');
|
|
371
|
-
detail.textContent = `${checkpoint.checkpointId} · revision ${checkpoint.projectRevision} · ${checkpoint.reason.toLowerCase().replace(/_/gu, ' ')}`;
|
|
372
|
-
const restore = button('Restore checkpoint');
|
|
373
|
-
restore.addEventListener('click', () => void this.run(() => this.controller.restoreCheckpoint(checkpoint.checkpointId)));
|
|
374
|
-
card.append(title, detail, restore);
|
|
375
|
-
cards.push(card);
|
|
376
|
-
}
|
|
377
|
-
this.checkpoints.replaceChildren(...cards);
|
|
378
|
-
this.changesSummary.textContent =
|
|
379
|
-
cards.length > 0 ? `Changes (${cards.length})` : 'Changes';
|
|
380
|
-
if (cards.length === 0) {
|
|
381
|
-
const none = document.createElement('p');
|
|
382
|
-
none.className = 'ck-crowdy-studio-empty';
|
|
383
|
-
none.textContent = 'No agent edits or checkpoints yet.';
|
|
384
|
-
this.checkpoints.append(none);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
async run(operation) {
|
|
388
|
-
try {
|
|
389
|
-
await operation();
|
|
390
|
-
}
|
|
391
|
-
catch (error) {
|
|
392
|
-
this.status.textContent =
|
|
393
|
-
error instanceof Error ? error.message : 'Agent action failed';
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
function disclosure(label, body) {
|
|
398
|
-
const details = document.createElement('details');
|
|
399
|
-
details.className = 'ck-crowdy-studio-agent-disclosure';
|
|
400
|
-
const summary = document.createElement('summary');
|
|
401
|
-
summary.textContent = label;
|
|
402
|
-
details.append(summary, body);
|
|
403
|
-
return [details, summary];
|
|
404
|
-
}
|
|
405
|
-
function button(label, type = 'button') {
|
|
406
|
-
const control = document.createElement('button');
|
|
407
|
-
control.type = type;
|
|
408
|
-
control.textContent = label;
|
|
409
|
-
return control;
|
|
410
|
-
}
|
|
411
|
-
function heading(text, level = 2) {
|
|
412
|
-
const value = document.createElement(`h${level}`);
|
|
413
|
-
value.textContent = text;
|
|
414
|
-
return value;
|
|
415
|
-
}
|
|
416
|
-
function titleCase(value) {
|
|
417
|
-
return `${value[0]}${value.slice(1).toLowerCase()}`;
|
|
418
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { CrowdyStudioAgentStateV1 } from '../crowdy-agent/controller.js';
|
|
2
|
-
import type { PlayerControlGate } from './control-gate.js';
|
|
3
|
-
export interface AgentControlBannerController {
|
|
4
|
-
getState(): CrowdyStudioAgentStateV1;
|
|
5
|
-
subscribe(listener: (state: CrowdyStudioAgentStateV1) => void): () => void;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Always-visible-on-control safety surface outside the Studio dock. Text,
|
|
9
|
-
* status, Pause, and Stop remain keyboard/screen-reader accessible over the
|
|
10
|
-
* game canvas; Stop clears locally before any transport promise is attempted.
|
|
11
|
-
*/
|
|
12
|
-
export declare class AgentControlBanner {
|
|
13
|
-
private readonly gate;
|
|
14
|
-
readonly root: HTMLElement;
|
|
15
|
-
private readonly summary;
|
|
16
|
-
private readonly expiry;
|
|
17
|
-
private readonly pauseButton;
|
|
18
|
-
private readonly stopButton;
|
|
19
|
-
private controller;
|
|
20
|
-
private agentState;
|
|
21
|
-
private gateState;
|
|
22
|
-
private unsubscribeAgent;
|
|
23
|
-
private unsubscribeGate;
|
|
24
|
-
private readonly countdown;
|
|
25
|
-
constructor(parent: HTMLElement, gate: PlayerControlGate);
|
|
26
|
-
bind(controller: AgentControlBannerController): () => void;
|
|
27
|
-
showUnavailable(message: string): void;
|
|
28
|
-
unbind(): void;
|
|
29
|
-
destroy(): void;
|
|
30
|
-
private render;
|
|
31
|
-
}
|
|
32
|
-
export declare function ensureAgentControlBannerStyles(doc?: Document | null): void;
|
|
33
|
-
/**
|
|
34
|
-
* Injected presentation for the visible lease safety surface. Games that
|
|
35
|
-
* dock a studio can set `--ck-game-right-inset` on `document.body` so the
|
|
36
|
-
* banner keeps clear of the dock (the Crowdy Studio embed kit does this
|
|
37
|
-
* automatically).
|
|
38
|
-
*/
|
|
39
|
-
export declare const AGENT_CONTROL_BANNER_STYLES = "\n.ck-agent-control-banner {\n position: fixed;\n top: 12px;\n right: calc(12px + var(--ck-game-right-inset, 0px));\n z-index: 65;\n display: grid;\n grid-template-columns: auto minmax(180px, 1fr) auto auto;\n align-items: center;\n gap: 10px;\n max-width: min(760px, calc(100vw - var(--ck-game-right-inset, 0px) - 24px));\n padding: 9px 10px;\n border: 1px solid rgba(110, 231, 183, 0.65);\n border-radius: 10px;\n color: #ecfdf5;\n background: rgba(2, 44, 34, 0.94);\n box-shadow: 0 12px 30px rgba(2, 6, 23, 0.45);\n pointer-events: auto;\n}\n\n.ck-agent-control-banner[hidden] {\n display: none;\n}\n\n.ck-agent-control-banner[data-state=\"unavailable\"] {\n border-color: rgba(251, 191, 36, 0.65);\n background: rgba(69, 26, 3, 0.94);\n}\n\n.ck-agent-control-summary,\n.ck-agent-control-expiry {\n overflow: hidden;\n color: #d1fae5;\n font-size: 12px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.ck-agent-control-expiry {\n color: #a7f3d0;\n}\n\n.ck-agent-control-actions {\n display: flex;\n gap: 6px;\n}\n\n.ck-agent-control-actions button {\n padding: 6px 9px;\n border: 1px solid rgba(167, 243, 208, 0.5);\n border-radius: 7px;\n color: #ecfdf5;\n background: rgba(6, 78, 59, 0.85);\n cursor: pointer;\n}\n\n.ck-agent-control-actions .ck-agent-control-stop {\n border-color: rgba(254, 202, 202, 0.75);\n background: rgba(153, 27, 27, 0.9);\n}\n\n.ck-agent-control-actions button:focus-visible {\n outline: 2px solid #fef3c7;\n outline-offset: 2px;\n}\n\n@media (max-width: 900px) {\n .ck-agent-control-banner {\n right: 8px;\n left: 8px;\n grid-template-columns: auto minmax(0, 1fr) auto;\n max-width: none;\n }\n\n .ck-agent-control-expiry {\n display: none;\n }\n}\n\n@media (max-width: 620px) {\n .ck-agent-control-banner {\n grid-template-columns: minmax(0, 1fr) auto;\n }\n\n .ck-agent-control-banner > strong {\n display: none;\n }\n}\n";
|
|
40
|
-
//# sourceMappingURL=control-banner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"control-banner.d.ts","sourceRoot":"","sources":["../../src/player-host/control-banner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,IAAI,wBAAwB,CAAC;IACrC,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5E;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAe3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAdvB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,UAAU,CAAyC;IAC3D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;gBAGzD,MAAM,EAAE,WAAW,EACF,IAAI,EAAE,iBAAiB;IAqC1C,IAAI,CAAC,UAAU,EAAE,4BAA4B,GAAG,MAAM,IAAI;IAc1D,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAUtC,MAAM,IAAI,IAAI;IASd,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,MAAM;CAuDf;AA2BD,wBAAgB,8BAA8B,CAC5C,GAAG,GAAE,QAAQ,GAAG,IAAwD,GACvE,IAAI,CAMN;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,+4DAwFvC,CAAC"}
|