@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
@@ -269,10 +269,26 @@ what the person just did is never one: it is an echo and is not announced.
269
269
 
270
270
  ---
271
271
 
272
+ ### ParakeetAwaiting
273
+
274
+ ```ts
275
+ type ParakeetAwaiting = Readonly<{
276
+ items: readonly AwaitingItem[];
277
+ later: ReadonlySet<string>;
278
+ forced: boolean;
279
+ requests: number;
280
+ }>;
281
+ ```
282
+
283
+ The decisions waiting on the person, which the composer takes over for.
284
+
285
+ ---
286
+
272
287
  ### ParakeetInteractionState
273
288
 
274
289
  ```ts
275
290
  type ParakeetInteractionState = Readonly<{
291
+ awaiting: ParakeetAwaiting;
276
292
  open?: ParakeetOpenInteraction;
277
293
  inspection?: Readonly<{
278
294
  entryId: string;
@@ -299,6 +315,12 @@ type ParakeetInteractions = Readonly<{
299
315
  subscribeToasts: (listener) => () => void;
300
316
  attach: (present) => () => void;
301
317
  lastEnd: () => WhistleInteractionEnd["status"] | undefined;
318
+ awaiting: Readonly<{
319
+ add: (item) => () => void;
320
+ remove: (key) => void;
321
+ later: (key) => void;
322
+ focus: () => void;
323
+ }>;
302
324
  }>;
303
325
  ```
304
326
 
@@ -357,12 +379,18 @@ type SlashCommandController = Readonly<{
357
379
  hints: readonly KeyHint[];
358
380
  interactions: ParakeetInteractionState;
359
381
  store: ParakeetInteractions;
382
+ awaiting: AwaitingQueue &
383
+ Readonly<{
384
+ forced: boolean;
385
+ }>;
360
386
  move: (delta) => boolean;
361
387
  highlight: (index) => void;
362
388
  complete: () => boolean;
363
389
  dismiss: () => boolean;
364
390
  submit: (delivery?) => void;
365
391
  choose: (index) => void;
392
+ available: (alias) => boolean;
393
+ runCommand: (alias) => void;
366
394
  }>;
