@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.
Files changed (119) hide show
  1. package/MIGRATION.md +55 -0
  2. package/README.md +67 -41
  3. package/dist/client.d.ts +1 -0
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +3 -0
  6. package/dist/crowdy-client.d.ts +2 -3
  7. package/dist/crowdy-client.d.ts.map +1 -1
  8. package/dist/crowdy-client.js +9 -11
  9. package/dist/crowdy-dsh/bridge.d.ts +156 -0
  10. package/dist/crowdy-dsh/bridge.d.ts.map +1 -0
  11. package/dist/crowdy-dsh/bridge.js +523 -0
  12. package/dist/crowdy-dsh/index.d.ts +11 -0
  13. package/dist/crowdy-dsh/index.d.ts.map +1 -0
  14. package/dist/crowdy-dsh/index.js +10 -0
  15. package/dist/crowdy-dsh/pane.d.ts +64 -0
  16. package/dist/crowdy-dsh/pane.d.ts.map +1 -0
  17. package/dist/crowdy-dsh/pane.js +247 -0
  18. package/dist/crowdy-dsh/protocol.d.ts +249 -0
  19. package/dist/crowdy-dsh/protocol.d.ts.map +1 -0
  20. package/dist/crowdy-dsh/protocol.js +39 -0
  21. package/dist/crowdy-dsh/transport.d.ts +66 -0
  22. package/dist/crowdy-dsh/transport.d.ts.map +1 -0
  23. package/dist/crowdy-dsh/transport.js +88 -0
  24. package/dist/crowdy-studio/controller.d.ts +8 -0
  25. package/dist/crowdy-studio/controller.d.ts.map +1 -1
  26. package/dist/crowdy-studio/controller.js +33 -1
  27. package/dist/crowdy-studio/dom-shell.d.ts +21 -4
  28. package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
  29. package/dist/crowdy-studio/dom-shell.js +32 -17
  30. package/dist/crowdy-studio/embed/index.d.ts +1 -1
  31. package/dist/crowdy-studio/embed/index.d.ts.map +1 -1
  32. package/dist/crowdy-studio/embed/panel.d.ts +18 -18
  33. package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
  34. package/dist/crowdy-studio/embed/panel.js +7 -21
  35. package/dist/crowdy-studio/index.d.ts +2 -3
  36. package/dist/crowdy-studio/index.d.ts.map +1 -1
  37. package/dist/crowdy-studio/index.js +1 -2
  38. package/dist/crowdy-studio/mount.d.ts +29 -14
  39. package/dist/crowdy-studio/mount.d.ts.map +1 -1
  40. package/dist/crowdy-studio/mount.js +39 -126
  41. package/dist/crowdy-studio/styles.d.ts +1 -1
  42. package/dist/crowdy-studio/styles.d.ts.map +1 -1
  43. package/dist/crowdy-studio/styles.js +5 -0
  44. package/dist/default-origin.d.ts +6 -6
  45. package/dist/default-origin.d.ts.map +1 -1
  46. package/dist/default-origin.js +6 -6
  47. package/dist/generated/graphql.d.ts +76 -2438
  48. package/dist/generated/graphql.d.ts.map +1 -1
  49. package/dist/generated/graphql.js +0 -50
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +1 -1
  53. package/dist/kit/npcs.d.ts.map +1 -1
  54. package/dist/kit/social.d.ts.map +1 -1
  55. package/dist/{crowdy-agent/errors.d.ts → player-host/agent-errors.d.ts} +1 -1
  56. package/dist/player-host/agent-errors.d.ts.map +1 -0
  57. package/dist/player-host/agent-types.d.ts +18 -0
  58. package/dist/player-host/agent-types.d.ts.map +1 -0
  59. package/dist/player-host/agent-types.js +7 -0
  60. package/dist/player-host/index.d.ts +12 -4
  61. package/dist/player-host/index.d.ts.map +1 -1
  62. package/dist/player-host/index.js +11 -4
  63. package/dist/{crowdy-agent/schema.d.ts → player-host/json-schema.d.ts} +1 -1
  64. package/dist/player-host/json-schema.d.ts.map +1 -0
  65. package/dist/{crowdy-agent/schema.js → player-host/json-schema.js} +1 -1
  66. package/dist/player-host/schemas.d.ts +1 -1
  67. package/dist/player-host/schemas.d.ts.map +1 -1
  68. package/dist/player-host/schemas.js +2 -2
  69. package/dist/player-host/types.d.ts +2 -2
  70. package/dist/player-host/types.d.ts.map +1 -1
  71. package/package.json +5 -7
  72. package/dist/crowdy-agent/browser-dispatcher.d.ts +0 -41
  73. package/dist/crowdy-agent/browser-dispatcher.d.ts.map +0 -1
  74. package/dist/crowdy-agent/browser-dispatcher.js +0 -264
  75. package/dist/crowdy-agent/controller.d.ts +0 -152
  76. package/dist/crowdy-agent/controller.d.ts.map +0 -1
  77. package/dist/crowdy-agent/controller.js +0 -1289
  78. package/dist/crowdy-agent/errors.d.ts.map +0 -1
  79. package/dist/crowdy-agent/graphql-transport.d.ts +0 -154
  80. package/dist/crowdy-agent/graphql-transport.d.ts.map +0 -1
  81. package/dist/crowdy-agent/graphql-transport.js +0 -854
  82. package/dist/crowdy-agent/index.d.ts +0 -17
  83. package/dist/crowdy-agent/index.d.ts.map +0 -1
  84. package/dist/crowdy-agent/index.js +0 -16
  85. package/dist/crowdy-agent/registry.d.ts +0 -29
  86. package/dist/crowdy-agent/registry.d.ts.map +0 -1
  87. package/dist/crowdy-agent/registry.js +0 -281
  88. package/dist/crowdy-agent/schema.d.ts.map +0 -1
  89. package/dist/crowdy-agent/session-resume.d.ts +0 -24
  90. package/dist/crowdy-agent/session-resume.d.ts.map +0 -1
  91. package/dist/crowdy-agent/session-resume.js +0 -76
  92. package/dist/crowdy-agent/studio-tools.d.ts +0 -15
  93. package/dist/crowdy-agent/studio-tools.d.ts.map +0 -1
  94. package/dist/crowdy-agent/studio-tools.js +0 -280
  95. package/dist/crowdy-agent/tool-descriptors.d.ts +0 -4
  96. package/dist/crowdy-agent/tool-descriptors.d.ts.map +0 -1
  97. package/dist/crowdy-agent/tool-descriptors.js +0 -1049
  98. package/dist/crowdy-agent/transport.d.ts +0 -152
  99. package/dist/crowdy-agent/transport.d.ts.map +0 -1
  100. package/dist/crowdy-agent/transport.js +0 -27
  101. package/dist/crowdy-agent/types.d.ts +0 -328
  102. package/dist/crowdy-agent/types.d.ts.map +0 -1
  103. package/dist/crowdy-agent/types.js +0 -37
  104. package/dist/crowdy-studio/agent-dom-shell.d.ts +0 -68
  105. package/dist/crowdy-studio/agent-dom-shell.d.ts.map +0 -1
  106. package/dist/crowdy-studio/agent-dom-shell.js +0 -418
  107. package/dist/player-host/control-banner.d.ts +0 -40
  108. package/dist/player-host/control-banner.d.ts.map +0 -1
  109. package/dist/player-host/control-banner.js +0 -252
  110. package/dist/player-host/control-gate.d.ts +0 -77
  111. package/dist/player-host/control-gate.d.ts.map +0 -1
  112. package/dist/player-host/control-gate.js +0 -197
  113. package/dist/player-host/lease-manager.d.ts +0 -66
  114. package/dist/player-host/lease-manager.d.ts.map +0 -1
  115. package/dist/player-host/lease-manager.js +0 -428
  116. package/dist/player-host/tools.d.ts +0 -13
  117. package/dist/player-host/tools.d.ts.map +0 -1
  118. package/dist/player-host/tools.js +0 -79
  119. /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"}