@ask-thane/thane-cli 0.1.17 → 0.1.19
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.
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +233 -19
- package/dist/chat.js.map +1 -1
- package/dist/commands.js +3 -3
- package/dist/commands.js.map +1 -1
- package/dist/hosted.d.ts +33 -0
- package/dist/hosted.d.ts.map +1 -0
- package/dist/hosted.js +96 -0
- package/dist/hosted.js.map +1 -0
- package/dist/index.js +98 -11
- package/dist/index.js.map +1 -1
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +1 -0
- package/dist/slash-commands.js.map +1 -1
- package/dist/store.d.ts +9 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +51 -0
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AA+hBA,wBAAsB,OAAO,CAAC,cAAc,SAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA4vBvE"}
|
package/dist/chat.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stdin as input, stdout as output } from "node:process";
|
|
2
2
|
import { emitKeypressEvents } from "node:readline";
|
|
3
|
-
import {
|
|
3
|
+
import { createHostedChannel, hasHostedChat, reactHostedMessage, sendHostedMessage, syncHostedStore } from "./hosted.js";
|
|
4
|
+
import { renderChannels, renderInbox, renderMessages, renderUsers } from "./render.js";
|
|
4
5
|
import { completeSlashCommand, renderSlashCommands, slashCommands } from "./slash-commands.js";
|
|
5
6
|
import { ThaneStore } from "./store.js";
|
|
6
7
|
import { checkForUpdate, renderUpdateStatus } from "./update.js";
|
|
@@ -299,6 +300,19 @@ function renderMenuLines(selectedIndex, availableRows, updateStatus) {
|
|
|
299
300
|
})
|
|
300
301
|
];
|
|
301
302
|
}
|
|
303
|
+
function renderWorkspacePickerLines(store, selectedIndex) {
|
|
304
|
+
const workspaces = store.listWorkspaces();
|
|
305
|
+
return [
|
|
306
|
+
`${BOLD}Workspaces${RESET}`,
|
|
307
|
+
`${DIM}Use arrows, Return to switch, Esc to close.${RESET}`,
|
|
308
|
+
"",
|
|
309
|
+
...workspaces.map((workspace, index) => {
|
|
310
|
+
const active = workspace.id === store.activeWorkspace.id ? "*" : " ";
|
|
311
|
+
const row = `${active} ${workspace.slug} - ${workspace.name}`;
|
|
312
|
+
return index === selectedIndex ? `${INVERSE}${row}${RESET}` : row;
|
|
313
|
+
})
|
|
314
|
+
];
|
|
315
|
+
}
|
|
302
316
|
function renderReactionPickerLines(selectedIndex) {
|
|
303
317
|
const options = QUICK_REACTIONS.map((reaction, index) => {
|
|
304
318
|
const label = ` ${index + 1} ${reaction} `;
|
|
@@ -347,7 +361,7 @@ function requireHostedAuthToken(store) {
|
|
|
347
361
|
}
|
|
348
362
|
return token;
|
|
349
363
|
}
|
|
350
|
-
async function createWorkspaceInviteLink(store, role = "member") {
|
|
364
|
+
async function createWorkspaceInviteLink(store, role = "member", inviteeEmail) {
|
|
351
365
|
store.requireWorkspaceAdmin();
|
|
352
366
|
const token = requireHostedAuthToken(store);
|
|
353
367
|
const response = await postThaneApiWithAuth("/v1/thane-cli/workspace-invites", token, {
|
|
@@ -355,8 +369,12 @@ async function createWorkspaceInviteLink(store, role = "member") {
|
|
|
355
369
|
workspaceSlug: store.activeWorkspace.slug,
|
|
356
370
|
workspaceName: store.activeWorkspace.name,
|
|
357
371
|
role,
|
|
358
|
-
expiresInHours: 24 * 7
|
|
372
|
+
expiresInHours: 24 * 7,
|
|
373
|
+
...(inviteeEmail ? { inviteeEmail, maxUses: 1 } : {})
|
|
359
374
|
});
|
|
375
|
+
if (response.invite.inviteeEmail) {
|
|
376
|
+
return `${response.invite.emailSent ? "Sent" : "Created"} invite for ${response.invite.inviteeEmail} (${response.invite.role}, expires ${response.invite.expiresAt})`;
|
|
377
|
+
}
|
|
360
378
|
return `${response.invite.url} (${response.invite.role}, expires ${response.invite.expiresAt})`;
|
|
361
379
|
}
|
|
362
380
|
function renderScreen(inputText, state) {
|
|
@@ -449,12 +467,21 @@ function renderScreen(inputText, state) {
|
|
|
449
467
|
}
|
|
450
468
|
export async function runChat(initialChannel = "general") {
|
|
451
469
|
let store = await ThaneStore.open();
|
|
470
|
+
try {
|
|
471
|
+
await syncHostedStore(store);
|
|
472
|
+
store = await ThaneStore.open();
|
|
473
|
+
}
|
|
474
|
+
catch (_error) {
|
|
475
|
+
// Stay usable offline; the footer will surface explicit command failures.
|
|
476
|
+
}
|
|
452
477
|
let activeChannel = await selectConversation(store, initialChannel);
|
|
453
478
|
let inputText = "";
|
|
454
479
|
let status = "";
|
|
455
480
|
let showHelp = false;
|
|
456
481
|
let showMenu = false;
|
|
457
482
|
let sidePanelLines;
|
|
483
|
+
let workspacePickerOpen = false;
|
|
484
|
+
let workspacePickerIndex = 0;
|
|
458
485
|
let menuIndex = 0;
|
|
459
486
|
let showReactionPicker = false;
|
|
460
487
|
let reactionIndex = 0;
|
|
@@ -465,8 +492,22 @@ export async function runChat(initialChannel = "general") {
|
|
|
465
492
|
let updateStatus = { state: "checking" };
|
|
466
493
|
let targetMessageId;
|
|
467
494
|
let isOpen = true;
|
|
495
|
+
let lastHostedSyncMs = 0;
|
|
468
496
|
const refresh = async () => {
|
|
469
497
|
store = await ThaneStore.open();
|
|
498
|
+
if (hasHostedChat(store) && Date.now() - lastHostedSyncMs > 2500) {
|
|
499
|
+
try {
|
|
500
|
+
await syncHostedStore(store, { workspaceId: store.activeWorkspace.id });
|
|
501
|
+
lastHostedSyncMs = Date.now();
|
|
502
|
+
store = await ThaneStore.open();
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
status ||= `Hosted sync failed: ${error.message}`;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (!store.findChannel(activeChannel.id)) {
|
|
509
|
+
activeChannel = await selectConversation(store, "general");
|
|
510
|
+
}
|
|
470
511
|
const items = conversations(store, activeChannel.id);
|
|
471
512
|
const activeIndex = items.findIndex((item) => item.id === activeChannel.id);
|
|
472
513
|
if (focus !== "sidebar") {
|
|
@@ -513,6 +554,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
513
554
|
showHelp = false;
|
|
514
555
|
showMenu = false;
|
|
515
556
|
sidePanelLines = undefined;
|
|
557
|
+
workspacePickerOpen = false;
|
|
516
558
|
showReactionPicker = false;
|
|
517
559
|
focus = nextFocus;
|
|
518
560
|
messageIndex = Math.max(0, threadedMessages(store.recent(activeChannel.id, 200)).length - 1);
|
|
@@ -578,7 +620,13 @@ export async function runChat(initialChannel = "general") {
|
|
|
578
620
|
status = "No reaction target selected.";
|
|
579
621
|
return;
|
|
580
622
|
}
|
|
581
|
-
|
|
623
|
+
if (hasHostedChat(store)) {
|
|
624
|
+
await reactHostedMessage(store, { messageId: targetMessageId, emoji });
|
|
625
|
+
store = await ThaneStore.open();
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
await store.react(targetMessageId, emoji);
|
|
629
|
+
}
|
|
582
630
|
composerMode = "message";
|
|
583
631
|
targetMessageId = undefined;
|
|
584
632
|
showReactionPicker = false;
|
|
@@ -600,10 +648,18 @@ export async function runChat(initialChannel = "general") {
|
|
|
600
648
|
status = "No reply target selected.";
|
|
601
649
|
return;
|
|
602
650
|
}
|
|
603
|
-
const
|
|
651
|
+
const root = selectedMessage();
|
|
652
|
+
const threadRootId = root?.threadRootId ?? root?.id ?? targetMessageId;
|
|
653
|
+
if (hasHostedChat(store)) {
|
|
654
|
+
await sendHostedMessage(store, { channelId: activeChannel.id, text: trimmed, source: "chat", threadRootId });
|
|
655
|
+
store = await ThaneStore.open();
|
|
656
|
+
}
|
|
657
|
+
const sent = hasHostedChat(store)
|
|
658
|
+
? threadedMessages(store.recent(activeChannel.id, 200)).at(-1)
|
|
659
|
+
: await store.reply(targetMessageId, trimmed, "chat");
|
|
604
660
|
composerMode = "message";
|
|
605
661
|
targetMessageId = undefined;
|
|
606
|
-
messageIndex = Math.max(0, threadedMessages(store.recent(activeChannel.id, 200)).findIndex((message) => message.id === sent
|
|
662
|
+
messageIndex = Math.max(0, threadedMessages(store.recent(activeChannel.id, 200)).findIndex((message) => message.id === sent?.id));
|
|
607
663
|
status = "";
|
|
608
664
|
await store.markReadConversation(activeChannel.id);
|
|
609
665
|
return;
|
|
@@ -616,6 +672,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
616
672
|
showMenu = true;
|
|
617
673
|
showHelp = false;
|
|
618
674
|
sidePanelLines = undefined;
|
|
675
|
+
workspacePickerOpen = false;
|
|
619
676
|
status = "Command menu";
|
|
620
677
|
return;
|
|
621
678
|
}
|
|
@@ -638,12 +695,27 @@ export async function runChat(initialChannel = "general") {
|
|
|
638
695
|
status = "Reset workspace art to generated default.";
|
|
639
696
|
return;
|
|
640
697
|
}
|
|
698
|
+
if (trimmed.startsWith("/invite ")) {
|
|
699
|
+
const email = trimmed.slice("/invite ".length).trim();
|
|
700
|
+
if (!email) {
|
|
701
|
+
status = "Usage: /invite <email>";
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
status = await createWorkspaceInviteLink(store, "member", email);
|
|
705
|
+
showHelp = false;
|
|
706
|
+
showMenu = false;
|
|
707
|
+
sidePanelLines = undefined;
|
|
708
|
+
workspacePickerOpen = false;
|
|
709
|
+
showReactionPicker = false;
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
641
712
|
if (trimmed === "/invite-link" || trimmed === "/invite-link create" || trimmed === "/invite-link admin") {
|
|
642
713
|
const role = trimmed.endsWith(" admin") ? "admin" : "member";
|
|
643
714
|
status = `Invite link: ${await createWorkspaceInviteLink(store, role)}`;
|
|
644
715
|
showHelp = false;
|
|
645
716
|
showMenu = false;
|
|
646
717
|
sidePanelLines = undefined;
|
|
718
|
+
workspacePickerOpen = false;
|
|
647
719
|
showReactionPicker = false;
|
|
648
720
|
return;
|
|
649
721
|
}
|
|
@@ -651,17 +723,15 @@ export async function runChat(initialChannel = "general") {
|
|
|
651
723
|
showHelp = !showHelp;
|
|
652
724
|
showMenu = false;
|
|
653
725
|
sidePanelLines = undefined;
|
|
726
|
+
workspacePickerOpen = false;
|
|
654
727
|
status = showHelp ? "Command help" : "";
|
|
655
728
|
return;
|
|
656
729
|
}
|
|
657
730
|
if (trimmed === "/workspaces") {
|
|
658
|
-
const workspaces =
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
"",
|
|
663
|
-
...workspaces.split("\n")
|
|
664
|
-
];
|
|
731
|
+
const workspaces = store.listWorkspaces();
|
|
732
|
+
workspacePickerIndex = Math.max(0, workspaces.findIndex((workspace) => workspace.id === store.activeWorkspace.id));
|
|
733
|
+
sidePanelLines = renderWorkspacePickerLines(store, workspacePickerIndex);
|
|
734
|
+
workspacePickerOpen = true;
|
|
665
735
|
showHelp = false;
|
|
666
736
|
showMenu = false;
|
|
667
737
|
showReactionPicker = false;
|
|
@@ -670,6 +740,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
670
740
|
}
|
|
671
741
|
if (trimmed === "/channels") {
|
|
672
742
|
sidePanelLines = [`${BOLD}Channels${RESET}`, "", ...renderChannels(store.listChannels()).split("\n")];
|
|
743
|
+
workspacePickerOpen = false;
|
|
673
744
|
showHelp = false;
|
|
674
745
|
showMenu = false;
|
|
675
746
|
showReactionPicker = false;
|
|
@@ -677,11 +748,13 @@ export async function runChat(initialChannel = "general") {
|
|
|
677
748
|
return;
|
|
678
749
|
}
|
|
679
750
|
if (trimmed === "/members") {
|
|
680
|
-
|
|
751
|
+
const members = activeChannel.kind === "channel" ? store.channelMembers(activeChannel.name) : store.listUsers();
|
|
752
|
+
sidePanelLines = [`${BOLD}Members: ${channelLabel(activeChannel)}${RESET}`, "", ...renderUsers(members).split("\n")];
|
|
753
|
+
workspacePickerOpen = false;
|
|
681
754
|
showHelp = false;
|
|
682
755
|
showMenu = false;
|
|
683
756
|
showReactionPicker = false;
|
|
684
|
-
status =
|
|
757
|
+
status = `Members in ${channelLabel(activeChannel)}.`;
|
|
685
758
|
return;
|
|
686
759
|
}
|
|
687
760
|
if (trimmed === "/inbox" || trimmed === "/inbox all") {
|
|
@@ -691,6 +764,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
691
764
|
"",
|
|
692
765
|
...renderInbox(store.inbox({ allWorkspaces })).split("\n")
|
|
693
766
|
];
|
|
767
|
+
workspacePickerOpen = false;
|
|
694
768
|
showHelp = false;
|
|
695
769
|
showMenu = false;
|
|
696
770
|
showReactionPicker = false;
|
|
@@ -703,12 +777,89 @@ export async function runChat(initialChannel = "general") {
|
|
|
703
777
|
"",
|
|
704
778
|
...renderMessages(store.recent(activeChannel.id, 12)).split("\n")
|
|
705
779
|
];
|
|
780
|
+
workspacePickerOpen = false;
|
|
706
781
|
showHelp = false;
|
|
707
782
|
showMenu = false;
|
|
708
783
|
showReactionPicker = false;
|
|
709
784
|
status = `Recent messages in ${channelLabel(activeChannel)}.`;
|
|
710
785
|
return;
|
|
711
786
|
}
|
|
787
|
+
if (trimmed.startsWith("/thread ")) {
|
|
788
|
+
const messageId = trimmed.slice("/thread ".length).trim();
|
|
789
|
+
sidePanelLines = [`${BOLD}Thread${RESET}`, "", ...renderMessages(store.thread(messageId)).split("\n")];
|
|
790
|
+
workspacePickerOpen = false;
|
|
791
|
+
showHelp = false;
|
|
792
|
+
showMenu = false;
|
|
793
|
+
showReactionPicker = false;
|
|
794
|
+
status = `Thread ${messageId}`;
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (trimmed.startsWith("/reply ")) {
|
|
798
|
+
const match = trimmed.match(/^\/reply\s+(\S+)\s+([\s\S]+)$/);
|
|
799
|
+
if (!match?.[1] || !match[2]?.trim()) {
|
|
800
|
+
status = "Usage: /reply <message-id> <text>";
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const messageId = match[1];
|
|
804
|
+
const text = match[2].trim();
|
|
805
|
+
const root = store.thread(messageId)[0];
|
|
806
|
+
if (!root) {
|
|
807
|
+
status = `Message ${messageId} was not found.`;
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const target = store.findChannel(root.channel);
|
|
811
|
+
if (!target) {
|
|
812
|
+
status = `Channel ${root.channel} was not found.`;
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (hasHostedChat(store)) {
|
|
816
|
+
await sendHostedMessage(store, { channelId: target.id, text, source: "chat", threadRootId: root.threadRootId ?? root.id });
|
|
817
|
+
store = await ThaneStore.open();
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
await store.reply(messageId, text, "chat");
|
|
821
|
+
}
|
|
822
|
+
activeChannel = target;
|
|
823
|
+
sidePanelLines = [`${BOLD}Thread${RESET}`, "", ...renderMessages(store.thread(messageId)).split("\n")];
|
|
824
|
+
workspacePickerOpen = false;
|
|
825
|
+
showHelp = false;
|
|
826
|
+
showMenu = false;
|
|
827
|
+
showReactionPicker = false;
|
|
828
|
+
status = `Replied in thread ${messageId}.`;
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
if (trimmed.startsWith("/react ")) {
|
|
832
|
+
const match = trimmed.match(/^\/react\s+(\S+)\s+(.+)$/);
|
|
833
|
+
if (!match?.[1] || !match[2]?.trim()) {
|
|
834
|
+
status = "Usage: /react <message-id> <emoji>";
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const messageId = match[1];
|
|
838
|
+
const emoji = match[2].trim();
|
|
839
|
+
if (hasHostedChat(store)) {
|
|
840
|
+
await reactHostedMessage(store, { messageId, emoji });
|
|
841
|
+
store = await ThaneStore.open();
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
await store.react(messageId, emoji);
|
|
845
|
+
}
|
|
846
|
+
status = `Reacted ${emoji}`;
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (trimmed.startsWith("/search ")) {
|
|
850
|
+
const query = trimmed.slice("/search ".length).trim();
|
|
851
|
+
if (!query) {
|
|
852
|
+
status = "Usage: /search <query>";
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
sidePanelLines = [`${BOLD}Search: ${query}${RESET}`, "", ...renderMessages(store.search(query, 20)).split("\n")];
|
|
856
|
+
workspacePickerOpen = false;
|
|
857
|
+
showHelp = false;
|
|
858
|
+
showMenu = false;
|
|
859
|
+
showReactionPicker = false;
|
|
860
|
+
status = `Search results for ${query}.`;
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
712
863
|
if (trimmed === "/leave") {
|
|
713
864
|
if (activeChannel.kind === "dm") {
|
|
714
865
|
status = "DMs cannot be left.";
|
|
@@ -717,6 +868,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
717
868
|
const left = await store.leaveChannel(activeChannel.name);
|
|
718
869
|
activeChannel = await selectConversation(store, "general");
|
|
719
870
|
sidePanelLines = undefined;
|
|
871
|
+
workspacePickerOpen = false;
|
|
720
872
|
showHelp = false;
|
|
721
873
|
showMenu = false;
|
|
722
874
|
showReactionPicker = false;
|
|
@@ -724,12 +876,18 @@ export async function runChat(initialChannel = "general") {
|
|
|
724
876
|
return;
|
|
725
877
|
}
|
|
726
878
|
if (trimmed.startsWith("/join ")) {
|
|
727
|
-
|
|
879
|
+
const channelName = trimmed.slice("/join ".length).trim();
|
|
880
|
+
if (hasHostedChat(store)) {
|
|
881
|
+
await createHostedChannel(store, { name: channelName });
|
|
882
|
+
store = await ThaneStore.open();
|
|
883
|
+
}
|
|
884
|
+
activeChannel = await selectConversation(store, channelName);
|
|
728
885
|
await store.markReadConversation(activeChannel.id);
|
|
729
886
|
status = `Joined ${channelLabel(activeChannel)}`;
|
|
730
887
|
showHelp = false;
|
|
731
888
|
showMenu = false;
|
|
732
889
|
sidePanelLines = undefined;
|
|
890
|
+
workspacePickerOpen = false;
|
|
733
891
|
showReactionPicker = false;
|
|
734
892
|
focus = "messages";
|
|
735
893
|
messageIndex = Math.max(0, threadedMessages(store.recent(activeChannel.id, 200)).length - 1);
|
|
@@ -742,6 +900,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
742
900
|
showHelp = false;
|
|
743
901
|
showMenu = false;
|
|
744
902
|
sidePanelLines = undefined;
|
|
903
|
+
workspacePickerOpen = false;
|
|
745
904
|
showReactionPicker = false;
|
|
746
905
|
focus = "messages";
|
|
747
906
|
messageIndex = Math.max(0, threadedMessages(store.recent(activeChannel.id, 200)).length - 1);
|
|
@@ -749,11 +908,16 @@ export async function runChat(initialChannel = "general") {
|
|
|
749
908
|
}
|
|
750
909
|
if (trimmed.startsWith("/workspace ")) {
|
|
751
910
|
const workspace = await store.useWorkspace(trimmed.slice("/workspace ".length).trim());
|
|
911
|
+
if (hasHostedChat(store)) {
|
|
912
|
+
await syncHostedStore(store, { workspaceId: workspace.id });
|
|
913
|
+
store = await ThaneStore.open();
|
|
914
|
+
}
|
|
752
915
|
activeChannel = await selectConversation(store, "general");
|
|
753
916
|
status = `Switched to workspace ${workspace.slug}`;
|
|
754
917
|
showHelp = false;
|
|
755
918
|
showMenu = false;
|
|
756
919
|
sidePanelLines = undefined;
|
|
920
|
+
workspacePickerOpen = false;
|
|
757
921
|
showReactionPicker = false;
|
|
758
922
|
return;
|
|
759
923
|
}
|
|
@@ -761,13 +925,20 @@ export async function runChat(initialChannel = "general") {
|
|
|
761
925
|
status = "Unknown command. Type /help.";
|
|
762
926
|
return;
|
|
763
927
|
}
|
|
764
|
-
|
|
928
|
+
if (hasHostedChat(store)) {
|
|
929
|
+
await sendHostedMessage(store, { channelId: activeChannel.id, text: trimmed, source: "chat" });
|
|
930
|
+
store = await ThaneStore.open();
|
|
931
|
+
}
|
|
932
|
+
const sent = hasHostedChat(store)
|
|
933
|
+
? threadedMessages(store.recent(activeChannel.id, 200)).at(-1)
|
|
934
|
+
: await store.sendMessage(activeChannel.id, trimmed, undefined, "chat");
|
|
765
935
|
const messages = threadedMessages(store.recent(activeChannel.id, 200));
|
|
766
|
-
status = messages.some((message) => message.id === sent.id) ? "" : "";
|
|
767
|
-
messageIndex = Math.max(0, messages.findIndex((message) => message.id === sent.id));
|
|
936
|
+
status = sent && messages.some((message) => message.id === sent.id) ? "" : "";
|
|
937
|
+
messageIndex = Math.max(0, sent ? messages.findIndex((message) => message.id === sent.id) : messages.length - 1);
|
|
768
938
|
showHelp = false;
|
|
769
939
|
showMenu = false;
|
|
770
940
|
sidePanelLines = undefined;
|
|
941
|
+
workspacePickerOpen = false;
|
|
771
942
|
await store.markReadConversation(activeChannel.id);
|
|
772
943
|
};
|
|
773
944
|
const completeInput = () => {
|
|
@@ -800,6 +971,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
800
971
|
showMenu = true;
|
|
801
972
|
showHelp = false;
|
|
802
973
|
sidePanelLines = undefined;
|
|
974
|
+
workspacePickerOpen = false;
|
|
803
975
|
status = "Command menu";
|
|
804
976
|
}
|
|
805
977
|
else {
|
|
@@ -894,6 +1066,47 @@ export async function runChat(initialChannel = "general") {
|
|
|
894
1066
|
await refresh();
|
|
895
1067
|
return;
|
|
896
1068
|
}
|
|
1069
|
+
if (workspacePickerOpen) {
|
|
1070
|
+
const workspaces = store.listWorkspaces();
|
|
1071
|
+
if (key.name === "escape") {
|
|
1072
|
+
workspacePickerOpen = false;
|
|
1073
|
+
sidePanelLines = undefined;
|
|
1074
|
+
status = "";
|
|
1075
|
+
}
|
|
1076
|
+
else if (key.name === "up") {
|
|
1077
|
+
workspacePickerIndex = workspacePickerIndex === 0 ? Math.max(0, workspaces.length - 1) : workspacePickerIndex - 1;
|
|
1078
|
+
sidePanelLines = renderWorkspacePickerLines(store, workspacePickerIndex);
|
|
1079
|
+
}
|
|
1080
|
+
else if (key.name === "down" || key.name === "tab") {
|
|
1081
|
+
workspacePickerIndex = workspacePickerIndex >= workspaces.length - 1 ? 0 : workspacePickerIndex + 1;
|
|
1082
|
+
sidePanelLines = renderWorkspacePickerLines(store, workspacePickerIndex);
|
|
1083
|
+
}
|
|
1084
|
+
else if (key.name === "return") {
|
|
1085
|
+
const selected = workspaces[workspacePickerIndex];
|
|
1086
|
+
if (selected) {
|
|
1087
|
+
const workspace = await store.useWorkspace(selected.slug);
|
|
1088
|
+
if (hasHostedChat(store)) {
|
|
1089
|
+
await syncHostedStore(store, { workspaceId: workspace.id });
|
|
1090
|
+
store = await ThaneStore.open();
|
|
1091
|
+
}
|
|
1092
|
+
activeChannel = await selectConversation(store, "general");
|
|
1093
|
+
workspacePickerOpen = false;
|
|
1094
|
+
sidePanelLines = undefined;
|
|
1095
|
+
status = `Switched to workspace ${workspace.slug}`;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
else if (key.sequence && key.sequence >= " " && !key.ctrl) {
|
|
1099
|
+
workspacePickerOpen = false;
|
|
1100
|
+
sidePanelLines = undefined;
|
|
1101
|
+
inputText = key.sequence;
|
|
1102
|
+
focusComposer();
|
|
1103
|
+
}
|
|
1104
|
+
if (!isOpen) {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
await refresh();
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
897
1110
|
if (focus === "sidebar") {
|
|
898
1111
|
const items = conversations(store, activeChannel.id);
|
|
899
1112
|
if (key.name === "up") {
|
|
@@ -1002,6 +1215,7 @@ export async function runChat(initialChannel = "general") {
|
|
|
1002
1215
|
showHelp = false;
|
|
1003
1216
|
showMenu = false;
|
|
1004
1217
|
sidePanelLines = undefined;
|
|
1218
|
+
workspacePickerOpen = false;
|
|
1005
1219
|
showReactionPicker = false;
|
|
1006
1220
|
if (composerMode !== "message") {
|
|
1007
1221
|
composerMode = "message";
|