@fungi.computer/parakeet 0.4.0 → 0.5.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 (55) hide show
  1. package/dist/client-contributions.d.ts +1 -0
  2. package/dist/commands/awaiting-driver.d.ts +20 -0
  3. package/dist/commands/awaiting-driver.js +121 -0
  4. package/dist/commands/builtins.js +6 -4
  5. package/dist/commands/interactions.d.ts +25 -0
  6. package/dist/commands/interactions.js +76 -2
  7. package/dist/commands/run.js +3 -3
  8. package/dist/commands/slash.d.ts +7 -3
  9. package/dist/commands/slash.js +2 -0
  10. package/dist/commands/use-slash-commands.d.ts +13 -0
  11. package/dist/commands/use-slash-commands.js +58 -1
  12. package/dist/components/ChatComposer.d.ts +2 -0
  13. package/dist/components/ChatComposer.js +150 -38
  14. package/dist/components/ClientRows.js +42 -26
  15. package/dist/components/CompletionMenu.d.ts +54 -0
  16. package/dist/components/CompletionMenu.js +52 -0
  17. package/dist/components/DecisionComposer.d.ts +30 -0
  18. package/dist/components/DecisionComposer.js +146 -0
  19. package/dist/components/InteractionPanel.d.ts +10 -1
  20. package/dist/components/InteractionPanel.js +9 -4
  21. package/dist/components/SlashMenu.d.ts +1 -3
  22. package/dist/components/SlashMenu.js +5 -13
  23. package/dist/components/TimelineItem.d.ts +1 -0
  24. package/dist/components/TimelineItem.js +3 -3
  25. package/dist/components/ToolGroup.d.ts +1 -0
  26. package/dist/components/ToolGroup.js +7 -7
  27. package/dist/conversation.d.ts +5 -1
  28. package/dist/conversation.js +72 -20
  29. package/dist/core/approval-decision.d.ts +198 -0
  30. package/dist/core/approval-decision.js +291 -0
  31. package/dist/core/awaiting-answer.d.ts +229 -0
  32. package/dist/core/awaiting-answer.js +303 -0
  33. package/dist/core/build-timeline.js +56 -5
  34. package/dist/core/client-actions.d.ts +1 -0
  35. package/dist/core/client-actions.js +7 -1
  36. package/dist/core/draft-storage.d.ts +4 -0
  37. package/dist/core/draft-storage.js +12 -5
  38. package/dist/core/session-query.d.ts +8 -0
  39. package/dist/core/session-query.js +13 -11
  40. package/dist/headless.d.ts +6 -2
  41. package/dist/headless.js +5 -1
  42. package/dist/parakeet.d.ts +6 -2
  43. package/dist/parakeet.js +15 -6
  44. package/dist/store/types.d.ts +5 -1
  45. package/dist/styles.css +395 -113
  46. package/dist/use-approval-awaiting.d.ts +22 -0
  47. package/dist/use-approval-awaiting.js +81 -0
  48. package/dist/use-decision.d.ts +20 -0
  49. package/dist/use-decision.js +79 -0
  50. package/docs/api/commands/slash.md +30 -26
  51. package/docs/api/headless.md +822 -41
  52. package/docs/api/index.md +13 -4
  53. package/package.json +13 -7
  54. package/src/completion-menu.css +71 -0
  55. package/src/styles.css +174 -46
@@ -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,49 @@ Fixed positions and command anchors follow loaded history, never event time.
1376
2064
 
1377
2065
  ---
1378
2066
 
2067
+ ### formatWhen()
2068
+
2069
+ ```ts
2070
+ function formatWhen(epochMillis, now): string;
2071
+ ```
2072
+
2073
+ When something happened, as a picker column: `14:02` for today, `Yesterday`, or
2074
+ `2026-10-24`. Shared by every picker that lists past work.
2075
+
2076
+ #### Parameters
2077
+
2078
+ | Parameter | Type |
2079
+ | ------------- | -------- |
2080
+ | `epochMillis` | `number` |
2081
+ | `now` | `number` |
2082
+
2083
+ #### Returns
2084
+
2085
+ `string`
2086
+
2087
+ ---
2088
+
2089
+ ### oneLine()
2090
+
2091
+ ```ts
2092
+ function oneLine(text, limit): string;
2093
+ ```
2094
+
2095
+ `text` on one line, whitespace collapsed and cut at a word to `limit`.
2096
+
2097
+ #### Parameters
2098
+
2099
+ | Parameter | Type |
2100
+ | --------- | -------- |
2101
+ | `text` | `string` |
2102
+ | `limit` | `number` |
2103
+
2104
+ #### Returns
2105
+
2106
+ `string`
2107
+
2108
+ ---
2109
+
1379
2110
  ### mergeTerminals()
