@toothfairyai/tfcode 1.0.0-beta.3 → 1.0.0-beta.5
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/tfcode.js +119 -58
- package/package.json +1 -1
package/bin/tfcode.js
CHANGED
|
@@ -42,45 +42,35 @@ function info(msg) {
|
|
|
42
42
|
|
|
43
43
|
function question(rl, prompt, hidden = false) {
|
|
44
44
|
return new Promise((resolve) => {
|
|
45
|
-
if (hidden) {
|
|
46
|
-
|
|
47
|
-
const wasRaw = stdin.isRaw;
|
|
48
|
-
|
|
45
|
+
if (hidden && process.stdin.isTTY) {
|
|
46
|
+
// Use simpler approach for hidden input
|
|
49
47
|
process.stdout.write(prompt);
|
|
50
48
|
|
|
51
|
-
if (stdin.isTTY) {
|
|
52
|
-
stdin.setRawMode(true);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
49
|
let input = '';
|
|
50
|
+
const stdin = process.stdin;
|
|
56
51
|
|
|
52
|
+
stdin.setRawMode(true);
|
|
53
|
+
stdin.setEncoding('utf8');
|
|
57
54
|
stdin.resume();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
case '\u0003':
|
|
74
|
-
process.exit();
|
|
75
|
-
break;
|
|
76
|
-
case '\u007F':
|
|
77
|
-
input = input.slice(0, -1);
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
input += c;
|
|
81
|
-
break;
|
|
55
|
+
|
|
56
|
+
const onKeypress = (str) => {
|
|
57
|
+
if (str === '\n' || str === '\r' || str === '\u0004') {
|
|
58
|
+
stdin.setRawMode(false);
|
|
59
|
+
stdin.pause();
|
|
60
|
+
stdin.removeListener('data', onKeypress);
|
|
61
|
+
process.stdout.write('\n');
|
|
62
|
+
resolve(input);
|
|
63
|
+
} else if (str === '\u0003') {
|
|
64
|
+
process.stdout.write('\n');
|
|
65
|
+
process.exit();
|
|
66
|
+
} else if (str === '\u007F' || str === '\b') {
|
|
67
|
+
input = input.slice(0, -1);
|
|
68
|
+
} else if (str.length === 1 && str.charCodeAt(0) >= 32) {
|
|
69
|
+
input += str;
|
|
82
70
|
}
|
|
83
|
-
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
stdin.on('data', onKeypress);
|
|
84
74
|
} else {
|
|
85
75
|
rl.question(prompt, (answer) => {
|
|
86
76
|
resolve(answer.trim());
|
|
@@ -89,7 +79,7 @@ function question(rl, prompt, hidden = false) {
|
|
|
89
79
|
});
|
|
90
80
|
}
|
|
91
81
|
|
|
92
|
-
function select(
|
|
82
|
+
function select(prompt, options) {
|
|
93
83
|
return new Promise((resolve) => {
|
|
94
84
|
log('');
|
|
95
85
|
log(prompt);
|
|
@@ -99,13 +89,16 @@ function select(rl, prompt, options) {
|
|
|
99
89
|
});
|
|
100
90
|
log('');
|
|
101
91
|
|
|
102
|
-
|
|
92
|
+
// Create a fresh readline for select
|
|
93
|
+
const rlSelect = readline.createInterface({
|
|
94
|
+
input: process.stdin,
|
|
95
|
+
output: process.stdout
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
rlSelect.question('Select (1-' + options.length + '): ', (answer) => {
|
|
99
|
+
rlSelect.close();
|
|
103
100
|
const idx = parseInt(answer.trim()) - 1;
|
|
104
|
-
|
|
105
|
-
resolve(idx);
|
|
106
|
-
} else {
|
|
107
|
-
resolve(0);
|
|
108
|
-
}
|
|
101
|
+
resolve(idx >= 0 && idx < options.length ? idx : 0);
|
|
109
102
|
});
|
|
110
103
|
});
|
|
111
104
|
}
|
|
@@ -257,11 +250,6 @@ function saveToolsCache(tools) {
|
|
|
257
250
|
}
|
|
258
251
|
|
|
259
252
|
async function interactiveSetup() {
|
|
260
|
-
const rl = readline.createInterface({
|
|
261
|
-
input: process.stdin,
|
|
262
|
-
output: process.stdout
|
|
263
|
-
});
|
|
264
|
-
|
|
265
253
|
log('');
|
|
266
254
|
log(`${COLORS.bold}${COLORS.magenta}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
|
267
255
|
log(`${COLORS.bold}${COLORS.magenta} tfcode Setup${COLORS.reset}`);
|
|
@@ -273,38 +261,86 @@ async function interactiveSetup() {
|
|
|
273
261
|
log(`${COLORS.dim} https://app.toothfairyai.com → Settings → API Keys${COLORS.reset}`);
|
|
274
262
|
log('');
|
|
275
263
|
|
|
276
|
-
// Workspace ID
|
|
264
|
+
// Step 1: Workspace ID
|
|
277
265
|
log(`${COLORS.bold}Step 1: Workspace ID${COLORS.reset}`);
|
|
278
266
|
log(`${COLORS.dim}This is your workspace UUID (e.g., 12345678-1234-1234-1234-123456789012)${COLORS.reset}`);
|
|
279
267
|
log('');
|
|
280
|
-
|
|
268
|
+
|
|
269
|
+
const workspaceId = await new Promise((resolve) => {
|
|
270
|
+
const rl = readline.createInterface({
|
|
271
|
+
input: process.stdin,
|
|
272
|
+
output: process.stdout
|
|
273
|
+
});
|
|
274
|
+
rl.question('Enter your Workspace ID: ', (answer) => {
|
|
275
|
+
rl.close();
|
|
276
|
+
resolve(answer.trim());
|
|
277
|
+
});
|
|
278
|
+
});
|
|
281
279
|
|
|
282
280
|
if (!workspaceId) {
|
|
283
281
|
error('Workspace ID is required');
|
|
284
|
-
rl.close();
|
|
285
282
|
process.exit(1);
|
|
286
283
|
}
|
|
287
284
|
|
|
288
285
|
log('');
|
|
289
286
|
|
|
290
|
-
// API Key
|
|
287
|
+
// Step 2: API Key (hidden)
|
|
291
288
|
log(`${COLORS.bold}Step 2: API Key${COLORS.reset}`);
|
|
292
289
|
log(`${COLORS.dim}Your API key will be hidden as you type${COLORS.reset}`);
|
|
293
290
|
log('');
|
|
294
|
-
|
|
291
|
+
|
|
292
|
+
const apiKey = await new Promise((resolve) => {
|
|
293
|
+
if (!process.stdin.isTTY) {
|
|
294
|
+
const rl = readline.createInterface({
|
|
295
|
+
input: process.stdin,
|
|
296
|
+
output: process.stdout
|
|
297
|
+
});
|
|
298
|
+
rl.question('Enter your API Key: ', (answer) => {
|
|
299
|
+
rl.close();
|
|
300
|
+
resolve(answer.trim());
|
|
301
|
+
});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
process.stdout.write('Enter your API Key: ');
|
|
306
|
+
let input = '';
|
|
307
|
+
const stdin = process.stdin;
|
|
308
|
+
|
|
309
|
+
stdin.setRawMode(true);
|
|
310
|
+
stdin.setEncoding('utf8');
|
|
311
|
+
stdin.resume();
|
|
312
|
+
|
|
313
|
+
const onKeypress = (str) => {
|
|
314
|
+
if (str === '\n' || str === '\r' || str === '\u0004') {
|
|
315
|
+
stdin.setRawMode(false);
|
|
316
|
+
stdin.pause();
|
|
317
|
+
stdin.removeListener('data', onKeypress);
|
|
318
|
+
process.stdout.write('\n');
|
|
319
|
+
resolve(input);
|
|
320
|
+
} else if (str === '\u0003') {
|
|
321
|
+
process.stdout.write('\n');
|
|
322
|
+
process.exit();
|
|
323
|
+
} else if (str === '\u007F' || str === '\b') {
|
|
324
|
+
input = input.slice(0, -1);
|
|
325
|
+
} else if (str.length === 1 && str.charCodeAt(0) >= 32) {
|
|
326
|
+
input += str;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
stdin.on('data', onKeypress);
|
|
331
|
+
});
|
|
295
332
|
|
|
296
333
|
if (!apiKey) {
|
|
297
334
|
error('API Key is required');
|
|
298
|
-
rl.close();
|
|
299
335
|
process.exit(1);
|
|
300
336
|
}
|
|
301
337
|
|
|
302
338
|
log('');
|
|
303
339
|
|
|
304
|
-
// Region
|
|
340
|
+
// Step 3: Region
|
|
305
341
|
log(`${COLORS.bold}Step 3: Region${COLORS.reset}`);
|
|
306
342
|
const regions = ['dev (Development)', 'au (Australia)', 'eu (Europe)', 'us (United States)'];
|
|
307
|
-
const regionIdx = await select(
|
|
343
|
+
const regionIdx = await select('Select your region:', regions);
|
|
308
344
|
const regions_map = ['dev', 'au', 'eu', 'us'];
|
|
309
345
|
const region = regions_map[regionIdx];
|
|
310
346
|
|
|
@@ -319,7 +355,16 @@ async function interactiveSetup() {
|
|
|
319
355
|
log(` Region: ${region}`);
|
|
320
356
|
log('');
|
|
321
357
|
|
|
322
|
-
const confirm = await
|
|
358
|
+
const confirm = await new Promise((resolve) => {
|
|
359
|
+
const rl = readline.createInterface({
|
|
360
|
+
input: process.stdin,
|
|
361
|
+
output: process.stdout
|
|
362
|
+
});
|
|
363
|
+
rl.question('Save these credentials? (Y/n): ', (answer) => {
|
|
364
|
+
rl.close();
|
|
365
|
+
resolve(answer.trim());
|
|
366
|
+
});
|
|
367
|
+
});
|
|
323
368
|
|
|
324
369
|
if (confirm.toLowerCase() !== 'n' && confirm.toLowerCase() !== 'no') {
|
|
325
370
|
const config = { workspace_id: workspaceId, api_key: apiKey, region };
|
|
@@ -328,7 +373,16 @@ async function interactiveSetup() {
|
|
|
328
373
|
log('');
|
|
329
374
|
|
|
330
375
|
// Validate
|
|
331
|
-
const testNow = await
|
|
376
|
+
const testNow = await new Promise((resolve) => {
|
|
377
|
+
const rl = readline.createInterface({
|
|
378
|
+
input: process.stdin,
|
|
379
|
+
output: process.stdout
|
|
380
|
+
});
|
|
381
|
+
rl.question('Validate credentials now? (Y/n): ', (answer) => {
|
|
382
|
+
rl.close();
|
|
383
|
+
resolve(answer.trim());
|
|
384
|
+
});
|
|
385
|
+
});
|
|
332
386
|
|
|
333
387
|
if (testNow.toLowerCase() !== 'n' && testNow.toLowerCase() !== 'no') {
|
|
334
388
|
log('');
|
|
@@ -344,7 +398,16 @@ async function interactiveSetup() {
|
|
|
344
398
|
log(` Workspace ID: ${result.workspace_id}`);
|
|
345
399
|
log('');
|
|
346
400
|
|
|
347
|
-
const syncNow = await
|
|
401
|
+
const syncNow = await new Promise((resolve) => {
|
|
402
|
+
const rl = readline.createInterface({
|
|
403
|
+
input: process.stdin,
|
|
404
|
+
output: process.stdout
|
|
405
|
+
});
|
|
406
|
+
rl.question('Sync tools now? (Y/n): ', (answer) => {
|
|
407
|
+
rl.close();
|
|
408
|
+
resolve(answer.trim());
|
|
409
|
+
});
|
|
410
|
+
});
|
|
348
411
|
|
|
349
412
|
if (syncNow.toLowerCase() !== 'n' && syncNow.toLowerCase() !== 'no') {
|
|
350
413
|
log('');
|
|
@@ -400,8 +463,6 @@ async function interactiveSetup() {
|
|
|
400
463
|
} else {
|
|
401
464
|
log('Setup cancelled.');
|
|
402
465
|
}
|
|
403
|
-
|
|
404
|
-
rl.close();
|
|
405
466
|
}
|
|
406
467
|
|
|
407
468
|
const cli = yargs(hideBin(process.argv))
|