@fungi.computer/parakeet 0.4.0 → 0.6.0

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 (82) hide show
  1. package/README.md +17 -1
  2. package/dist/client-contributions.d.ts +1 -0
  3. package/dist/commands/awaiting-driver.d.ts +20 -0
  4. package/dist/commands/awaiting-driver.js +121 -0
  5. package/dist/commands/builtins.js +6 -4
  6. package/dist/commands/interactions.d.ts +25 -0
  7. package/dist/commands/interactions.js +76 -2
  8. package/dist/commands/run.js +3 -3
  9. package/dist/commands/slash.d.ts +7 -3
  10. package/dist/commands/slash.js +2 -0
  11. package/dist/commands/use-slash-commands.d.ts +13 -0
  12. package/dist/commands/use-slash-commands.js +58 -1
  13. package/dist/components/ChatComposer.d.ts +2 -0
  14. package/dist/components/ChatComposer.js +158 -40
  15. package/dist/components/ClientRows.js +42 -26
  16. package/dist/components/CodeBlock.js +3 -2
  17. package/dist/components/CompletionMenu.d.ts +54 -0
  18. package/dist/components/CompletionMenu.js +52 -0
  19. package/dist/components/ComposerModelKey.d.ts +11 -0
  20. package/dist/components/ComposerModelKey.js +9 -0
  21. package/dist/components/ComposerShell.d.ts +47 -0
  22. package/dist/components/ComposerShell.js +29 -0
  23. package/dist/components/DecisionComposer.d.ts +30 -0
  24. package/dist/components/DecisionComposer.js +145 -0
  25. package/dist/components/InteractionPanel.d.ts +10 -1
  26. package/dist/components/InteractionPanel.js +9 -4
  27. package/dist/components/SlashMenu.d.ts +1 -3
  28. package/dist/components/SlashMenu.js +5 -13
  29. package/dist/components/TimelineItem.d.ts +1 -0
  30. package/dist/components/TimelineItem.js +4 -4
  31. package/dist/components/ToolGroup.d.ts +1 -0
  32. package/dist/components/ToolGroup.js +8 -8
  33. package/dist/conversation-opening.d.ts +1 -1
  34. package/dist/conversation-opening.js +2 -2
  35. package/dist/conversation.d.ts +5 -1
  36. package/dist/conversation.js +84 -29
  37. package/dist/core/approval-decision.d.ts +198 -0
  38. package/dist/core/approval-decision.js +291 -0
  39. package/dist/core/awaiting-answer.d.ts +229 -0
  40. package/dist/core/awaiting-answer.js +303 -0
  41. package/dist/core/build-timeline.js +61 -7
  42. package/dist/core/client-actions.d.ts +1 -0
  43. package/dist/core/client-actions.js +7 -1
  44. package/dist/core/composer-model-name.d.ts +3 -0
  45. package/dist/core/composer-model-name.js +21 -0
  46. package/dist/core/display-text.d.ts +2 -0
  47. package/dist/core/display-text.js +7 -0
  48. package/dist/core/draft-storage.d.ts +6 -0
  49. package/dist/core/draft-storage.js +25 -5
  50. package/dist/core/session-projection.d.ts +1 -0
  51. package/dist/core/session-projection.js +3 -2
  52. package/dist/core/session-query.d.ts +8 -0
  53. package/dist/core/session-query.js +13 -11
  54. package/dist/core/session-view-state.d.ts +2 -4
  55. package/dist/core/session-view-state.js +27 -9
  56. package/dist/core/tool-groups.d.ts +3 -0
  57. package/dist/core/tool-groups.js +37 -1
  58. package/dist/core/tool-view.d.ts +6 -0
  59. package/dist/core/tool-view.js +33 -0
  60. package/dist/core/use-timeline-item-key.d.ts +3 -4
  61. package/dist/core/use-timeline-item-key.js +8 -14
  62. package/dist/headless.d.ts +10 -5
  63. package/dist/headless.js +9 -4
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.js +3 -0
  66. package/dist/parakeet.d.ts +6 -2
  67. package/dist/parakeet.js +24 -17
  68. package/dist/store/types.d.ts +14 -1
  69. package/dist/styles.css +911 -162
  70. package/dist/use-approval-awaiting.d.ts +22 -0
  71. package/dist/use-approval-awaiting.js +81 -0
  72. package/dist/use-decision.d.ts +20 -0
  73. package/dist/use-decision.js +79 -0
  74. package/docs/api/commands/slash.md +30 -26
  75. package/docs/api/headless.md +917 -54
  76. package/docs/api/index.md +166 -5
  77. package/package.json +17 -8
  78. package/src/completion-menu.css +72 -0
  79. package/src/composer-shell.css +125 -0
  80. package/src/styles.css +99 -53
  81. package/dist/components/WaitingNotice.d.ts +0 -7
  82. package/dist/components/WaitingNotice.js +0 -8
