@cardstack/boxel-cli 0.11.0-unstable.2 → 0.11.0-unstable.3

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 (106) hide show
  1. package/bundled-realms/pretui/components/agent-mark.gts +98 -0
  2. package/bundled-realms/pretui/components/agent-question.gts +340 -37
  3. package/bundled-realms/pretui/components/answer-footer.gts +249 -0
  4. package/bundled-realms/pretui/components/card-embed.gts +523 -0
  5. package/bundled-realms/pretui/components/card-pills.gts +725 -0
  6. package/bundled-realms/pretui/components/code-block.gts +87 -45
  7. package/bundled-realms/pretui/components/collapsed-turn.gts +133 -12
  8. package/bundled-realms/pretui/components/compaction-chip.gts +81 -67
  9. package/bundled-realms/pretui/components/composer-cap.gts +516 -0
  10. package/bundled-realms/pretui/components/context-ring.gts +108 -0
  11. package/bundled-realms/pretui/components/diff-block.gts +1002 -31
  12. package/bundled-realms/pretui/components/diff-stat.gts +102 -0
  13. package/bundled-realms/pretui/components/jump-chip.gts +86 -53
  14. package/bundled-realms/pretui/components/markdown-stream.gts +799 -0
  15. package/bundled-realms/pretui/components/markdown-surface.gts +71 -0
  16. package/bundled-realms/pretui/components/plan-mark.gts +147 -0
  17. package/bundled-realms/pretui/components/prose.gts +185 -8
  18. package/bundled-realms/pretui/components/prose.md +6 -8
  19. package/bundled-realms/pretui/components/quick-look.gts +377 -0
  20. package/bundled-realms/pretui/components/reactions.gts +136 -0
  21. package/bundled-realms/pretui/components/recommendation.gts +67 -36
  22. package/bundled-realms/pretui/components/result-card.gts +58 -22
  23. package/bundled-realms/pretui/components/segmented-control.gts +13 -8
  24. package/bundled-realms/pretui/components/session-prep.gts +12 -11
  25. package/bundled-realms/pretui/components/sliding-highlight.gts +8 -3
  26. package/bundled-realms/pretui/components/speaker-label.gts +132 -0
  27. package/bundled-realms/pretui/components/state-glyph.gts +121 -0
  28. package/bundled-realms/pretui/components/step-list.gts +62 -60
  29. package/bundled-realms/pretui/components/stick-to-bottom.gts +1150 -0
  30. package/bundled-realms/pretui/components/system-line.gts +143 -0
  31. package/bundled-realms/pretui/components/task-checklist.gts +184 -0
  32. package/bundled-realms/pretui/components/thinking.gts +63 -94
  33. package/bundled-realms/pretui/components/tool-change-table.gts +285 -0
  34. package/bundled-realms/pretui/components/tool-gate.gts +462 -0
  35. package/bundled-realms/pretui/components/tool-group.gts +920 -0
  36. package/bundled-realms/pretui/components/tool-icon.ts +64 -0
  37. package/bundled-realms/pretui/components/tool-meta.gts +82 -0
  38. package/bundled-realms/pretui/components/tool-plan.gts +197 -0
  39. package/bundled-realms/pretui/components/tool-row.gts +2087 -0
  40. package/bundled-realms/pretui/components/turn-changes.gts +227 -0
  41. package/bundled-realms/pretui/components/user-bubble.gts +575 -0
  42. package/bundled-realms/pretui/components/work-item.gts +185 -48
  43. package/bundled-realms/pretui/docs/scroll-anchoring-protocol.md +136 -0
  44. package/bundled-realms/pretui/internal/markdown-projection.ts +438 -0
  45. package/bundled-realms/pretui/internal/mount-queue.ts +79 -0
  46. package/bundled-realms/pretui/internal/tool-phrases.ts +168 -0
  47. package/bundled-realms/pretui/package.json +2 -1
  48. package/bundled-test-harness/assets/{ai-module-creation-test-beRNwH-e.js → ai-module-creation-test-B6FQKqIl.js} +1 -1
  49. package/bundled-test-harness/assets/{app-CtezUCip.js → app-KpPqdyX3.js} +4 -4
  50. package/bundled-test-harness/assets/{binary-upload-dedupe-test-bI8T0QLl.js → binary-upload-dedupe-test-DN00y1tM.js} +1 -1
  51. package/bundled-test-harness/assets/{can-invoke-test-DVaU_yRT.js → can-invoke-test-Bl-EUFM3.js} +1 -1
  52. package/bundled-test-harness/assets/{card-chooser-paging-test-DnxMnXKR.js → card-chooser-paging-test-BNuZRHX3.js} +1 -1
  53. package/bundled-test-harness/assets/{card-chooser-test-DUSnLr-u.js → card-chooser-test-wKfPOOT4.js} +1 -1
  54. package/bundled-test-harness/assets/{card-def-field-def-relationships-test-GBUr3tFK.js → card-def-field-def-relationships-test-CduQ6zan.js} +1 -1
  55. package/bundled-test-harness/assets/{card-delete-test-CQveO1VC.js → card-delete-test-DKxolj5o.js} +1 -1
  56. package/bundled-test-harness/assets/{check-correctness-test-D2M2p66N.js → check-correctness-test-B-kgHztp.js} +1 -1
  57. package/bundled-test-harness/assets/{codeblocks-test-AdolhdCA.js → codeblocks-test-BDD7qK_V.js} +1 -1
  58. package/bundled-test-harness/assets/{compaction-test-DvyAQq56.js → compaction-test-BweolkhG.js} +1 -1
  59. package/bundled-test-harness/assets/{container-DIF_9lZ9.css → container-B5B6u-xm.css} +29 -22
  60. package/bundled-test-harness/assets/{container-DvvqmNpg.js → container-BnJjIM6J.js} +9 -6
  61. package/bundled-test-harness/assets/{create-listing-modal-test-D95JfQab.js → create-listing-modal-test-FvcAKpIa.js} +1 -1
  62. package/bundled-test-harness/assets/{debug-message-test-BcNtj7Wr.js → debug-message-test-CJ18Evt7.js} +1 -1
  63. package/bundled-test-harness/assets/{externals-DCnB4XSS.js → externals-BWjhmCD4.js} +1 -1
  64. package/bundled-test-harness/assets/{fallback-banner-live-delete-test-5lnN1pv2.js → fallback-banner-live-delete-test-C2H3BrT-.js} +1 -1
  65. package/bundled-test-harness/assets/{fallback-banner-test-DFb_m_Kq.js → fallback-banner-test-C10aYjkj.js} +1 -1
  66. package/bundled-test-harness/assets/{fallback-models-test-p3YIwj1L.js → fallback-models-test-BxoPiaGF.js} +1 -1
  67. package/bundled-test-harness/assets/{file-attachment-test-CmyjNWRR.js → file-attachment-test-DeKyzYaz.js} +1 -1
  68. package/bundled-test-harness/assets/{general-test-CX-TFDuX.js → general-test-BewzrpoB.js} +1 -1
  69. package/bundled-test-harness/assets/{index-query-engine-test-CY2tAkot.js → index-query-engine-test-BtI8Y2LR.js} +1 -1
  70. package/bundled-test-harness/assets/{instance-filter-matcher-test-CMBTh8xn.js → instance-filter-matcher-test-BHXHGHjE.js} +1 -1
  71. package/bundled-test-harness/assets/{main-BOZbZVem.js → main-CqAHZ2kK.js} +1 -1
  72. package/bundled-test-harness/assets/{message-tool-test-CfjRSJvt.js → message-tool-test-NMaPJFsd.js} +1 -1
  73. package/bundled-test-harness/assets/{model-cost-tier-test-mZG84Uso.js → model-cost-tier-test-BgbfN2LH.js} +1 -1
  74. package/bundled-test-harness/assets/{operation-lowering-test-CHnjKSJb.js → operation-lowering-test-C4IaOjsA.js} +1 -1
  75. package/bundled-test-harness/assets/{operator-mode-card-chooser-test-KWS8lq16.js → operator-mode-card-chooser-test-Bwe47Rn7.js} +1 -1
  76. package/bundled-test-harness/assets/{operator-mode-links-test-CViFt0Ws.js → operator-mode-links-test-BU4jkC-B.js} +1 -1
  77. package/bundled-test-harness/assets/{operator-mode-test-D0gZM2yw.js → operator-mode-test-Bh0rGM9z.js} +1 -1
  78. package/bundled-test-harness/assets/{operator-mode-ui-test-CEvHJ9DS.js → operator-mode-ui-test-whgUw0ju.js} +1 -1
  79. package/bundled-test-harness/assets/{overlay-menu-items-test-Pw80RXsr.js → overlay-menu-items-test-Cwn1vr8q.js} +1 -1
  80. package/bundled-test-harness/assets/{past-sessions-test-CW0-Bjav.js → past-sessions-test-Bh24N-Kz.js} +1 -1
  81. package/bundled-test-harness/assets/{permission-checking-realm-test-D5uXQypS.js → permission-checking-realm-test-DKnnAy0f.js} +1 -1
  82. package/bundled-test-harness/assets/{realm-config-policy-standing-test-Btatheni.js → realm-config-policy-standing-test-DngdYypq.js} +1 -1
  83. package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-Dh5zW13o.js → realm-config-routing-rule-edit-test-_rkFU8SN.js} +1 -1
  84. package/bundled-test-harness/assets/{realm-config-settings-test-BJa8gv_C.js → realm-config-settings-test-CR9NH0Zn.js} +1 -1
  85. package/bundled-test-harness/assets/{reasoning-test-2Zp37cQB.js → reasoning-test-0lH10kRl.js} +1 -1
  86. package/bundled-test-harness/assets/{room-message-test-BsrON13e.js → room-message-test-C-PddE4Y.js} +1 -1
  87. package/bundled-test-harness/assets/{run-realm-code-BxktQf6R.js → run-realm-code-C8N7DtN-.js} +1 -1
  88. package/bundled-test-harness/assets/{run-realm-code-test-7grpTos-.js → run-realm-code-test-DBdp147q.js} +1 -1
  89. package/bundled-test-harness/assets/{schema-generation-test-CM9ggQji.js → schema-generation-test-CB1Hb7GQ.js} +1 -1
  90. package/bundled-test-harness/assets/{scrolling-test-BER00htB.js → scrolling-test-3PhVin8h.js} +1 -1
  91. package/bundled-test-harness/assets/{searchable-option-test-Ctf8r3HZ.js → searchable-option-test-BAdOiL4U.js} +1 -1
  92. package/bundled-test-harness/assets/{sending-test-BJGobs2E.js → sending-test-KSmu1tSJ.js} +1 -1
  93. package/bundled-test-harness/assets/{skills-test-GPOsHRN6.js → skills-test-D-dlcFpd.js} +1 -1
  94. package/bundled-test-harness/assets/{store-test-QvvHimzH.js → store-test-CEW7xQjZ.js} +1 -1
  95. package/bundled-test-harness/assets/{tests-DoTEpvcF.js → tests-QYqqa6nv.js} +47 -47
  96. package/bundled-test-harness/assets/{text-input-validator-test-CYYH2N0L.js → text-input-validator-test-D8iNOWep.js} +1 -1
  97. package/bundled-test-harness/assets/{to-device-streaming-test-Ctqa0bVp.js → to-device-streaming-test-trCX-505.js} +1 -1
  98. package/bundled-test-harness/assets/{token-usage-test-BQVbK3X0.js → token-usage-test-C6sULooH.js} +1 -1
  99. package/bundled-test-harness/assets/{tools-DU8Rc15s.js → tools-UJfD-_al.js} +1 -1
  100. package/bundled-test-harness/assets/{tools-test-B13yvEKE.js → tools-test-Brav31AV.js} +1 -1
  101. package/bundled-test-harness/assets/{worker-DHBEBihX.js → worker-9ph9_Lpv.js} +31 -26
  102. package/bundled-test-harness/index.html +8 -8
  103. package/bundled-test-harness/tests/index.html +8 -8
  104. package/bundled-types/host-app/lib/realm-runner/worker.ts +8 -51
  105. package/bundled-types/runtime-common/realm-runner-script.d.ts +3 -0
  106. package/package.json +1 -1