1380
2111
 
1381
2112
  ```ts
@@ -1464,6 +2195,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1464
2195
  }>;
1465
2196
  }>
1466
2197
  | undefined;
2198
+ lastReplyAt: number | undefined;
1467
2199
  latestPrompt: | Readonly<{
1468
2200
  commandId: string;
1469
2201
  text: string;
@@ -1523,6 +2255,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1523
2255
  }>;
1524
2256
  }>
1525
2257
  | undefined;
2258
+ lastReplyAt: number | undefined;
1526
2259
  latestPrompt: | Readonly<{
1527
2260
  commandId: string;
1528
2261
  text: string;
@@ -1596,6 +2329,7 @@ function sessionQueryOptions(session): OmitKeyof<UseQueryOptions<Readonly<{
1596
2329
  }>;
1597
2330
  }>
1598
2331
  | undefined;
2332
+ lastReplyAt: number | undefined;
1599
2333
  latestPrompt: | Readonly<{
1600
2334
  commandId: string;
1601
2335
  text: string;
@@ -1631,27 +2365,28 @@ readonly `Readonly`\<\{ `toolCallId`: ...; `revision`: ...; `tail`: ...;
1631
2365
  `droppedBytes`: ...; `totalBytes`: ...; \}\>[]; `extensions`:
1632
2366
  `SessionExtensionSlots`; `attention`: readonly `object`[]; `context?`:
1633
2367
  `Readonly`\<\{ `tokens`: ...; `window`: ...; \}\>; \}\> \| `undefined`;
1634
- `latestPrompt`: \| `Readonly`\<\{ `commandId`: `string`; `text`: `string`;
1635
- `images`: readonly `object`[] \| `undefined`; \}\> \| `undefined`; \}\>,
1636
- `Error`, `Readonly`\<\{ `observation`: `"connecting"` \| `"live"`; `snapshot`:
1637
- \| `Readonly`\<\{ `sessionId`: `string`; `cursor`: `string` \| `null`;
1638
- `hasMore`: `boolean`; `oldestCursor?`: `string` \| `null`; `messages`: readonly
1639
- `Readonly`\<\{ `requestId?`: ...; `meta?`: ...; `data?`: ...; `origin?`: ...;
1640
- `id`: ...; `sequence`: ...; `commandId`: ...; `value`: ...; \}\>[]; `terminals`:
1641
- readonly `Readonly`\<\{ `commandId`: ...; `outcome`: ...; `sequence`: ...;
1642
- `diagnostic`: ...; `meta?`: ...; \}\>[]; `compactions?`: readonly
1643
- `Readonly`\<...\>[]; `compactionNotices?`: readonly `Readonly`\<...\>[];
1644
- `sandboxFailures?`: readonly `object`[]; `pending`: `SessionPendingPrompts`;
1645
- `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
2368
+ `lastReplyAt`: `number` \| `undefined`; `latestPrompt`: \| `Readonly`\<\{
2369
+ `commandId`: `string`; `text`: `string`; `images`: readonly `object`[] \|
2370
+ `undefined`; \}\> \| `undefined`; \}\>, `Error`, `Readonly`\<\{ `observation`:
2371
+ `"connecting"` \| `"live"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`;
2372
+ `cursor`: `string` \| `null`; `hasMore`: `boolean`; `oldestCursor?`: `string` \|
2373
+ `null`; `messages`: readonly `Readonly`\<\{ `requestId?`: ...; `meta?`: ...;
2374
+ `data?`: ...; `origin?`: ...; `id`: ...; `sequence`: ...; `commandId`: ...;
2375
+ `value`: ...; \}\>[]; `terminals`: readonly `Readonly`\<\{ `commandId`: ...;
2376
+ `outcome`: ...; `sequence`: ...; `diagnostic`: ...; `meta?`: ...; \}\>[];
2377
+ `compactions?`: readonly `Readonly`\<...\>[]; `compactionNotices?`: readonly
2378
+ `Readonly`\<...\>[]; `sandboxFailures?`: readonly `object`[]; `pending`:
2379
+ `SessionPendingPrompts`; `activity`: `SessionActivity`; `progress`: \|
2380
+ `Readonly`\<\{ `messageId`: ...; `revision`: ...; `text`: ...; `thinking`: ...;
2381
+ `textTruncated`: ...; `thinkingTruncated`: ...; \}\> \| `null`; `toolOutput`:
2382
+ readonly `Readonly`\<\{ `toolCallId`: ...; `revision`: ...; `tail`: ...;
2383
+ `droppedBytes`: ...; `totalBytes`: ...; \}\>[]; `extensions`:
2384
+ `SessionExtensionSlots`; `attention`: readonly `object`[]; `context?`:
2385
+ `Readonly`\<\{ `tokens`: ...; `window`: ...; \}\>; \}\> \| `undefined`;
2386
+ `lastReplyAt`: `number` \| `undefined`; `latestPrompt`: \| `Readonly`\<\{
2387
+ `commandId`: `string`; `text`: `string`; `images`: readonly `object`[] \|
2388
+ `undefined`; \}\> \| `undefined`; \}\>, readonly \[`"shiitake-session"`,
2389
+ `string`\]\>, `"queryFn"`\> & `object` & `QueryKeyWithDataTag`\<readonly
1655
2390
  \[`"shiitake-session"`, `string`\], `Readonly`\<\{ `observation`: `"connecting"`
1656
2391
  \| `"live"`; `snapshot`: \| `Readonly`\<\{ `sessionId`: `string`; `cursor`:
1657
2392
  `string` \| `null`; `hasMore`: `boolean`; `oldestCursor?`: `string` \| `null`;
@@ -1672,9 +2407,9 @@ readonly `Readonly`\<\{ `commandId`: `string`; `outcome`: ... \| ... \| ... \|
1672
2407
  `number`; `tail`: `string`; `droppedBytes`: `number`; `totalBytes`: `number`;
1673
2408
  \}\>[]; `extensions`: `SessionExtensionSlots`; `attention`: readonly `object`[];
1674
2409
  `context?`: `Readonly`\<\{ `tokens`: `number`; `window`: ... \| ...; \}\>; \}\>
1675
- \| `undefined`; `latestPrompt`: \| `Readonly`\<\{ `commandId`: `string`; `text`:
1676
- `string`; `images`: readonly `object`[] \| `undefined`; \}\> \| `undefined`;
1677
- \}\>, `Error`\>
2410
+ \| `undefined`; `lastReplyAt`: `number` \| `undefined`; `latestPrompt`: \|
2411
+ `Readonly`\<\{ `commandId`: `string`; `text`: `string`; `images`: readonly
2412
+ `object`[] \| `undefined`; \}\> \| `undefined`; \}\>, `Error`\>
1678
2413
 
