iris-chatbot 5.1.0 → 5.3.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.
@@ -0,0 +1,71 @@
1
+ import {
2
+ autocompleteContacts,
3
+ type ContactAutocompleteMode,
4
+ } from "../../../../lib/tooling/tools/communication";
5
+
6
+ export const runtime = "nodejs";
7
+ export const dynamic = "force-dynamic";
8
+
9
+ function isContactsPermissionError(message: string): boolean {
10
+ const normalized = message.toLowerCase();
11
+ return (
12
+ normalized.includes("not authorized") ||
13
+ normalized.includes("not permitted") ||
14
+ normalized.includes("permission") ||
15
+ normalized.includes("operation not permitted")
16
+ );
17
+ }
18
+
19
+ export async function POST(request: Request) {
20
+ try {
21
+ const body = (await request.json()) as {
22
+ query?: unknown;
23
+ mode?: unknown;
24
+ };
25
+ const query = typeof body.query === "string" ? body.query.trim() : "";
26
+ const mode: ContactAutocompleteMode =
27
+ body.mode === "email" ? "email" : "message";
28
+
29
+ if (!query) {
30
+ return new Response(
31
+ JSON.stringify({ ok: true, suggestions: [] }),
32
+ { headers: { "Content-Type": "application/json" } },
33
+ );
34
+ }
35
+
36
+ const suggestions = await autocompleteContacts({
37
+ query,
38
+ mode,
39
+ signal: request.signal,
40
+ });
41
+
42
+ return new Response(
43
+ JSON.stringify({ ok: true, suggestions }),
44
+ { headers: { "Content-Type": "application/json" } },
45
+ );
46
+ } catch (error) {
47
+ const message = error instanceof Error ? error.message : "Contacts lookup failed.";
48
+ if (isContactsPermissionError(message)) {
49
+ return new Response(
50
+ JSON.stringify({
51
+ ok: false,
52
+ permissionRequired: true,
53
+ error:
54
+ "Contacts access is required for suggestions. macOS should prompt the app running this server (Terminal/VS Code/Cursor).",
55
+ }),
56
+ {
57
+ status: 403,
58
+ headers: { "Content-Type": "application/json" },
59
+ },
60
+ );
61
+ }
62
+ return new Response(
63
+ JSON.stringify({ ok: false, error: message }),
64
+ {
65
+ status: 500,
66
+ headers: { "Content-Type": "application/json" },
67
+ },
68
+ );
69
+ }
70
+ }
71
+
@@ -8,6 +8,9 @@ export async function POST(request: Request) {
8
8
  const body = (await request.json()) as {
9
9
  approvalId?: unknown;
10
10
  decision?: unknown;
11
+ args?: unknown;
12
+ source?: unknown;
13
+ reasonCode?: unknown;
11
14
  };
12
15
 
13
16
  if (typeof body.approvalId !== "string" || !body.approvalId.trim()) {
@@ -17,7 +20,7 @@ export async function POST(request: Request) {
17
20
  });
18
21
  }
19
22
 
