thinkncollab-shell 0.0.7 → 0.0.9

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.
@@ -1,130 +1,130 @@
1
- /**
2
- * src/commands/index.js — Command Registry
3
- */
4
- const chalk = require('chalk');
5
-
6
- class CommandRegistry {
7
- constructor(shell) {
8
- this.shell = shell;
9
- this.commands = new Map();
10
- this.aliases = new Map();
11
- this.categories = new Map();
12
- this.loadCommands();
13
- }
14
-
15
- loadCommands() {
16
- const load = (path, category) => {
17
- try {
18
- const cmd = require(path);
19
- if (!cmd || !cmd.name) {
20
- console.error(chalk.red(`❌ BAD COMMAND (no name): ${path}`));
21
- return;
22
- }
23
- this.register(cmd, category);
24
- }
25
- catch (e) { console.error(chalk.red(`❌ Failed to load ${path}: ${e.message}`)); }
26
- };
27
-
28
- // Auth
29
- load('./auth/login', 'auth');
30
- load('./auth/logout', 'auth');
31
- load('./auth/whoami', 'auth');
32
- load('./auth/register', 'auth');
33
-
34
- // Team
35
- load('./team/myteam', 'team');
36
- load('./team/teammates', 'team');
37
- load('./team/invite', 'team');
38
-
39
- // Room
40
- load('./room/join', 'room');
41
- load('./room/leave', 'room');
42
- load('./room/rooms', 'room');
43
-
44
- // Message
45
- load('./message/say', 'message');
46
-
47
- // Shell
48
- load('./shell/status', 'shell');
49
- load('./shell/notify', 'shell');
50
-
51
- // Tasks
52
- load('./tasks/tasks', 'tasks');
53
- load('./tasks/task', 'tasks');
54
- load('./tasks/task-status', 'tasks');
55
- // load('./tasks/start', 'tasks');
56
- load('./tasks/complete', 'tasks');
57
- // load('./tasks/comment', 'tasks');
58
- load('./tasks/create-task', 'tasks');
59
-
60
-
61
- // Terminal
62
- load('./terminal/share', 'terminal');
63
-
64
-
65
-
66
-
67
-
68
- }
69
-
70
- register(command, category) {
71
- if (!command || !command.name) {
72
- console.error(chalk.yellow(`⚠️ Skipping invalid command in category: ${category}`));
73
- return;
74
- }
75
- this.commands.set(command.name, command);
76
- if (!this.categories.has(category)) this.categories.set(category, []);
77
- this.categories.get(category).push(command.name);
78
- if (command.aliases) command.aliases.forEach(a => this.aliases.set(a, command.name));
79
- }
80
-
81
- addAlias(alias, command) { this.aliases.set(alias, command); }
82
-
83
- getCommand(name) {
84
- if (this.aliases.has(name)) name = this.aliases.get(name);
85
- return this.commands.get(name);
86
- }
87
-
88
- async execute(input, shell) {
89
- const args = shell.parseCommand(input);
90
- const cmdName = args[0].toLowerCase();
91
- const cmdArgs = args.slice(1);
92
-
93
- const command = this.getCommand(cmdName);
94
- if (!command) return false;
95
-
96
- try {
97
- if (command.requiresAuth && !shell.api?.isAuthenticated()) {
98
- console.log(chalk.red('❌ Please login first: login'));
99
- return true;
100
- }
101
- if (command.requiresRoom && !shell.ws?.getCurrentRoom()) {
102
- console.log(chalk.red('❌ Please join a room first: join <room-id>'));
103
- return true;
104
- }
105
- await command.execute(cmdArgs, shell);
106
- } catch (error) {
107
- console.log(chalk.red(`❌ Command error: ${error.message}`));
108
- }
109
-
110
- return true;
111
- }
112
-
113
- getHelpText() {
114
- let help = chalk.cyan('\n📚 Available Commands:\n');
115
- help += chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n');
116
- for (const [category, commands] of this.categories) {
117
- help += chalk.yellow(`${category.toUpperCase()}:\n`);
118
- commands.forEach(cmdName => {
119
- const cmd = this.commands.get(cmdName);
120
- if (!cmd || !cmdName) return; // ← ye line add karo
121
- const aliases = cmd.aliases ? chalk.dim(` (${cmd.aliases.join(', ')})`) : '';
122
- help += ` ${chalk.green(cmdName.padEnd(14))}${aliases} - ${cmd.description || ''}\n`;
123
- });
124
- help += '\n';
125
- }
126
- return help;
127
- }
128
- }
129
-
1
+ /*
2
+ src/commands/index.js — Command Registry
3
+ */
4
+ const chalk = require('chalk');
5
+
6
+ class CommandRegistry {
7
+ constructor(shell) {
8
+ this.shell = shell;
9
+ this.commands = new Map();
10
+ this.aliases = new Map();
11
+ this.categories = new Map();
12
+ this.loadCommands();
13
+ }
14
+
15
+ loadCommands() {
16
+ const load = (path, category) => {
17
+ try {
18
+ const cmd = require(path);
19
+ if (!cmd || !cmd.name) {
20
+ console.error(chalk.red(`❌ BAD COMMAND (no name): ${path}`));
21
+ return;
22
+ }
23
+ this.register(cmd, category);
24
+ }
25
+ catch (e) { console.error(chalk.red(`❌ Failed to load ${path}: ${e.message}`)); }
26
+ };
27
+
28
+ // Auth
29
+ load('./auth/login', 'auth');
30
+ load('./auth/logout', 'auth');
31
+ load('./auth/whoami', 'auth');
32
+ load('./auth/register', 'auth');
33
+
34
+ // Team
35
+ load('./team/myteam', 'team');
36
+ load('./team/teammates', 'team');
37
+ load('./team/invite', 'team');
38
+
39
+ // Room
40
+ load('./room/join', 'room');
41
+ load('./room/leave', 'room');
42
+ load('./room/rooms', 'room');
43
+
44
+ // Message
45
+ load('./message/say', 'message');
46
+
47
+ // Shell
48
+ load('./shell/status', 'shell');
49
+ load('./shell/notify', 'shell');
50
+
51
+ // Tasks
52
+ load('./tasks/tasks', 'tasks');
53
+ load('./tasks/task', 'tasks');
54
+ load('./tasks/task-status', 'tasks');
55
+ // load('./tasks/start', 'tasks');
56
+ load('./tasks/complete', 'tasks');
57
+ // load('./tasks/comment', 'tasks');
58
+ load('./tasks/create-task', 'tasks');
59
+
60
+
61
+ // Terminal
62
+ load('./terminal/share', 'terminal');
63
+
64
+
65
+
66
+
67
+
68
+ }
69
+
70
+ register(command, category) {
71
+ if (!command || !command.name) {
72
+ console.error(chalk.yellow(`⚠️ Skipping invalid command in category: ${category}`));
73
+ return;
74
+ }
75
+ this.commands.set(command.name, command);
76
+ if (!this.categories.has(category)) this.categories.set(category, []);
77
+ this.categories.get(category).push(command.name);
78
+ if (command.aliases) command.aliases.forEach(a => this.aliases.set(a, command.name));
79
+ }
80
+
81
+ addAlias(alias, command) { this.aliases.set(alias, command); }
82
+
83
+ getCommand(name) {
84
+ if (this.aliases.has(name)) name = this.aliases.get(name);
85
+ return this.commands.get(name);
86
+ }
87
+
88
+ async execute(input, shell) {
89
+ const args = shell.parseCommand(input);
90
+ const cmdName = args[0].toLowerCase();
91
+ const cmdArgs = args.slice(1);
92
+
93
+ const command = this.getCommand(cmdName);
94
+ if (!command) return false;
95
+
96
+ try {
97
+ if (command.requiresAuth && !shell.api?.isAuthenticated()) {
98
+ console.log(chalk.red('❌ Please login first: login'));
99
+ return true;
100
+ }
101
+ if (command.requiresRoom && !shell.ws?.getCurrentRoom()) {
102
+ console.log(chalk.red('❌ Please join a room first: join <room-id>'));
103
+ return true;
104
+ }
105
+ await command.execute(cmdArgs, shell);
106
+ } catch (error) {
107
+ console.log(chalk.red(`❌ Command error: ${error.message}`));
108
+ }
109
+
110
+ return true;
111
+ }
112
+
113
+ getHelpText() {
114
+ let help = chalk.cyan('\n📚 Available Commands:\n');
115
+ help += chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n');
116
+ for (const [category, commands] of this.categories) {
117
+ help += chalk.yellow(`${category.toUpperCase()}:\n`);
118
+ commands.forEach(cmdName => {
119
+ const cmd = this.commands.get(cmdName);
120
+ if (!cmd || !cmdName) return; // ← ye line add karo
121
+ const aliases = cmd.aliases ? chalk.dim(` (${cmd.aliases.join(', ')})`) : '';
122
+ help += ` ${chalk.green(cmdName.padEnd(14))}${aliases} - ${cmd.description || ''}\n`;
123
+ });
124
+ help += '\n';
125
+ }
126
+ return help;
127
+ }
128
+ }
129
+
130
130
  module.exports = CommandRegistry;