1679
2414
  ---
1680
2415
 
@@ -2286,6 +3021,52 @@ Contribute the shared Session command vocabulary to one Whistle host.
2286
3021
 
2287
3022
  `Readonly`\<\{ `update`: (`commands`) => `void`; `dispose`: () => `void`; \}\>
2288
3023
 
3024
+ ---
3025
+
3026
+ ### useApprovalAwaiting()
3027
+
3028
+ ```ts
3029
+ function useApprovalAwaiting(options): void;
3030
+ ```
3031
+
3032
+ Put one source's pending approval in the composer's queue. While the record is
3033
+ answerable and the person is present it asks through decision prompts; a changed
3034
+ revision replaces the item, so only the record on screen can be answered. Esc
3035
+ postpones it: the record stays pending in the ledger.
3036
+
3037
+ #### Parameters
3038
+
3039
+ | Parameter | Type |
3040
+ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3041
+ | `options` | `Readonly`\<\{ `source`: [`ApprovalSource`](#approvalsource) \| `undefined`; `store`: [`ParakeetInteractions`](#parakeetinteractions); `enabled`: `boolean`; `home`: `string`; `width`: `number`; `noteLimit`: `number`; `onFailure`: (`cause`) => `void`; \}\> |
3042
+
3043
+ #### Returns
3044
+
3045
+ `void`
3046
+
3047
+ ---
3048
+
3049
+ ### useDecision()
3050
+
3051
+ ```ts
3052
+ function useDecision(item, context): DecisionController;
3053
+ ```
3054
+
3055
+ Own the answering of one waiting decision for any renderer: the reducer's state
3056
+ per prompt, the answer sent to the item's host, and the refusal that comes back.
3057
+ Renderers draw `view` and forward intents, nothing else.
3058
+
3059
+ #### Parameters
3060
+
3061
+ | Parameter | Type |
3062
+ | --------- | ----------------------------------------------------------------------------------- |
3063
+ | `item` | [`AwaitingItem`](#awaitingitem) |
3064
+ | `context` | `Readonly`\<\{ `position`: `number`; `total`: `number`; `later`: () => `void`; \}\> |
3065
+
3066
+ #### Returns
3067
+
3068
+ [`DecisionController`](#decisioncontroller)
3069
+
2289
3070
  ## References
2290
3071
 
2291
3072
  ### formatModelIdentity