20
- if (body.decision !== "approve" && body.decision !== "deny") {
23
+ if (body.decision !== "approve" && body.decision !== "deny" && body.decision !== "supersede") {
21
24
  return new Response(JSON.stringify({ ok: false, error: "Invalid decision." }), {
22
25
  status: 400,
23
26
  headers: { "Content-Type": "application/json" },
@@ -25,8 +28,33 @@ export async function POST(request: Request) {
25
28
  }
26
29
 
27
30
  const approvalId = body.approvalId.trim();
31
+ const args =
32
+ body.args && typeof body.args === "object" && !Array.isArray(body.args)
33
+ ? (body.args as Record<string, unknown>)
34
+ : undefined;
35
+ if (body.args !== undefined && !args) {
36
+ return new Response(JSON.stringify({ ok: false, error: "Invalid args payload." }), {
37
+ status: 400,
38
+ headers: { "Content-Type": "application/json" },
39
+ });
40
+ }
41
+
42
+ const source =
43
+ body.source === "user" || body.source === "system"
44
+ ? body.source
45
+ : "user";
46
+ const reasonCode =
47
+ body.reasonCode === "user_cancel" ||
48
+ body.reasonCode === "internal_replace" ||
49
+ body.reasonCode === "timeout" ||
50
+ body.reasonCode === "other"
51
+ ? body.reasonCode
52
+ : undefined;
28
53
 
29
- const resolved = resolveApprovalDecision(approvalId, body.decision);
54
+ const resolved = resolveApprovalDecision(approvalId, body.decision, args, {
55
+ source,
56
+ reasonCode,
57
+ });
30
58
  if (!resolved) {
31
59
  return new Response(JSON.stringify({ ok: false, error: "Unable to resolve approval." }), {
32
60
  status: 404,
@@ -172,13 +172,12 @@ button:focus-visible {
172
172
  top: 2px;
173
173
  right: 0;
174
174
  opacity: 0;
175
- pointer-events: none;
175
+ pointer-events: auto;
176
176
  transition: opacity 0.2s ease;
177
177
  }
178
178
 
179
- .assistant-card:hover .assistant-collapse-row {
179
+ .assistant-collapse-row:hover {
180
180
  opacity: 1;
181
- pointer-events: auto;
182
181
  }
183
182
 
184
183
  .assistant-collapse-toggle {
@@ -465,6 +464,9 @@ button:focus-visible {
465
464
  text-align: left;
466
465
  border-right: 1px solid var(--border-strong);
467
466
  border-bottom: 1px solid var(--border-strong);
467
+ /* Keep words intact: wrap at spaces; only break long words when necessary */
468
+ overflow-wrap: break-word;
469
+ word-break: normal;
468
470
  }
469
471
 
470
472
  .message-content tr> :last-child {
@@ -502,8 +504,8 @@ button:focus-visible {
502
504
  }
503
505
 
504
506
  .message-content strong {
505
- font-weight: 760;
506
- color: var(--text-primary);
507
+ font-weight: 600;
508
+ color: inherit;
507
509
  }
508
510
 
509
511
  .message-content em {
@@ -614,6 +616,220 @@ button:focus-visible {
614
616
  color: #111111;
615
617
  }
616
618
 
619
+ .draft-approval-card {
620
+ border: 1px solid var(--border);
621
+ border-radius: 14px;
622
+ background: var(--panel-2);
623
+ padding: 10px;
624
+ }
625
+
626
+ .draft-approval-header {
627
+ display: flex;
628
+ align-items: center;
629
+ justify-content: space-between;
630
+ gap: 8px;
631
+ margin-bottom: 10px;
632
+ }
633
+
634
+ .draft-approval-title {
635
+ font-size: 13px;
636
+ font-weight: 600;
637
+ color: var(--text-secondary);
638
+ }
639
+
640
+ .draft-approval-actions {
641
+ display: flex;
642
+ align-items: center;
643
+ gap: 6px;
644
+ }
645
+
646
+ .draft-approval-icon-btn {
647
+ height: 28px;
648
+ width: 28px;
649
+ border-radius: 999px;
650
+ border: 1px solid var(--border);
651
+ background: var(--panel);
652
+ color: var(--text-secondary);
653
+ display: inline-flex;
654
+ align-items: center;
655
+ justify-content: center;
656
+ transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
657
+ }
658
+
659
+ .draft-approval-icon-btn:hover {
660
+ border-color: var(--border-strong);
661
+ color: var(--text-primary);
662
+ }
663
+
664
+ .draft-approval-icon-btn.primary {
665
+ background: #ffffff;
666
+ color: #101010;
667
+ border-color: transparent;
668
+ }
669
+
670
+ [data-theme="light"] .draft-approval-icon-btn.primary {
671
+ background: #161616;
672
+ color: #ffffff;
673
+ }
674
+
675
+ .draft-approval-icon-btn:disabled {
676
+ opacity: 0.55;
677
+ cursor: not-allowed;
678
+ }
679
+
680
+ .draft-approval-field {
681
+ display: flex;
682
+ flex-direction: column;
683
+ gap: 6px;
684
+ margin-bottom: 10px;
685
+ }
686
+
687
+ .draft-approval-label {
688
+ font-size: 11px;
689
+ text-transform: uppercase;
690
+ letter-spacing: 0.08em;
691
+ color: var(--text-muted);
692
+ }
693
+
694
+ .draft-recipient-input-wrap {
695
+ min-height: 38px;
696
+ border: 1px solid var(--border);
697
+ border-radius: 10px;
698
+ background: var(--panel);
699
+ padding: 5px 6px;
700
+ display: flex;
701
+ align-items: center;
702
+ flex-wrap: wrap;
703
+ gap: 5px;
704
+ }
705
+
706
+ .draft-recipient-field-stack {
707
+ position: relative;
708
+ }
709
+
710
+ .draft-recipient-chip {
711
+ max-width: 100%;
712
+ border-radius: 999px;
713
+ border: 1px solid var(--border);
714
+ background: var(--panel-2);
715
+ color: var(--text-secondary);
716
+ font-size: 11px;
717
+ padding: 4px 8px;
718
+ display: inline-flex;
719
+ align-items: center;
720
+ gap: 4px;
721
+ }
722
+
723
+ .draft-recipient-chip-remove {
724
+ border: none;
725
+ background: transparent;
726
+ color: var(--text-muted);
727
+ display: inline-flex;
728
+ align-items: center;
729
+ justify-content: center;
730
+ }
731
+
732
+ .draft-recipient-chip-remove:hover {
733
+ color: var(--text-primary);
734
+ }
735
+
736
+ .draft-recipient-input {
737
+ border: none;
738
+ background: transparent;
739
+ color: var(--text-primary);
740
+ font-size: 12px;
741
+ flex: 1;
742
+ min-width: 120px;
743
+ padding: 4px 6px;
744
+ }
745
+
746
+ .draft-recipient-input:focus {
747
+ outline: none;
748
+ }
749
+
750
+ .draft-contact-suggestions {
751
+ margin-top: 4px;
752
+ border: 1px solid var(--border);
753
+ border-radius: 10px;
754
+ background: var(--panel);
755
+ max-height: 180px;
756
+ overflow-y: auto;
757
+ }
758
+
759
+ .draft-contact-suggestion-item {
760
+ width: 100%;
761
+ border: none;
762
+ border-bottom: 1px solid var(--border);
763
+ background: transparent;
764
+ text-align: left;
765
+ padding: 8px 10px;
766
+ display: flex;
767
+ flex-direction: column;
768
+ gap: 2px;
769
+ }
770
+
771
+ .draft-contact-suggestion-item:last-child {
772
+ border-bottom: none;
773
+ }
774
+
775
+ .draft-contact-suggestion-item:hover {
776
+ background: var(--panel-2);
777
+ }
778
+
779
+ .draft-contact-suggestion-name {
780
+ font-size: 12px;
781
+ color: var(--text-primary);
782
+ }
783
+
784
+ .draft-contact-suggestion-detail {
785
+ font-size: 11px;
786
+ color: var(--text-muted);
787
+ }
788
+
789
+ .draft-contact-suggestion-hint {
790
+ padding: 8px 10px;
791
+ font-size: 11px;
792
+ color: var(--text-muted);
793
+ }
794
+
795
+ .draft-approval-text-input,
796
+ .draft-approval-textarea {
797
+ width: 100%;
798
+ border: 1px solid var(--border);
799
+ border-radius: 10px;
800
+ background: var(--panel);
801
+ color: var(--text-primary);
802
+ font-size: 13px;
803
+ line-height: 1.5;
804
+ padding: 8px 10px;
805
+ resize: vertical;
806
+ }
807
+
808
+ .draft-approval-text-input:focus,
809
+ .draft-approval-textarea:focus {
810
+ outline: none;
811
+ border-color: var(--border-strong);
812
+ }
813
+
814
+ .draft-approval-footer {
815
+ display: flex;
816
+ justify-content: flex-end;
817
+ }
818
+
819
+ .draft-approval-cancel {
820
+ border-radius: 999px;
821
+ border: 1px solid var(--border);
822
+ background: var(--panel);
823
+ color: var(--text-secondary);
824
+ font-size: 11px;
825
+ padding: 4px 10px;
826
+ }
827
+
828
+ .draft-approval-cancel:hover {
829
+ border-color: var(--border-strong);
830
+ color: var(--text-primary);
831
+ }
832
+
617
833
  .message-content hr {
618
834
  border: 0;
619
835
  border-top: 1px solid var(--border);
@@ -871,6 +1087,14 @@ button:focus-visible {
871
1087
  .message-card.user {
872
1088
  max-width: 92%;
873
1089
  }
1090
+
1091
+ .draft-approval-header {
1092
+ align-items: flex-start;
1093
+ }
1094
+
1095
+ .draft-recipient-input {
1096
+ min-width: 92px;
1097
+ }
874
1098
  }
875
1099
 
876
1100
  .model-menu {
@@ -1101,4 +1325,4 @@ button:focus-visible {
1101
1325
 
1102
1326
  [data-theme="light"] .quoted-context-dismiss:hover {
1103
1327
  background: rgba(0, 0, 0, 0.06);
1104
- }
1328
+ }