367
395
  ```
368
396
 
@@ -429,6 +457,432 @@ Result of retrying the shared Session observation.
429
457
 
430
458
  ---
431
459
 
460
+ ### ApprovalFacts
461
+
462
+ ```ts
463
+ type ApprovalFacts = Readonly<{
464
+ record: Readonly<{
465
+ recordId: string;
466
+ revision: number;
467
+ requester: Readonly<{
468
+ displayName: string;
469
+ agentId: string | null;
470
+ sessionId: string | null;
471
+ principalId: string;
472
+ }>;
473
+ module: string;
474
+ operation: string;
475
+ access: string;
476
+ description: Readonly<{
477
+ inputBytes: number;
478
+ inputSha256: string;
479
+ }>;
480
+ reversibility: string;
481
+ expiresAt: number;
482
+ }>;
483
+ canAnswer: boolean;
484
+ }>;
485
+ ```
486
+
487
+ The ledger facts an approval card reads; the approvals ledger's own view
488
+ satisfies it.
489
+
490
+ ---
491
+
492
+ ### ApprovalReview
493
+
494
+ ```ts
495
+ type ApprovalReview = Readonly<{
496
+ command: string;
497
+ cwd: string;
498
+ justification: string;
499
+ form: "direct" | "shell";
500
+ kind: "exec" | "extension-install";
501
+ argv?: readonly string[];
502
+ prefix?: readonly string[];
503
+ warning?: string;
504
+ alwaysAllowCoverage?: string;
505
+ alwaysAllowUnavailableReason?: string;
506
+ risk?: Readonly<{
507
+ summary: string;
508
+ detail: string;
509
+ }>;
510
+ }>;
511
+ ```
512
+
513
+ What the host knows about a command the Agent asked to run outside the sandbox.
514
+
515
+ ---
516
+
517
+ ### ApprovalEntry
518
+
519
+ ```ts
520
+ type ApprovalEntry = Readonly<{
521
+ label: string;
522
+ value: string;
523
+ }>;
524
+ ```
525
+
526
+ One labelled value in a card's facts or details.
527
+
528
+ ---
529
+
530
+ ### ApprovalContent
531
+
532
+ ```ts
533
+ type ApprovalContent = Readonly<{
534
+ title: string;
535
+ summary?: string;
536
+ facts?: readonly ApprovalEntry[];
537
+ body?: string;
538
+ bodyLabel?: string;
539
+ details?: readonly ApprovalEntry[];
540
+ }>;
541
+ ```
542
+
543
+ The words an approval prompt carries above its choices.
544
+
545
+ ---
546
+
547
+ ### ApprovalCard
548
+
549
+ ```ts
550
+ type ApprovalCard = Readonly<{
551
+ content: ApprovalContent;
552
+ always?: string;
553
+ confirmation?: ApprovalContent & object;
554
+ confirmWarning?: string;
555
+ confirmYes?: string;
556
+ }>;
557
+ ```
558
+
559
+ Everything one approval shows, and what Always allow would confirm.
560
+
561
+ ---
562
+
563
+ ### ApprovalDecision
564
+
565
+ ```ts
566
+ type ApprovalDecision = "approve" | "deny" | "always-allow";
567
+ ```
568
+
569
+ What the person decided.
570
+
571
+ ---
572
+
573
+ ### ApprovalAnswerInput
574
+
575
+ ```ts
576
+ type ApprovalAnswerInput = Readonly<{
577
+ recordId: string;
578
+ decision: ApprovalDecision;
579
+ expectedRevision: number;
580
+ denialNote?: string;
581
+ }>;
582
+ ```
583
+
584
+ A decision, pinned to the revision the person saw.
585
+
586
+ ---
587
+
588
+ ### ApprovalAnswerResult
589
+
590
+ ```ts
591
+ type ApprovalAnswerResult = Readonly<{
592
+ kind: string;
593
+ reason?: string;
594
+ }>;
595
+ ```
596
+
597
+ How the owner took an answer; a refusal names its reason.
598
+
599
+ ---
600
+
601
+ ### ApprovalSource
602
+
603
+ ```ts
604
+ type ApprovalSource = Readonly<{
605
+ snapshot: () => ApprovalFacts | undefined;
606
+ subscribe: (listener) => () => void;
607
+ review?: ApprovalReview;
608
+ answer: (input) => Promise<ApprovalAnswerResult>;
609
+ family?: Readonly<{
610
+ label: string;
611
+ enable: () => Promise<boolean>;
612
+ }>;
613
+ }>;
614
+ ```
615
+
616
+ Where approvals come from and where answers go.
617
+
618
+ ---
619
+
620
+ ### ApprovalAnswered
621
+
622
+ ```ts
623
+ type ApprovalAnswered = Readonly<{
624
+ kind: "answered";
625
+ }>;
626
+ ```
627
+
628
+ The answer was sent.
629
+
630
+ ---
631
+
632
+ ### ApprovalRefused
633
+
634
+ ```ts
635
+ type ApprovalRefused = Readonly<{
636
+ kind: "refused";
637
+ message: string;
638
+ }>;
639
+ ```
640
+
641
+ The answer was refused, or could not be sent.
642
+
643
+ ---
644
+
645
+ ### ApprovalAbandoned
646
+
647
+ ```ts
648
+ type ApprovalAbandoned = Readonly<{
649
+ kind: "abandoned";
650
+ }>;
651
+ ```
652
+
653
+ The record changed or went away before an answer was sent.
654
+
655
+ ---
656
+
657
+ ### ApprovalOutcome
658
+
659
+ ```ts
660
+ type ApprovalOutcome = ApprovalAnswered | ApprovalRefused | ApprovalAbandoned;
661
+ ```
662
+
663
+ How asking ended.
664
+
665
+ ---
666
+
667
+ ### AwaitingKind
668
+
669
+ ```ts
670
+ type AwaitingKind = "question" | "approval";
671
+ ```
672
+
673
+ What the Agent needs from the person.
674
+
675
+ ---
676
+
677
+ ### AwaitingItem
678
+
679
+ ```ts
680
+ type AwaitingItem = Readonly<{
681
+ key: string;
682
+ kind: AwaitingKind;
683
+ arrivedAt: number;
684
+ host: WhistleInteractionHost;
685
+ }>;
686
+ ```
687
+
688
+ One decision waiting for the person. Its `host` is the renderer-neutral
689
+ conversation that holds the current `decision` prompt and takes the answer.
690
+
691
+ ---
692
+
693
+ ### AwaitingQueue
694
+
695
+ ```ts
696
+ type AwaitingQueue = Readonly<{
697
+ items: readonly AwaitingItem[];
698
+ current?: AwaitingItem;
699
+ position: number;
700
+ total: number;
701
+ }>;
702
+ ```
703
+
704
+ Which item the composer shows and where it stands among all of them.
705
+
706
+ ---
707
+
708
+ ### DecisionPrompt
709
+
710
+ ```ts
711
+ type DecisionPrompt = WhistlePromptOf<"decision">;
712
+ ```
713
+
714
+ The decision prompt both renderers draw.
715
+
716
+ ---
717
+
718
+ ### DecisionPhase
719
+
720
+ ```ts
721
+ type DecisionPhase = "choose" | "other" | "confirm" | "sending" | "refused";
722
+ ```
723
+
724
+ Where one decision is in its short life.
725
+
726
+ ---
727
+
728
+ ### DecisionState
729
+
730
+ ```ts
731
+ type DecisionState = Readonly<{
732
+ highlight: number;
733
+ toggled: ReadonlySet<string>;
734
+ other: string;
735
+ phase: DecisionPhase;
736
+ refusal?: string;
737
+ details: boolean;
738
+ }>;
739
+ ```
740
+
741
+ Everything the reducer remembers about one decision prompt.
742
+
743
+ ---
744
+
745
+ ### DecisionIntent
746
+
747
+ ```ts
748
+ type DecisionIntent =
749
+ | Readonly<{
750
+ type: "move";
751
+ delta: -1 | 1;
752
+ }>
753
+ | Readonly<{
754
+ type: "pick";
755
+ number: number;
756
+ }>
757
+ | Readonly<{
758
+ type: "toggle";
759
+ }>
760
+ | Readonly<{
761
+ type: "type";
762
+ text: string;
763
+ }>
764
+ | Readonly<{
765
+ type: "append";
766
+ text: string;
767
+ }>
768
+ | Readonly<{
769
+ type: "enter";
770
+ }>
771
+ | Readonly<{
772
+ type: "escape";
773
+ }>
774
+ | Readonly<{
775
+ type: "details";
776
+ }>
777
+ | Readonly<{
778
+ type: "refused";
779
+ message: string;
780
+ }>;
781
+ ```
782
+
783
+ What the person did, independent of which key or click did it.
784
+
785
+ ---
786
+
787
+ ### DecisionEffect
788
+
789
+ ```ts
790
+ type DecisionEffect =
791
+ | Readonly<{
792
+ type: "answer";
793
+ selected: string[];
794
+ text?: string;
795
+ }>
796
+ | Readonly<{
797
+ type: "later";
798
+ }>
799
+ | Readonly<{
800
+ type: "back";
801
+ }>;
802
+ ```
803
+
804
+ What the owner of the decision must now do.
805
+
806
+ ---
807
+
808
+ ### DecisionOutcome
809
+
810
+ ```ts
811
+ type DecisionOutcome = Readonly<{
812
+ state: DecisionState;
813
+ effect?: DecisionEffect;
814
+ }>;
815
+ ```
816
+
817
+ The next state, and what the decision's owner must do about the intent.
818
+
819
+ ---
820
+
821
+ ### DecisionRowView
822
+
823
+ ```ts
824
+ type DecisionRowView = Readonly<{
825
+ index: number;
826
+ kind: "option" | "other";
827
+ marker: string;
828
+ label: string;
829
+ description?: string;
830
+ recommended: boolean;
831
+ highlighted: boolean;
832
+ toggled: boolean;
833
+ destructive: boolean;
834
+ caption: string;
835
+ text: string;
836
+ }>;
837
+ ```
838
+
839
+ One drawn row of a decision.
840
+
841
+ ---
842
+
843
+ ### DecisionView
844
+
845
+ ```ts
846
+ type DecisionView = Readonly<{
847
+ kind: AwaitingKind;
848
+ label: string;
849
+ title: string;
850
+ counter?: string;
851
+ summary?: string;
852
+ facts: readonly Readonly<{
853
+ label: string;
854
+ value: string;
855
+ }>[];
856
+ body?: string;
857
+ bodyLabel?: string;
858
+ details: readonly Readonly<{
859
+ label: string;
860
+ value: string;
861
+ }>[];
862
+ detailsOpen: boolean;
863
+ rows: readonly DecisionRowView[];
864
+ other?: Readonly<{
865
+ label: string;
866
+ placeholder?: string;
867
+ text: string;
868
+ focused: boolean;
869
+ maxLength: number;
870
+ }>;
871
+ multiple: boolean;
872
+ phase: DecisionPhase;
873
+ canSend: boolean;
874
+ status?: Readonly<{
875
+ tone: "info" | "error";
876
+ text: string;
877
+ }>;
878
+ hints: readonly KeyHint[];
879
+ }>;
880
+ ```
881
+
882
+ What both renderers must draw for one decision.
883
+
884
+ ---
885
+
432
886
  ### ClientContribution
433
887
 
434
888
  ```ts
