thinkncollab-shell 0.0.6 → 0.0.8
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 +1 -1
- 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 +62 -26
- package/src/core/project-config.js +2 -2
- package/src/core/shell.js +67 -48
package/src/core/shell.js
CHANGED
|
@@ -138,49 +138,67 @@ class ThinkNCollabShell extends EventEmitter {
|
|
|
138
138
|
|
|
139
139
|
// ─── WebSocket → Shell + TCP bridge ──────────────────────────────────────
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.
|
|
144
|
-
this.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const myId = this.api.getUser()?._id;
|
|
148
|
-
if (myId && d.userId === myId) return;
|
|
149
|
-
this.pushNotification({ type: 'message', from: d.username, text: d.message });
|
|
150
|
-
});
|
|
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
|
+
});
|
|
151
147
|
|
|
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
|
-
});
|
|
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
|
+
});
|
|
164
153
|
|
|
165
|
-
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
this.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
154
|
+
this.ws.on('reconnected', () => {
|
|
155
|
+
this.api.logEvent('reconnected');
|
|
156
|
+
this.api.startHeartbeat();
|
|
157
|
+
this.pushNotification({ type: 'connected', socketId: 'reconnected' });
|
|
158
|
+
});
|
|
159
|
+
|
|
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
|
}
|
|
@@ -505,7 +523,7 @@ async execute(input) {
|
|
|
505
523
|
stdio: 'inherit'
|
|
506
524
|
});
|
|
507
525
|
child.on('close', (code) => {
|
|
508
|
-
// Update currentDir in case command changed it (cd won't but others might)
|
|
526
|
+
// Update currentDir in case command changed it (cd won't but others might) https://thinkncollab.com
|
|
509
527
|
try { this.currentDir = process.cwd(); } catch {}
|
|
510
528
|
process.stdout.write('\r\n');
|
|
511
529
|
resolve();
|
|
@@ -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.8 ║
|
|
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;
|