@toothfairyai/tfcode 1.0.0-beta.2 → 1.0.0-beta.4

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.
Files changed (3) hide show
  1. package/README.md +39 -20
  2. package/bin/tfcode.js +52 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
  ## Installation
18
18
 
19
19
  ```bash
20
- npm install -g tfcode
20
+ npm install -g @toothfairyai/tfcode@beta
21
21
  ```
22
22
 
23
23
  The installer will:
@@ -26,6 +26,21 @@ The installer will:
26
26
 
27
27
  ## Quick Start
28
28
 
29
+ ### Option A: Interactive Setup (Recommended)
30
+
31
+ ```bash
32
+ # Run interactive setup
33
+ tfcode setup
34
+ ```
35
+
36
+ This will guide you through entering your credentials step by step:
37
+ 1. Enter your Workspace ID
38
+ 2. Enter your API Key (hidden as you type)
39
+ 3. Select your region
40
+ 4. Validate and sync automatically
41
+
42
+ ### Option B: Manual Setup
43
+
29
44
  ```bash
30
45
  # 1. Set your ToothFairyAI credentials
31
46
  export TF_WORKSPACE_ID="your-workspace-id"
@@ -38,21 +53,20 @@ tfcode validate
38
53
  # 3. Sync tools from your workspace
39
54
  tfcode sync
40
55
 
41
- # 4. Start coding!
42
- tfcode
56
+ # 4. List your tools
57
+ tfcode tools list
43
58
  ```
44
59
 
45
60
  ## Commands
46
61
 
47
62
  | Command | Description |
48
63
  |---------|-------------|
49
- | `tfcode` | Start the AI coding assistant |
64
+ | `tfcode setup` | **Interactive credential setup** |
50
65
  | `tfcode quickstart` | Show quick start guide |
51
66
  | `tfcode validate` | Test your credentials |
52
67
  | `tfcode sync` | Sync tools from workspace |
53
68
  | `tfcode tools list` | List synced tools |
54
- | `tfcode tools list --type mcp` | List MCP servers |
55
- | `tfcode tools credentials <name> --set` | Set API key for a tool |
69
+ | `tfcode tools list --type api_function` | Filter by type |
56
70
 
57
71
  ## Regions
58
72
 
@@ -65,7 +79,17 @@ tfcode
65
79
 
66
80
  ## Configuration
67
81
 
68
- Credentials can be set via environment variables:
82
+ Credentials are stored in `~/.tfcode/config.json`:
83
+
84
+ ```json
85
+ {
86
+ "workspace_id": "your-workspace-id",
87
+ "api_key": "your-api-key",
88
+ "region": "au"
89
+ }
90
+ ```
91
+
92
+ You can also set credentials via environment variables (takes priority over config file):
69
93
 
70
94
  ```bash
71
95
  export TF_WORKSPACE_ID="your-workspace-id"
@@ -73,18 +97,6 @@ export TF_API_KEY="your-api-key"
73
97
  export TF_REGION="au"
74
98
  ```
75
99
 
76
- Or in `~/.tfcode/tfcode.json`:
77
-
78
- ```json
79
- {
80
- "toothfairy": {
81
- "workspace_id": "your-workspace-id",
82
- "api_key": "your-api-key",
83
- "region": "au"
84
- }
85
- }
86
- ```
87
-
88
100
  ## Getting Your Credentials
89
101
 