@@ -621,6 +1075,20 @@ type ParakeetSessionCommandOptions = Readonly<{
621
1075
 
622
1076
  Shared Session actions with optional human presentation callbacks.
623
1077
 
1078
+ ---
1079
+
1080
+ ### DecisionController
1081
+
1082
+ ```ts
1083
+ type DecisionController = Readonly<{
1084
+ view: DecisionView | undefined;
1085
+ dispatch: (intent) => void;
1086
+ later: () => void;
1087
+ }>;
1088
+ ```
1089
+
1090
+ One decision being answered, ready for a renderer to draw and drive.
1091
+
624
1092
  ## Variables
625
1093
 
626
1094
  ### toolKindSigils
@@ -882,11 +1350,11 @@ Ordinary advertised actions over the current admitted rows and observation.
882
1350
 
883
1351
  #### Returns
884
1352
 
885
- | Name | Type | Description |
886
- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
887
- | `state` | `ReadonlyMap`\<\{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; \}, `Readonly`\<\{ `pending`: `boolean`; `error?`: `string`; \}\>\> | Current Session-owned state of admitted action intents. |
888
- | `enabled` | `boolean` | Observation is live and this Session's action owner is attached. |
889
- | `execute()` | (`entryId`, `action`, `waiting`) => `Promise`\<`void`\> | Execute an admitted intent through its owning advertised command. |
1353
+ | Name | Type | Description |
1354
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
1355
+ | `state` | `ReadonlyMap`\<\{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; `awaiting?`: `"question"`; \}, `Readonly`\<\{ `pending`: `boolean`; `error?`: `string`; \}\>\> | Current Session-owned state of admitted action intents. |
1356
+ | `enabled` | `boolean` | Observation is live and this Session's action owner is attached. |
1357
+ | `execute()` | (`entryId`, `action`, `waiting`) => `Promise`\<`void`\> | Execute an admitted intent through its owning advertised command. |
890
1358
 
891
1359
  ---
892
1360
 
@@ -907,12 +1375,12 @@ command: a new extension's catalog appears as new commands.
907
1375
 
908
1376
  #### Parameters
909
1377
 
910
- | Parameter | Type | Description |
911
- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
912
- | `runtime` | `Pick`\<`WhistleRuntime`, `"contribute"`\> | - |
913
- | `session` | `Pick`\<[`ParakeetSession`](index.md#parakeetsession), `"extension"`\> | - |
914
- | `contributions` | () => readonly `Readonly`\<\{ `entryId`: `string`; `value`: \{ `chips`: readonly `object`[]; `panel`: readonly `object`[]; `timeline`: \{ `cells`: readonly `object`[]; `omitted`: `number`; \}; `waiting`: \| \{ `summary`: `string`; `cancel`: \{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; \}; \} \| `null`; \}; \}\>[] | Current admitted panels that own unanswered prompts. |
915
- | `onInspect?` | (`entryId`, `commandId`) => `void` | - |
1378
+ | Parameter | Type | Description |
1379
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
1380
+ | `runtime` | `Pick`\<`WhistleRuntime`, `"contribute"`\> | - |
1381
+ | `session` | `Pick`\<[`ParakeetSession`](index.md#parakeetsession), `"extension"`\> | - |
1382
+ | `contributions` | () => readonly `Readonly`\<\{ `entryId`: `string`; `value`: \{ `chips`: readonly `object`[]; `panel`: readonly `object`[]; `timeline`: \{ `cells`: readonly `object`[]; `omitted`: `number`; \}; `waiting`: \| \{ `summary`: `string`; `cancel`: \{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; `awaiting?`: `"question"`; \}; \} \| `null`; \}; \}\>[] | Current admitted panels that own unanswered prompts. |
1383
+ | `onInspect?` | (`entryId`, `commandId`) => `void` | - |
916
1384
 
917
1385
  #### Returns
918
1386
 
@@ -1277,6 +1745,20 @@ Read the Session's extension slots, including advertised command catalogs.
1277
1745
 
1278
1746
  ---
1279
1747
 
1748
+ ### useLastSessionReplyAt()
1749
+
1750
+ ```ts
1751
+ function useLastSessionReplyAt(): number | undefined;
1752
+ ```
1753
+
1754
+ Time of the last delivered watch snapshot or frame, not an SSE comment.
1755
+
1756
+ #### Returns
1757
+
1758
+ `number` \| `undefined`
1759
+
1760
+ ---
1761
+
1280
1762
  ### useClientContributions()
1281
1763
 
1282
1764
  ```ts
@@ -1297,6 +1779,7 @@ function useClientContributions(): readonly Readonly<{
1297
1779
  input?: {
1298
1780
  [key: string]: Json;
1299
1781
  };
1782
+ awaiting?: "question";
1300
1783
  };
1301
1784
  } | null;
1302
1785
  };
@@ -1311,7 +1794,7 @@ readonly `Readonly`\<\{ `entryId`: `string`; `value`: \{ `chips`: readonly
1311
1794
  `object`[]; `panel`: readonly `object`[]; `timeline`: \{ `cells`: readonly
1312
1795
  `object`[]; `omitted`: `number`; \}; `waiting`: \| \{ `summary`: `string`;
1313
1796
  `cancel`: \{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`:
1314
- `string`\]: `Json`; \}; \}; \} \| `null`; \}; \}\>[]
1797
+ `string`\]: `Json`; \}; `awaiting?`: `"question"`; \}; \} \| `null`; \}; \}\>[]
1315
1798
 
