thinkncollab-shell 0.0.6 → 0.0.7
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/Readme.md +322 -179
- package/bin/thinknsh.js +3 -3
- package/package.json +1 -1
- package/src/commands/auth/whoami.js +44 -39
- package/src/commands/index.js +7 -0
- package/src/commands/tasks/complete.js +1 -1
- package/src/commands/tasks/task-status.js +61 -0
- package/src/commands/tasks/tasks.js +165 -56
- package/src/core/api-client.js +64 -28
- package/src/core/project-config.js +1 -1
- package/src/core/shell.js +68 -49
- package/src/core/websocket.js +1 -1
package/src/core/shell.js
CHANGED
|
@@ -35,7 +35,7 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
35
35
|
configDir: path.join(os.homedir(), '.thinkncollab'),
|
|
36
36
|
maxHistory: 1000,
|
|
37
37
|
websocket: {
|
|
38
|
-
serverUrl: options.serverUrl || '
|
|
38
|
+
serverUrl: options.serverUrl || 'http://localhost:3001',
|
|
39
39
|
autoConnect: options.autoConnect || false
|
|
40
40
|
},
|
|
41
41
|
...options
|
|
@@ -54,8 +54,8 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
54
54
|
this.tcpServer = null;
|
|
55
55
|
|
|
56
56
|
this.api = new ThinkNCollabAPI({
|
|
57
|
-
apiUrl: options.apiUrl || '
|
|
58
|
-
wsUrl: options.wsUrl || '
|
|
57
|
+
apiUrl: options.apiUrl || 'http://localhost:3001',
|
|
58
|
+
wsUrl: options.wsUrl || 'http://localhost:3001'
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
this.commands = new Map();
|
|
@@ -138,49 +138,67 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
138
138
|
|
|
139
139
|
// ─── WebSocket → Shell + TCP bridge ──────────────────────────────────────
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.
|
|
144
|
-
this.
|
|
141
|
+
setupWebSocketHandlers() {
|
|
142
|
+
this.ws.on('connected', (d) => {
|
|
143
|
+
this.api.logEvent('connected', null, { socketId: d?.socketId });
|
|
144
|
+
this.api.startHeartbeat();
|
|
145
|
+
this.pushNotification({ type: 'connected', socketId: d?.socketId });
|
|
146
|
+
});
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
this.ws.on('disconnected', (d) => {
|
|
149
|
+
this.api.logEvent('disconnected', null, { reason: d?.reason });
|
|
150
|
+
this.api.stopHeartbeat();
|
|
151
|
+
this.pushNotification({ type: 'disconnected', reason: d?.reason });
|
|
152
|
+
});
|
|
151
153
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const text = msg.message || msg.content || msg.text || '';
|
|
158
|
-
const ts = msg.timestamp || msg.createdAt;
|
|
159
|
-
const timeStr = ts ? chalk.dim(`[${new Date(ts).toLocaleTimeString()}]`) : '';
|
|
160
|
-
console.log(` ${timeStr} ${chalk.cyan(from + ':')} ${chalk.white(text)}`);
|
|
161
|
-
});
|
|
162
|
-
console.log(chalk.dim(' ────────────────────────────────────────────────\n'));
|
|
163
|
-
});
|
|
154
|
+
this.ws.on('reconnected', () => {
|
|
155
|
+
this.api.logEvent('reconnected');
|
|
156
|
+
this.api.startHeartbeat();
|
|
157
|
+
this.pushNotification({ type: 'connected', socketId: 'reconnected' });
|
|
158
|
+
});
|
|
164
159
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
this.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
160
|
+
this.ws.on('message', (d) => {
|
|
161
|
+
const myId = this.api.getUser()?._id;
|
|
162
|
+
if (myId && d.userId === myId) return;
|
|
163
|
+
this.pushNotification({ type: 'message', from: d.username, text: d.message });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
this.ws.on('messageHistory', (messages) => {
|
|
167
|
+
if (!messages?.length) return;
|
|
168
|
+
console.log(chalk.dim('\n ─── Room History ───────────────────────────────'));
|
|
169
|
+
messages.forEach(msg => {
|
|
170
|
+
const from = msg.name || msg.username || msg.sender?.name || 'Unknown';
|
|
171
|
+
const text = msg.message || msg.content || msg.text || '';
|
|
172
|
+
const ts = msg.timestamp || msg.createdAt;
|
|
173
|
+
const timeStr = ts ? chalk.dim(`[${new Date(ts).toLocaleTimeString()}]`) : '';
|
|
174
|
+
console.log(` ${timeStr} ${chalk.cyan(from + ':')} ${chalk.white(text)}`);
|
|
177
175
|
});
|
|
176
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────\n'));
|
|
177
|
+
});
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
this.ws.on('userJoined', (d) => this.pushNotification({ type: 'userJoined', username: d.username }));
|
|
180
|
+
this.ws.on('userLeft', (d) => this.pushNotification({ type: 'userLeft', username: d.username }));
|
|
181
|
+
|
|
182
|
+
// room join/leave events
|
|
183
|
+
this.ws.on('joined', (roomId) => this.api.logEvent('room_join', roomId));
|
|
184
|
+
this.ws.on('left', (roomId) => this.api.logEvent('room_leave', roomId));
|
|
185
|
+
|
|
186
|
+
this.ws.on('notification', (d) => {
|
|
187
|
+
this.pushNotification({
|
|
188
|
+
type: 'notification',
|
|
189
|
+
level: d.type,
|
|
190
|
+
title: d.title,
|
|
191
|
+
message: d.message,
|
|
192
|
+
taskTitle: d.taskTitle,
|
|
193
|
+
assignedBy: d.assignedBy,
|
|
182
194
|
});
|
|
183
|
-
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
this.ws.on('error', (e) => {
|
|
198
|
+
console.log(chalk.red(`⚠️ WebSocket error: ${e.message}`));
|
|
199
|
+
this.pushNotification({ type: 'notification', level: 'error', title: 'WebSocket Error', message: e.message });
|
|
200
|
+
});
|
|
201
|
+
}
|
|
184
202
|
|
|
185
203
|
// ─── Start ────────────────────────────────────────────────────────────────
|
|
186
204
|
|
|
@@ -233,11 +251,11 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
233
251
|
try {
|
|
234
252
|
cfg = loadProjectConfig();
|
|
235
253
|
} catch (err) {
|
|
236
|
-
console.log(chalk.yellow(`⚠️
|
|
254
|
+
console.log(chalk.yellow(`⚠️ tncproject: ${err.message}\n`));
|
|
237
255
|
return false;
|
|
238
256
|
}
|
|
239
257
|
|
|
240
|
-
console.log(chalk.dim(` 📄
|
|
258
|
+
console.log(chalk.dim(` 📄 tncproject found`));
|
|
241
259
|
console.log(chalk.dim(` Room : ${cfg.roomId}`));
|
|
242
260
|
console.log(chalk.dim(` File : ${cfg.filePath}\n`));
|
|
243
261
|
|
|
@@ -249,7 +267,7 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
249
267
|
roomId: cfg.roomId,
|
|
250
268
|
});
|
|
251
269
|
} catch (err) {
|
|
252
|
-
console.log(chalk.red(`❌
|
|
270
|
+
console.log(chalk.red(`❌ tncproject auth failed: ${err.message}`));
|
|
253
271
|
console.log(chalk.dim(' Falling back to manual login.\n'));
|
|
254
272
|
return false;
|
|
255
273
|
}
|
|
@@ -521,7 +539,7 @@ async execute(input) {
|
|
|
521
539
|
try { const figlet = require('figlet'); console.log(chalk.cyan(figlet.textSync('ThinkNCollab', { font: 'Standard' }))); } catch {}
|
|
522
540
|
console.log(chalk.cyan(`
|
|
523
541
|
╔══════════════════════════════════════════════════════╗
|
|
524
|
-
║ ThinkNCollab Shell v0.0.
|
|
542
|
+
║ ThinkNCollab Shell v0.0.6 ║
|
|
525
543
|
║ Type 'help' for commands ║
|
|
526
544
|
╚══════════════════════════════════════════════════════╝`));
|
|
527
545
|
}
|
|
@@ -537,11 +555,12 @@ async execute(input) {
|
|
|
537
555
|
try { fs.writeFileSync(this.config.historyFile, this.history.slice(-this.config.maxHistory).join('\n')); } catch {}
|
|
538
556
|
}
|
|
539
557
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
558
|
+
cleanup() {
|
|
559
|
+
this.api.logout(); // session end + heartbeat stop + lastSeen update
|
|
560
|
+
if (this.tcpServer) { try { this.tcpServer.close(); } catch {} }
|
|
561
|
+
if (this.ws) this.ws.disconnect();
|
|
562
|
+
this.saveHistory();
|
|
563
|
+
}
|
|
545
564
|
}
|
|
546
565
|
|
|
547
566
|
module.exports = ThinkNCollabShell;
|
package/src/core/websocket.js
CHANGED
|
@@ -10,7 +10,7 @@ class WebSocketManager extends EventEmitter {
|
|
|
10
10
|
constructor(config = {}) {
|
|
11
11
|
super();
|
|
12
12
|
this.config = {
|
|
13
|
-
serverUrl: config.serverUrl || '
|
|
13
|
+
serverUrl: config.serverUrl || 'http://localhost:3001',
|
|
14
14
|
reconnectAttempts: config.reconnectAttempts || 5,
|
|
15
15
|
reconnectDelay: config.reconnectDelay || 1000,
|
|
16
16
|
...config
|