thinkncollab-cli 0.0.85 → 0.0.87
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/commands/createTask.js +113 -118
- package/commands/myTeam.js +48 -17
- package/package.json +1 -1
package/commands/createTask.js
CHANGED
|
@@ -57,133 +57,129 @@ async function createTask() {
|
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
//
|
|
61
|
-
|
|
60
|
+
// STEP 1: Find available port FIRST
|
|
61
|
+
console.log(chalk.gray('🔍 Finding available port for callback server...'));
|
|
62
|
+
const PORT = await findAvailablePort(3002);
|
|
63
|
+
console.log(chalk.green(`✅ Callback server will run on port: ${PORT}`));
|
|
62
64
|
|
|
63
|
-
// Construct the URL with
|
|
64
|
-
const redirectUrl = `https://thinkncollab.in/cli/tasks/${roomId}/${token}/create?cli=true`;
|
|
65
|
+
// STEP 2: Construct the URL with the found port
|
|
66
|
+
const redirectUrl = `https://thinkncollab.in/cli/tasks/${roomId}/${token}/create?cli=true&callbackPort=${PORT}`;
|
|
65
67
|
|
|
66
68
|
const spinner = createSpinner('Preparing task creation interface...');
|
|
67
69
|
|
|
68
70
|
console.log(chalk.blue('🔗 Opening task creation interface in your browser...'));
|
|
69
71
|
console.log(chalk.gray(`URL: ${redirectUrl}`));
|
|
70
72
|
|
|
71
|
-
// Find available port
|
|
72
|
-
const PORT = await findAvailablePort(3002);
|
|
73
73
|
spinner.stop();
|
|
74
74
|
|
|
75
|
-
// Create callback server
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Parse URL
|
|
94
|
-
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
95
|
-
|
|
96
|
-
// Check for callback (handle both /callback and direct query params)
|
|
97
|
-
if (req.url.includes('/callback') || url.searchParams.has('taskId')) {
|
|
98
|
-
const taskId = url.searchParams.get('taskId');
|
|
99
|
-
const attachments = url.searchParams.get('attachments');
|
|
100
|
-
const status = url.searchParams.get('status');
|
|
101
|
-
|
|
102
|
-
// Log success
|
|
103
|
-
if (status === 'error') {
|
|
104
|
-
console.log(chalk.red('\n❌ Task creation failed!'));
|
|
105
|
-
} else {
|
|
106
|
-
console.log(chalk.green('\n✅ Task created successfully!'));
|
|
107
|
-
if (taskId) {
|
|
108
|
-
console.log(chalk.blue(`📋 Task ID: ${taskId}`));
|
|
109
|
-
|
|
110
|
-
// Save task ID to file
|
|
111
|
-
const taskMetaPath = path.join(CWD, ".tnc", "last-task.json");
|
|
112
|
-
fs.writeFileSync(taskMetaPath, JSON.stringify({
|
|
113
|
-
taskId,
|
|
114
|
-
attachments: attachments ? attachments.length : 0,
|
|
115
|
-
timestamp: new Date().toISOString(),
|
|
116
|
-
roomId
|
|
117
|
-
}, null, 2));
|
|
118
|
-
console.log(chalk.gray(`📝 Task ID saved to .tnc/last-task.json`));
|
|
75
|
+
// STEP 3: Create callback server
|
|
76
|
+
const server = http.createServer((req, res) => {
|
|
77
|
+
console.log(chalk.yellow(`\n📨 Callback received: ${req.url}`));
|
|
78
|
+
|
|
79
|
+
// CORS headers for all responses
|
|
80
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
81
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
82
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-CLI-Callback-URL');
|
|
83
|
+
res.setHeader('Access-Control-Max-Age', '86400'); // 24 hours
|
|
84
|
+
|
|
85
|
+
// Handle preflight
|
|
86
|
+
if (req.method === 'OPTIONS') {
|
|
87
|
+
res.writeHead(200);
|
|
88
|
+
res.end();
|
|
89
|
+
return;
|
|
119
90
|
}
|
|
120
|
-
|
|
121
|
-
|
|
91
|
+
|
|
92
|
+
// Parse URL
|
|
93
|
+
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
94
|
+
|
|
95
|
+
// Check for callback (handle both /callback and direct query params)
|
|
96
|
+
if (req.url.includes('/callback') || url.searchParams.has('taskId')) {
|
|
97
|
+
const taskId = url.searchParams.get('taskId');
|
|
98
|
+
const attachments = url.searchParams.get('attachments');
|
|
99
|
+
const status = url.searchParams.get('status');
|
|
100
|
+
|
|
101
|
+
// Log success
|
|
102
|
+
if (status === 'error') {
|
|
103
|
+
console.log(chalk.red('\n❌ Task creation failed!'));
|
|
104
|
+
} else {
|
|
105
|
+
console.log(chalk.green('\n✅ Task created successfully!'));
|
|
106
|
+
if (taskId) {
|
|
107
|
+
console.log(chalk.blue(`📋 Task ID: ${taskId}`));
|
|
108
|
+
|
|
109
|
+
// Save task ID to file
|
|
110
|
+
const taskMetaPath = path.join(CWD, ".tnc", "last-task.json");
|
|
111
|
+
fs.writeFileSync(taskMetaPath, JSON.stringify({
|
|
112
|
+
taskId,
|
|
113
|
+
attachments: attachments ? parseInt(attachments) : 0,
|
|
114
|
+
timestamp: new Date().toISOString(),
|
|
115
|
+
roomId
|
|
116
|
+
}, null, 2));
|
|
117
|
+
console.log(chalk.gray(`📝 Task ID saved to .tnc/last-task.json`));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Send response to close browser (HTML with auto-close)
|
|
122
|
+
res.writeHead(200, {
|
|
123
|
+
'Content-Type': 'text/html',
|
|
124
|
+
'Access-Control-Allow-Origin': '*'
|
|
125
|
+
});
|
|
126
|
+
res.end(`
|
|
127
|
+
<!DOCTYPE html>
|
|
128
|
+
<html>
|
|
129
|
+
<head>
|
|
130
|
+
<title>${status === 'error' ? 'Failed' : 'Success'}</title>
|
|
131
|
+
<style>
|
|
132
|
+
body {
|
|
133
|
+
font-family: Arial, sans-serif;
|
|
134
|
+
display: flex;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
align-items: center;
|
|
137
|
+
height: 100vh;
|
|
138
|
+
margin: 0;
|
|
139
|
+
background: ${status === 'error' ? '#f44336' : '#4CAF50'};
|
|
140
|
+
color: white;
|
|
141
|
+
}
|
|
142
|
+
.message {
|
|
143
|
+
text-align: center;
|
|
144
|
+
padding: 20px;
|
|
145
|
+
}
|
|
146
|
+
</style>
|
|
147
|
+
</head>
|
|
148
|
+
<body>
|
|
149
|
+
<div class="message">
|
|
150
|
+
<h1>${status === 'error' ? '❌ Task Failed' : '✅ Task Created'}</h1>
|
|
151
|
+
${taskId ? `<p>Task ID: ${taskId}</p>` : ''}
|
|
152
|
+
<p>Closing in 3 seconds...</p>
|
|
153
|
+
</div>
|
|
154
|
+
<script>
|
|
155
|
+
// Send one more callback to ensure it was received
|
|
156
|
+
fetch(window.location.href, { method: 'GET', mode: 'no-cors' });
|
|
157
|
+
|
|
158
|
+
// Auto close
|
|
159
|
+
setTimeout(() => window.close(), 3000);
|
|
160
|
+
|
|
161
|
+
// Fallback
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
window.location.href = 'about:blank';
|
|
164
|
+
setTimeout(() => window.close(), 100);
|
|
165
|
+
}, 4000);
|
|
166
|
+
</script>
|
|
167
|
+
</body>
|
|
168
|
+
</html>
|
|
169
|
+
`);
|
|
170
|
+
|
|
171
|
+
// Close server after response
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
server.close();
|
|
174
|
+
console.log(chalk.gray('\n📡 Callback server closed'));
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}, 2000);
|
|
177
|
+
} else {
|
|
178
|
+
// Handle other requests (like favicon)
|
|
179
|
+
res.writeHead(404);
|
|
180
|
+
res.end('Not found');
|
|
122
181
|
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Send response to close browser (HTML with auto-close)
|
|
126
|
-
res.writeHead(200, {
|
|
127
|
-
'Content-Type': 'text/html',
|
|
128
|
-
'Access-Control-Allow-Origin': '*'
|
|
129
182
|
});
|
|
130
|
-
res.end(`
|
|
131
|
-
<!DOCTYPE html>
|
|
132
|
-
<html>
|
|
133
|
-
<head>
|
|
134
|
-
<title>${status === 'error' ? 'Failed' : 'Success'}</title>
|
|
135
|
-
<style>
|
|
136
|
-
body {
|
|
137
|
-
font-family: Arial, sans-serif;
|
|
138
|
-
display: flex;
|
|
139
|
-
justify-content: center;
|
|
140
|
-
align-items: center;
|
|
141
|
-
height: 100vh;
|
|
142
|
-
margin: 0;
|
|
143
|
-
background: ${status === 'error' ? '#f44336' : '#4CAF50'};
|
|
144
|
-
color: white;
|
|
145
|
-
}
|
|
146
|
-
.message {
|
|
147
|
-
text-align: center;
|
|
148
|
-
padding: 20px;
|
|
149
|
-
}
|
|
150
|
-
</style>
|
|
151
|
-
</head>
|
|
152
|
-
<body>
|
|
153
|
-
<div class="message">
|
|
154
|
-
<h1>${status === 'error' ? '❌ Task Failed' : '✅ Task Created'}</h1>
|
|
155
|
-
${taskId ? `<p>Task ID: ${taskId}</p>` : ''}
|
|
156
|
-
<p>Closing in 3 seconds...</p>
|
|
157
|
-
</div>
|
|
158
|
-
<script>
|
|
159
|
-
// Send one more callback to ensure it was received
|
|
160
|
-
fetch(window.location.href, { method: 'GET', mode: 'no-cors' });
|
|
161
|
-
|
|
162
|
-
// Auto close
|
|
163
|
-
setTimeout(() => window.close(), 3000);
|
|
164
|
-
|
|
165
|
-
// Fallback
|
|
166
|
-
setTimeout(() => {
|
|
167
|
-
window.location.href = 'about:blank';
|
|
168
|
-
setTimeout(() => window.close(), 100);
|
|
169
|
-
}, 4000);
|
|
170
|
-
</script>
|
|
171
|
-
</body>
|
|
172
|
-
</html>
|
|
173
|
-
`);
|
|
174
|
-
|
|
175
|
-
// Close server after response
|
|
176
|
-
setTimeout(() => {
|
|
177
|
-
server.close();
|
|
178
|
-
console.log(chalk.gray('\n📡 Callback server closed'));
|
|
179
|
-
process.exit(0);
|
|
180
|
-
}, 2000);
|
|
181
|
-
} else {
|
|
182
|
-
// Handle other requests (like favicon)
|
|
183
|
-
res.writeHead(404);
|
|
184
|
-
res.end('Not found');
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
183
|
|
|
188
184
|
// Server error handling
|
|
189
185
|
server.on('error', (err) => {
|
|
@@ -197,15 +193,14 @@ const server = http.createServer((req, res) => {
|
|
|
197
193
|
|
|
198
194
|
// Start server
|
|
199
195
|
server.listen(PORT, () => {
|
|
200
|
-
|
|
201
|
-
// console.log(chalk.gray('The browser will automatically close after task creation\n'));
|
|
196
|
+
console.log(chalk.gray(`📡 Waiting for callback on http://localhost:${PORT}/callback`));
|
|
202
197
|
});
|
|
203
198
|
|
|
204
199
|
// Open browser
|
|
205
200
|
setTimeout(async () => {
|
|
206
201
|
try {
|
|
207
202
|
await open(redirectUrl);
|
|
208
|
-
|
|
203
|
+
console.log(chalk.green('✅ Browser opened successfully!'));
|
|
209
204
|
} catch (err) {
|
|
210
205
|
if (err.message.includes('No application')) {
|
|
211
206
|
console.error(chalk.red('❌ Could not open browser automatically.'));
|
package/commands/myTeam.js
CHANGED
|
@@ -1,44 +1,75 @@
|
|
|
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";
|
|
7
|
-
import FormData from "form-data";
|
|
8
6
|
import getVerify from "../lib/getVerify.js";
|
|
9
7
|
|
|
10
8
|
const CWD = process.cwd();
|
|
11
|
-
const TNC_API_URL = "
|
|
9
|
+
const TNC_API_URL = "https://thinkncollab.com/";
|
|
12
10
|
const metaDataFile = path.join(CWD, ".tnc", ".tncmeta.json");
|
|
13
|
-
const metaData = JSON.parse(fs.readFileSync(metaDataFile, "utf-8"));
|
|
14
|
-
const roomId = metaData.roomId;
|
|
15
11
|
|
|
16
12
|
async function myTeam() {
|
|
17
13
|
try {
|
|
14
|
+
// ✅ Check initialization first
|
|
15
|
+
if (!fs.existsSync(metaDataFile)) {
|
|
16
|
+
console.log(chalk.red("❌ Project not initialized."));
|
|
17
|
+
console.log(chalk.yellow("👉 Run `tnc init` first."));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const metaData = JSON.parse(
|
|
22
|
+
fs.readFileSync(metaDataFile, "utf-8")
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (!metaData.roomId) {
|
|
26
|
+
console.log(chalk.red("❌ No room associated with this project."));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const roomId = metaData.roomId;
|
|
31
|
+
|
|
18
32
|
const verifyData = await getVerify();
|
|
19
33
|
const { email, token } = verifyData;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
|
|
35
|
+
const response = await axios.get(
|
|
36
|
+
`${TNC_API_URL}cli/myTeam/${roomId}`,
|
|
37
|
+
{
|
|
38
|
+
headers: {
|
|
39
|
+
email,
|
|
40
|
+
token,
|
|
41
|
+
machineId: machine.machineIdSync(),
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
27
46
|
const teamMembers = response.data.RoomMembers || [];
|
|
47
|
+
|
|
28
48
|
if (teamMembers.length === 0) {
|
|
29
49
|
console.log(chalk.yellow("⚠️ You are not part of any team yet."));
|
|
30
50
|
return;
|
|
31
51
|
}
|
|
32
|
-
|
|
52
|
+
|
|
53
|
+
console.log(chalk.green("👥 Your Team Members:"));
|
|
33
54
|
teamMembers.forEach(member => {
|
|
34
|
-
console.log(
|
|
55
|
+
console.log(
|
|
56
|
+
chalk.blue(`- ${member.name} (${member.email})`)
|
|
57
|
+
);
|
|
35
58
|
});
|
|
59
|
+
|
|
36
60
|
} catch (err) {
|
|
37
61
|
if (err.response) {
|
|
38
|
-
console.error(
|
|
62
|
+
console.error(
|
|
63
|
+
chalk.red("❌ Error:"),
|
|
64
|
+
chalk.red(err.response.data.error)
|
|
65
|
+
);
|
|
39
66
|
} else {
|
|
40
|
-
console.error(
|
|
67
|
+
console.error(
|
|
68
|
+
chalk.red("❌ Error:"),
|
|
69
|
+
chalk.red(err.message)
|
|
70
|
+
);
|
|
41
71
|
}
|
|
42
72
|
}
|
|
43
73
|
}
|
|
44
|
-
|
|
74
|
+
|
|
75
|
+
export default myTeam;
|