1316
1799
  ---
1317
1800
 
@@ -1329,6 +1812,75 @@ The selected Session's ordinary command interaction owner.
1329
1812
 
1330
1813
  ---
1331
1814
 
1815
+ ### approvalCardCopy()
1816
+
1817
+ ```ts
1818
+ function approvalCardCopy(view, review, options): ApprovalCard;
1819
+ ```
1820
+
1821
+ The words of one approval. A connected tool gets its effect; a command the Agent
1822
+ wants to run outside the sandbox gets its folder, reason and rule. `home`
1823
+ shortens paths inside it to `~`; `now` dates the expiry.
1824
+
1825
+ #### Parameters
1826
+
1827
+ | Parameter | Type |
1828
+ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1829
+ | `view` | [`ApprovalFacts`](#approvalfacts) |
1830
+ | `review` | \| `Readonly`\<\{ `command`: `string`; `cwd`: `string`; `justification`: `string`; `form`: `"direct"` \| `"shell"`; `kind`: `"exec"` \| `"extension-install"`; `argv?`: readonly `string`[]; `prefix?`: readonly `string`[]; `warning?`: `string`; `alwaysAllowCoverage?`: `string`; `alwaysAllowUnavailableReason?`: `string`; `risk?`: `Readonly`\<\{ `summary`: `string`; `detail`: `string`; \}\>; \}\> \| `undefined` |
1831
+ | `options` | `Readonly`\<\{ `width`: `number`; `home`: `string`; `now`: `number`; \}\> |
1832
+
1833
+ #### Returns
1834
+
1835
+ [`ApprovalCard`](#approvalcard)
1836
+
1837
+ ---
1838
+
1839
+ ### approvalRefusal()
1840
+
1841
+ ```ts
1842
+ function approvalRefusal(reason, decision): string;
1843
+ ```
1844
+
1845
+ What an answer was refused for, in words for the person.
1846
+
1847
+ #### Parameters
1848
+
1849
+ | Parameter | Type |
1850
+ | ---------- | ------------------------------------------- |
1851
+ | `reason` | `string` |
1852
+ | `decision` | `"approve"` \| `"deny"` \| `"always-allow"` |
1853
+
1854
+ #### Returns
1855
+
1856
+ `string`
1857
+
1858
+ ---
1859
+
1860
+ ### askApproval()
1861
+
1862
+ ```ts
1863
+ function askApproval(interaction, input): Promise<ApprovalOutcome>;
1864
+ ```
1865
+
1866
+ Ask the person about one approval through a conversation's decision prompts,
1867
+ then send the answer. Nothing is sent until Enter answers, Always allow and the
1868
+ family rule each need a second, separate confirmation whose default is Back, and
1869
+ an answer is only sent while the record is still the one that was shown.
1870
+
1871
+ #### Parameters
1872
+
1873
+ | Parameter | Type |
1874
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1875
+ | `interaction` | `WhistleInteraction` |
1876
+ | `input` | `Readonly`\<\{ `view`: [`ApprovalFacts`](#approvalfacts); `source`: [`ApprovalSource`](#approvalsource); `home`: `string`; `width`: `number`; `now`: `number`; `noteLimit`: `number`; `stillCurrent`: () => `boolean`; `onFailure`: (`cause`) => `void`; \}\> |
1877
+
1878
+ #### Returns
1879
+
1880
+ `Promise`\<[`ApprovalOutcome`](#approvaloutcome)\>
1881
+
1882
+ ---
1883
+
1332
1884
  ### assistantMessageVisible()
1333
1885
 
1334
1886
  ```ts
@@ -1349,6 +1901,142 @@ One rule for whether an assistant row has content either renderer shows.
1349
1901
 
1350
1902
  ---
1351
1903
 
1904
+ ### awaitingQueue()
1905
+
1906
+ ```ts
1907
+ function awaitingQueue(items, later): AwaitingQueue;
1908
+ ```
1909
+
1910
+ Order the items by arrival and pick the one the composer shows. A postponed item
1911
+ leaves the composer but stays counted: it is the footer row.
1912
+
1913
+ #### Parameters
1914
+
1915
+ | Parameter | Type |
1916
+ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
1917
+ | `items` | readonly `Readonly`\<\{ `key`: `string`; `kind`: [`AwaitingKind`](#awaitingkind); `arrivedAt`: `number`; `host`: `WhistleInteractionHost`; \}\>[] |
1918
+ | `later` | `ReadonlySet`\<`string`\> |
1919
+
1920
+ #### Returns
1921
+
1922
+ [`AwaitingQueue`](#awaitingqueue)
1923
+
1924
+ ---
1925
+
1926
+ ### awaitingTakeover()
1927
+
1928
+ ```ts
1929
+ function awaitingTakeover(
1930
+ awaiting,
1931
+ draft,
1932
+ ):
1933
+ | Readonly<{
1934
+ key: string;
1935
+ kind: AwaitingKind;
1936
+ arrivedAt: number;
1937
+ host: WhistleInteractionHost;
1938
+ }>
1939
+ | undefined;
1940
+ ```
1941
+
1942
+ The item that owns the composer right now. An empty draft is taken over; a draft
1943
+ with text is never, unless the person asked for the decision.
1944
+
1945
+ #### Parameters
1946
+
1947
+ | Parameter | Type |
1948
+ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1949
+ | `awaiting` | `Readonly`\<\{ `items`: readonly `Readonly`\<\{ `key`: `string`; `kind`: [`AwaitingKind`](#awaitingkind); `arrivedAt`: `number`; `host`: `WhistleInteractionHost`; \}\>[]; `current?`: `Readonly`\<\{ `key`: `string`; `kind`: [`AwaitingKind`](#awaitingkind); `arrivedAt`: `number`; `host`: `WhistleInteractionHost`; \}\>; `position`: `number`; `total`: `number`; \}\> & `Readonly`\<\{ `forced`: `boolean`; \}\> |
1950
+ | `draft` | `string` |
1951
+
1952
+ #### Returns
1953
+
1954
+ \| `Readonly`\<\{ `key`: `string`; `kind`: [`AwaitingKind`](#awaitingkind);
1955
+ `arrivedAt`: `number`; `host`: `WhistleInteractionHost`; \}\> \| `undefined`
1956
+
1957
+ ---
1958
+
1959
+ ### initialDecisionState()
1960
+
1961
+ ```ts
1962
+ function initialDecisionState(): DecisionState;
1963
+ ```
1964
+
1965
+ The state a decision starts in.
1966
+
1967
+ #### Returns
1968
+
1969
+ [`DecisionState`](#decisionstate)
1970
+
1971
+ ---
1972
+
1973
+ ### reduceDecision()
1974
+
1975
+ ```ts
1976
+ function reduceDecision(state, intent, prompt): DecisionOutcome;
1977
+ ```
1978
+
1979
+ The one set of rules both renderers follow. Number keys only move the highlight,
1980
+ Enter is the only way to answer, and Esc steps back one level until it reaches
1981
+ the option list, where it postpones the decision.
1982
+
1983
+ #### Parameters
1984
+
1985
+ | Parameter | Type |
1986
+ | --------- | ----------------------------------- |
1987
+ | `state` | [`DecisionState`](#decisionstate) |
1988
+ | `intent` | [`DecisionIntent`](#decisionintent) |
1989
+ | `prompt` | `object` & `object` |
1990
+
1991
+ #### Returns
1992
+
1993
+ [`DecisionOutcome`](#decisionoutcome)
1994
+
1995
+ ---
1996
+
1997
+ ### decisionView()
1998
+
1999
+ ```ts
2000
+ function decisionView(state, prompt, context): DecisionView;
2001
+ ```
2002
+
2003
+ Project a decision's state into the view every renderer draws.
2004
+
2005
+ #### Parameters
2006
+
2007
+ | Parameter | Type |
2008
+ | --------- | ----------------------------------------------------------------------------------------------------- |
2009
+ | `state` | [`DecisionState`](#decisionstate) |
2010
+ | `prompt` | `object` & `object` |
2011
+ | `context` | `Readonly`\<\{ `kind`: [`AwaitingKind`](#awaitingkind); `position`: `number`; `total`: `number`; \}\> |
2012
+
2013
+ #### Returns
2014
+
2015
+ [`DecisionView`](#decisionview)
2016
+
2017
+ ---
2018
+
2019
+ ### decisionViewText()
2020
+
2021
+ ```ts
2022
+ function decisionViewText(view): readonly string[];
2023
+ ```
2024
+
2025
+ The plain strings a renderer must show for a view, in reading order. The
2026
+ lockstep tests hold every surface to this list.
2027
+
2028
+ #### Parameters
2029
+
2030
+ | Parameter | Type |
2031
+ | --------- | ------------------------------- |
2032
+ | `view` | [`DecisionView`](#decisionview) |
2033
+
2034
+ #### Returns
2035
+
2036
+ readonly `string`[]
2037
+
2038
+ ---
2039
+
1352
2040
  ### placeClientTimeline()
1353
2041
 
1354
2042
  ```ts
@@ -1359,11 +2047,11 @@ Fixed positions and command anchors follow loaded history, never event time.
1359
2047
 
1360
2048
  #### Parameters
1361
2049
 
1362
- | Parameter | Type |
1363
- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1364
- | `entries` | readonly `Readonly`\<\{ `entryId`: `string`; `value`: \{ `chips`: readonly `object`[]; `panel`: readonly `object`[]; `timeline`: \{ `cells`: readonly `object`[]; `omitted`: `number`; \}; `waiting`: \| \{ `summary`: `string`; `cancel`: \{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; \}; \} \| `null`; \}; \}\>[] |
1365
- | `anchors` | `ReadonlyMap`\<`string`, `string`\> |
1366
- | `positions` | `ReadonlyMap`\<`number`, `string` \| `null`\> |
2050
+ | Parameter | Type |
2051
+ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2052
+ | `entries` | readonly `Readonly`\<\{ `entryId`: `string`; `value`: \{ `chips`: readonly `object`[]; `panel`: readonly `object`[]; `timeline`: \{ `cells`: readonly `object`[]; `omitted`: `number`; \}; `waiting`: \| \{ `summary`: `string`; `cancel`: \{ `id`: `string`; `label`: `string`; `input?`: \{ \[`key`: `string`\]: `Json`; \}; `awaiting?`: `"question"`; \}; \} \| `null`; \}; \}\>[] |
2053
+ | `anchors` | `ReadonlyMap`\<`string`, `string`\> |
2054
+ | `positions` | `ReadonlyMap`\<`number`, `string` \| `null`\> |
1367
2055
 
1368
2056
  #### Returns
1369
2057
 
@@ -1376,6 +2064,70 @@ Fixed positions and command anchors follow loaded history, never event time.
1376
2064
 
1377
2065
  ---
1378
2066
 
2067
+ ### sanitizeDisplayText()
2068
+
2069
+ ```ts
2070
+ function sanitizeDisplayText(value): string;
2071
+ ```
2072
+
2073
+ Display text keeps shaping characters, never terminal programs or bidi
2074
+ overrides.
2075
+
2076
+ #### Parameters
2077
+
2078
+ | Parameter | Type |
2079
+ | --------- | -------- |
2080
+ | `value` | `string` |
2081
+
2082
+ #### Returns
2083
+
2084
+ `string`
2085
+
2086
+ ---
2087
+
2088
+ ### formatWhen()
2089
+
2090
+ ```ts
2091
+ function formatWhen(epochMillis, now): string;
2092
+ ```
2093
+
2094
+ When something happened, as a picker column: `14:02` for today, `Yesterday`, or
2095
+ `2026-10-24`. Shared by every picker that lists past work.
2096
+
2097
+ #### Parameters
2098
+
2099
+ | Parameter | Type |
2100
+ | ------------- | -------- |
2101
+ | `epochMillis` | `number` |
2102
+ | `now` | `number` |
2103
+
2104
+ #### Returns
2105
+
2106
+ `string`
2107
+
2108
+ ---
2109
+
2110
+ ### oneLine()
2111
+
2112
+ ```ts
2113
+ function oneLine(text, limit): string;
2114
+ ```
2115
+
2116
+ `text` on one line, whitespace collapsed and cut at a word to `limit`.
2117
+
2118
+ #### Parameters
2119
+
2120
+ | Parameter | Type |
2121
+ | --------- | -------- |
2122
+ | `text` | `string` |
2123
+ | `limit` | `number` |
2124
+
2125
+ #### Returns
2126
+
2127
+ `string`
2128
+
2129
+ ---
2130
+
1379
2131
  ### mergeTerminals()
1380
2132
 
1381
2133
  ```ts
@@ -1408,11 +2160,32 @@ readonly `Readonly`\<\{ `commandId`: `string`; `outcome`: `"failed"` \|
1408
2160
 
1409
2161
  ---
1410
2162
 
2163
+ ### applySessionFrame()
2164
+
2165
+ ```ts
2166
+ function applySessionFrame(current, frame): SessionSnapshot;
2167
+ ```
2168
+
2169
+ Apply one already-decoded Shiitake frame to its authoritative projection.
2170
+
2171
+ #### Parameters
2172
+
2173
+ | Parameter | Type |
2174
+ | --------- | ----------------- |
2175
+ | `current` | `SessionSnapshot` |
2176
+ | `frame` | `SessionFrame` |
2177
+
2178
+ #### Returns
2179
+
2180
+ `SessionSnapshot`
2181
+
2182
+ ---
2183
+
1411
2184
  ### sessionQueryOptions()
1412
2185
 
1413
2186
  ```ts
1414
2187
  function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1415
- observation: "connecting" | "live";
2188
+ observation: "live" | "connecting";
1416
2189
  snapshot: | Readonly<{
1417
2190
  sessionId: string;
1418
2191
  cursor: string | null;
@@ -1445,6 +2218,8 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1445
2218
  revision: ...;
1446
2219
  text: ...;
1447
2220
  thinking: ...;
2221
+ textOffset: ...;
2222
+ thinkingOffset: ...;
1448
2223
  textTruncated: ...;
1449
2224
  thinkingTruncated: ...;
1450
2225
  }>
@@ -1464,6 +2239,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1464
2239
  }>;
1465
2240
  }>
1466
2241
  | undefined;
2242
+ lastReplyAt: number | undefined;
1467
2243
  latestPrompt: | Readonly<{
1468
2244
  commandId: string;
1469
2245
  text: string;
@@ -1471,7 +2247,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1471
2247
  }>
1472
2248
  | undefined;
1473
2249
  }>, Error, Readonly<{
1474
- observation: "connecting" | "live";
2250
+ observation: "live" | "connecting";
1475
2251
  snapshot: | Readonly<{
1476
2252
  sessionId: string;
1477
2253
  cursor: string | null;
@@ -1504,6 +2280,8 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1504
2280
  revision: ...;
1505
2281
  text: ...;
1506
2282
  thinking: ...;
2283
+ textOffset: ...;
2284
+ thinkingOffset: ...;
1507
2285
  textTruncated: ...;
1508
2286
  thinkingTruncated: ...;
1509
2287
  }>
@@ -1523,6 +2301,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1523
2301
  }>;
1524
2302
  }>
1525
2303
  | undefined;
2304
+ lastReplyAt: number | undefined;
1526
2305
  latestPrompt: | Readonly<{
1527
2306
  commandId: string;
1528
2307
  text: string;
@@ -1530,7 +2309,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1530
2309
  }>
1531
2310
  | undefined;
1532
2311
  }>, readonly ["shiitake-session", string]>, "queryFn"> & object & QueryKeyWithDataTag<readonly ["shiitake-session", string], Readonly<{
1533
- observation: "connecting" | "live";
2312
+ observation: "live" | "connecting";
1534
2313
  snapshot: | Readonly<{
1535
2314
  sessionId: string;
1536
2315
  cursor: string | null;
@@ -1577,6 +2356,8 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1577
2356
  revision: number;
1578
2357
  text: string;
1579
2358
  thinking: string;
2359
+ textOffset: number;
2360
+ thinkingOffset: number;
1580
2361
  textTruncated: boolean;
1581
2362
  thinkingTruncated: boolean;
1582
2363
  }>
@@ -1596,6 +2377,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1596
2377
  }>;