@@ -1,43 +1,43 @@
1
- /**
2
- * Say Command
3
- *
4
- * Usage: say <message>
5
- */
6
-
7
- const chalk = require('chalk');
8
-
9
- module.exports = {
10
- name: 'say',
11
- description: 'Send a message to the current room',
12
- aliases: ['msg', 'm', 'send'],
13
- requiresAuth: true,
14
- requiresRoom: true,
15
-
16
- async execute(args, shell) {
17
- const message = args.join(' ');
18
-
19
- if (!message) {
20
- console.log(chalk.red('❌ Usage: say <message>'));
21
- return;
22
- }
23
-
24
- try {
25
- await shell.api.sendMessage(message);
26
-
27
- // Clear typing indicator
28
- if (shell.isTyping) {
29
- shell.api.sendTyping(false);
30
- shell.isTyping = false;
31
- clearTimeout(shell.typingTimeout);
32
- }
33
-
34
- // Echo locally (server will also broadcast)
35
- const user = shell.api.getUser();
36
- const time = new Date().toLocaleTimeString();
37
- console.log(chalk.dim(`[${time}] `) + chalk.green(`You: ${message}`));
38
-
39
- } catch (error) {
40
- console.log(chalk.red(`❌ Failed to send: ${error.message}`));
41
- }
42
- }
1
+ /*
2
+ Say Command
3
+
4
+ Usage: say <message>
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+
9
+ module.exports = {
10
+ name: 'say',
11
+ description: 'Send a message to the current room',
12
+ aliases: ['msg', 'm', 'send'],
13
+ requiresAuth: true,
14
+ requiresRoom: true,
15
+
16
+ async execute(args, shell) {
17
+ const message = args.join(' ');
18
+
19
+ if (!message) {
20
+ console.log(chalk.red('❌ Usage: say <message>'));
21
+ return;
22
+ }
23
+
24
+ try {
25
+ await shell.api.sendMessage(message);
26
+
27
+ // Clear typing indicator
28
+ if (shell.isTyping) {
29
+ shell.api.sendTyping(false);
30
+ shell.isTyping = false;
31
+ clearTimeout(shell.typingTimeout);
32
+ }
33
+
34
+ // Echo locally (server will also broadcast)
35
+ const user = shell.api.getUser();
36
+ const time = new Date().toLocaleTimeString();
37
+ console.log(chalk.dim(`[${time}] `) + chalk.green(`You: ${message}`));
38
+
39
+ } catch (error) {
40
+ console.log(chalk.red(`❌ Failed to send: ${error.message}`));
41
+ }
42
+ }
43
43
  };
@@ -1,142 +1,142 @@
1
- /**
2
- * Join Command
3
- *
4
- * Usage: join <room-id> [password]
5
- *
6
- * Flow:
7
- * 1. REST call → shell.api.joinRoom() — validates membership + fetches room info
8
- * 2. WebSocket → thinknsh:join — registers socket in the room on the server
9
- * 3. Wait for → thinknsh:joined — server confirms + sends message history
10
- */
11
-
12
- const chalk = require('chalk');
13
-
14
- // How long to wait for thinknsh:joined after emitting thinknsh:join (ms)
15
- const JOIN_TIMEOUT_MS = 8000;
16
-
17
- module.exports = {
18
- name: 'join',
19
- description: 'Join a collaboration room',
20
- aliases: ['enter', 'goto'],
21
- requiresAuth: true,
22
-
23
- async execute(args, shell) {
24
- if (args.length === 0) {
25
- console.log(chalk.red('❌ Usage: join <room-id> [password]'));
26
- return;
27
- }
28
-
29
- const roomId = args[0];
30
- const password = args[1];
31
-
32
- // ── Step 1: auto-connect WebSocket if needed ──────────────────────
33
- if (!shell.ws.isConnected()) {
34
- console.log(chalk.dim(' Connecting...'));
35
- try {
36
- await shell.ws.connect();
37
- } catch (err) {
38
- console.log(chalk.red(`❌ WebSocket connect failed: ${err.message}`));
39
- return;
40
- }
41
- }
42
-
43
- console.log(chalk.cyan(`🔗 Joining room ${chalk.bold(roomId)}...`));
44
-
45
- // ── Step 2: REST call — validates membership, returns room meta ───
46
- let result;
47
- try {
48
- result = await shell.api.joinRoom(roomId, password);
49
- } catch (error) {
50
- if (error.message?.toLowerCase().includes('password')) {
51
- console.log(chalk.red(`❌ Room requires a password: join ${roomId} <password>`));
52
- } else if (error.message?.toLowerCase().includes('not found')) {
53
- console.log(chalk.red(`❌ Room not found: ${roomId}`));
54
- console.log(chalk.dim(' Type "rooms" to see available rooms'));
55
- } else if (error.message?.toLowerCase().includes('not a member') ||
56
- error.message?.toLowerCase().includes('unauthorized')) {
57
- console.log(chalk.red(`❌ You are not a member of this room`));
58
- } else {
59
- console.log(chalk.red(`❌ Failed to join: ${error.message}`));
60
- }
61
- return;
62
- }
63
-
64
- const room = result.room || result;
65
- const user = shell.api.getUser?.() || {};
66
-
67
- // ── Step 3: emit thinknsh:join and wait for thinknsh:joined ──────
68
- await new Promise((resolve) => {
69
- const timer = setTimeout(() => {
70
- shell.ws.socket?.off('thinknsh:joined', onJoined);
71
- shell.ws.socket?.off('thinknsh:error', onError);
72
- console.log(chalk.red('❌ Join timeout — server did not confirm. Try again.'));
73
- resolve();
74
- }, JOIN_TIMEOUT_MS);
75
-
76
- function onJoined(data) {
77
- clearTimeout(timer);
78
- shell.ws.socket?.off('thinknsh:error', onError);
79
-
80
- if (!data.success) {
81
- console.log(chalk.red(`❌ Join rejected: ${data.message || 'unknown error'}`));
82
- resolve();
83
- return;
84
- }
85
-
86
- // ── Success output ────────────────────────────────────────
87
- console.log(chalk.green(`✅ Joined ${chalk.bold(room.name || roomId)}`));
88
-
89
- if (room.description)
90
- console.log(chalk.dim(` 📝 ${room.description}`));
91
-
92
- const participants = result.participants || [];
93
- if (participants.length)
94
- console.log(chalk.dim(` 👥 ${participants.length} participant(s)`));
95
-
96
- // Recent message history from thinknsh:joined payload
97
- const history = data.history || [];
98
- if (history.length) {
99
- console.log(chalk.cyan('\n📜 Recent messages:'));
100
- history.slice(-5).forEach(msg => {
101
- const time = new Date(msg.timestamp).toLocaleTimeString();
102
- const isYou = msg.userId === user._id?.toString() || msg.userId === user.id?.toString();
103
- const who = isYou ? chalk.green('you') : chalk.cyan(msg.name || 'Unknown');
104
- const src = msg.source === 'shell' ? chalk.dim('[shell]') : '';
105
- console.log(` ${chalk.dim(`[${time}]`)} ${who}${src}: ${msg.message}`);
106
- });
107
- }
108
-
109
- // Online participants
110
- const online = participants.filter(p => p.online);
111
- if (online.length) {
112
- console.log(chalk.cyan('\n👥 Online:'));
113
- online.forEach(p => {
114
- const isYou = p.email === user.email ? chalk.green(' (you)') : '';
115
- console.log(` ${chalk.green('●')} ${p.name || p.email}${isYou}`);
116
- });
117
- }
118
-
119
- console.log(chalk.dim('\n💡 say <message> to chat | leave to exit\n'));
120
- resolve();
121
- }
122
-
123
- function onError(data) {
124
- clearTimeout(timer);
125
- shell.ws.socket?.off('thinknsh:joined', onJoined);
126
- console.log(chalk.red(`❌ ${data.message || 'Join error'}`));
127
- resolve();
128
- }
129
-
130
- shell.ws.socket.once('thinknsh:joined', onJoined);
131
- shell.ws.socket.once('thinknsh:error', onError);
132
-
133
- // Emit the WebSocket join event
134
- shell.ws.socket.emit('thinknsh:join', {
135
- roomId,
136
- userId: user._id?.toString() || user.id?.toString(),
137
- name: user.name || user.username || 'Unknown',
138
- userType: user.model || user.role || 'User',
139
- });
140
- });
141
- }
1
+ /**
2
+ Join Command
3
+
4
+ Usage: join <room-id> [password]
5
+
6
+ Flow:
7
+ 1. REST call → shell.api.joinRoom() — validates membership + fetches room info
8
+ 2. WebSocket → thinknsh:join — registers socket in the room on the server
9
+ 3. Wait for → thinknsh:joined — server confirms + sends message history
10
+ */
11
+
12
+ const chalk = require('chalk');
13
+
14
+ // How long to wait for thinknsh:joined after emitting thinknsh:join (ms)
15
+ const JOIN_TIMEOUT_MS = 8000;
16
+
17
+ module.exports = {
18
+ name: 'join',
19
+ description: 'Join a collaboration room',
20
+ aliases: ['enter', 'goto'],
21
+ requiresAuth: true,
22
+
23
+ async execute(args, shell) {
24
+ if (args.length === 0) {
25
+ console.log(chalk.red('❌ Usage: join <room-id> [password]'));
26
+ return;
27
+ }
28
+
29
+ const roomId = args[0];
30
+ const password = args[1];
31
+
32
+ // ── Step 1: auto-connect WebSocket if needed ──────────────────────
33
+ if (!shell.ws.isConnected()) {
34
+ console.log(chalk.dim(' Connecting...'));
35
+ try {
36
+ await shell.ws.connect();
37
+ } catch (err) {
38
+ console.log(chalk.red(`❌ WebSocket connect failed: ${err.message}`));
39
+ return;
40
+ }
41
+ }
42
+
43
+ console.log(chalk.cyan(`🔗 Joining room ${chalk.bold(roomId)}...`));
44
+
45
+ // ── Step 2: REST call — validates membership, returns room meta ───
46
+ let result;
47
+ try {
48
+ result = await shell.api.joinRoom(roomId, password);
49
+ } catch (error) {
50
+ if (error.message?.toLowerCase().includes('password')) {
51
+ console.log(chalk.red(`❌ Room requires a password: join ${roomId} <password>`));
52
+ } else if (error.message?.toLowerCase().includes('not found')) {
53
+ console.log(chalk.red(`❌ Room not found: ${roomId}`));
54
+ console.log(chalk.dim(' Type "rooms" to see available rooms'));
55
+ } else if (error.message?.toLowerCase().includes('not a member') ||
56
+ error.message?.toLowerCase().includes('unauthorized')) {
57
+ console.log(chalk.red(`❌ You are not a member of this room`));
58
+ } else {
59
+ console.log(chalk.red(`❌ Failed to join: ${error.message}`));
60
+ }
61
+ return;
62
+ }
63
+
64
+ const room = result.room || result;
65
+ const user = shell.api.getUser?.() || {};
66
+
67
+ // ── Step 3: emit thinknsh:join and wait for thinknsh:joined ──────
68
+ await new Promise((resolve) => {
69
+ const timer = setTimeout(() => {
70
+ shell.ws.socket?.off('thinknsh:joined', onJoined);
71
+ shell.ws.socket?.off('thinknsh:error', onError);
72
+ console.log(chalk.red('❌ Join timeout — server did not confirm. Try again.'));
73
+ resolve();
74
+ }, JOIN_TIMEOUT_MS);
75
+
76
+ function onJoined(data) {
77
+ clearTimeout(timer);
78
+ shell.ws.socket?.off('thinknsh:error', onError);
79
+
80
+ if (!data.success) {
81
+ console.log(chalk.red(`❌ Join rejected: ${data.message || 'unknown error'}`));
82
+ resolve();
83
+ return;
84
+ }
85
+
86
+ // ── Success output ────────────────────────────────────────
87
+ console.log(chalk.green(`✅ Joined ${chalk.bold(room.name || roomId)}`));
88
+
89
+ if (room.description)
90
+ console.log(chalk.dim(` 📝 ${room.description}`));
91
+
92
+ const participants = result.participants || [];
93
+ if (participants.length)
94
+ console.log(chalk.dim(` 👥 ${participants.length} participant(s)`));
95
+
96
+ // Recent message history from thinknsh:joined payload
97
+ const history = data.history || [];
98
+ if (history.length) {
99
+ console.log(chalk.cyan('\n📜 Recent messages:'));
100
+ history.slice(-5).forEach(msg => {
101
+ const time = new Date(msg.timestamp).toLocaleTimeString();
102
+ const isYou = msg.userId === user._id?.toString() || msg.userId === user.id?.toString();
103
+ const who = isYou ? chalk.green('you') : chalk.cyan(msg.name || 'Unknown');
104
+ const src = msg.source === 'shell' ? chalk.dim('[shell]') : '';
105
+ console.log(` ${chalk.dim(`[${time}]`)} ${who}${src}: ${msg.message}`);
106
+ });
107
+ }
108
+
109
+ // Online participants
110
+ const online = participants.filter(p => p.online);
111
+ if (online.length) {
112
+ console.log(chalk.cyan('\n👥 Online:'));
113
+ online.forEach(p => {
114
+ const isYou = p.email === user.email ? chalk.green(' (you)') : '';
115
+ console.log(` ${chalk.green('●')} ${p.name || p.email}${isYou}`);
116
+ });
117
+ }
118
+
119
+ console.log(chalk.dim('\n💡 say <message> to chat | leave to exit\n'));
120
+ resolve();
121
+ }
122
+
123
+ function onError(data) {
124
+ clearTimeout(timer);
125
+ shell.ws.socket?.off('thinknsh:joined', onJoined);
126
+ console.log(chalk.red(`❌ ${data.message || 'Join error'}`));
127
+ resolve();
128
+ }
129
+
130
+ shell.ws.socket.once('thinknsh:joined', onJoined);
131
+ shell.ws.socket.once('thinknsh:error', onError);
132
+
133
+ // Emit the WebSocket join event
134
+ shell.ws.socket.emit('thinknsh:join', {
135
+ roomId,
136
+ userId: user._id?.toString() || user.id?.toString(),
137
+ name: user.name || user.username || 'Unknown',
138
+ userType: user.model || user.role || 'User',
139
+ });
140
+ });
141
+ }
142
142
  };