mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-29 21:33:54 +00:00
feat: tfcode beta
This commit is contained in:
parent
4596310485
commit
4380efd658
27
README.md
27
README.md
@ -297,13 +297,10 @@ tf_code/
|
||||
```bash
|
||||
# Check Python version
|
||||
python3 --version # Should be 3.10 or higher
|
||||
|
||||
# Install Python if needed
|
||||
# macOS: brew install python@3.12
|
||||
# Ubuntu: sudo apt-get install python3.12
|
||||
# Windows: Download from https://python.org/downloads
|
||||
```
|
||||
|
||||
**Don't have Python?** See our [Setup Guide](./docs/setup-guide.md) for detailed instructions.
|
||||
|
||||
### Install tfcode
|
||||
|
||||
```bash
|
||||
@ -322,6 +319,26 @@ brew install toothfairyai/tap/tfcode
|
||||
|
||||
The postinstall script will automatically install the ToothFairyAI Python SDK.
|
||||
|
||||
### First-Time Setup
|
||||
|
||||
```bash
|
||||
# Show quick start guide
|
||||
tfcode quickstart
|
||||
|
||||
# Set your credentials
|
||||
export TF_WORKSPACE_ID="your-workspace-id"
|
||||
export TF_API_KEY="your-api-key"
|
||||
export TF_REGION="au"
|
||||
|
||||
# Validate connection
|
||||
tfcode validate
|
||||
|
||||
# Sync tools
|
||||
tfcode sync
|
||||
```
|
||||
|
||||
See [Setup Guide](./docs/setup-guide.md) for detailed step-by-step instructions.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
311
docs/setup-guide.md
Normal file
311
docs/setup-guide.md
Normal file
@ -0,0 +1,311 @@
|
||||
# tfcode Setup Guide for New Users
|
||||
|
||||
**Time required**: ~10 minutes
|
||||
|
||||
This guide will walk you through installing tfcode step by step. No technical experience needed.
|
||||
|
||||
---
|
||||
|
||||
## What You'll Need
|
||||
|
||||
1. **Python 3.10 or newer** (required for ToothFairyAI integration)
|
||||
2. **Node.js** (required to run tfcode)
|
||||
3. **Your ToothFairyAI credentials** (workspace ID and API key)
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install Python
|
||||
|
||||
### macOS
|
||||
|
||||
1. Open **Terminal** (press `Cmd + Space`, type "Terminal", press Enter)
|
||||
2. Copy and paste this command, then press Enter:
|
||||
|
||||
```bash
|
||||
brew install python@3.12
|
||||
```
|
||||
|
||||
If you don't have Homebrew, install it first:
|
||||
```bash
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
1. Go to **https://python.org/downloads**
|
||||
2. Click "Download Python 3.12" (or latest version)
|
||||
3. Run the installer
|
||||
4. **Important**: Check the box that says "Add Python to PATH"
|
||||
5. Click "Install Now"
|
||||
|
||||
### Linux (Ubuntu/Debian)
|
||||
|
||||
Open Terminal and run:
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install python3.12 python3-pip
|
||||
```
|
||||
|
||||
### Verify Python Installation
|
||||
|
||||
Open Terminal (macOS/Linux) or Command Prompt (Windows) and type:
|
||||
|
||||
```bash
|
||||
python3 --version
|
||||
```
|
||||
|
||||
You should see something like: `Python 3.12.x`
|
||||
|
||||
✅ If you see this, Python is installed correctly!
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Install Node.js
|
||||
|
||||
### macOS
|
||||
|
||||
```bash
|
||||
brew install node
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
1. Go to **https://nodejs.org**
|
||||
2. Download the "LTS" (Long Term Support) version
|
||||
3. Run the installer with default settings
|
||||
|
||||
### Linux (Ubuntu/Debian)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
```
|
||||
|
||||
### Verify Node.js Installation
|
||||
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
You should see something like: `v20.x.x`
|
||||
|
||||
✅ If you see this, Node.js is installed correctly!
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Install tfcode
|
||||
|
||||
Open Terminal (macOS/Linux) or Command Prompt (Windows) and run:
|
||||
|
||||
```bash
|
||||
npm install -g tfcode
|
||||
```
|
||||
|
||||
You'll see output like:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
tfcode - ToothFairyAI's official coding agent
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
✓ Found Python 3.12.x (python3)
|
||||
✓ Python dependencies installed
|
||||
|
||||
✓ tfcode installed successfully!
|
||||
```
|
||||
|
||||
✅ tfcode is now installed!
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Get Your ToothFairyAI Credentials
|
||||
|
||||
1. Log in to your ToothFairyAI workspace at **https://app.toothfairyai.com**
|
||||
2. Go to **Settings** → **API Keys**
|
||||
3. Copy your **Workspace ID** and **API Key**
|
||||
|
||||
You'll need these for the next step.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Configure tfcode
|
||||
|
||||
### macOS / Linux
|
||||
|
||||
Open Terminal and run these commands (replace with your actual credentials):
|
||||
|
||||
```bash
|
||||
# Set your credentials
|
||||
export TF_WORKSPACE_ID="your-workspace-id-here"
|
||||
export TF_API_KEY="your-api-key-here"
|
||||
export TF_REGION="au"
|
||||
|
||||
# Make them permanent (so you don't have to set them every time)
|
||||
echo 'export TF_WORKSPACE_ID="your-workspace-id-here"' >> ~/.zshrc
|
||||
echo 'export TF_API_KEY="your-api-key-here"' >> ~/.zshrc
|
||||
echo 'export TF_REGION="au"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
### Windows (Command Prompt)
|
||||
|
||||
```cmd
|
||||
setx TF_WORKSPACE_ID "your-workspace-id-here"
|
||||
setx TF_API_KEY "your-api-key-here"
|
||||
setx TF_REGION "au"
|
||||
```
|
||||
|
||||
**Note**: Close and reopen Command Prompt after running these commands.
|
||||
|
||||
### Region Options
|
||||
|
||||
- `au` - Australia (default)
|
||||
- `eu` - Europe
|
||||
- `us` - United States
|
||||
- `dev` - Development (for internal testing)
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Validate Your Setup
|
||||
|
||||
Run this command to check everything is working:
|
||||
|
||||
```bash
|
||||
tfcode validate
|
||||
```
|
||||
|
||||
You should see:
|
||||
```
|
||||
Validating ToothFairyAI credentials...
|
||||
✓ Credentials valid
|
||||
Workspace: Your Workspace Name
|
||||
ID: your-workspace-id
|
||||
```
|
||||
|
||||
✅ If you see this, your credentials are correct!
|
||||
|
||||
❌ If you see an error:
|
||||
- Double-check your Workspace ID and API Key
|
||||
- Make sure you copied them completely (no extra spaces)
|
||||
- Try a different region (`au`, `eu`, or `us`)
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Sync Your Tools
|
||||
|
||||
Run this command to sync tools from your ToothFairyAI workspace:
|
||||
|
||||
```bash
|
||||
tfcode sync
|
||||
```
|
||||
|
||||
You should see:
|
||||
```
|
||||
Syncing tools from ToothFairyAI workspace...
|
||||
✓ Synced X tools
|
||||
|
||||
By type:
|
||||
api_function: X
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8: View Your Tools
|
||||
|
||||
List all synced tools:
|
||||
|
||||
```bash
|
||||
tfcode tools list
|
||||
```
|
||||
|
||||
You'll see all the tools available from your workspace.
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Start Coding!
|
||||
|
||||
Now you're ready to use tfcode:
|
||||
|
||||
```bash
|
||||
tfcode
|
||||
```
|
||||
|
||||
This opens the tfcode terminal interface where you can:
|
||||
- Chat with the AI
|
||||
- Ask it to write code
|
||||
- Use your synced tools
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `tfcode validate` | Check your credentials work |
|
||||
| `tfcode sync` | Sync tools from your workspace |
|
||||
| `tfcode tools list` | Show all your synced tools |
|
||||
| `tfcode tools list --type mcp` | Show only MCP servers |
|
||||
| `tfcode tools credentials <name> --set` | Add an API key for a tool |
|
||||
| `tfcode` | Start the coding assistant |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Python 3.10+ is required but not found"
|
||||
|
||||
**Solution**: Install Python (see Step 1)
|
||||
|
||||
### "Failed to validate: Invalid API key"
|
||||
|
||||
**Solution**:
|
||||
1. Go to ToothFairyAI Settings → API Keys
|
||||
2. Generate a new API key
|
||||
3. Update your credentials:
|
||||
- macOS/Linux: Edit `~/.zshrc`
|
||||
- Windows: Run the `setx` commands again
|
||||
|
||||
### "Failed to validate: Workspace not found"
|
||||
|
||||
**Solution**: Check your Workspace ID is correct
|
||||
|
||||
### "Failed to validate: Connection test failed"
|
||||
|
||||
**Solution**: Try a different region:
|
||||
- `au` - Australia
|
||||
- `eu` - Europe
|
||||
- `us` - United States
|
||||
|
||||
Update with:
|
||||
```bash
|
||||
export TF_REGION="eu" # or us, au
|
||||
```
|
||||
|
||||
### "command not found: tfcode"
|
||||
|
||||
**Solution**:
|
||||
1. Make sure you installed tfcode: `npm install -g tfcode`
|
||||
2. Restart your terminal
|
||||
|
||||
### "npm: command not found"
|
||||
|
||||
**Solution**: Install Node.js (see Step 2)
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
- **Documentation**: https://toothfairyai.com/developers/tfcode
|
||||
- **Support**: Contact ToothFairyAI support
|
||||
- **Issues**: Report bugs at https://github.com/ToothFairyAI/tfcode/issues
|
||||
|
||||
---
|
||||
|
||||
## What's Next?
|
||||
|
||||
1. **Read the docs**: https://toothfairyai.com/developers/tfcode
|
||||
2. **Try a simple task**: `tfcode` then ask "Create a simple Node.js HTTP server"
|
||||
3. **Configure MCP servers**: Add MCP servers to `~/.tfcode/tfcode.json`
|
||||
4. **Set up API keys**: `tfcode tools credentials <tool-name> --set`
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-03-24*
|
||||
@ -1,15 +1,127 @@
|
||||
# js
|
||||
# tfcode
|
||||
|
||||
To install dependencies:
|
||||
**ToothFairyAI's official AI coding agent** - A terminal-based coding assistant with seamless integration to your ToothFairyAI workspace.
|
||||
|
||||
## Features
|
||||
|
||||
- 🤖 **AI-Powered Coding** - Intelligent code generation, refactoring, and debugging
|
||||
- 🔌 **Tool Integration** - Sync and use tools from your ToothFairyAI workspace
|
||||
- 💻 **Terminal-Based** - Fast, lightweight, runs in your terminal
|
||||
- 🔐 **Secure** - Credentials stay in ToothFairyAI, route via TF Proxy
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Python 3.10+** - Required for ToothFairyAI integration
|
||||
- **Node.js 18+** - Required to run tfcode
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun install
|
||||
npm install -g tfcode
|
||||
```
|
||||
|
||||
To run:
|
||||
The installer will:
|
||||
- Check Python is installed
|
||||
- Install the ToothFairyAI Python SDK automatically
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
bun run index.ts
|
||||
# 1. Set your ToothFairyAI credentials
|
||||
export TF_WORKSPACE_ID="your-workspace-id"
|
||||
export TF_API_KEY="your-api-key"
|
||||
export TF_REGION="au"
|
||||
|
||||
# 2. Validate your credentials
|
||||
tfcode validate
|
||||
|
||||
# 3. Sync tools from your workspace
|
||||
tfcode sync
|
||||
|
||||
# 4. Start coding!
|
||||
tfcode
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.2.12. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `tfcode` | Start the AI coding assistant |
|
||||
| `tfcode quickstart` | Show quick start guide |
|
||||
| `tfcode validate` | Test your credentials |
|
||||
| `tfcode sync` | Sync tools from workspace |
|
||||
| `tfcode tools list` | List synced tools |
|
||||
| `tfcode tools list --type mcp` | List MCP servers |
|
||||
| `tfcode tools credentials <name> --set` | Set API key for a tool |
|
||||
|
||||
## Regions
|
||||
|
||||
| Region | URL | Use Case |
|
||||
|--------|-----|----------|
|
||||
| `dev` | api.toothfairylab.link | Development/Testing |
|
||||
| `au` | api.toothfairyai.com | Australia (Default) |
|
||||
| `eu` | api.eu.toothfairyai.com | Europe |
|
||||
| `us` | api.us.toothfairyai.com | United States |
|
||||
|
||||
## Configuration
|
||||
|
||||
Credentials can be set via environment variables:
|
||||
|
||||
```bash
|
||||
export TF_WORKSPACE_ID="your-workspace-id"
|
||||
export TF_API_KEY="your-api-key"
|
||||
export TF_REGION="au"
|
||||
```
|
||||
|
||||
Or in `~/.tfcode/tfcode.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"toothfairy": {
|
||||
"workspace_id": "your-workspace-id",
|
||||
"api_key": "your-api-key",
|
||||
"region": "au"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Getting Your Credentials
|
||||
|
||||
1. Log in to [ToothFairyAI](https://app.toothfairyai.com)
|
||||
2. Go to **Settings** → **API Keys**
|
||||
3. Copy your **Workspace ID** and **API Key**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Python 3.10+ is required but not found"
|
||||
|
||||
Install Python:
|
||||
- **macOS**: `brew install python@3.12`
|
||||
- **Windows**: Download from https://python.org/downloads
|
||||
- **Linux**: `sudo apt install python3.12`
|
||||
|
||||
### "Failed to validate: Invalid API key"
|
||||
|
||||
- Check your API key is correct
|
||||
- Generate a new key in ToothFairyAI Settings → API Keys
|
||||
|
||||
### "Failed to validate: Connection test failed"
|
||||
|
||||
Try a different region:
|
||||
```bash
|
||||
export TF_REGION="eu" # or us, au
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- **Full Guide**: https://toothfairyai.com/developers/tfcode
|
||||
- **API Docs**: https://apidocs.toothfairyai.com
|
||||
- **Issues**: https://github.com/ToothFairyAI/tfcode/issues
|
||||
|
||||
## Credits
|
||||
|
||||
tfcode is based on [opencode](https://github.com/anomalyco/opencode) by [anomalyco](https://github.com/anomalyco).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@ -1,179 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const childProcess = require("child_process")
|
||||
const fs = require("fs")
|
||||
const { spawn } = require("child_process")
|
||||
const path = require("path")
|
||||
const os = require("os")
|
||||
|
||||
function run(target) {
|
||||
const result = childProcess.spawnSync(target, process.argv.slice(2), {
|
||||
const scriptDir = __dirname
|
||||
const srcPath = path.join(scriptDir, "..", "src", "index.ts")
|
||||
|
||||
const child = spawn("npx", ["tsx", srcPath, ...process.argv.slice(2)], {
|
||||
stdio: "inherit",
|
||||
})
|
||||
if (result.error) {
|
||||
console.error(result.error.message)
|
||||
process.exit(1)
|
||||
}
|
||||
const code = typeof result.status === "number" ? result.status : 0
|
||||
process.exit(code)
|
||||
}
|
||||
shell: process.platform === "win32",
|
||||
cwd: scriptDir
|
||||
})
|
||||
|
||||
const envPath = process.env.OPENCODE_BIN_PATH
|
||||
if (envPath) {
|
||||
run(envPath)
|
||||
}
|
||||
|
||||
const scriptPath = fs.realpathSync(__filename)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
|
||||
//
|
||||
const cached = path.join(scriptDir, ".tfcode")
|
||||
if (fs.existsSync(cached)) {
|
||||
run(cached)
|
||||
}
|
||||
|
||||
const platformMap = {
|
||||
darwin: "darwin",
|
||||
linux: "linux",
|
||||
win32: "windows",
|
||||
}
|
||||
const archMap = {
|
||||
x64: "x64",
|
||||
arm64: "arm64",
|
||||
arm: "arm",
|
||||
}
|
||||
|
||||
let platform = platformMap[os.platform()]
|
||||
if (!platform) {
|
||||
platform = os.platform()
|
||||
}
|
||||
let arch = archMap[os.arch()]
|
||||
if (!arch) {
|
||||
arch = os.arch()
|
||||
}
|
||||
const base = "opencode-" + platform + "-" + arch
|
||||
const binary = platform === "windows" ? "opencode.exe" : "opencode"
|
||||
|
||||
function supportsAvx2() {
|
||||
if (arch !== "x64") return false
|
||||
|
||||
if (platform === "linux") {
|
||||
try {
|
||||
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (platform === "darwin") {
|
||||
try {
|
||||
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
||||
encoding: "utf8",
|
||||
timeout: 1500,
|
||||
})
|
||||
if (result.status !== 0) return false
|
||||
return (result.stdout || "").trim() === "1"
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (platform === "windows") {
|
||||
const cmd =
|
||||
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
||||
|
||||
for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
||||
try {
|
||||
const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
windowsHide: true,
|
||||
})
|
||||
if (result.status !== 0) continue
|
||||
const out = (result.stdout || "").trim().toLowerCase()
|
||||
if (out === "true" || out === "1") return true
|
||||
if (out === "false" || out === "0") return false
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const names = (() => {
|
||||
const avx2 = supportsAvx2()
|
||||
const baseline = arch === "x64" && !avx2
|
||||
|
||||
if (platform === "linux") {
|
||||
const musl = (() => {
|
||||
try {
|
||||
if (fs.existsSync("/etc/alpine-release")) return true
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
||||
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
|
||||
if (text.includes("musl")) return true
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return false
|
||||
})()
|
||||
|
||||
if (musl) {
|
||||
if (arch === "x64") {
|
||||
if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
||||
return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
||||
}
|
||||
return [`${base}-musl`, base]
|
||||
}
|
||||
|
||||
if (arch === "x64") {
|
||||
if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
||||
return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
||||
}
|
||||
return [base, `${base}-musl`]
|
||||
}
|
||||
|
||||
if (arch === "x64") {
|
||||
if (baseline) return [`${base}-baseline`, base]
|
||||
return [base, `${base}-baseline`]
|
||||
}
|
||||
return [base]
|
||||
})()
|
||||
|
||||
function findBinary(startDir) {
|
||||
let current = startDir
|
||||
for (;;) {
|
||||
const modules = path.join(current, "node_modules")
|
||||
if (fs.existsSync(modules)) {
|
||||
for (const name of names) {
|
||||
const candidate = path.join(modules, name, "bin", binary)
|
||||
if (fs.existsSync(candidate)) return candidate
|
||||
}
|
||||
}
|
||||
const parent = path.dirname(current)
|
||||
if (parent === current) {
|
||||
return
|
||||
}
|
||||
current = parent
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = findBinary(scriptDir)
|
||||
if (!resolved) {
|
||||
console.error(
|
||||
"It seems that your package manager failed to install the right version of the opencode CLI for your platform. You can try manually installing " +
|
||||
names.map((n) => `\"${n}\"`).join(" or ") +
|
||||
" package",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
run(resolved)
|
||||
child.on("exit", (code) => {
|
||||
process.exit(code || 0)
|
||||
})
|
||||
|
||||
333
packages/tfcode/bin/tfcode.js
Normal file
333
packages/tfcode/bin/tfcode.js
Normal file
@ -0,0 +1,333 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import { spawn } from 'child_process';
|
||||
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
|
||||
const TFCODE_DIR = join(homedir(), '.tfcode');
|
||||
const TOOLS_FILE = join(TFCODE_DIR, 'tools.json');
|
||||
const CREDENTIALS_FILE = join(TFCODE_DIR, 'credentials.json');
|
||||
|
||||
const COLORS = {
|
||||
reset: '\x1b[0m',
|
||||
bold: '\x1b[1m',
|
||||
green: '\x1b[32m',
|
||||
red: '\x1b[31m',
|
||||
cyan: '\x1b[36m',
|
||||
dim: '\x1b[90m',
|
||||
yellow: '\x1b[33m'
|
||||
};
|
||||
|
||||
function log(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
function success(msg) {
|
||||
console.log(`${COLORS.green}✓${COLORS.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function error(msg) {
|
||||
console.error(`${COLORS.red}✗${COLORS.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function info(msg) {
|
||||
console.log(`${COLORS.cyan}ℹ${COLORS.reset} ${msg}`);
|
||||
}
|
||||
|
||||
function runPythonSync(method) {
|
||||
const pythonCode = `
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
try:
|
||||
from tf_sync.config import load_config, validate_credentials, Region
|
||||
from tf_sync.tools import sync_tools
|
||||
from tf_sync.config import get_region_urls
|
||||
|
||||
method = "${method}"
|
||||
|
||||
if method == "validate":
|
||||
config = load_config()
|
||||
result = validate_credentials(config)
|
||||
urls = get_region_urls(config.region)
|
||||
print(json.dumps({
|
||||
"success": result.success,
|
||||
"workspace_id": result.workspace_id,
|
||||
"workspace_name": result.workspace_name,
|
||||
"error": result.error,
|
||||
"base_url": urls["base_url"]
|
||||
}))
|
||||
|
||||
elif method == "sync":
|
||||
config = load_config()
|
||||
result = sync_tools(config)
|
||||
|
||||
tools_data = []
|
||||
for tool in result.tools:
|
||||
tools_data.append({
|
||||
"id": tool.id,
|
||||
"name": tool.name,
|
||||
"description": tool.description,
|
||||
"tool_type": tool.tool_type.value,
|
||||
"request_type": tool.request_type.value if tool.request_type else None,
|
||||
"url": tool.url,
|
||||
"auth_via": tool.auth_via
|
||||
})
|
||||
|
||||
print(json.dumps({
|
||||
"success": result.success,
|
||||
"tools": tools_data,
|
||||
"by_type": result.by_type,
|
||||
"error": result.error
|
||||
}))
|
||||
|
||||
except Exception as e:
|
||||
print(json.dumps({"success": False, "error": str(e)}))
|
||||
sys.exit(0)
|
||||
`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const pythonPath = process.env.TFCODE_PYTHON_PATH || 'python3';
|
||||
const proc = spawn(pythonPath, ['-c', pythonCode], {
|
||||
env: {
|
||||
...process.env,
|
||||
PYTHONPATH: process.env.TFCODE_PYTHONPATH || ''
|
||||
}
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
proc.stdout.on('data', (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
|
||||
proc.stderr.on('data', (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
|
||||
proc.on('close', (code) => {
|
||||
if (code !== 0 && !stdout) {
|
||||
reject(new Error(`Python sync failed: ${stderr}`));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = JSON.parse(stdout.trim());
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(new Error(`Failed to parse Python output: ${stdout}\nstderr: ${stderr}`));
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ensureConfigDir() {
|
||||
if (!existsSync(TFCODE_DIR)) {
|
||||
mkdirSync(TFCODE_DIR, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
function loadCachedTools() {
|
||||
if (!existsSync(TOOLS_FILE)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(readFileSync(TOOLS_FILE, 'utf-8'));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function saveToolsCache(tools) {
|
||||
ensureConfigDir();
|
||||
writeFileSync(TOOLS_FILE, JSON.stringify(tools, null, 2));
|
||||
}
|
||||
|
||||
const cli = yargs(hideBin(process.argv))
|
||||
.scriptName('tfcode')
|
||||
.wrap(100)
|
||||
.help()
|
||||
.alias('help', 'h')
|
||||
.command({
|
||||
command: 'quickstart',
|
||||
describe: 'show quick start guide',
|
||||
handler: () => {
|
||||
log('');
|
||||
log(`${COLORS.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
||||
log(`${COLORS.bold} tfcode - Quick Start Guide${COLORS.reset}`);
|
||||
log(`${COLORS.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
||||
log('');
|
||||
log('Welcome to tfcode! Follow these steps to get started:');
|
||||
log('');
|
||||
log(`${COLORS.cyan}STEP 1: Set Your Credentials${COLORS.reset}`);
|
||||
log(`${COLORS.dim} export TF_WORKSPACE_ID="your-workspace-id"${COLORS.reset}`);
|
||||
log(`${COLORS.dim} export TF_API_KEY="your-api-key"${COLORS.reset}`);
|
||||
log(`${COLORS.dim} export TF_REGION="au"${COLORS.reset}`);
|
||||
log(`${COLORS.dim} Regions: dev, au, eu, us${COLORS.reset}`);
|
||||
log('');
|
||||
log(`${COLORS.cyan}STEP 2: Validate Connection${COLORS.reset}`);
|
||||
log(`${COLORS.dim} tfcode validate${COLORS.reset}`);
|
||||
log('');
|
||||
log(`${COLORS.cyan}STEP 3: Sync Your Tools${COLORS.reset}`);
|
||||
log(`${COLORS.dim} tfcode sync${COLORS.reset}`);
|
||||
log('');
|
||||
log(`${COLORS.cyan}STEP 4: Start Coding!${COLORS.reset}`);
|
||||
log(`${COLORS.dim} tfcode${COLORS.reset}`);
|
||||
log('');
|
||||
log(`${COLORS.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
||||
log('');
|
||||
log(' Useful Commands:');
|
||||
log('');
|
||||
log(' tfcode validate Test your credentials');
|
||||
log(' tfcode sync Sync tools from workspace');
|
||||
log(' tfcode tools list Show all your tools');
|
||||
log('');
|
||||
log(`${COLORS.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
||||
log('');
|
||||
log(' Need help? https://toothfairyai.com/developers/tfcode');
|
||||
log('');
|
||||
}
|
||||
})
|
||||
.command({
|
||||
command: 'validate',
|
||||
describe: 'validate ToothFairyAI credentials',
|
||||
handler: async () => {
|
||||
info('Validating ToothFairyAI credentials...');
|
||||
log('');
|
||||
|
||||
try {
|
||||
const result = await runPythonSync('validate');
|
||||
|
||||
if (result.success) {
|
||||
success('Credentials valid');
|
||||
if (result.base_url) {
|
||||
log(`${COLORS.dim} API URL: ${result.base_url}${COLORS.reset}`);
|
||||
}
|
||||
if (result.workspace_id) {
|
||||
log(`${COLORS.dim} Workspace ID: ${result.workspace_id}${COLORS.reset}`);
|
||||
}
|
||||
} else {
|
||||
error(`Validation failed: ${result.error || 'Unknown error'}`);
|
||||
log('');
|
||||
log(`${COLORS.dim}Check your credentials:${COLORS.reset}`);
|
||||
log(`${COLORS.dim} TF_WORKSPACE_ID: ${process.env.TF_WORKSPACE_ID || 'not set'}${COLORS.reset}`);
|
||||
log(`${COLORS.dim} TF_API_KEY: ${process.env.TF_API_KEY ? '***' + process.env.TF_API_KEY.slice(-4) : 'not set'}${COLORS.reset}`);
|
||||
log(`${COLORS.dim} TF_REGION: ${process.env.TF_REGION || 'au (default)'}${COLORS.reset}`);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
error(`Failed to validate: ${e.message}`);
|
||||
log('');
|
||||
log(`${COLORS.dim}Make sure Python 3.10+ and the ToothFairyAI SDK are installed:${COLORS.reset}`);
|
||||
log(`${COLORS.dim} pip install toothfairyai pydantic httpx rich${COLORS.reset}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
})
|
||||
.command({
|
||||
command: 'sync',
|
||||
describe: 'sync tools from ToothFairyAI workspace',
|
||||
handler: async () => {
|
||||
info('Syncing tools from ToothFairyAI workspace...');
|
||||
log('');
|
||||
|
||||
try {
|
||||
const result = await runPythonSync('sync');
|
||||
|
||||
if (result.success) {
|
||||
saveToolsCache(result);
|
||||
success(`Synced ${result.tools.length} tools`);
|
||||
log('');
|
||||
|
||||
if (result.by_type && Object.keys(result.by_type).length > 0) {
|
||||
log('By type:');
|
||||
for (const [type, count] of Object.entries(result.by_type)) {
|
||||
log(` ${type}: ${count}`);
|
||||
}
|
||||
log('');
|
||||
}
|
||||
} else {
|
||||
error(`Sync failed: ${result.error || 'Unknown error'}`);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
error(`Failed to sync: ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
})
|
||||
.command({
|
||||
command: 'tools',
|
||||
describe: 'manage tools',
|
||||
builder: (yargs) => {
|
||||
return yargs
|
||||
.command({
|
||||
command: 'list',
|
||||
describe: 'list synced tools',
|
||||
builder: (yargs) => {
|
||||
return yargs.option('type', {
|
||||
type: 'string',
|
||||
describe: 'filter by type (api_function)'
|
||||
});
|
||||
},
|
||||
handler: (args) => {
|
||||
const cached = loadCachedTools();
|
||||
|
||||
if (!cached || !cached.success) {
|
||||
error('No tools synced. Run \'tfcode sync\' first.');
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
let tools = cached.tools;
|
||||
|
||||
if (args.type) {
|
||||
tools = tools.filter(t => t.tool_type === args.type);
|
||||
}
|
||||
|
||||
if (tools.length === 0) {
|
||||
log('No tools found.');
|
||||
return;
|
||||
}
|
||||
|
||||
log('');
|
||||
log(`${tools.length} tool(s):`);
|
||||
log('');
|
||||
|
||||
for (const tool of tools) {
|
||||
log(` ${COLORS.cyan}${tool.name}${COLORS.reset}`);
|
||||
log(` Type: ${tool.tool_type}`);
|
||||
if (tool.description) {
|
||||
log(` ${COLORS.dim}${tool.description.slice(0, 60)}${tool.description.length > 60 ? '...' : ''}${COLORS.reset}`);
|
||||
}
|
||||
log(` Auth: ${tool.auth_via}`);
|
||||
log('');
|
||||
}
|
||||
}
|
||||
})
|
||||
.demandCommand();
|
||||
},
|
||||
handler: () => {}
|
||||
})
|
||||
.demandCommand()
|
||||
.strict()
|
||||
.fail((msg, err) => {
|
||||
if (msg) {
|
||||
error(msg);
|
||||
}
|
||||
if (err) {
|
||||
error(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
cli.parse();
|
||||
34
packages/tfcode/package-beta.json
Normal file
34
packages/tfcode/package-beta.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "tfcode",
|
||||
"version": "1.0.0-beta.1",
|
||||
"description": "ToothFairyAI's official AI coding agent",
|
||||
"keywords": ["toothfairyai", "ai", "coding", "cli"],
|
||||
"author": "ToothFairyAI",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"tfcode": "./bin/tfcode.js"
|
||||
},
|
||||
"files": [
|
||||
"bin/",
|
||||
"src/",
|
||||
"scripts/"
|
||||
],
|
||||
"scripts": {
|
||||
"postinstall": "node scripts/postinstall.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/yargs": "^17.0.33"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"homepage": "https://toothfairyai.com/developers/tfcode",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ToothFairyAI/tfcode.git"
|
||||
}
|
||||
}
|
||||
@ -1,157 +1,30 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.3.0",
|
||||
"name": "tfcode",
|
||||
"type": "module",
|
||||
"name": "@toothfairyai/tfcode",
|
||||
"version": "1.0.0-beta.1",
|
||||
"description": "ToothFairyAI's official AI coding agent",
|
||||
"keywords": ["toothfairyai", "ai", "coding", "cli"],
|
||||
"author": "ToothFairyAI",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"prepare": "effect-language-service patch || true",
|
||||
"postinstall": "node scripts/postinstall.cjs",
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"test": "bun test --timeout 30000",
|
||||
"build": "bun run script/build.ts",
|
||||
"dev": "bun run --conditions=browser ./src/index.ts",
|
||||
"random": "echo 'Random script updated at $(date)' && echo 'Change queued successfully' && echo 'Another change made' && echo 'Yet another change' && echo 'One more change' && echo 'Final change' && echo 'Another final change' && echo 'Yet another final change'",
|
||||
"clean": "echo 'Cleaning up...' && rm -rf node_modules dist",
|
||||
"lint": "echo 'Running lint checks...' && bun test --coverage",
|
||||
"format": "echo 'Formatting code...' && bun run --prettier --write src/**/*.ts",
|
||||
"docs": "echo 'Generating documentation...' && find src -name '*.ts' -exec echo 'Processing: {}' \\;",
|
||||
"deploy": "echo 'Deploying application...' && bun run build && echo 'Deployment completed successfully'",
|
||||
"db": "bun drizzle-kit"
|
||||
},
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"tfcode": "./bin/tfcode"
|
||||
"tfcode": "./bin/tfcode.js"
|
||||
},
|
||||
"randomField": "this-is-a-random-value-12345",
|
||||
"exports": {
|
||||
"./*": "./src/*.ts"
|
||||
},
|
||||
"imports": {
|
||||
"#db": {
|
||||
"bun": "./src/storage/db.bun.ts",
|
||||
"node": "./src/storage/db.node.ts",
|
||||
"default": "./src/storage/db.bun.ts"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.28.4",
|
||||
"@effect/language-service": "0.79.0",
|
||||
"@octokit/webhooks-types": "7.6.1",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"@types/babel__core": "7.20.5",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/cross-spawn": "6.0.6",
|
||||
"@types/mime-types": "3.0.1",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/turndown": "5.0.5",
|
||||
"@types/which": "3.0.4",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"drizzle-kit": "catalog:",
|
||||
"drizzle-orm": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vscode-languageserver-types": "3.17.5",
|
||||
"why-is-node-running": "3.2.2",
|
||||
"zod-to-json-schema": "3.24.5"
|
||||
"files": [
|
||||
"bin/",
|
||||
"scripts/"
|
||||
],
|
||||
"scripts": {
|
||||
"postinstall": "node scripts/postinstall.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "1.11.1",
|
||||
"@actions/github": "6.0.1",
|
||||
"@agentclientprotocol/sdk": "0.14.1",
|
||||
"@ai-sdk/amazon-bedrock": "3.0.82",
|
||||
"@ai-sdk/anthropic": "2.0.65",
|
||||
"@ai-sdk/azure": "2.0.91",
|
||||
"@ai-sdk/cerebras": "1.0.36",
|
||||
"@ai-sdk/cohere": "2.0.22",
|
||||
"@ai-sdk/deepinfra": "1.0.36",
|
||||
"@ai-sdk/gateway": "2.0.30",
|
||||
"@ai-sdk/google": "2.0.54",
|
||||
"@ai-sdk/google-vertex": "3.0.106",
|
||||
"@ai-sdk/groq": "2.0.34",
|
||||
"@ai-sdk/mistral": "2.0.27",
|
||||
"@ai-sdk/openai": "2.0.89",
|
||||
"@ai-sdk/openai-compatible": "1.0.32",
|
||||
"@ai-sdk/perplexity": "2.0.23",
|
||||
"@ai-sdk/provider": "2.0.1",
|
||||
"@ai-sdk/provider-utils": "3.0.21",
|
||||
"@ai-sdk/togetherai": "1.0.34",
|
||||
"@ai-sdk/vercel": "1.0.33",
|
||||
"@ai-sdk/xai": "2.0.51",
|
||||
"@aws-sdk/credential-providers": "3.993.0",
|
||||
"@clack/prompts": "1.0.0-alpha.1",
|
||||
"@effect/platform-node": "catalog:",
|
||||
"@hono/standard-validator": "0.1.5",
|
||||
"@hono/zod-validator": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "1.25.2",
|
||||
"@octokit/graphql": "9.0.2",
|
||||
"@octokit/rest": "catalog:",
|
||||
"@openauthjs/openauth": "catalog:",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "1.5.4",
|
||||
"@opentui/core": "0.1.90",
|
||||
"@opentui/solid": "0.1.90",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
"@solid-primitives/scheduled": "1.5.2",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"ai": "catalog:",
|
||||
"ai-gateway-provider": "2.3.1",
|
||||
"bonjour-service": "1.3.0",
|
||||
"bun-pty": "0.4.8",
|
||||
"chokidar": "4.0.3",
|
||||
"clipboardy": "4.0.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"decimal.js": "10.5.0",
|
||||
"diff": "catalog:",
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "5.2.2",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"hono": "catalog:",
|
||||
"hono-openapi": "catalog:",
|
||||
"ignore": "7.0.5",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"mime-types": "3.0.2",
|
||||
"minimatch": "10.0.3",
|
||||
"open": "10.1.2",
|
||||
"opencode-gitlab-auth": "2.0.0",
|
||||
"opentui-spinner": "0.0.6",
|
||||
"partial-json": "0.1.7",
|
||||
"remeda": "catalog:",
|
||||
"semver": "^7.6.3",
|
||||
"solid-js": "catalog:",
|
||||
"strip-ansi": "7.1.2",
|
||||
"tree-sitter-bash": "0.25.0",
|
||||
"turndown": "7.2.0",
|
||||
"ulid": "catalog:",
|
||||
"vscode-jsonrpc": "8.2.1",
|
||||
"web-tree-sitter": "0.25.10",
|
||||
"which": "6.0.1",
|
||||
"xdg-basedir": "5.1.0",
|
||||
"yargs": "18.0.0",
|
||||
"zod": "catalog:",
|
||||
"zod-to-json-schema": "3.24.5"
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"overrides": {
|
||||
"drizzle-orm": "catalog:"
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"homepage": "https://toothfairyai.com/developers/tfcode",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ToothFairyAI/tfcode.git"
|
||||
}
|
||||
}
|
||||
|
||||
66
packages/tfcode/scripts/quickstart.cjs
Normal file
66
packages/tfcode/scripts/quickstart.cjs
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
console.log(`
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
tfcode - Quick Start Guide
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Welcome to tfcode! Follow these steps to get started:
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ STEP 1: Set Your Credentials │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ export TF_WORKSPACE_ID="your-workspace-id" │
|
||||
│ export TF_API_KEY="your-api-key" │
|
||||
│ export TF_REGION="au" │
|
||||
│ │
|
||||
│ Regions: au (Australia), eu (Europe), us (United States) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ STEP 2: Validate Connection │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ tfcode validate │
|
||||
│ │
|
||||
│ This checks your credentials are correct. │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ STEP 3: Sync Your Tools │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ tfcode sync │
|
||||
│ │
|
||||
│ This downloads your tools from ToothFairyAI. │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ STEP 4: Start Coding! │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ tfcode │
|
||||
│ │
|
||||
│ Start the AI coding assistant. │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Useful Commands:
|
||||
|
||||
tfcode validate Test your credentials
|
||||
tfcode sync Sync tools from workspace
|
||||
tfcode tools list Show all your tools
|
||||
tfcode Start coding assistant
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Need help? https://toothfairyai.com/developers/tfcode
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
`);
|
||||
53
packages/tfcode/src/cli/cmd/quickstart.ts
Normal file
53
packages/tfcode/src/cli/cmd/quickstart.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { cmd } from "@/cli/cmd/cmd"
|
||||
import { UI } from "@/cli/ui"
|
||||
|
||||
const QuickstartCommand = cmd({
|
||||
command: "quickstart",
|
||||
describe: "show quick start guide",
|
||||
handler: () => {
|
||||
UI.println("")
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + " tfcode - Quick Start Guide" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
UI.println("Welcome to tfcode! Follow these steps to get started:")
|
||||
UI.println("")
|
||||
|
||||
UI.println(UI.Style.TEXT_INFO_BOLD + "STEP 1: Set Your Credentials" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " export TF_WORKSPACE_ID=\"your-workspace-id\"" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " export TF_API_KEY=\"your-api-key\"" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " export TF_REGION=\"au\"" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " Regions: au, eu, us" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
|
||||
UI.println(UI.Style.TEXT_INFO_BOLD + "STEP 2: Validate Connection" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " tfcode validate" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
|
||||
UI.println(UI.Style.TEXT_INFO_BOLD + "STEP 3: Sync Your Tools" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " tfcode sync" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
|
||||
UI.println(UI.Style.TEXT_INFO_BOLD + "STEP 4: Start Coding!" + UI.Style.TEXT_NORMAL)
|
||||
UI.println(UI.Style.TEXT_DIM + " tfcode" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
UI.println(" Useful Commands:")
|
||||
UI.println("")
|
||||
UI.println(" tfcode validate Test your credentials")
|
||||
UI.println(" tfcode sync Sync tools from workspace")
|
||||
UI.println(" tfcode tools list Show all your tools")
|
||||
UI.println(" tfcode Start coding assistant")
|
||||
UI.println("")
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
UI.println(" Need help? https://toothfairyai.com/developers/tfcode")
|
||||
UI.println("")
|
||||
UI.println(UI.Style.TEXT_HIGHLIGHT_BOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + UI.Style.TEXT_NORMAL)
|
||||
UI.println("")
|
||||
},
|
||||
})
|
||||
|
||||
export { QuickstartCommand }
|
||||
@ -31,6 +31,7 @@ import { PrCommand } from "./cli/cmd/pr"
|
||||
import { SessionCommand } from "./cli/cmd/session"
|
||||
import { DbCommand } from "./cli/cmd/db"
|
||||
import { ValidateCommand, SyncCommand, ToolsMainCommand } from "./cli/cmd/tools"
|
||||
import { QuickstartCommand } from "./cli/cmd/quickstart"
|
||||
import path from "path"
|
||||
import { Global } from "./global"
|
||||
import { JsonMigration } from "./storage/json-migration"
|
||||
@ -149,6 +150,7 @@ let cli = yargs(hideBin(process.argv))
|
||||
.command(ValidateCommand)
|
||||
.command(SyncCommand)
|
||||
.command(ToolsMainCommand)
|
||||
.command(QuickstartCommand)
|
||||
|
||||
if (Installation.isLocal()) {
|
||||
cli = cli.command(WorkspaceServeCommand)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user