90
102
  1. Log in to [ToothFairyAI](https://app.toothfairyai.com)
@@ -104,12 +116,19 @@ Install Python:
104
116
 
105
117
  - Check your API key is correct
106
118
  - Generate a new key in ToothFairyAI Settings → API Keys
119
+ - Run `tfcode setup` to re-enter credentials
107
120
 
108
121
  ### "Failed to validate: Connection test failed"
109
122
 
110
123
  Try a different region:
124
+ - Run `tfcode setup` and select a different region
125
+ - Or set `TF_REGION="eu"` or `TF_REGION="us"`
126
+
127
+ ### "No credentials found"
128
+
129
+ Run interactive setup:
111
130
  ```bash
112
- export TF_REGION="eu" # or us, au
131
+ tfcode setup
113
132
  ```
114
133
 
115
134
  ## Documentation
package/bin/tfcode.js CHANGED
@@ -43,19 +43,17 @@ function info(msg) {
43
43
  function question(rl, prompt, hidden = false) {
44
44
  return new Promise((resolve) => {
45
45
  if (hidden) {
46
- const stdin = process.stdin;
47
- const wasRaw = stdin.isRaw;
48
-
49
46
  process.stdout.write(prompt);
50
47
 
48
+ let input = '';
49
+ const stdin = process.stdin;
50
+
51
51
  if (stdin.isTTY) {
52
52
  stdin.setRawMode(true);
53
53
  }
54
-
55
- let input = '';
56
-
57
54
  stdin.resume();
58
- stdin.on('data', function charListener(char) {
55
+
56
+ const onData = (char) => {
59
57
  const c = char.toString('utf8');
60
58
 
61
59
  switch (c) {
@@ -63,24 +61,28 @@ function question(rl, prompt, hidden = false) {
63
61
  case '\r':
64
62
  case '\u0004':
65
63
  if (stdin.isTTY) {
66
- stdin.setRawMode(wasRaw || false);
64
+ stdin.setRawMode(false);
67
65
  }
68
66
  stdin.pause();
69
- stdin.removeListener('data', charListener);
67
+ stdin.removeListener('data', onData);
70
68
  process.stdout.write('\n');
71
69
  resolve(input);
72
70
  break;
73
71
  case '\u0003':
72
+ process.stdout.write('\n');
74
73
  process.exit();
75
74
  break;
76
75
  case '\u007F':
76
+ case '\b':
77
77
  input = input.slice(0, -1);
78
78
  break;
79
79
  default:
80
80
  input += c;
81
81
  break;
82
82
  }
83
- });
83
+ };
84
+
85
+ stdin.on('data', onData);
84
86
  } else {
85
87
  rl.question(prompt, (answer) => {
86
88
  resolve(answer.trim());
@@ -89,7 +91,7 @@ function question(rl, prompt, hidden = false) {
89
91
  });
90
92
  }
91
93
 
92
- function select(rl, prompt, options) {
94
+ function select(prompt, options) {
93
95
  return new Promise((resolve) => {
94
96
  log('');
95
97
  log(prompt);
@@ -99,14 +101,42 @@ function select(rl, prompt, options) {
99
101
  });
100
102
  log('');
101
103
 
102
- rl.question('Select (1-' + options.length + '): ', (answer) => {
103
- const idx = parseInt(answer.trim()) - 1;
104
- if (idx >= 0 && idx < options.length) {
105
- resolve(idx);
106
- } else {
107
- resolve(0);
104
+ process.stdout.write('Select (1-' + options.length + '): ');
105
+
106
+ let input = '';
107
+ const stdin = process.stdin;
108
+
109
+ if (stdin.isTTY) {
110
+ stdin.setRawMode(true);
111
+ }
112
+ stdin.resume();
113
+
114
+ const onData = (char) => {
115
+ const c = char.toString('utf8');
116
+
117
+ if (c === '\n' || c === '\r' || c === '\u0004') {
118
+ if (stdin.isTTY) {
119
+ stdin.setRawMode(false);
120
+ }
121
+ stdin.pause();
122
+ stdin.removeListener('data', onData);
123
+ process.stdout.write('\n');
124
+
125
+ const idx = parseInt(input) - 1;
126
+ resolve(idx >= 0 && idx < options.length ? idx : 0);
127
+ } else if (c === '\u0003') {
128
+ process.stdout.write('\n');
129
+ process.exit();
130
+ } else if (c >= '1' && c <= '9') {
131
+ input += c;
132
+ process.stdout.write(c);
133
+ } else if (c === '\u007F' || c === '\b') {
134
+ input = input.slice(0, -1);
135
+ process.stdout.write('\b \b');
108
136
  }
109
- });
137
+ };
138
+
139
+ stdin.on('data', onData);
110
140
  });
111
141
  }
112
142
 
@@ -304,7 +334,7 @@ async function interactiveSetup() {
304
334
  // Region
305
335
  log(`${COLORS.bold}Step 3: Region${COLORS.reset}`);
306
336
  const regions = ['dev (Development)', 'au (Australia)', 'eu (Europe)', 'us (United States)'];
307
- const regionIdx = await select(rl, 'Select your region:', regions);
337
+ const regionIdx = await select('Select your region:', regions);
308
338
  const regions_map = ['dev', 'au', 'eu', 'us'];
309
339
  const region = regions_map[regionIdx];
310
340
 
@@ -319,6 +349,7 @@ async function interactiveSetup() {
319
349
  log(` Region: ${region}`);
320
350
  log('');
321
351
 
352
+ rl.resume();
322
353
  const confirm = await question(rl, 'Save these credentials? (Y/n): ');
323
354
 
324
355
  if (confirm.toLowerCase() !== 'n' && confirm.toLowerCase() !== 'no') {
@@ -328,6 +359,7 @@ async function interactiveSetup() {
328
359
  log('');
329
360
 
330
361
  // Validate
362
+ rl.resume();
331
363
  const testNow = await question(rl, 'Validate credentials now? (Y/n): ');
332
364
 
333
365
  if (testNow.toLowerCase() !== 'n' && testNow.toLowerCase() !== 'no') {
@@ -344,6 +376,7 @@ async function interactiveSetup() {
344
376
  log(` Workspace ID: ${result.workspace_id}`);
345
377
  log('');
346
378
 
379
+ rl.resume();
347
380
  const syncNow = await question(rl, 'Sync tools now? (Y/n): ');
348
381
 
349
382
  if (syncNow.toLowerCase() !== 'n' && syncNow.toLowerCase() !== 'no') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toothfairyai/tfcode",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "ToothFairyAI's official AI coding agent",
5
5
  "keywords": ["toothfairyai", "ai", "coding", "cli"],
6
6
  "author": "ToothFairyAI",