@scindo/cli 1.0.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 (54) hide show
  1. package/README.md +136 -0
  2. package/dist/commands/agent.d.ts +2 -0
  3. package/dist/commands/agent.d.ts.map +1 -0
  4. package/dist/commands/agent.js +91 -0
  5. package/dist/commands/agent.js.map +1 -0
  6. package/dist/commands/channels.d.ts +2 -0
  7. package/dist/commands/channels.d.ts.map +1 -0
  8. package/dist/commands/channels.js +67 -0
  9. package/dist/commands/channels.js.map +1 -0
  10. package/dist/commands/dm.d.ts +2 -0
  11. package/dist/commands/dm.d.ts.map +1 -0
  12. package/dist/commands/dm.js +86 -0
  13. package/dist/commands/dm.js.map +1 -0
  14. package/dist/commands/login.d.ts +3 -0
  15. package/dist/commands/login.d.ts.map +1 -0
  16. package/dist/commands/login.js +95 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/push.d.ts +7 -0
  19. package/dist/commands/push.d.ts.map +1 -0
  20. package/dist/commands/push.js +100 -0
  21. package/dist/commands/push.js.map +1 -0
  22. package/dist/commands/read.d.ts +4 -0
  23. package/dist/commands/read.d.ts.map +1 -0
  24. package/dist/commands/read.js +93 -0
  25. package/dist/commands/read.js.map +1 -0
  26. package/dist/commands/send.d.ts +2 -0
  27. package/dist/commands/send.d.ts.map +1 -0
  28. package/dist/commands/send.js +49 -0
  29. package/dist/commands/send.js.map +1 -0
  30. package/dist/commands/thread.d.ts +3 -0
  31. package/dist/commands/thread.d.ts.map +1 -0
  32. package/dist/commands/thread.js +123 -0
  33. package/dist/commands/thread.js.map +1 -0
  34. package/dist/commands/unread.d.ts +2 -0
  35. package/dist/commands/unread.d.ts.map +1 -0
  36. package/dist/commands/unread.js +91 -0
  37. package/dist/commands/unread.js.map +1 -0
  38. package/dist/config.d.ts +16 -0
  39. package/dist/config.d.ts.map +1 -0
  40. package/dist/config.js +30 -0
  41. package/dist/config.js.map +1 -0
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +83 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/stream.d.ts +5 -0
  47. package/dist/stream.d.ts.map +1 -0
  48. package/dist/stream.js +55 -0
  49. package/dist/stream.js.map +1 -0
  50. package/dist/supabase.d.ts +4 -0
  51. package/dist/supabase.d.ts.map +1 -0
  52. package/dist/supabase.js +42 -0
  53. package/dist/supabase.js.map +1 -0
  54. package/package.json +48 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAkCA,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFjG"}