package/docs/api/index.md CHANGED
@@ -20,6 +20,64 @@ What the head is doing: at rest, working something out, or talking.
20
20
 
21
21
  ---
22
22
 
23
+ ### ComposerModelKeyProps
24
+
25
+ ```ts
26
+ type ComposerModelKeyProps = Omit<
27
+ KeycapButtonProps,
28
+ "icon" | "readout" | "label"
29
+ > &
30
+ object;
31
+ ```
32
+
33
+ A model label on the shared native key; callers own selection and menus.
34
+
35
+ #### Type Declaration
36
+
37
+ | Name | Type | Description |
38
+ | ------- | -------- | ------------------------------------------------------------------------ |
39
+ | `label` | `string` | Friendly catalog name, or the real model identity when no name is known. |
40
+
41
+ ---
42
+
43
+ ### ComposerShellRow
44
+
45
+ ```ts
46
+ type ComposerShellRow = Readonly<{
47
+ controls: ReactNode;
48
+ action: ReactNode;
49
+ status?: ReactNode;
50
+ readout?: ReactNode;
51
+ items: readonly StatusTrayItem[];
52
+ openId: string | null;
53
+ onOpenChange: (id) => void;
54
+ }>;
55
+ ```
56
+
57
+ App-owned controls and tray contents; Parakeet owns their single row.
58
+
59
+ ---
60
+
61
+ ### ComposerShellProps
62
+
63
+ ```ts
64
+ type ComposerShellProps = HTMLAttributes<HTMLDivElement> & object;
65
+ ```
66
+
67
+ Content slots for the shared chat and generation composer surface.
68
+
69
+ #### Type Declaration
70
+
71
+ | Name | Type | Description |
72
+ | -------------- | --------------------------------------- | ----------------------------------------------------------------- |
73
+ | `input` | `ReactNode` | Draft field or decision surface, using the shared input geometry. |
74
+ | `attachments?` | `ReactNode` | Optional draft attachments rendered by the Composer primitive. |
75
+ | `action?` | `ReactNode` | Retained field-and-Send mode without an internal control row. |
76
+ | `menu?` | `ReactNode` | Optional completion menu anchored to this shell. |
77
+ | `row?` | [`ComposerShellRow`](#composershellrow) | Omit while a decision owns the input and its own actions. |
78
+
79
+ ---
80
+
23
81
  ### InteractionPanelProps
24
82
 
25
83
  ```ts
@@ -147,12 +205,13 @@ type ComposerController = Readonly<{
147
205
  recall: () => Promise<QueuedRecallOutcome>;
148
206
  checkpointDraft: () => ParakeetDraftCheckpoint;
149
207
  failure: "admission" | "failed" | "cancelled" | "interrupted" | undefined;
150
- admissionError: "queue_full" | undefined;
208
+ admissionError: "offline_queue_full" | "queue_full" | undefined;
151
209
  retry: () => void;
152
210
  dismissFailed: (requestId) => void;
153
211
  send: (delivery?) => void;
154
212
  submitCommand: (run) => Promise<WhistleExecutionOutcome | undefined>;
155
213
  setDraft: (value) => void;
214
+ setImages: (images) => void;
156
215
  }>;
157
216
  ```
158
217
 
@@ -231,6 +290,7 @@ Durable owner identity, independent of the current service endpoint.
231
290
  type ParakeetDraftStorage = Readonly<{
232
291
  getItem: (key) => string | null;
233
292
  setItem: (key, value) => void;
293
+ removeItem: (key) => void;
234
294
  }>;
235
295
  ```
236
296
 
@@ -463,6 +523,7 @@ type ParakeetToolCallView = Readonly<{
463
523
  exitCode?: number;
464
524
  error?: string;
465
525
  sections: readonly ParakeetToolCallSection[];
526
+ live?: ParakeetToolItem["live"];
466
527
  }>;
467
528
  ```
468
529
 
@@ -494,6 +555,7 @@ type ParakeetProps = Readonly<{
494
555
  clients?: readonly ClientEntryV1[];
495
556
  composerActionVariant?: "primary" | "outline";
496
557
  renderToolActions?: (item) => ReactNode;
558
+ claimsToolMedia?: (item) => boolean;
497
559
  renderAssistantAttachment?: (text) => ReactNode;
498
560
  formatAssistantText?: (text) => string;
499
561
  onLink?: (href) => boolean;
@@ -515,6 +577,7 @@ type ParakeetViewProps = Readonly<{
515
577
  visitor?: ParakeetVisitor;
516
578
  composerActionVariant?: "primary" | "outline";
517
579
  renderToolActions?: (item) => ReactNode;
580
+ claimsToolMedia?: (item) => boolean;
518
581
  renderAssistantAttachment?: (text) => ReactNode;
519
582
  formatAssistantText?: (text) => string;
520
583
  onLink?: (href) => boolean;
@@ -558,6 +621,7 @@ type ParakeetSessionCommand = {
558
621
  | Readonly<{
559
622
  status: "accepted";
560
623
  commandId: string;
624
+ sessionId?: string;
561
625
  }>
562
626
  | Readonly<{
563
627
  status: "recorded";
@@ -665,6 +729,7 @@ Return the owner-issued address of a forked Session.
665
729
  | Readonly<{
666
730
  status: "accepted";
667
731
  commandId: string;
732
+ sessionId?: string;
668
733
  }>
669
734
  | Readonly<{
670
735
  status: "recorded";
@@ -693,9 +758,10 @@ Dispatch a typed command without inventing an admission result.
693
758
  ##### Returns
694
759
 
695
760
  `Promise`\< \| `Readonly`\<\{ `status`: `"accepted"`; `commandId`: `string`;
696
- \}\> \| `Readonly`\<\{ `status`: `"recorded"`; \}\> \| `Readonly`\<\{ `status`:
697
- `"too_late"`; `commandId`: `string`; \}\> \| `Readonly`\<\{ `status`:
698
- `"unknown"`; \}\> \| `Readonly`\<\{ `sessionId`: `string`; \}\> \| `undefined`\>
761
+ `sessionId?`: `string`; \}\> \| `Readonly`\<\{ `status`: `"recorded"`; \}\> \|
762
+ `Readonly`\<\{ `status`: `"too_late"`; `commandId`: `string`; \}\> \|
763
+ `Readonly`\<\{ `status`: `"unknown"`; \}\> \| `Readonly`\<\{ `sessionId`:
764
+ `string`; \}\> \| `undefined`\>
699
765
 
700
766
  ---
701
767
 
@@ -748,6 +814,9 @@ type ParakeetAssistantMessageItem = Readonly<{
748
814
  pending: boolean;
749
815
  at?: number;
750
816
  text: string;
817
+ providerError?: string;
818
+ errorDetail?: string;
819
+ repeatCount?: number;
751
820
  thinking?: string;
752
821
  usage?: Readonly<{
753
822
  cost: number;
@@ -772,6 +841,11 @@ type ParakeetToolItem = Readonly<{
772
841
  data?: SessionMessage["data"];
773
842
  startedAt?: number;
774
843
  status: "completed" | "error" | "running" | "unknown";
844
+ live?: Readonly<{
845
+ lines: readonly string[];
846
+ droppedBytes: number;
847
+ revision: number;
848
+ }>;
775
849
  }>;
776
850
  ```
777
851
 
@@ -923,6 +997,20 @@ ready. The live canvas stays mounted and is paused unless `thinking` or
923
997
 
924
998
  ---
925
999
 
1000
+ ### ComposerModelKey
1001
+
1002
+ ```ts
1003
+ const ComposerModelKey: ForwardRefExoticComponent<
1004
+ Omit<KeycapButtonProps, "label" | "icon" | "readout"> &
1005
+ object &
1006
+ RefAttributes<HTMLButtonElement>
1007
+ >;
1008
+ ```
1009
+
1010
+ The same model face and chevron in chat and generation composers.
1011
+
1012
+ ---
1013
+
926
1014
  ### ShiitakeAvatar
927
1015
 
928
1016
  ```ts
@@ -968,6 +1056,72 @@ Defaults only, with no reader choices.
968
1056
 
969
1057
  ## Functions
970
1058
 
1059
+ ### composerSendState()
1060
+
1061
+ ```ts
1062
+ function composerSendState(__namedParameters): SendActionState;
1063
+ ```
1064
+
1065
+ One input-to-action rule for both Apps; Caps owns the resulting key's look.
1066
+
1067
+ #### Parameters
1068
+
1069
+ | Parameter | Type | Description |
1070
+ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
1071
+ | `__namedParameters` | \{ `draft`: `string`; `hasAttachments?`: `boolean`; `busy`: `boolean`; `queueWhileBusy?`: `boolean`; `blocked?`: `boolean`; \} | - |
1072
+ | `__namedParameters.draft` | `string` | - |
1073
+ | `__namedParameters.hasAttachments?` | `boolean` | - |
1074
+ | `__namedParameters.busy` | `boolean` | - |
1075
+ | `__namedParameters.queueWhileBusy?` | `boolean` | Chat can queue a follow-up; generation stays busy until it settles. |
1076
+ | `__namedParameters.blocked?` | `boolean` | An input owner can temporarily block submission, such as during recall. |
1077
+
1078
+ #### Returns
1079
+
1080
+ `SendActionState`
1081
+
1082
+ ---
1083
+
1084
+ ### ComposerShell()
1085
+
1086
+ ```ts
1087
+ function ComposerShell(__namedParameters): Element;
1088
+ ```
1089
+
1090
+ One field surface and one non-wrapping control row, with Send at its end.
1091
+
1092
+ #### Parameters
1093
+
1094
+ | Parameter | Type |
1095
+ | ------------------- | ------------------------------------------- |
1096
+ | `__namedParameters` | [`ComposerShellProps`](#composershellprops) |
1097
+
1098
+ #### Returns
1099
+
1100
+ `Element`
1101
+
1102
+ ---
1103
+
1104
+ ### useComposerTextareaSize()
1105
+
1106
+ ```ts
1107
+ function useComposerTextareaSize(ref, value): void;
1108
+ ```
1109
+
1110
+ Grow either App's field with its draft; shell CSS owns the height limits.
1111
+
1112
+ #### Parameters
1113
+
1114
+ | Parameter | Type |
1115
+ | --------- | ------------------------------------ |
1116
+ | `ref` | `RefObject`\<`HTMLTextAreaElement`\> |
1117
+ | `value` | `string` |
1118
+
1119
+ #### Returns
1120
+
1121
+ `void`
1122
+
1123
+ ---
1124
+
971
1125
  ### InteractionPanel()
972
1126
 
973
1127
  ```ts
@@ -1174,6 +1328,11 @@ function visibleToolCalls(
1174
1328
  exitCode?: number;
1175
1329
  error?: string;
1176
1330
  sections: readonly ParakeetToolCallSection[];
1331
+ live?: Readonly<{
1332
+ lines: readonly string[];
1333
+ droppedBytes: number;
1334
+ revision: number;
1335
+ }>;
1177
1336
  }>[];
1178
1337
  ```
1179
1338
 
@@ -1193,7 +1352,9 @@ readonly `Readonly`\<\{ `id`: `string`; `kind`:
1193
1352
  `activeVerb`: `string`; `label`: `string`; `paths`: readonly `string`[];
1194
1353
  `status`: `"error"` \| `"unknown"` \| `"running"` \| `"completed"`;
1195
1354
  `durationMs?`: `number`; `exitCode?`: `number`; `error?`: `string`; `sections`:
1196
- readonly [`ParakeetToolCallSection`](#parakeettoolcallsection)[]; \}\>[]
1355
+ readonly [`ParakeetToolCallSection`](#parakeettoolcallsection)[]; `live?`:
1356
+ `Readonly`\<\{ `lines`: readonly `string`[]; `droppedBytes`: `number`;
1357
+ `revision`: `number`; \}\>; \}\>[]
1197
1358
 
1198
1359
  ---
1199
1360
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/parakeet",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "private": false,
6
6
  "description": "Standalone React composer for a typed Shiitake Session",
@@ -31,6 +31,12 @@
31
31
  "types": "./dist/commands/slash.d.ts",
32
32
  "import": "./dist/commands/slash.js"
33
33
  },
34
+ "./completion-menu": {
35
+ "types": "./dist/components/CompletionMenu.d.ts",
36
+ "import": "./dist/components/CompletionMenu.js"
37
+ },
38
+ "./completion-menu.css": "./src/completion-menu.css",
39
+ "./composer-shell.css": "./src/composer-shell.css",
34
40
  "./styles.css": "./dist/styles.css",
35
41
  "./tailwind.css": "./src/styles.css"
36
42
  },
@@ -39,6 +45,8 @@
39
45
  "README.md",
40
46
  "LICENSE",
41
47
  "src/styles.css",
48
+ "src/completion-menu.css",
49
+ "src/composer-shell.css",
42
50
  "docs/api"
43
51
  ],
44
52
  "peerDependencies": {
@@ -47,17 +55,18 @@
47
55
  "react-dom": "^18.2.0 || ^19.2.0"
48
56
  },
49
57
  "dependencies": {
50
- "@fungi.computer/agar": "0.4.0",
51
- "@fungi.computer/bird-dog": "0.2.1",
58
+ "@earendil-works/pi-ai": "1.3.0",
59
+ "@fungi.computer/agar": "0.6.0",
60
+ "@fungi.computer/bird-dog": "0.3.1",
52
61
  "@fungi.computer/cairn": "0.1.0",
53
- "@fungi.computer/caps": "0.3.1",
62
+ "@fungi.computer/caps": "0.5.0",
54
63
  "@fungi.computer/gills": "0.2.0",
55
- "@fungi.computer/knapsack": "0.3.1",
56
- "@fungi.computer/shiitake": "0.5.0",
64
+ "@fungi.computer/knapsack": "0.4.1",
65
+ "@fungi.computer/shiitake": "0.7.0",
57
66
  "@fungi.computer/sigils": "0.2.0",
58
67
  "@fungi.computer/sprite": "0.2.0",
59
- "@fungi.computer/sprite-zdog": "0.2.0",
60
- "@fungi.computer/whistle": "0.2.0",
68
+ "@fungi.computer/sprite-zdog": "0.3.0",
69
+ "@fungi.computer/whistle": "0.3.0",
61
70
  "@tanstack/markdown": "0.0.12",
62
71
  "@tanstack/react-virtual": "3.14.10",
63
72
  "diff": "8.0.4",
@@ -0,0 +1,72 @@
1
+ /* The shared completion menu's look: Grove's slash commands and Prints' slash and @character menus. */
2
+
3
+ /*
4
+ * The menu joins the composer surface instead of floating as a second box:
5
+ * same width and inset, flush on its top edge, and the surface's own top
6
+ * border is the one line between them. --parakeet-completion-inset is the
7
+ * distance from the menu's containing block to the surface's outer edge: an
8
+ * anchor's padding or a field's own containing box. ComposerShell supplies
9
+ * zero inset; there is no Prints-specific negative card-border offset.
10
+ * --parakeet-completion-face and --parakeet-completion-edge carry the
11
+ * surface's own background and border colour, so the two read as one.
12
+ */
13
+ .caps-popover[data-parakeet-slash][data-side="top"] {
14
+ inset-inline: var(--parakeet-completion-inset, 0);
15
+ bottom: calc(100% - var(--parakeet-completion-inset, 0px));
16
+ border-color: var(
17
+ --parakeet-completion-edge,
18
+ color-mix(in oklab, var(--color-base-content) 16%, transparent)
19
+ );
20
+ border-bottom-width: 0;
21
+ background: var(--parakeet-completion-face, var(--color-base-200));
22
+ border-end-start-radius: 0;
23
+ border-end-end-radius: 0;
24
+ box-shadow: none;
25
+ }
26
+ .parakeet-slash-menu .parakeet-slash-label {
27
+ min-width: 7rem;
28
+ font-family: var(--font-mono);
29
+ font-weight: 600;
30
+ }
31
+
32
+ .parakeet-slash-match {
33
+ background: none;
34
+ color: var(--color-primary);
35
+ }
36
+
37
+ .parakeet-slash-detail {
38
+ flex: 1;
39
+ min-width: 0;
40
+ overflow: hidden;
41
+ text-overflow: ellipsis;
42
+ white-space: nowrap;
43
+ color: var(--stipe-fg-muted);
44
+ }
45
+
46
+ .parakeet-slash-keys {
47
+ font-family: var(--font-mono);
48
+ font-size: 0.65rem;
49
+ color: var(--stipe-fg-muted);
50
+ }
51
+
52
+ .parakeet-slash-hint {
53
+ margin: 0;
54
+ padding: 0.25rem 0.5rem;
55
+ font-family: var(--font-mono);
56
+ font-size: 0.75rem;
57
+ color: var(--stipe-fg-muted);
58
+ }
59
+
60
+ .parakeet-slash-menu [data-disabled="true"] {
61
+ opacity: 0.5;
62
+ }
63
+
64
+ /* A row with a thumbnail centres its text on the thumbnail rather than its top. */
65
+ .parakeet-slash-menu [role="option"]:has(> .parakeet-slash-media) {
66
+ align-items: center;
67
+ }
68
+
69
+ .parakeet-slash-media {
70
+ display: flex;
71
+ flex: none;
72
+ }
@@ -0,0 +1,125 @@
1
+ /* Chat and generation share one surface, field inset and control-row grid.
2
+ Apps supply controls and content, never a second composer layout. */
3
+ .parakeet-composer-anchor {
4
+ --parakeet-completion-inset: 0px;
5
+ --parakeet-completion-face: var(--color-base-200);
6
+ --parakeet-completion-edge: var(--stipe-hairline);
7
+ display: block;
8
+ min-width: 0;
9
+ }
10
+
11
+ .parakeet-composer-anchor:has([data-parakeet-slash])
12
+ > .parakeet-composer-shell {
13
+ border-start-start-radius: 0;
14
+ border-start-end-radius: 0;
15
+ }
16
+
17
+ .parakeet-composer-shell {
18
+ padding: var(--spacing-sm);
19
+ container-type: inline-size;
20
+ }
21
+
22
+ .parakeet-composer-shell .caps-composer-input {
23
+ padding: var(--spacing-xs) var(--spacing-sm) 0;
24
+ }
25
+
26
+ .parakeet-composer-shell .caps-composer-input textarea {
27
+ min-height: 3rem;
28
+ max-height: 160px;
29
+ padding: var(--spacing-xs) 0;
30
+ resize: none;
31
+ overflow-x: hidden;
32
+ overflow-y: auto;
33
+ white-space: pre-wrap;
34
+ overflow-wrap: break-word;
35
+ font-family: var(--font-sans);
36
+ font-size: var(--text-base);
37
+ line-height: 1.6;
38
+ }
39
+
40
+ .parakeet-composer-shell .parakeet-composer-row {
41
+ --caps-status-tray-row-wrap: nowrap;
42
+ padding: var(--spacing-xs);
43
+ }
44
+
45
+ .parakeet-composer-row .caps-status-tray-row {
46
+ white-space: nowrap;
47
+ }
48
+
49
+ /* A menu trigger can carry Button's touch minimum as well as its Keycap face.
50
+ The shared row, not either App or the generic Button, owns key geometry. */
51
+ .parakeet-composer-row .caps-keycap-button {
52
+ height: var(--caps-status-tray-key-height);
53
+ min-height: var(--caps-status-tray-key-height);
54
+ }
55
+
56
+ /* Composer keys already disclose through their face and chevron. Keep native
57
+ expanded/pressed semantics without redundant decorative corner lamps. */
58
+ .parakeet-composer-row .caps-keycap-led {
59
+ display: none;
60
+ }
61
+
62
+ .parakeet-composer-row [data-status-tray-chip] {
63
+ min-width: 0;
64
+ }
65
+
66
+ .parakeet-composer-row .caps-status-tray-label,
67
+ .parakeet-composer-row .caps-keycap-button-label {
68
+ min-width: 0;
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ }
73
+
74
+ .parakeet-composer-row .parakeet-composer-model-key {
75
+ --caps-keycap-justify: space-between;
76
+ flex: 0 1 auto;
77
+ min-width: 4.5rem;
78
+ max-width: 220px;
79
+ font-size: var(--text-xs);
80
+ }
81
+
82
+ .parakeet-composer-trailing {
83
+ display: flex;
84
+ align-items: center;
85
+ flex: none;
86
+ gap: var(--spacing-xs);
87
+ margin-inline-start: auto;
88
+ }
89
+
90
+ .parakeet-composer-action {
91
+ display: flex;
92
+ flex: none;
93
+ }
94
+
95
+ .parakeet-composer-readout {
96
+ color: var(--stipe-fg-muted);
97
+ font-size: var(--text-xs);
98
+ line-height: 1;
99
+ font-variant-numeric: tabular-nums;
100
+ white-space: nowrap;
101
+ }
102
+
103
+ .parakeet-composer-row .composer-attention-label {
104
+ @apply sr-only;
105
+ }
106
+
107
+ .parakeet-composer-row .parakeet-composer-status {
108
+ gap: 0;
109
+ }
110
+
111
+ /* The status dot stays beside Send when usage yields to Settings; the model
112
+ label then yields to ellipsis.
113
+ Edge keys never shrink or change rows. The budget is the shell's width:
114
+ Grove's split pane can be narrower at 900px than at 640px. */
115
+ @container (max-width: 34rem) {
116
+ .parakeet-composer-readout {
117
+ display: none;
118
+ }
119
+ }
120
+
121
+ @container (max-width: 26rem) {
122
+ .parakeet-composer-row .parakeet-composer-model-key {
123
+ max-width: 7rem;
124
+ }
125
+ }