1597
2378
  }>
1598
2379
  | undefined;
2380
+ lastReplyAt: number | undefined;
1599
2381
  latestPrompt: | Readonly<{
1600
2382
  commandId: string;
1601
2383
  text: string;
@@ -1615,8 +2397,8 @@ One shared TanStack observation keyed by Shiitake's logical Session address.
1615
2397
 
1616
2398
  #### Returns
1617
2399
 
1618
- `OmitKeyof`\<`UseQueryOptions`\<`Readonly`\<\{ `observation`: `"connecting"` \|
1619
- `"live"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`; `cursor`:
2400
+ `OmitKeyof`\<`UseQueryOptions`\<`Readonly`\<\{ `observation`: `"live"` \|
2401
+ `"connecting"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`; `cursor`:
1620
2402
  `string` \| `null`; `hasMore`: `boolean`; `oldestCursor?`: `string` \| `null`;
1621
2403
  `messages`: readonly `Readonly`\<\{ `requestId?`: ...; `meta?`: ...; `data?`:
1622
2404
  ...; `origin?`: ...; `id`: ...; `sequence`: ...; `commandId`: ...; `value`: ...;
@@ -1626,14 +2408,15 @@ readonly `Readonly`\<...\>[]; `compactionNotices?`: readonly
1626
2408
  `Readonly`\<...\>[]; `sandboxFailures?`: readonly `object`[]; `pending`:
1627
2409
  `SessionPendingPrompts`; `activity`: `SessionActivity`; `progress`: \|
1628
2410
  `Readonly`\<\{ `messageId`: ...; `revision`: ...; `text`: ...; `thinking`: ...;
1629
- `textTruncated`: ...; `thinkingTruncated`: ...; \}\> \| `null`; `toolOutput`:
1630
- readonly `Readonly`\<\{ `toolCallId`: ...; `revision`: ...; `tail`: ...;
1631
- `droppedBytes`: ...; `totalBytes`: ...; \}\>[]; `extensions`:
1632
- `SessionExtensionSlots`; `attention`: readonly `object`[]; `context?`:
1633
- `Readonly`\<\{ `tokens`: ...; `window`: ...; \}\>; \}\> \| `undefined`;
2411
+ `textOffset`: ...; `thinkingOffset`: ...; `textTruncated`: ...;
2412
+ `thinkingTruncated`: ...; \}\> \| `null`; `toolOutput`: readonly `Readonly`\<\{
2413
+ `toolCallId`: ...; `revision`: ...; `tail`: ...; `droppedBytes`: ...;
2414
+ `totalBytes`: ...; \}\>[]; `extensions`: `SessionExtensionSlots`; `attention`:
2415
+ readonly `object`[]; `context?`: `Readonly`\<\{ `tokens`: ...; `window`: ...;
2416
+ \}\>; \}\> \| `undefined`; `lastReplyAt`: `number` \| `undefined`;
1634
2417
  `latestPrompt`: \| `Readonly`\<\{ `commandId`: `string`; `text`: `string`;
1635
2418
  `images`: readonly `object`[] \| `undefined`; \}\> \| `undefined`; \}\>,