@@ -0,0 +1,93 @@
1
+ import chalk from 'chalk';
2
+ import { getSupabase } from '../supabase.js';
3
+ import { getConfig, setConfig } from '../config.js';
4
+ function formatTime(iso) {
5
+ const d = new Date(iso);
6
+ return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
7
+ }
8
+ function formatDate(iso) {
9
+ const d = new Date(iso);
10
+ const today = new Date();
11
+ if (d.toDateString() === today.toDateString())
12
+ return 'Today';
13
+ const yesterday = new Date(today);
14
+ yesterday.setDate(yesterday.getDate() - 1);
15
+ if (d.toDateString() === yesterday.toDateString())
16
+ return 'Yesterday';
17
+ return d.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' });
18
+ }
19
+ function getDisplayName(profiles) {
20
+ if (Array.isArray(profiles))
21
+ return profiles[0]?.display_name ?? 'Unknown';
22
+ return profiles?.display_name ?? 'Unknown';
23
+ }
24
+ export async function readCommand(channelName, options) {
25
+ const supabase = getSupabase();
26
+ const config = getConfig();
27
+ const slug = channelName.replace(/^#/, '');
28
+ let workspaceId = config.lastWorkspaceId;
29
+ if (!workspaceId) {
30
+ const { data: member } = await supabase
31
+ .from('workspace_members')
32
+ .select('workspace_id')
33
+ .limit(1)
34
+ .single();
35
+ if (!member) {
36
+ console.log(chalk.red('No workspaces found'));
37
+ return;
38
+ }
39
+ workspaceId = member.workspace_id;
40
+ setConfig({ lastWorkspaceId: workspaceId });
41
+ }
42
+ // Find channel
43
+ const { data: channel, error: chErr } = await supabase
44
+ .from('channels')
45
+ .select('id, name')
46
+ .eq('workspace_id', workspaceId)
47
+ .eq('slug', slug)
48
+ .single();
49
+ if (chErr || !channel) {
50
+ console.log(chalk.red(`Channel #${slug} not found`));
51
+ return;
52
+ }
53
+ setConfig({ lastChannelId: channel.id });
54
+ const limit = parseInt(options.limit ?? '20', 10);
55
+ const { data: messages, error } = await supabase
56
+ .from('messages')
57
+ .select('id, content, created_at, user_id, is_edited, reply_count, profiles:user_id(display_name)')
58
+ .eq('channel_id', channel.id)
59
+ .is('thread_id', null)
60
+ .is('deleted_at', null)
61
+ .order('created_at', { ascending: false })
62
+ .limit(limit);
63
+ if (error) {
64
+ console.log(chalk.red(`Error: ${error.message}`));
65
+ return;
66
+ }
67
+ const msgs = (messages ?? []).reverse();
68
+ console.log(chalk.bold(`#${channel.name}`));
69
+ console.log();
70
+ let lastDate = '';
71
+ for (const msg of msgs) {
72
+ const date = formatDate(msg.created_at);
73
+ if (date !== lastDate) {
74
+ console.log(chalk.dim(` ── ${date} ──`));
75
+ lastDate = date;
76
+ }
77
+ const time = chalk.dim(formatTime(msg.created_at));
78
+ const author = chalk.bold(getDisplayName(msg.profiles));
79
+ const edited = msg.is_edited ? chalk.dim(' (edited)') : '';
80
+ const thread = msg.reply_count > 0 ? chalk.cyan(` [${msg.reply_count} replies]`) : '';
81
+ console.log(` ${time} ${author}${edited}${thread}`);
82
+ console.log(` ${msg.content}`);
83
+ }
84
+ // Mark as read
85
+ if (config.userId) {
86
+ await supabase
87
+ .from('channel_members')
88
+ .update({ last_read_at: new Date().toISOString() })
89
+ .eq('channel_id', channel.id)
90
+ .eq('user_id', config.userId);
91
+ }
92
+ }
93
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function sendCommand(channelName: string, message: string): Promise<void>;
2
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDrF"}
@@ -0,0 +1,49 @@
1
+ import chalk from 'chalk';
2
+ import { getSupabase } from '../supabase.js';
3
+ import { getConfig, setConfig } from '../config.js';
4
+ export async function sendCommand(channelName, message) {
5
+ const supabase = getSupabase();
6
+ const config = getConfig();
7
+ if (!config.userId) {
8
+ console.log(chalk.red('Not logged in. Run: scindo login'));
9
+ return;
10
+ }
11
+ const slug = channelName.replace(/^#/, '');
12
+ let workspaceId = config.lastWorkspaceId;
13
+ if (!workspaceId) {
14
+ const { data: member } = await supabase
15
+ .from('workspace_members')
16
+ .select('workspace_id')
17
+ .limit(1)
18
+ .single();
19
+ if (!member) {
20
+ console.log(chalk.red('No workspaces found'));
21
+ return;
22
+ }
23
+ workspaceId = member.workspace_id;
24
+ setConfig({ lastWorkspaceId: workspaceId });
25
+ }
26
+ // Find channel
27
+ const { data: channel, error: chErr } = await supabase
28
+ .from('channels')
29
+ .select('id, name')
30
+ .eq('workspace_id', workspaceId)
31
+ .eq('slug', slug)
32
+ .single();
33
+ if (chErr || !channel) {
34
+ console.log(chalk.red(`Channel #${slug} not found`));
35
+ return;
36
+ }
37
+ const { error } = await supabase.from('messages').insert({
38
+ workspace_id: workspaceId,
39
+ channel_id: channel.id,
40
+ user_id: config.userId,
41
+ content: message,
42
+ });
43
+ if (error) {
44
+ console.log(chalk.red(`Failed to send: ${error.message}`));
45
+ return;
46
+ }
47
+ console.log(chalk.green(`Message sent to #${channel.name}`));
48
+ }
49
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAEnD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,WAAmB,EAAE,OAAe;IACpE,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC,CAAA;QAC1D,OAAM;IACR,CAAC;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC1C,IAAI,WAAW,GAAG,MAAM,CAAC,eAAe,CAAA;IAExC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ;aACpC,IAAI,CAAC,mBAAmB,CAAC;aACzB,MAAM,CAAC,cAAc,CAAC;aACtB,KAAK,CAAC,CAAC,CAAC;aACR,MAAM,EAAE,CAAA;QAEX,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAA;YAC7C,OAAM;QACR,CAAC;QACD,WAAW,GAAG,MAAM,CAAC,YAAY,CAAA;QACjC,SAAS,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC,CAAA;IAC7C,CAAC;IAED,eAAe;IACf,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;SACnD,IAAI,CAAC,UAAU,CAAC;SAChB,MAAM,CAAC,UAAU,CAAC;SAClB,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC;SAC/B,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;SAChB,MAAM,EAAE,CAAA;IAEX,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,CAAC,CAAA;QACpD,OAAM;IACR,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;QACvD,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,OAAO,CAAC,EAAE;QACtB,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAA;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAC1D,OAAM;IACR,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;AAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function threadCommand(channelName: string): Promise<void>;
2
+ export declare function replyCommand(message: string): Promise<void>;
3
+ //# sourceMappingURL=thread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/commands/thread.ts"],"names":[],"mappings":"AAuBA,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFtE;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CjE"}
@@ -0,0 +1,123 @@
1
+ import chalk from 'chalk';
2
+ import { getSupabase } from '../supabase.js';
3
+ import { getConfig, setConfig } from '../config.js';
4
+ function formatTime(iso) {
5
+ return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
6
+ }
7
+ function getDisplayName(profiles) {
8
+ if (Array.isArray(profiles))
9
+ return profiles[0]?.display_name ?? 'Unknown';
10
+ return profiles?.display_name ?? 'Unknown';
11
+ }
12
+ export async function threadCommand(channelName) {
13
+ const supabase = getSupabase();
14
+ const config = getConfig();
15
+ const slug = channelName.replace(/^#/, '');
16
+ let workspaceId = config.lastWorkspaceId;
17
+ if (!workspaceId) {
18
+ const { data: member } = await supabase
19
+ .from('workspace_members')
20
+ .select('workspace_id')
21
+ .limit(1)
22
+ .single();
23
+ if (!member) {
24
+ console.log(chalk.red('No workspaces found'));
25
+ return;
26
+ }
27
+ workspaceId = member.workspace_id;
28
+ setConfig({ lastWorkspaceId: workspaceId });
29
+ }
30
+ // Find channel
31
+ const { data: channel, error: chErr } = await supabase
32
+ .from('channels')
33
+ .select('id, name')
34
+ .eq('workspace_id', workspaceId)
35
+ .eq('slug', slug)
36
+ .single();
37
+ if (chErr || !channel) {
38
+ console.log(chalk.red(`Channel #${slug} not found`));
39
+ return;
40
+ }
41
+ // Find the latest message with replies
42
+ const { data: parent } = await supabase
43
+ .from('messages')
44
+ .select('id, content, created_at, user_id, is_edited, reply_count, profiles:user_id(display_name)')
45
+ .eq('channel_id', channel.id)
46
+ .is('thread_id', null)
47
+ .is('deleted_at', null)
48
+ .gt('reply_count', 0)
49
+ .order('last_reply_at', { ascending: false })
50
+ .limit(1)
51
+ .single();
52
+ if (!parent) {
53
+ console.log(chalk.dim('No threads found in this channel'));
54
+ return;
55
+ }
56
+ const parentMsg = parent;
57
+ setConfig({ lastThreadId: parentMsg.id });
58
+ console.log(chalk.bold(`Thread in #${channel.name}`));
59
+ console.log();
60
+ // Show parent message
61
+ const parentAuthor = chalk.bold(getDisplayName(parentMsg.profiles));
62
+ const parentTime = chalk.dim(formatTime(parentMsg.created_at));
63
+ console.log(` ${parentTime} ${parentAuthor}`);
64
+ console.log(` ${parentMsg.content}`);
65
+ console.log(chalk.dim(` ── ${parentMsg.reply_count} replies ──`));
66
+ console.log();
67
+ // Fetch replies
68
+ const { data: replies } = await supabase
69
+ .from('messages')
70
+ .select('id, content, created_at, user_id, is_edited, reply_count, profiles:user_id(display_name)')
71
+ .eq('thread_id', parentMsg.id)
72
+ .is('deleted_at', null)
73
+ .order('created_at', { ascending: true })
74
+ .limit(50);
75
+ const replyMsgs = (replies ?? []);
76
+ for (const msg of replyMsgs) {
77
+ const time = chalk.dim(formatTime(msg.created_at));
78
+ const author = chalk.bold(getDisplayName(msg.profiles));
79
+ const edited = msg.is_edited ? chalk.dim(' (edited)') : '';
80
+ console.log(` ${time} ${author}${edited}`);
81
+ console.log(` ${msg.content}`);
82
+ }
83
+ }
84
+ export async function replyCommand(message) {
85
+ const supabase = getSupabase();
86
+ const config = getConfig();
87
+ if (!config.userId) {
88
+ console.log(chalk.red('Not logged in. Run: scindo login'));
89
+ return;
90
+ }
91
+ if (!config.lastThreadId) {
92
+ console.log(chalk.red('No active thread. Run: scindo thread #channel'));
93
+ return;
94
+ }
95
+ if (!config.lastWorkspaceId) {
96
+ console.log(chalk.red('No workspace selected. Run: scindo channels'));
97
+ return;
98
+ }
99
+ // Get the parent message to find its channel_id
100
+ const { data: parent } = await supabase
101
+ .from('messages')
102
+ .select('channel_id, conversation_id')
103
+ .eq('id', config.lastThreadId)
104
+ .single();
105
+ if (!parent) {
106
+ console.log(chalk.red('Thread not found'));
107
+ return;
108
+ }
109
+ const { error } = await supabase.from('messages').insert({
110
+ workspace_id: config.lastWorkspaceId,
111
+ channel_id: parent.channel_id,
112
+ conversation_id: parent.conversation_id,
113
+ thread_id: config.lastThreadId,
114
+ user_id: config.userId,
115
+ content: message,
116
+ });
117
+ if (error) {
118
+ console.log(chalk.red(`Failed to reply: ${error.message}`));
119
+ return;
120
+ }
121
+ console.log(chalk.green('Reply sent'));
122
+ }
123
+ //# sourceMappingURL=thread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/commands/thread.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function unreadCommand(): Promise<void>;
2
+ //# sourceMappingURL=unread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA6GnD"}
@@ -0,0 +1,91 @@
1
+ import chalk from 'chalk';
2
+ import { getSupabase } from '../supabase.js';
3
+ import { getConfig, setConfig } from '../config.js';
4
+ export async function unreadCommand() {
5
+ const supabase = getSupabase();
6
+ const config = getConfig();
7
+ if (!config.userId) {
8
+ console.log(chalk.red('Not logged in. Run: scindo login'));
9
+ return;
10
+ }
11
+ let workspaceId = config.lastWorkspaceId;
12
+ if (!workspaceId) {
13
+ const { data: member } = await supabase
14
+ .from('workspace_members')
15
+ .select('workspace_id, workspaces(name)')
16
+ .limit(1)
17
+ .single();
18
+ if (!member) {
19
+ console.log(chalk.red('No workspaces found'));
20
+ return;
21
+ }
22
+ workspaceId = member.workspace_id;
23
+ setConfig({ lastWorkspaceId: workspaceId });
24
+ }
25
+ // Channel unreads
26
+ const { data: channelUnreads } = await supabase.rpc('get_unread_counts', {
27
+ p_workspace_id: workspaceId,
28
+ p_user_id: config.userId,
29
+ });
30
+ // DM unreads
31
+ const { data: dmUnreads } = await supabase.rpc('get_dm_unread_counts', {
32
+ p_workspace_id: workspaceId,
33
+ p_user_id: config.userId,
34
+ });
35
+ const channelEntries = (channelUnreads ?? []);
36
+ const dmEntries = (dmUnreads ?? []);
37
+ const hasChannelUnreads = channelEntries.some((u) => u.unread_count > 0);
38
+ const hasDmUnreads = dmEntries.some((u) => u.unread_count > 0);
39
+ if (!hasChannelUnreads && !hasDmUnreads) {
40
+ console.log(chalk.green('All caught up! No unread messages.'));
41
+ return;
42
+ }
43
+ // Fetch channel names for unread channels
44
+ if (hasChannelUnreads) {
45
+ const unreadChannelIds = channelEntries
46
+ .filter((u) => u.unread_count > 0)
47
+ .map((u) => u.channel_id);
48
+ const { data: channels } = await supabase
49
+ .from('channels')
50
+ .select('id, name')
51
+ .in('id', unreadChannelIds);
52
+ const channelMap = new Map();
53
+ for (const ch of channels ?? []) {
54
+ channelMap.set(ch.id, ch.name);
55
+ }
56
+ console.log(chalk.bold('Channels'));
57
+ for (const entry of channelEntries.filter((u) => u.unread_count > 0)) {
58
+ const name = channelMap.get(entry.channel_id) ?? 'unknown';
59
+ const badge = entry.has_mention
60
+ ? chalk.red.bold(`${entry.unread_count} unread, @mention`)
61
+ : chalk.yellow(`${entry.unread_count} unread`);
62
+ console.log(` # ${name} ${badge}`);
63
+ }
64
+ }
65
+ if (hasDmUnreads) {
66
+ if (hasChannelUnreads)
67
+ console.log();
68
+ // Fetch participant display names for unread DM conversations
69
+ const unreadConvoIds = dmEntries
70
+ .filter((u) => u.unread_count > 0)
71
+ .map((u) => u.conversation_id);
72
+ const { data: members } = await supabase
73
+ .from('conversation_members')
74
+ .select('conversation_id, user_id, profiles(display_name, handle)')
75
+ .in('conversation_id', unreadConvoIds);
76
+ const convoNameMap = new Map();
77
+ for (const m of members ?? []) {
78
+ if (m.user_id === config.userId)
79
+ continue;
80
+ const profile = m.profiles;
81
+ const name = profile?.display_name ?? profile?.handle ?? 'unknown';
82
+ convoNameMap.set(m.conversation_id, name);
83
+ }
84
+ console.log(chalk.bold('Direct Messages'));
85
+ for (const entry of dmEntries.filter((u) => u.unread_count > 0)) {
86
+ const name = convoNameMap.get(entry.conversation_id) ?? 'unknown';
87
+ console.log(` @ ${name} ${chalk.yellow(`${entry.unread_count} unread`)}`);
88
+ }
89
+ }
90
+ }
91
+ //# sourceMappingURL=unread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ interface ScindoConfig {
2
+ supabaseUrl: string;
3
+ supabaseAnonKey: string;
4
+ accessToken: string;
5
+ refreshToken: string;
6
+ userId: string;
7
+ lastWorkspaceId?: string;
8
+ lastChannelId?: string;
9
+ lastThreadId?: string;
10
+ }
11
+ export declare function getConfig(): Partial<ScindoConfig>;
12
+ export declare function setConfig(data: Partial<ScindoConfig>): void;
13
+ export declare function clearConfig(): void;
14
+ export declare function isLoggedIn(): boolean;
15
+ export {};
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAMD,wBAAgB,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,CAWjD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAM3D;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC"}
package/dist/config.js ADDED
@@ -0,0 +1,30 @@
1
+ import Conf from 'conf';
2
+ const config = new Conf({
3
+ projectName: 'scindo',
4
+ });
5
+ export function getConfig() {
6
+ return {
7
+ supabaseUrl: config.get('supabaseUrl'),
8
+ supabaseAnonKey: config.get('supabaseAnonKey'),
9
+ accessToken: config.get('accessToken'),
10
+ refreshToken: config.get('refreshToken'),
11
+ userId: config.get('userId'),
12
+ lastWorkspaceId: config.get('lastWorkspaceId'),
13
+ lastChannelId: config.get('lastChannelId'),
14
+ lastThreadId: config.get('lastThreadId'),
15
+ };
16
+ }
17
+ export function setConfig(data) {
18
+ for (const [key, value] of Object.entries(data)) {
19
+ if (value !== undefined) {
20
+ config.set(key, value);
21
+ }
22
+ }
23
+ }
24
+ export function clearConfig() {
25
+ config.clear();
26
+ }
27
+ export function isLoggedIn() {
28
+ return !!config.get('accessToken') && !!config.get('supabaseUrl');
29
+ }
30
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAavB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAe;IACpC,WAAW,EAAE,QAAQ;CACtB,CAAC,CAAA;AAEF,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QACtC,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC9C,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QACtC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;QACxC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC9C,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC;QAC1C,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;KACzC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAA2B;IACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,CAAC,GAAyB,EAAE,KAAK,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,KAAK,EAAE,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;AACnE,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { loginCommand, logoutCommand } from './commands/login.js';
4
+ import { channelsCommand } from './commands/channels.js';
5
+ import { readCommand } from './commands/read.js';
6
+ import { sendCommand } from './commands/send.js';
7
+ import { dmCommand } from './commands/dm.js';
8
+ import { threadCommand, replyCommand } from './commands/thread.js';
9
+ import { unreadCommand } from './commands/unread.js';
10
+ import { agentCommand } from './commands/agent.js';
11
+ import { pushCommand } from './commands/push.js';
12
+ import { isLoggedIn } from './config.js';
13
+ import { refreshSession } from './supabase.js';
14
+ const program = new Command();
15
+ program
16
+ .name('scindo')
17
+ .description('Scindo CLI — team chat with AI agents from the terminal')
18
+ .version('1.0.0')
19
+ .hook('preAction', async (thisCommand) => {
20
+ // Refresh token before any command that needs auth
21
+ const name = thisCommand.name();
22
+ if (name !== 'login' && name !== 'logout' && isLoggedIn()) {
23
+ await refreshSession();
24
+ }
25
+ });
26
+ program
27
+ .command('login')
28
+ .description('Log in to Scindo')
29
+ .action(loginCommand);
30
+ program
31
+ .command('logout')
32
+ .description('Log out of Scindo')
33
+ .action(logoutCommand);
34
+ program
35
+ .command('channels')
36
+ .description('List channels with unread counts')
37
+ .action(channelsCommand);
38
+ program
39
+ .command('read')
40
+ .description('Read recent messages from a channel')
41
+ .argument('<channel>', 'Channel name (e.g. #general or general)')
42
+ .option('-n, --limit <count>', 'Number of messages to show', '20')
43
+ .action(readCommand);
44
+ program
45
+ .command('send')
46
+ .description('Send a message to a channel')
47
+ .argument('<channel>', 'Channel name (e.g. #general)')
48
+ .argument('<message>', 'Message content')
49
+ .action(sendCommand);
50
+ program
51
+ .command('dm')
52
+ .description('Send a direct message')
53
+ .argument('<user>', 'Username (e.g. @alice)')
54
+ .argument('<message>', 'Message content')
55
+ .action(dmCommand);
56
+ program
57
+ .command('thread')
58
+ .description('Read the latest thread in a channel')
59
+ .argument('<channel>', 'Channel name (e.g. #general)')
60
+ .action(threadCommand);
61
+ program
62
+ .command('reply')
63
+ .description('Reply to the last viewed thread')
64
+ .argument('<message>', 'Reply content')
65
+ .action(replyCommand);
66
+ program
67
+ .command('unread')
68
+ .description('Show all unread messages across channels and DMs')
69
+ .action(unreadCommand);
70
+ program
71
+ .command('agent')
72
+ .description('Send a message to the AI agent in a channel and stream the response')
73
+ .argument('<channel>', 'Channel name (e.g. #general)')
74
+ .argument('<message>', 'Message to send to the agent')
75
+ .action(agentCommand);
76
+ program
77
+ .command('push')
78
+ .description('Push stdin content to a channel')
79
+ .requiredOption('--channel <name>', 'Channel name (e.g. general)')
80
+ .option('--mention-agent', 'Mention @Scindo to trigger the agent')
81
+ .action(pushCommand);
82
+ program.parse();
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * SSE stream client for terminal — consumes agent streaming responses.
3
+ */
4
+ export declare function consumeSSEStream(response: Response, onToken: (token: string) => void, onDone: () => void): Promise<void>;
5
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAChC,MAAM,EAAE,MAAM,IAAI,GACjB,OAAO,CAAC,IAAI,CAAC,CAoDf"}
package/dist/stream.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * SSE stream client for terminal — consumes agent streaming responses.
3
+ */
4
+ export async function consumeSSEStream(response, onToken, onDone) {
5
+ const reader = response.body?.getReader();
6
+ if (!reader) {
7
+ onDone();
8
+ return;
9
+ }
10
+ const decoder = new TextDecoder();
11
+ let buffer = "";
12
+ try {
13
+ while (true) {
14
+ const { done, value } = await reader.read();
15
+ if (done)
16
+ break;
17
+ buffer += decoder.decode(value, { stream: true });
18
+ const lines = buffer.split("\n");
19
+ buffer = lines.pop() ?? "";
20
+ for (const line of lines) {
21
+ const trimmed = line.trim();
22
+ if (!trimmed.startsWith("data: "))
23
+ continue;
24
+ const jsonStr = trimmed.slice(6);
25
+ if (jsonStr === "[DONE]") {
26
+ onDone();
27
+ return;
28
+ }
29
+ try {
30
+ const data = JSON.parse(jsonStr);
31
+ if (data.done) {
32
+ onDone();
33
+ return;
34
+ }
35
+ if (data.token) {
36
+ onToken(data.token);
37
+ }
38
+ if (data.error) {
39
+ process.stderr.write(`\nError: ${data.error}\n`);
40
+ onDone();
41
+ return;
42
+ }
43
+ }
44
+ catch {
45
+ // Skip malformed JSON
46
+ }
47
+ }
48
+ }
49
+ }
50
+ finally {
51
+ reader.releaseLock();
52
+ }
53
+ onDone();
54
+ }
55
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAkB,EAClB,OAAgC,EAChC,MAAkB;IAElB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,EAAE,CAAC;QACT,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAEhB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAElD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACjC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACzB,MAAM,EAAE,CAAC;oBACT,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACjC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;wBACd,MAAM,EAAE,CAAC;wBACT,OAAO;oBACT,CAAC;oBACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACtB,CAAC;oBACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;wBACjD,MAAM,EAAE,CAAC;wBACT,OAAO;oBACT,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,sBAAsB;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,EAAE,CAAC;AACX,CAAC"}