@@ -0,0 +1,462 @@
1
+ // Pretui — ToolGate: the decision a tool call waits on, asked inside its row.
2
+ import Component from '@glimmer/component';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { on } from '@ember/modifier';
5
+ import { fn } from '@ember/helper';
6
+ import { guidFor } from '@ember/object/internals';
7
+ import { modifier } from 'ember-modifier';
8
+ import { StateGlyph } from './state-glyph';
9
+
10
+ export interface ToolGateAction {
11
+ /** the button's words: 'Allow once', 'Keep 40', 'Revert'. On a
12
+ * destructive gate the primary answer names the act it runs: 'Delete 3
13
+ * files', never 'OK' or 'Allow' */
14
+ label: string;
15
+ /** 'primary' (the one filled button), 'secondary' (outlined), or 'quiet'
16
+ * (text). Default 'secondary' */
17
+ kind?: 'primary' | 'secondary' | 'quiet';
18
+ /** a stable name for the answer ('apply', 'always', 'deny'): what a host
19
+ * finds it by, and its test hook. Default: the label */
20
+ id?: string;
21
+ /** the action; a returned promise keeps the gate busy until it settles */
22
+ onAct: () => unknown;
23
+ /** what the button reads while its action runs. Default: label and "…" */
24
+ busyLabel?: string;
25
+ /** an "always" answer: what it grants is said under it before it is
26
+ * given ("Allows realm.fs.delete in showcase/scratch/ for this session"),
27
+ * and a destructive gate never offers one */
28
+ always?: boolean;
29
+ /** the decline: the gate asks why (optional) and hands the reason to
30
+ * `onDecline` instead of running `onAct` */
31
+ declines?: boolean;
32
+ }
33
+
34
+ export interface ToolGateSignature {
35
+ Args: {
36
+ /** the question, in one sentence: "This waits for your click." */
37
+ prompt: string;
38
+ /** why it asks, or what the click allows; a quieter second line */
39
+ detail?: string;
40
+ /** the answers, most likely first. Omit when the decision is someone
41
+ * else's (@waitingOn) */
42
+ actions?: ToolGateAction[];
43
+ /** the decision belongs to this person: the gate says so and offers
44
+ * no buttons. "Rupert" → "Waiting on Rupert" */
45
+ waitingOn?: string;
46
+ /** 'attention' (default) for a question, 'conflict' when the call found
47
+ * that something moved since it asked */
48
+ tone?: 'attention' | 'conflict';
49
+ /** the call cannot be undone: the gate says so in words, draws its
50
+ * primary answer in the destructive colour (so that answer's label must
51
+ * name the act: 'Delete 3 files'), and drops any "always" answer, since
52
+ * a standing yes to a delete is not a yes the reader can see the cost
53
+ * of */
54
+ destructive?: boolean;
55
+ /** what an "always" answer grants, said under the answers while it is
56
+ * focused or hovered: "realm.fs.delete in showcase/scratch/" */
57
+ scope?: string;
58
+ /** the decline's reason, optional: asked when an answer marked
59
+ * `declines` is pressed, then handed here */
60
+ onDecline?: (reason: string) => unknown;
61
+ /** the call was allowed by a standing answer: the gate is a receipt,
62
+ * "Allowed for this session", with no buttons */
63
+ auto?: string;
64
+ /** the question ended without an answer: 'canceled' (the run went on
65
+ * without it) or 'expired' (nobody answered in time). The gate says so,
66
+ * with no buttons */
67
+ resolution?: 'canceled' | 'expired';
68
+ /** the reader cannot answer here (a read-only transcript, a teammate's
69
+ * request): the question shows, its answers do not */
70
+ readonly?: boolean;
71
+ };
72
+ /** what the reader decides about: a picker, the files a preview staged */
73
+ Blocks: { default: [] };
74
+ Element: HTMLDivElement;
75
+ }
76
+
77
+ /**
78
+ * The in-row gate. One question, its answers, and one busy state for all
79
+ * of them, so a decision is made once:
80
+ *
81
+ * ```hbs
82
+ * <ToolRow @name='run-realm-code' @state='ready' @framed={{true}}>
83
+ * <:gate>
84
+ * <ToolGate @prompt='This waits for your click.'
85
+ * @actions={{array (hash label='Allow once' kind='primary' onAct=this.allow)
86
+ * (hash label='Always for this session' onAct=this.always)
87
+ * (hash label='Deny' kind='quiet' onAct=this.deny)}} />
88
+ * </:gate>
89
+ * </ToolRow>
90
+ * ```
91
+ */
92
+ export class ToolGate extends Component<ToolGateSignature> {
93
+ /** the label of the action in flight; every answer waits on it */
94
+ @tracked busy: string | undefined;
95
+ @tracked declining = false;
96
+ @tracked reason = '';
97
+ readonly promptId = guidFor(this) + '-prompt';
98
+ /** the declining answer, which takes focus back when the reader leaves
99
+ * the reason field with Back or Escape */
100
+ private returnTo: ToolGateAction | undefined;
101
+
102
+ get actions(): ToolGateAction[] {
103
+ if (
104
+ this.args.waitingOn ||
105
+ this.args.auto ||
106
+ this.args.resolution ||
107
+ this.args.readonly
108
+ ) {
109
+ return [];
110
+ }
111
+ let actions = this.args.actions ?? [];
112
+ return this.args.destructive ? actions.filter((a) => !a.always) : actions;
113
+ }
114
+ get hasAlways(): boolean {
115
+ return Boolean(this.args.scope) && this.actions.some((a) => a.always);
116
+ }
117
+ get prompt(): string {
118
+ if (this.args.resolution) {
119
+ let how = this.args.resolution === 'expired' ? 'Expired' : 'Canceled';
120
+ return `${how} · ${this.args.prompt}`;
121
+ }
122
+ return this.args.waitingOn
123
+ ? `Waiting on ${this.args.waitingOn}`
124
+ : this.args.prompt;
125
+ }
126
+ labelOf = (action: ToolGateAction): string =>
127
+ this.busy === action.label
128
+ ? (action.busyLabel ?? `${action.label}…`)
129
+ : action.label;
130
+ kindOf = (action: ToolGateAction): string => action.kind ?? 'secondary';
131
+ isBusy = (action: ToolGateAction): boolean => this.busy === action.label;
132
+
133
+ act = async (action: ToolGateAction) => {
134
+ if (this.busy) {
135
+ return;
136
+ }
137
+ if (action.declines && this.args.onDecline) {
138
+ this.returnTo = action;
139
+ this.declining = true;
140
+ return;
141
+ }
142
+ this.busy = action.label;
143
+ try {
144
+ await action.onAct();
145
+ } finally {
146
+ if (!this.isDestroying && !this.isDestroyed) {
147
+ this.busy = undefined;
148
+ }
149
+ }
150
+ };
151
+
152
+ typeReason = (event: Event) =>
153
+ (this.reason = (event.target as HTMLInputElement).value);
154
+ cancelDecline = () => {
155
+ this.declining = false;
156
+ this.reason = '';
157
+ };
158
+ /** the reason field takes focus as it appears: the answer that opened it
159
+ * has just left the page */
160
+ focusOnInsert = modifier((element: HTMLElement) => {
161
+ element.focus();
162
+ });
163
+ /** the declining answer takes focus back as it reappears after Back or
164
+ * Escape */
165
+ refocus = modifier((element: HTMLElement, [action]: [ToolGateAction]) => {
166
+ if (this.returnTo?.label === action.label && !this.declining) {
167
+ this.returnTo = undefined;
168
+ element.focus();
169
+ }
170
+ });
171
+ confirmDecline = async () => {
172
+ if (this.busy) {
173
+ return;
174
+ }
175
+ this.busy = 'decline';
176
+ try {
177
+ await this.args.onDecline?.(this.reason.trim());
178
+ } finally {
179
+ if (!this.isDestroying && !this.isDestroyed) {
180
+ this.busy = undefined;
181
+ this.declining = false;
182
+ }
183
+ }
184
+ };
185
+ reasonKey = (e: Event) => {
186
+ let event = e as KeyboardEvent;
187
+ if (event.key === 'Enter') {
188
+ event.preventDefault();
189
+ this.confirmDecline();
190
+ } else if (event.key === 'Escape') {
191
+ // the field's own Escape: a host listening at the document must not
192
+ // also close what holds the gate
193
+ event.stopPropagation();
194
+ this.cancelDecline();
195
+ }
196
+ };
197
+
198
+ <template>
199
+ <div
200
+ class='pretui-toolgate'
201
+ role='group'
202
+ aria-labelledby={{this.promptId}}
203
+ aria-busy={{if this.busy 'true'}}
204
+ data-tone={{if @tone @tone 'attention'}}
205
+ data-routed={{if @waitingOn 'true'}}
206
+ data-destructive={{if @destructive 'true'}}
207
+ data-auto={{if @auto 'true'}}
208
+ data-resolution={{@resolution}}
209
+ data-test-pretui-tool-gate
210
+ ...attributes
211
+ >
212
+ <p class='pretui-toolgate-prompt' id={{this.promptId}}>
213
+ {{#if @auto}}<span
214
+ class='pretui-toolgate-auto'
215
+ data-test-pretui-tool-gate-auto
216
+ ><StateGlyph
217
+ class='pretui-toolgate-auto-mark'
218
+ @glyph='done'
219
+ />{{@auto}}</span>{{else}}{{this.prompt}}{{/if}}
220
+ {{#if @destructive}}<span
221
+ class='pretui-toolgate-destructive'
222
+ data-test-pretui-tool-gate-destructive
223
+ >This cannot be undone.</span>{{/if}}
224
+ {{#if @detail}}<span
225
+ class='pretui-toolgate-detail'
226
+ data-test-pretui-tool-gate-detail
227
+ >{{@detail}}</span>{{/if}}
228
+ </p>
229
+ {{yield}}
230
+ {{#if this.declining}}
231
+ <div class='pretui-toolgate-decline' data-test-pretui-tool-gate-decline>
232
+ <input
233
+ class='pretui-toolgate-reason'
234
+ aria-label='Why not? (optional)'
235
+ placeholder='Why not? (optional)'
236
+ value={{this.reason}}
237
+ {{on 'input' this.typeReason}}
238
+ {{on 'keydown' this.reasonKey}}
239
+ {{this.focusOnInsert}}
240
+ data-test-pretui-tool-gate-reason
241
+ />
242
+ <button
243
+ type='button'
244
+ class='pretui-toolgate-action'
245
+ data-kind='primary'
246
+ aria-disabled={{if this.busy 'true'}}
247
+ {{on 'click' this.confirmDecline}}
248
+ data-test-pretui-tool-gate-decline-confirm
249
+ >Decline</button>
250
+ <button
251
+ type='button'
252
+ class='pretui-toolgate-action'
253
+ data-kind='quiet'
254
+ {{on 'click' this.cancelDecline}}
255
+ data-test-pretui-tool-gate-decline-back
256
+ >Back</button>
257
+ </div>
258
+ {{else if this.actions.length}}
259
+ <div class='pretui-toolgate-actions'>
260
+ {{#each this.actions as |answer|}}
261
+ <button
262
+ type='button'
263
+ class='pretui-toolgate-action'
264
+ data-kind={{this.kindOf answer}}
265
+ data-busy={{if (this.isBusy answer) 'true'}}
266
+ aria-disabled={{if this.busy 'true'}}
267
+ aria-describedby={{this.promptId}}
268
+ data-tool-gate-action={{answer.id}}
269
+ {{on 'click' (fn this.act answer)}}
270
+ {{this.refocus answer}}
271
+ data-test-pretui-tool-gate-action={{if
272
+ answer.id
273
+ answer.id
274
+ answer.label
275
+ }}
276
+ >{{this.labelOf answer}}</button>
277
+ {{/each}}
278
+ </div>
279
+ {{#if this.hasAlways}}
280
+ <p
281
+ class='pretui-toolgate-scope'
282
+ data-test-pretui-tool-gate-scope
283
+ >“Always” allows {{@scope}}</p>
284
+ {{/if}}
285
+ {{/if}}
286
+ </div>
287
+ <style scoped>
288
+ @layer PretComponent {
289
+ /* the gate sits on the row's text edge, under its lines: a question
290
+ and its answers, with no box of its own (the row is the box) */
291
+ .pretui-toolgate {
292
+ display: grid;
293
+ gap: var(--boxel-sp-xs);
294
+ padding-block: var(--boxel-sp-4xs) var(--boxel-sp-6xs);
295
+ padding-inline-start: calc(
296
+ var(--pretui-toolrow-disc, var(--boxel-sp)) +
297
+ var(--pretui-toolrow-gap, var(--boxel-sp-xs))
298
+ );
299
+ }
300
+ .pretui-toolgate-prompt {
301
+ margin: 0;
302
+ font-size: var(--boxel-ui-label-font-size);
303
+ line-height: var(--boxel-ui-label-line-height);
304
+ font-weight: 600;
305
+ color: var(--foreground);
306
+ }
307
+ /* a conflict needs the reader: the prompt stays ink-1 and a dot
308
+ before it takes the attention state (the mark, never the text) */
309
+ .pretui-toolgate[data-tone='conflict'] .pretui-toolgate-prompt::before {
310
+ content: '';
311
+ display: inline-block;
312
+ width: 0.375rem;
313
+ height: 0.375rem;
314
+ margin-inline-end: var(--boxel-sp-2xs);
315
+ border-radius: 50%;
316
+ vertical-align: 0.1em;
317
+ background-color: var(--attention);
318
+ }
319
+ .pretui-toolgate[data-routed] .pretui-toolgate-prompt {
320
+ font-weight: 400;
321
+ color: var(--muted-foreground);
322
+ }
323
+ .pretui-toolgate[data-resolution] .pretui-toolgate-prompt {
324
+ font-weight: 400;
325
+ color: var(--muted-foreground);
326
+ }
327
+ .pretui-toolgate-destructive {
328
+ display: block;
329
+ font-weight: 600;
330
+ color: var(--destructive-ink);
331
+ }
332
+ .pretui-toolgate-auto {
333
+ font-weight: 400;
334
+ color: var(--muted-foreground);
335
+ }
336
+ .pretui-toolgate-auto-mark {
337
+ display: inline-grid;
338
+ margin-inline-end: var(--boxel-sp-4xs);
339
+ vertical-align: -0.1em;
340
+ }
341
+ .pretui-toolgate-scope {
342
+ margin: 0;
343
+ font-size: var(--boxel-caption-font-size);
344
+ line-height: var(--boxel-caption-line-height);
345
+ color: var(--subtle-foreground);
346
+ }
347
+ .pretui-toolgate-decline {
348
+ display: flex;
349
+ flex-wrap: wrap;
350
+ gap: var(--boxel-sp-xs);
351
+ align-items: center;
352
+ }
353
+ .pretui-toolgate-reason {
354
+ flex: 1 1 10rem;
355
+ min-width: 0;
356
+ height: 1.75rem;
357
+ padding: 0 var(--boxel-sp-xs);
358
+ border: 0;
359
+ border-radius: var(--boxel-border-radius-sm);
360
+ background-color: var(--field);
361
+ box-shadow: inset 0 0 0 1px var(--input);
362
+ font-family: inherit;
363
+ font-size: var(--boxel-ui-label-font-size);
364
+ line-height: var(--boxel-ui-label-line-height);
365
+ color: var(--foreground);
366
+ }
367
+ .pretui-toolgate-reason::placeholder {
368
+ color: var(--subtle-foreground);
369
+ }
370
+ .pretui-toolgate-reason:focus {
371
+ outline: 2px solid var(--ring);
372
+ outline-offset: 1px;
373
+ }
374
+ .pretui-toolgate-detail {
375
+ display: block;
376
+ font-size: var(--boxel-caption-font-size);
377
+ line-height: var(--boxel-caption-line-height);
378
+ font-weight: 400;
379
+ color: var(--muted-foreground);
380
+ }
381
+ .pretui-toolgate-actions {
382
+ display: flex;
383
+ flex-wrap: wrap;
384
+ align-items: center;
385
+ gap: var(--boxel-sp-xs);
386
+ }
387
+ /* answers: the one answer is --primary; the rest are outlined
388
+ (secondary) or quiet text */
389
+ .pretui-toolgate-action {
390
+ min-height: 1.75rem;
391
+ padding: 0 var(--boxel-sp-sm);
392
+ border: 0;
393
+ border-radius: var(--boxel-border-radius-sm);
394
+ background-color: transparent;
395
+ box-shadow: inset 0 0 0 1px var(--border-strong);
396
+ font-family: inherit;
397
+ font-size: var(--boxel-ui-label-font-size);
398
+ line-height: var(--boxel-ui-label-line-height);
399
+ font-weight: 600;
400
+ color: var(--foreground);
401
+ cursor: pointer;
402
+ white-space: nowrap;
403
+ }
404
+ .pretui-toolgate-action[data-kind='primary'] {
405
+ box-shadow: none;
406
+ background-color: var(--primary);
407
+ color: var(--primary-foreground);
408
+ }
409
+ /* the answer that runs an act that cannot be undone looks like one */
410
+ .pretui-toolgate[data-destructive]
411
+ .pretui-toolgate-action[data-kind='primary'] {
412
+ background-color: var(--destructive);
413
+ color: var(--destructive-foreground);
414
+ }
415
+ .pretui-toolgate-action[data-kind='quiet'] {
416
+ box-shadow: none;
417
+ font-weight: 400;
418
+ color: var(--muted-foreground);
419
+ }
420
+ .pretui-toolgate-action:hover:not([aria-disabled='true']) {
421
+ background-color: var(--hover);
422
+ }
423
+ .pretui-toolgate-action[data-kind='quiet']:hover:not(
424
+ [aria-disabled='true']
425
+ ) {
426
+ background-color: transparent;
427
+ color: var(--foreground);
428
+ }
429
+ .pretui-toolgate-action[data-kind='primary']:hover:not(
430
+ [aria-disabled='true']
431
+ ) {
432
+ background-color: color-mix(
433
+ in srgb,
434
+ var(--primary) 88%,
435
+ var(--foreground)
436
+ );
437
+ }
438
+ .pretui-toolgate[data-destructive]
439
+ .pretui-toolgate-action[data-kind='primary']:hover:not(
440
+ [aria-disabled='true']
441
+ ) {
442
+ background-color: color-mix(
443
+ in srgb,
444
+ var(--destructive) 88%,
445
+ var(--foreground)
446
+ );
447
+ }
448
+ .pretui-toolgate-action:focus-visible {
449
+ outline: 2px solid var(--ring);
450
+ outline-offset: 2px;
451
+ }
452
+ .pretui-toolgate-action[aria-disabled='true'] {
453
+ cursor: default;
454
+ opacity: 0.6;
455
+ }
456
+ .pretui-toolgate-action[data-busy] {
457
+ opacity: 1;
458
+ }
459
+ }
460
+ </style>
461
+ </template>
462
+ }