1636
- `Error`, `Readonly`\<\{ `observation`: `"connecting"` \| `"live"`; `snapshot`:
2419
+ `Error`, `Readonly`\<\{ `observation`: `"live"` \| `"connecting"`; `snapshot`:
1637
2420
  \| `Readonly`\<\{ `sessionId`: `string`; `cursor`: `string` \| `null`;
1638
2421
  `hasMore`: `boolean`; `oldestCursor?`: `string` \| `null`; `messages`: readonly
1639
2422
  `Readonly`\<\{ `requestId?`: ...; `meta?`: ...; `data?`: ...; `origin?`: ...;
@@ -1643,17 +2426,18 @@ readonly `Readonly`\<\{ `commandId`: ...; `outcome`: ...; `sequence`: ...;
1643
2426
  `Readonly`\<...\>[]; `compactionNotices?`: readonly `Readonly`\<...\>[];
1644
2427
  `sandboxFailures?`: readonly `object`[]; `pending`: `SessionPendingPrompts`;
1645
2428
  `activity`: `SessionActivity`; `progress`: \| `Readonly`\<\{ `messageId`: ...;
1646
- `revision`: ...; `text`: ...; `thinking`: ...; `textTruncated`: ...;
1647
- `thinkingTruncated`: ...; \}\> \| `null`; `toolOutput`: readonly `Readonly`\<\{
1648
- `toolCallId`: ...; `revision`: ...; `tail`: ...; `droppedBytes`: ...;
1649
- `totalBytes`: ...; \}\>[]; `extensions`: `SessionExtensionSlots`; `attention`:
1650
- readonly `object`[]; `context?`: `Readonly`\<\{ `tokens`: ...; `window`: ...;
1651
- \}\>; \}\> \| `undefined`; `latestPrompt`: \| `Readonly`\<\{ `commandId`:
1652
- `string`; `text`: `string`; `images`: readonly `object`[] \| `undefined`; \}\>
1653
- \| `undefined`; \}\>, readonly \[`"shiitake-session"`, `string`\]\>,
1654
- `"queryFn"`\> & `object` & `QueryKeyWithDataTag`\<readonly
1655
- \[`"shiitake-session"`, `string`\], `Readonly`\<\{ `observation`: `"connecting"`
1656
- \| `"live"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`; `cursor`:
2429
+ `revision`: ...; `text`: ...; `thinking`: ...; `textOffset`: ...;
2430
+ `thinkingOffset`: ...; `textTruncated`: ...; `thinkingTruncated`: ...; \}\> \|
2431
+ `null`; `toolOutput`: readonly `Readonly`\<\{ `toolCallId`: ...; `revision`:
2432
+ ...; `tail`: ...; `droppedBytes`: ...; `totalBytes`: ...; \}\>[]; `extensions`:
2433
+ `SessionExtensionSlots`; `attention`: readonly `object`[]; `context?`:
2434
+ `Readonly`\<\{ `tokens`: ...; `window`: ...; \}\>; \}\> \| `undefined`;
2435
+ `lastReplyAt`: `number` \| `undefined`; `latestPrompt`: \| `Readonly`\<\{
2436
+ `commandId`: `string`; `text`: `string`; `images`: readonly `object`[] \|
2437
+ `undefined`; \}\> \| `undefined`; \}\>, readonly \[`"shiitake-session"`,
2438
+ `string`\]\>, `"queryFn"`\> & `object` & `QueryKeyWithDataTag`\<readonly
2439
+ \[`"shiitake-session"`, `string`\], `Readonly`\<\{ `observation`: `"live"` \|
2440
+ `"connecting"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`; `cursor`:
1657
2441
  `string` \| `null`; `hasMore`: `boolean`; `oldestCursor?`: `string` \| `null`;
1658
2442
  `messages`: readonly `Readonly`\<\{ `requestId?`: ... \| ...; `meta?`: ... \|
1659
2443
  ...; `data?`: ... \| ...; `origin?`: ... \| ...; `id`: `string`; `sequence`:
@@ -1667,14 +2451,15 @@ readonly `Readonly`\<\{ `commandId`: `string`; `outcome`: ... \| ... \| ... \|
1667
2451
  `sandboxFailures?`: readonly `object`[]; `pending`: `SessionPendingPrompts`;
1668
2452
  `activity`: `SessionActivity`; `progress`: \| `Readonly`\<\{ `messageId`:
1669
2453
  `string`; `revision`: `number`; `text`: `string`; `thinking`: `string`;
1670
- `textTruncated`: `boolean`; `thinkingTruncated`: `boolean`; \}\> \| `null`;
1671
- `toolOutput`: readonly `Readonly`\<\{ `toolCallId`: `string`; `revision`:
1672
- `number`; `tail`: `string`; `droppedBytes`: `number`; `totalBytes`: `number`;
1673
- \}\>[]; `extensions`: `SessionExtensionSlots`; `attention`: readonly `object`[];
1674
- `context?`: `Readonly`\<\{ `tokens`: `number`; `window`: ... \| ...; \}\>; \}\>
1675
- \| `undefined`; `latestPrompt`: \| `Readonly`\<\{ `commandId`: `string`; `text`:
1676
- `string`; `images`: readonly `object`[] \| `undefined`; \}\> \| `undefined`;
1677
- \}\>, `Error`\>
2454
+ `textOffset`: `number`; `thinkingOffset`: `number`; `textTruncated`: `boolean`;
2455
+ `thinkingTruncated`: `boolean`; \}\> \| `null`; `toolOutput`: readonly
2456
+ `Readonly`\<\{ `toolCallId`: `string`; `revision`: `number`; `tail`: `string`;
2457
+ `droppedBytes`: `number`; `totalBytes`: `number`; \}\>[]; `extensions`:
2458
+ `SessionExtensionSlots`; `attention`: readonly `object`[]; `context?`:
2459
+ `Readonly`\<\{ `tokens`: `number`; `window`: ... \| ...; \}\>; \}\> \|
2460
+ `undefined`; `lastReplyAt`: `number` \| `undefined`; `latestPrompt`: \|
2461
+ `Readonly`\<\{ `commandId`: `string`; `text`: `string`; `images`: readonly
2462
+ `object`[] \| `undefined`; \}\> \| `undefined`; \}\>, `Error`\>
1678
2463
 
