thinkncollab-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.
package/Readme.md ADDED
File without changes
package/bin/index.js ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ import inquirer from "inquirer";
3
+ import axios from "axios";
4
+ import fs from "fs";
5
+ import os from "os";
6
+ import path from "path";
7
+
8
+ const RC_FILE = path.join(os.homedir(), ".tncrc");
9
+
10
+ async function login() {
11
+ const answers = await inquirer.prompt([
12
+ { type: "input", name: "email", message: "Email:" },
13
+ { type: "password", name: "password", message: "Password:" }
14
+ ]);
15
+
16
+ try {
17
+ const res = await axios.post("http://localhost:3001/signin", {
18
+ email: answers.email,
19
+ password: answers.password
20
+ });
21
+
22
+ const token = res.data.token;
23
+ fs.writeFileSync(RC_FILE, JSON.stringify({ token }, null, 2));
24
+ console.log("✅ Login successful! Token saved at", RC_FILE);
25
+ } catch (err) {
26
+ console.error("❌ Login failed:", err.response?.data?.message || err.message);
27
+ }
28
+ }
29
+
30
+ function readToken() {
31
+ if (!fs.existsSync(RC_FILE)) {
32
+ console.error("❌ Not logged in. Run 'tnc login'");
33
+ process.exit(1);
34
+ }
35
+ const data = JSON.parse(fs.readFileSync(RC_FILE));
36
+ return data.token;
37
+ }
38
+
39
+ function scanFolder(folderPath) {
40
+ const items = fs.readdirSync(folderPath, { withFileTypes: true });
41
+ return items.map((item) => {
42
+ const fullPath = path.join(folderPath, item.name);
43
+ if (item.isDirectory()) {
44
+ return { name: item.name, type: "folder", children: scanFolder(fullPath) };
45
+ } else {
46
+ const stats = fs.statSync(fullPath);
47
+ return { name: item.name, type: "file", path: fullPath, size: stats.size };
48
+ }
49
+ });
50
+ }
51
+
52
+ async function push(roomId, targetPath) {
53
+ const token = readToken();
54
+ let content;
55
+ const stats = fs.statSync(targetPath);
56
+ if (stats.isDirectory()) {
57
+ content = scanFolder(targetPath);
58
+ } else {
59
+ content = [{ name: path.basename(targetPath), type: "file", path: targetPath, size: stats.size }];
60
+ }
61
+
62
+ try {
63
+ await axios.post(
64
+ `http://localhost:3001/rooms/${roomId}/upload`,
65
+ { content },
66
+ { headers: { Authorization: `Bearer ${token}` } }
67
+ );
68
+ console.log("✅ Upload successful!");
69
+ console.log(content);
70
+ } catch (err) {
71
+ console.error("❌ Upload failed:", err.response?.data?.message || err.message);
72
+ }
73
+ }
74
+
75
+ // CLI arguments - only ONE declaration
76
+ const args = process.argv.slice(2);
77
+
78
+ if (args[0] === "login") {
79
+ login();
80
+ } else if (args[0] === "push") {
81
+ const roomIndex = args.indexOf("--room");
82
+ if (roomIndex === -1 || !args[roomIndex + 1] || !args[roomIndex + 2]) {
83
+ console.error("Usage: tnc push --room <roomId> <file-or-folder-path>");
84
+ process.exit(1);
85
+ }
86
+ const roomId = args[roomIndex + 1];
87
+ const targetPath = args[roomIndex + 2];
88
+ push(roomId, targetPath);
89
+ } else {
90
+ console.log("✅ TNC CLI is working! Use 'tnc login' or 'tnc push'");
91
+ }
package/bin/tnc.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { program } from "commander";
3
+ import { pushToRoom } from "../lib/api.js";
4
+
5
+ program
6
+ .name("tnc")
7
+ .description("ThinkNCollab CLI tool")
8
+ .version("0.1.0");
9
+
10
+ program
11
+ .command("push")
12
+ .option("--room <roomId>", "Room ID to push files")
13
+ .action(async (opts) => {
14
+ if (!opts.room) {
15
+ console.error("❌ Please provide a room id using --room <id>");
16
+ process.exit(1);
17
+ }
18
+ await pushToRoom(opts.room);
19
+ });
20
+
21
+ program.parse();
package/lib/api.js ADDED
@@ -0,0 +1,28 @@
1
+ import { scanDirectory } from "./scanner.js";
2
+ import { uploadFile } from "./uploader.js";
3
+ import path from "path";
4
+ import fs from "fs";
5
+
6
+ export async function pushToRoom(roomId) {
7
+ const currentDir = process.cwd();
8
+ console.log(`📂 Scanning directory: ${currentDir}`);
9
+
10
+ const files = scanDirectory(currentDir);
11
+
12
+ const uploadedFiles = [];
13
+ for (let file of files) {
14
+ const url = await uploadFile(file);
15
+ uploadedFiles.push({
16
+ name: file.name,
17
+ path: file.path,
18
+ size: file.size,
19
+ url,
20
+ });
21
+ }
22
+
23
+ // Instead of real backend, save JSON locally for now
24
+ const outputPath = path.join(currentDir, `tnc_snapshot_${roomId}.json`);
25
+ fs.writeFileSync(outputPath, JSON.stringify(uploadedFiles, null, 2));
26
+
27
+ console.log(`✅ Snapshot saved at ${outputPath}`);
28
+ }
package/lib/scanner.js ADDED
@@ -0,0 +1,27 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export function scanDirectory(dirPath) {
5
+ const result = [];
6
+
7
+ function walk(dir) {
8
+ const files = fs.readdirSync(dir);
9
+ for (let file of files) {
10
+ const fullPath = path.join(dir, file);
11
+ const stat = fs.statSync(fullPath);
12
+
13
+ if (stat.isDirectory()) {
14
+ walk(fullPath);
15
+ } else {
16
+ result.push({
17
+ name: file,
18
+ path: fullPath,
19
+ size: stat.size,
20
+ });
21
+ }
22
+ }
23
+ }
24
+
25
+ walk(dirPath);
26
+ return result;
27
+ }
@@ -0,0 +1,5 @@
1
+ export async function uploadFile(file) {
2
+ // Later: upload to S3/Cloudinary
3
+ // For now: just return a fake URL
4
+ return `https://fake-storage.com/${file.name}`;
5
+ }
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "thinkncollab-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for ThinkNCollab",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "tnc": "./bin/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node bin/index.js"
11
+ },
12
+ "type": "module",
13
+ "dependencies": {
14
+ "axios": "^1.12.2",
15
+ "inquirer": "^9.3.8"
16
+ }
17
+ }