thinkncollab-cli 0.0.90 → 0.0.91
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/bin/index.js +11 -7
- package/commands/connect.js +41 -30
- package/commands/createTask.js +63 -189
- package/commands/init.js +86 -48
- package/commands/myTask.js +144 -71
- package/commands/myTeam.js +75 -26
- package/commands/sendInvite.js +60 -25
- package/commands/task.js +140 -85
- package/commands/taskCompletion.js +36 -13
- package/package.json +1 -1
- package/commands/send.js +0 -16
package/bin/index.js
CHANGED
|
@@ -175,10 +175,16 @@ async function main() {
|
|
|
175
175
|
break;
|
|
176
176
|
|
|
177
177
|
case "my-tasks": {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
const n = args.indexOf("-n");
|
|
179
|
+
let limit = 5;
|
|
180
|
+
if (n !== -1 && args[n + 1]) {
|
|
181
|
+
limit = parseInt(args[n + 1], 10);
|
|
182
|
+
if (isNaN(limit) || limit <= 0) {
|
|
183
|
+
console.log("⚠️ Invalid number for -n. Using default of 5.");
|
|
184
|
+
limit = 5;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
await myTask(limit);
|
|
182
188
|
break;
|
|
183
189
|
}
|
|
184
190
|
case "create-task": {
|
|
@@ -236,9 +242,6 @@ default:
|
|
|
236
242
|
console.log(" tnc-cli status Show project status");
|
|
237
243
|
console.log("");
|
|
238
244
|
|
|
239
|
-
console.log("Branch:");
|
|
240
|
-
console.log(" tnc-cli create --room <roomId> Create branch for a room");
|
|
241
|
-
console.log("");
|
|
242
245
|
|
|
243
246
|
|
|
244
247
|
console.log("Tasks:");
|
|
@@ -248,6 +251,7 @@ default:
|
|
|
248
251
|
console.log(" tnc-cli task-complete Mark task as completed");
|
|
249
252
|
console.log("");
|
|
250
253
|
|
|
254
|
+
|
|
251
255
|
console.log("Team:");
|
|
252
256
|
console.log(" tnc-cli myteam Show team members");
|
|
253
257
|
console.log(" tnc-cli invite <email> Invite member to room");
|
package/commands/connect.js
CHANGED
|
@@ -12,56 +12,67 @@ async function connect(roomId) {
|
|
|
12
12
|
console.error("❌ You are not logged in. Run 'tnc login' first.");
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
|
|
16
|
+
const answer = await inquirer.prompt([
|
|
17
|
+
{ type: "input", name: "BranchName", message: "Enter Branch Name to create a branch:" }
|
|
18
|
+
]);
|
|
18
19
|
|
|
19
20
|
const data = fs.readFileSync(tncrcPath, "utf-8");
|
|
20
21
|
const { email, token } = JSON.parse(data);
|
|
22
|
+
const machineId = machine.machineIdSync();
|
|
21
23
|
|
|
22
24
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// USING HEADERS FOR AUTHENTICATION
|
|
26
|
+
const response = await axios({
|
|
27
|
+
method: 'post',
|
|
28
|
+
url: `https://thinkncollab.com/cli/connect/${roomId}`,
|
|
29
|
+
data: {
|
|
30
|
+
branchName: answer.BranchName // Only branchName in request body
|
|
31
|
+
},
|
|
32
|
+
headers: {
|
|
33
|
+
'x-user-email': email,
|
|
34
|
+
'x-user-token': token,
|
|
35
|
+
'x-machine-id': machineId
|
|
36
|
+
}
|
|
28
37
|
});
|
|
29
|
-
|
|
38
|
+
|
|
39
|
+
const CWD = process.cwd();
|
|
30
40
|
const tncFolderPath = path.join(CWD, ".tnc");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(tncFolderPath)) {
|
|
43
|
+
fs.mkdirSync(tncFolderPath, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Write metadata file
|
|
47
|
+
const metaFilePath = path.join(tncFolderPath, ".tncmeta.json");
|
|
48
|
+
const pushFilePath = path.join(tncFolderPath, ".tncpush.json");
|
|
36
49
|
|
|
37
50
|
const metaFileInfo = JSON.stringify({
|
|
38
51
|
"projectId": response.data.project._id,
|
|
39
52
|
"projectName": response.data.project.name,
|
|
40
53
|
"roomId": response.data.project.roomId,
|
|
41
|
-
"
|
|
42
|
-
|
|
54
|
+
"currentBranch": answer.BranchName,
|
|
55
|
+
"lastCommit": null,
|
|
56
|
+
"files": {}
|
|
57
|
+
}, null, 2);
|
|
58
|
+
|
|
43
59
|
fs.writeFileSync(metaFilePath, metaFileInfo);
|
|
44
|
-
|
|
45
|
-
pushFilePath,
|
|
46
|
-
" {} "
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
console.log(response.data);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
fs.writeFileSync(pushFilePath, JSON.stringify({}, null, 2));
|
|
54
61
|
|
|
55
62
|
console.log("✅ Connected to project:", response.data.project.name);
|
|
56
|
-
console.log("Members connected:", response.data.project.membersConnected);
|
|
63
|
+
console.log("👥 Members connected:", response.data.project.membersConnected.length);
|
|
64
|
+
console.log("🌿 Current branch:", answer.BranchName);
|
|
57
65
|
|
|
58
66
|
} catch (err) {
|
|
59
67
|
if (err.response) {
|
|
60
|
-
console.error(" Error:", err.response.data.error);
|
|
68
|
+
console.error("❌ Error:", err.response.data.error || err.response.data.message);
|
|
69
|
+
if (err.response.status === 401) {
|
|
70
|
+
console.error(" Please login again.");
|
|
71
|
+
}
|
|
61
72
|
} else {
|
|
62
|
-
console.error(" Error:", err.message);
|
|
73
|
+
console.error("❌ Error:", err.message);
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
export default connect;
|
|
78
|
+
export default connect;
|
package/commands/createTask.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import os from "os";
|
|
4
3
|
import path from "path";
|
|
5
4
|
import machine from "node-machine-id";
|
|
6
5
|
import chalk from "chalk";
|
|
@@ -9,250 +8,125 @@ import open from 'open';
|
|
|
9
8
|
import http from 'http';
|
|
10
9
|
|
|
11
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
|
|
13
|
-
|
|
14
11
|
const CWD = process.cwd();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function createSpinner(message) {
|
|
18
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
19
|
-
let i = 0;
|
|
20
|
-
|
|
21
|
-
const spinner = setInterval(() => {
|
|
22
|
-
process.stdout.write(`\r${chalk.cyan(frames[i])} ${message}`);
|
|
23
|
-
i = (i + 1) % frames.length;
|
|
24
|
-
}, 80);
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
stop: (clearMessage = true) => {
|
|
28
|
-
clearInterval(spinner);
|
|
29
|
-
if (clearMessage) {
|
|
30
|
-
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 50) + '\r');
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
update: (newMessage) => {
|
|
34
|
-
message = newMessage;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
12
|
+
const BASE_URL = "https://thinkncollab.com/cli";
|
|
38
13
|
|
|
39
14
|
async function createTask() {
|
|
40
15
|
try {
|
|
41
|
-
|
|
16
|
+
const { default: getVerify } = await import("../lib/getVerify.js");
|
|
17
|
+
const { email, token } = await getVerify();
|
|
18
|
+
const machineId = machine.machineIdSync();
|
|
42
19
|
|
|
43
|
-
const { token } = await getVerify();
|
|
44
|
-
|
|
45
|
-
const CWD = process.cwd();
|
|
46
20
|
const tncmetaPath = path.join(CWD, ".tnc", ".tncmeta.json");
|
|
47
21
|
|
|
48
22
|
if (!fs.existsSync(tncmetaPath)) {
|
|
49
23
|
console.error(chalk.red("❌ Not inside a ThinkNCollab project."));
|
|
50
|
-
console.log(chalk.yellow("Run `tnc-cli init <roomId>` first."));
|
|
51
24
|
return;
|
|
52
25
|
}
|
|
53
26
|
|
|
54
|
-
const fileData = JSON.parse(
|
|
55
|
-
fs.readFileSync(tncmetaPath, "utf-8")
|
|
56
|
-
);
|
|
57
|
-
|
|
27
|
+
const fileData = JSON.parse(fs.readFileSync(tncmetaPath, "utf-8"));
|
|
58
28
|
const roomId = fileData.roomId;
|
|
29
|
+
const projectName = fileData.projectName || "Unknown Project";
|
|
59
30
|
|
|
60
31
|
if (!roomId) {
|
|
61
32
|
console.error(chalk.red("❌ No roomId found."));
|
|
62
33
|
return;
|
|
63
34
|
}
|
|
64
|
-
console.log(chalk.blue('\n🚀 Task Creation CLI\n'));
|
|
65
|
-
|
|
66
|
-
// Validate roomId and token
|
|
67
|
-
if (!roomId) {
|
|
68
|
-
console.error(chalk.red('❌ No roomId found in .tnc/.tncmeta.json'));
|
|
69
|
-
console.log(chalk.yellow('Please ensure you are in a ThinkNCollab project directory'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!token) {
|
|
74
|
-
console.error(chalk.red('❌ No token found'));
|
|
75
|
-
console.log(chalk.yellow('Please login first using: tnc login'));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
35
|
|
|
79
|
-
|
|
80
|
-
console.log(chalk.gray(
|
|
81
|
-
|
|
82
|
-
console.log(chalk.green(`✅ Callback server will run on port: ${PORT}`));
|
|
36
|
+
console.log(chalk.blue('\n🚀 Task Creation CLI'));
|
|
37
|
+
console.log(chalk.gray(`📁 Project: ${projectName}`));
|
|
38
|
+
console.log(chalk.gray(`🏠 Room ID: ${roomId}\n`));
|
|
83
39
|
|
|
84
|
-
// STEP
|
|
85
|
-
|
|
40
|
+
// STEP 1: Find available port for callback
|
|
41
|
+
console.log(chalk.gray('🔍 Finding available port for callback...'));
|
|
42
|
+
const CALLBACK_PORT = await findAvailablePort(3002);
|
|
43
|
+
console.log(chalk.green(`✅ Callback server on port: ${CALLBACK_PORT}`));
|
|
86
44
|
|
|
87
|
-
|
|
45
|
+
// STEP 2: Create a session first using a direct API call
|
|
46
|
+
console.log(chalk.blue('\n🔐 Creating secure session...'));
|
|
88
47
|
|
|
89
|
-
|
|
90
|
-
|
|
48
|
+
const sessionResponse = await axios.post(`${BASE_URL}/create-session`, {}, {
|
|
49
|
+
headers: {
|
|
50
|
+
'x-user-email': email,
|
|
51
|
+
'x-user-token': token,
|
|
52
|
+
'x-machine-id': machineId,
|
|
53
|
+
'x-room-id': roomId
|
|
54
|
+
}
|
|
55
|
+
});
|
|
91
56
|
|
|
92
|
-
|
|
57
|
+
const { sessionToken } = sessionResponse.data;
|
|
58
|
+
console.log(chalk.green(`✅ Session created successfully!`));
|
|
93
59
|
|
|
94
60
|
// STEP 3: Create callback server
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// CORS headers for all responses
|
|
99
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
100
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
101
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-CLI-Callback-URL');
|
|
102
|
-
res.setHeader('Access-Control-Max-Age', '86400'); // 24 hours
|
|
103
|
-
|
|
104
|
-
// Handle preflight
|
|
105
|
-
if (req.method === 'OPTIONS') {
|
|
106
|
-
res.writeHead(200);
|
|
107
|
-
res.end();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Parse URL
|
|
112
|
-
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
113
|
-
|
|
114
|
-
// Check for callback (handle both /callback and direct query params)
|
|
115
|
-
if (req.url.includes('/callback') || url.searchParams.has('taskId')) {
|
|
61
|
+
const callbackServer = http.createServer((req, res) => {
|
|
62
|
+
if (req.url.includes('/callback') || req.url.includes('?taskId=')) {
|
|
63
|
+
const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
|
|
116
64
|
const taskId = url.searchParams.get('taskId');
|
|
117
|
-
const
|
|
118
|
-
const status = url.searchParams.get('status');
|
|
65
|
+
const taskTitle = url.searchParams.get('title');
|
|
119
66
|
|
|
120
|
-
|
|
121
|
-
if (status === 'error') {
|
|
122
|
-
console.log(chalk.red('\n❌ Task creation failed!'));
|
|
123
|
-
} else {
|
|
124
|
-
console.log(chalk.green('\n✅ Task created successfully!'));
|
|
125
|
-
if (taskId) {
|
|
126
|
-
console.log(chalk.blue(`📋 Task ID: ${taskId}`));
|
|
127
|
-
|
|
128
|
-
// Save task ID to file
|
|
129
|
-
const taskMetaPath = path.join(CWD, ".tnc", "last-task.json");
|
|
130
|
-
fs.writeFileSync(taskMetaPath, JSON.stringify({
|
|
131
|
-
taskId,
|
|
132
|
-
attachments: attachments ? parseInt(attachments) : 0,
|
|
133
|
-
timestamp: new Date().toISOString(),
|
|
134
|
-
roomId
|
|
135
|
-
}, null, 2));
|
|
136
|
-
console.log(chalk.gray(`📝 Task ID saved to .tnc/last-task.json`));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
67
|
+
console.log(chalk.green(`\n✅ Task Created: ${taskTitle || 'Untitled'} (ID: ${taskId})`));
|
|
139
68
|
|
|
140
|
-
|
|
141
|
-
res.writeHead(200, {
|
|
142
|
-
'Content-Type': 'text/html',
|
|
143
|
-
'Access-Control-Allow-Origin': '*'
|
|
144
|
-
});
|
|
69
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
145
70
|
res.end(`
|
|
146
|
-
<!DOCTYPE html>
|
|
147
71
|
<html>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
margin: 0;
|
|
158
|
-
background: ${status === 'error' ? '#f44336' : '#4CAF50'};
|
|
159
|
-
color: white;
|
|
160
|
-
}
|
|
161
|
-
.message {
|
|
162
|
-
text-align: center;
|
|
163
|
-
padding: 20px;
|
|
164
|
-
}
|
|
165
|
-
</style>
|
|
166
|
-
</head>
|
|
167
|
-
<body>
|
|
168
|
-
<div class="message">
|
|
169
|
-
<h1>${status === 'error' ? '❌ Task Failed' : '✅ Task Created'}</h1>
|
|
170
|
-
${taskId ? `<p>Task ID: ${taskId}</p>` : ''}
|
|
171
|
-
<p>Closing in 3 seconds...</p>
|
|
172
|
-
</div>
|
|
173
|
-
<script>
|
|
174
|
-
// Send one more callback to ensure it was received
|
|
175
|
-
fetch(window.location.href, { method: 'GET', mode: 'no-cors' });
|
|
176
|
-
|
|
177
|
-
// Auto close
|
|
178
|
-
setTimeout(() => window.close(), 3000);
|
|
179
|
-
|
|
180
|
-
// Fallback
|
|
181
|
-
setTimeout(() => {
|
|
182
|
-
window.location.href = 'about:blank';
|
|
183
|
-
setTimeout(() => window.close(), 100);
|
|
184
|
-
}, 4000);
|
|
185
|
-
</script>
|
|
186
|
-
</body>
|
|
72
|
+
<body style="font-family: Arial; text-align: center; padding: 50px;">
|
|
73
|
+
<h2>✅ Task Created Successfully!</h2>
|
|
74
|
+
<p>Task ID: ${taskId}</p>
|
|
75
|
+
<p>Title: ${taskTitle || 'Untitled'}</p>
|
|
76
|
+
<p>You can close this window now.</p>
|
|
77
|
+
<script>
|
|
78
|
+
setTimeout(() => window.close(), 2000);
|
|
79
|
+
</script>
|
|
80
|
+
</body>
|
|
187
81
|
</html>
|
|
188
82
|
`);
|
|
189
83
|
|
|
190
|
-
// Close
|
|
84
|
+
// Close servers after callback
|
|
191
85
|
setTimeout(() => {
|
|
192
|
-
|
|
193
|
-
console.log(chalk.
|
|
86
|
+
callbackServer.close();
|
|
87
|
+
console.log(chalk.green('\n✅ Task creation complete!'));
|
|
194
88
|
process.exit(0);
|
|
195
89
|
}, 2000);
|
|
196
90
|
} else {
|
|
197
|
-
// Handle other requests (like favicon)
|
|
198
91
|
res.writeHead(404);
|
|
199
92
|
res.end('Not found');
|
|
200
93
|
}
|
|
201
94
|
});
|
|
202
95
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (err.code === 'EADDRINUSE') {
|
|
206
|
-
console.log(chalk.yellow(`⚠️ Port ${PORT} is already in use. Callback might not work.`));
|
|
207
|
-
console.log(chalk.yellow('The task will still be created, but you may need to check manually.'));
|
|
208
|
-
} else {
|
|
209
|
-
console.error(chalk.red('Server error:'), err.message);
|
|
210
|
-
}
|
|
96
|
+
callbackServer.listen(CALLBACK_PORT, () => {
|
|
97
|
+
console.log(chalk.green(`✅ Callback server on http://localhost:${CALLBACK_PORT}`));
|
|
211
98
|
});
|
|
212
99
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
100
|
+
// STEP 4: Open the task creation page directly with session token
|
|
101
|
+
const taskCreationUrl = `http://localhost:3001/cli/tasks/${roomId}/create?session=${sessionToken}&cli=true&callbackPort=${CALLBACK_PORT}`;
|
|
102
|
+
|
|
103
|
+
console.log(chalk.blue('\n🔗 Opening task creation interface...'));
|
|
217
104
|
|
|
218
|
-
// Open browser
|
|
219
105
|
setTimeout(async () => {
|
|
220
106
|
try {
|
|
221
|
-
await open(
|
|
107
|
+
await open(taskCreationUrl);
|
|
222
108
|
console.log(chalk.green('✅ Browser opened successfully!'));
|
|
223
109
|
} catch (err) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
console.log(chalk.cyan(redirectUrl));
|
|
228
|
-
} else {
|
|
229
|
-
console.error(chalk.red('Browser error:'), err.message);
|
|
230
|
-
}
|
|
110
|
+
console.error(chalk.red('❌ Could not open browser automatically.'));
|
|
111
|
+
console.log(chalk.yellow('Please open this URL manually in your browser:'));
|
|
112
|
+
console.log(chalk.cyan(taskCreationUrl));
|
|
231
113
|
}
|
|
232
|
-
},
|
|
114
|
+
}, 1000);
|
|
233
115
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
console.log(chalk.gray('Check your browser to confirm.'));
|
|
240
|
-
server.close();
|
|
241
|
-
resolve();
|
|
242
|
-
}, 300000); // 5 minutes
|
|
243
|
-
|
|
244
|
-
server.on('close', () => {
|
|
245
|
-
clearTimeout(timeout);
|
|
246
|
-
resolve();
|
|
247
|
-
});
|
|
248
|
-
});
|
|
116
|
+
console.log(chalk.gray('\n⏳ Waiting for task creation in browser...'));
|
|
117
|
+
console.log(chalk.gray(' (The CLI will automatically close when task is created)\n'));
|
|
118
|
+
|
|
119
|
+
// Wait forever (until callback closes)
|
|
120
|
+
await new Promise(() => {});
|
|
249
121
|
|
|
250
122
|
} catch (err) {
|
|
251
|
-
console.error(chalk.red("❌
|
|
123
|
+
console.error(chalk.red("❌ Error:"), err.message);
|
|
124
|
+
if (err.response) {
|
|
125
|
+
console.error(chalk.red("Server response:"), err.response.data);
|
|
126
|
+
}
|
|
252
127
|
}
|
|
253
128
|
}
|
|
254
129
|
|
|
255
|
-
// Helper function to find available port
|
|
256
130
|
async function findAvailablePort(startPort) {
|
|
257
131
|
const net = await import('net');
|
|
258
132
|
return new Promise((resolve, reject) => {
|
package/commands/init.js
CHANGED
|
@@ -3,66 +3,104 @@ import os from "os";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import inquirer from "inquirer";
|
|
5
5
|
import axios from "axios";
|
|
6
|
-
import
|
|
6
|
+
import machineId from "node-machine-id";
|
|
7
7
|
|
|
8
8
|
const CWD = process.cwd();
|
|
9
9
|
|
|
10
10
|
async function projectInit(roomId) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
try {
|
|
12
|
+
const answer = await inquirer.prompt([
|
|
13
|
+
{ type: "input", name: "projectName", message: "Enter Project Name:" }
|
|
14
|
+
]);
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
const HomeDir = os.homedir();
|
|
17
|
+
const tncrcPath = path.join(HomeDir, ".tncrc");
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const data = fs.readFileSync(tncrcPath, "utf-8");
|
|
24
|
-
const currentUser = JSON.parse(data).email;
|
|
25
|
-
const userToken = JSON.parse(data).token;
|
|
19
|
+
if (!fs.existsSync(tncrcPath)) {
|
|
20
|
+
console.error("❌ You are not logged in. Run 'tnc login' first.");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
machineId
|
|
33
|
-
roomId: roomId
|
|
34
|
-
});
|
|
24
|
+
// Read user credentials from .tncrc
|
|
25
|
+
const data = fs.readFileSync(tncrcPath, "utf-8");
|
|
26
|
+
const userData = JSON.parse(data);
|
|
27
|
+
const currentUser = userData.email;
|
|
28
|
+
const userToken = userData.token;
|
|
29
|
+
const machineIdValue = machineId.machineIdSync(); // or await machineId.machineId()
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
console.log("Initializing project...");
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Write metadata file
|
|
43
|
-
const metaFilePath = path.join(tncFolderPath, ".tncmeta.json");
|
|
44
|
-
const pushFilePath = path.join(tncFolderPath, ".tncpush.json");
|
|
45
|
-
fs.writeFileSync(
|
|
46
|
-
metaFilePath,
|
|
47
|
-
JSON.stringify(
|
|
33
|
+
// Initialize project via backend - CREDENTIALS IN HEADERS
|
|
34
|
+
const response = await axios.post(
|
|
35
|
+
"https://thinkncollab.com/cli/init",
|
|
48
36
|
{
|
|
49
|
-
projectId,
|
|
50
37
|
projectName: answer.projectName,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
lastCommit: null,
|
|
54
|
-
files: {}
|
|
38
|
+
roomId: roomId
|
|
39
|
+
// Note: owner, token, machineId are NOT in body
|
|
55
40
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
{
|
|
42
|
+
headers: {
|
|
43
|
+
'x-user-email': currentUser,
|
|
44
|
+
'x-user-token': userToken,
|
|
45
|
+
'x-machine-id': machineIdValue
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
);
|
|
64
49
|
|
|
65
|
-
|
|
50
|
+
const projectData = response.data;
|
|
51
|
+
const projectId = projectData.project._id;
|
|
52
|
+
|
|
53
|
+
// Ensure .tnc folder exists at project root
|
|
54
|
+
const tncFolderPath = path.join(CWD, ".tnc");
|
|
55
|
+
if (!fs.existsSync(tncFolderPath)) {
|
|
56
|
+
fs.mkdirSync(tncFolderPath, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Write metadata file
|
|
60
|
+
const metaFilePath = path.join(tncFolderPath, ".tncmeta.json");
|
|
61
|
+
const pushFilePath = path.join(tncFolderPath, ".tncpush.json");
|
|
62
|
+
|
|
63
|
+
fs.writeFileSync(
|
|
64
|
+
metaFilePath,
|
|
65
|
+
JSON.stringify(
|
|
66
|
+
{
|
|
67
|
+
projectId,
|
|
68
|
+
projectName: answer.projectName,
|
|
69
|
+
currentBranch: "main",
|
|
70
|
+
roomId: roomId,
|
|
71
|
+
lastCommit: null,
|
|
72
|
+
files: {}
|
|
73
|
+
},
|
|
74
|
+
null,
|
|
75
|
+
2
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
fs.writeFileSync(
|
|
80
|
+
pushFilePath,
|
|
81
|
+
JSON.stringify({}, null, 2)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
console.log("✅ Project initialized successfully!");
|
|
85
|
+
console.log(`📁 Project ID: ${projectId}`);
|
|
86
|
+
console.log(`🌿 Branch: main`);
|
|
87
|
+
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error.response) {
|
|
90
|
+
// The request was made and the server responded with a status code outside of 2xx
|
|
91
|
+
console.error(`❌ Server error: ${error.response.data.message || error.response.status}`);
|
|
92
|
+
if (error.response.status === 400) {
|
|
93
|
+
console.error("Please check your login credentials");
|
|
94
|
+
}
|
|
95
|
+
} else if (error.request) {
|
|
96
|
+
// The request was made but no response was received
|
|
97
|
+
console.error("❌ No response from server. Please check your internet connection.");
|
|
98
|
+
} else {
|
|
99
|
+
// Something happened in setting up the request
|
|
100
|
+
console.error("❌ Error:", error.message);
|
|
101
|
+
}
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
66
104
|
}
|
|
67
105
|
|
|
68
|
-
export default projectInit;
|
|
106
|
+
export default projectInit;
|