1679
2464
  ---
1680
2465
 
@@ -1750,23 +2535,34 @@ Decide a Session's view state from its activity, terminals and progress.
1750
2535
 
1751
2536
  ---
1752
2537
 
1753
- ### queuedSessionLabel()
2538
+ ### sessionStateLabel()
1754
2539
 
1755
2540
  ```ts
1756
- function queuedSessionLabel(state): string;
2541
+ function sessionStateLabel(
2542
+ state,
2543
+ waitingOnYou?,
2544
+ ):
2545
+ | "idle"
2546
+ | "thinking"
2547
+ | "failed"
2548
+ | "streaming"
2549
+ | "running a tool"
2550
+ | "waiting on you";
1757
2551
  ```
1758
2552
 
1759
- Explain a queued Session using its owner's executor fact.
2553
+ Activity only: queued messages belong in the transcript, never in this label.
1760
2554
 
1761
2555
  #### Parameters
1762
2556
 
1763
- | Parameter | Type |
1764
- | --------- | ------------------------------------------------------------------------------------------- |
1765
- | `state` | `Extract`\<[`ParakeetOwnerViewState`](#parakeetownerviewstate), \{ `kind`: `"queued"`; \}\> |
2557
+ | Parameter | Type | Default value |
2558
+ | -------------- | --------------------------------------------------- | ------------- |
2559
+ | `state` | [`ParakeetOwnerViewState`](#parakeetownerviewstate) | `undefined` |
2560
+ | `waitingOnYou` | `boolean` | `false` |
1766
2561
 
1767
2562
  #### Returns
1768
2563
 
1769
- `string`
2564
+ \| `"idle"` \| `"thinking"` \| `"failed"` \| `"streaming"` \| `"running a tool"`
2565
+ \| `"waiting on you"`
1770
2566
 
1771
2567
  ---
1772
2568
 
@@ -1810,6 +2606,27 @@ Shared tool status meaning, used by the browser and native presentations.
1810
2606
 
1811
2607
  ---
1812
2608
 
2609
+ ### toolLiveLines()
2610
+
2611
+ ```ts
2612
+ function toolLiveLines(call, open): readonly string[];
2613
+ ```
2614
+
2615
+ Live output stays visible when folded, independent of result disclosure.
2616
+
2617
+ #### Parameters
2618
+
2619
+ | Parameter | Type |
2620
+ | --------- | ------------------------------------------------------- |
2621
+ | `call` | [`ParakeetToolCallView`](index.md#parakeettoolcallview) |
2622
+ | `open` | `boolean` |
2623
+
2624
+ #### Returns
2625
+
2626
+ readonly `string`[]
2627
+
2628
+ ---
2629
+
1813
2630
  ### toolCallView()
1814
2631
 
1815
2632
  ```ts
@@ -2286,6 +3103,52 @@ Contribute the shared Session command vocabulary to one Whistle host.
2286
3103
 
2287
3104
  `Readonly`\<\{ `update`: (`commands`) => `void`; `dispose`: () => `void`; \}\>
2288
3105
 
3106
+ ---
3107
+
3108
+ ### useApprovalAwaiting()
3109
+
3110
+ ```ts
3111
+ function useApprovalAwaiting(options): void;
3112
+ ```
3113
+
3114
+ Put one source's pending approval in the composer's queue. While the record is
3115
+ answerable and the person is present it asks through decision prompts; a changed
3116
+ revision replaces the item, so only the record on screen can be answered. Esc
3117
+ postpones it: the record stays pending in the ledger.
3118
+
3119
+ #### Parameters
3120
+
3121
+ | Parameter | Type |
3122
+ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3123
+ | `options` | `Readonly`\<\{ `source`: [`ApprovalSource`](#approvalsource) \| `undefined`; `store`: [`ParakeetInteractions`](#parakeetinteractions); `enabled`: `boolean`; `home`: `string`; `width`: `number`; `noteLimit`: `number`; `onFailure`: (`cause`) => `void`; \}\> |
3124
+
3125
+ #### Returns
3126
+
3127
+ `void`
3128
+
3129
+ ---
3130
+
3131
+ ### useDecision()
3132
+
3133
+ ```ts
3134
+ function useDecision(item, context): DecisionController;
3135
+ ```
3136
+
3137
+ Own the answering of one waiting decision for any renderer: the reducer's state
3138
+ per prompt, the answer sent to the item's host, and the refusal that comes back.
3139
+ Renderers draw `view` and forward intents, nothing else.
3140
+
3141
+ #### Parameters
3142
+
3143
+ | Parameter | Type |
3144
+ | --------- | ----------------------------------------------------------------------------------- |
3145
+ | `item` | [`AwaitingItem`](#awaitingitem) |
3146
+ | `context` | `Readonly`\<\{ `position`: `number`; `total`: `number`; `later`: () => `void`; \}\> |
3147
+
3148
+ #### Returns
3149
+
3150
+ [`DecisionController`](#decisioncontroller)
3151
+
2289
3152
  ## References
2290
3153
 
2291
3154
  ### formatModelIdentity