mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-29 21:33:54 +00:00
feat: tfcode
This commit is contained in:
parent
2ae12f8d6b
commit
3fe808d64c
90
PROGRESS.md
Normal file
90
PROGRESS.md
Normal file
@ -0,0 +1,90 @@
|
||||
# tfcode Progress Summary
|
||||
|
||||
## Goal
|
||||
|
||||
Build and deploy **tfcode** - ToothFairyAI's official AI coding agent, a fork of opencode.
|
||||
|
||||
## Completed Tasks
|
||||
|
||||
1. ✅ Implemented ToothFairyAI branding (logo, colors, strings)
|
||||
2. ✅ Created ToothFairyAI provider with dynamic model fetching
|
||||
3. ✅ Synced tools/agents/skills from ToothFairyAI workspace
|
||||
4. ✅ Filtered models to only `deploymentType: "serverless"`
|
||||
5. ✅ Implemented the `/predictions` endpoint for ToothFairyAI provider
|
||||
6. ✅ Added `tfcode setup` command to persist credentials
|
||||
7. ✅ Fixed npm installation flow (v1.0.4)
|
||||
- Binary now included in main npm package
|
||||
- Postinstall script checks if binary exists before downloading
|
||||
- ESM-compatible module resolution for npm fallback
|
||||
- Wrapper script fixed to look for binary in correct location
|
||||
|
||||
## Current Status
|
||||
|
||||
**Working**: npm installation flow is now fully functional. Users can install via:
|
||||
|
||||
```bash
|
||||
npm install @toothfairyai/tfcode
|
||||
```
|
||||
|
||||
The binary is included in the main package, making installation instant without needing to download from Gitea or copy from optionalDependencies.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Build all platform binaries (12 targets: linux/darwin/windows × arm64/x64 × baseline/musl)
|
||||
2. Test on different platforms (currently only darwin-arm64 is tested)
|
||||
3. Create Gitea releases for backup download mechanism
|
||||
4. Consider making Gitea repo public for transparency
|
||||
|
||||
## Technical Details
|
||||
|
||||
### npm Package Structure
|
||||
|
||||
The published package includes:
|
||||
|
||||
- `bin/tfcode` - The actual binary (92MB)
|
||||
- `bin/tfcode.js` - Wrapper script that spawns the binary
|
||||
- `postinstall.mjs` - Installation script (checks for binary, downloads if missing, installs Python SDK)
|
||||
- `package.json` - Package metadata
|
||||
- `LICENSE` - MIT license
|
||||
|
||||
### Installation Flow
|
||||
|
||||
1. npm installs main package + optionalDependencies
|
||||
2. npm extracts files to `node_modules/@toothfairyai/tfcode/`
|
||||
3. postinstall runs:
|
||||
- Checks if binary already exists (✓ for darwin-arm64)
|
||||
- If not, tries to download from Gitea
|
||||
- If that fails, copies from optionalDependencies
|
||||
- Installs Python SDK for TF integration
|
||||
4. User can run `tfcode` command
|
||||
|
||||
### Key Fixes in v1.0.4
|
||||
|
||||
1. **Postinstall script**: Fixed duplicate variable declaration (`binaryName`)
|
||||
2. **Postinstall script**: Added early return if binary already exists
|
||||
3. **Postinstall script**: Fixed ESM module resolution (replaced `require.resolve` with `import.meta.resolve`)
|
||||
4. **Publish script**: Copy current platform binary to main package
|
||||
5. **Wrapper script**: Fixed binary path (removed extra `bin/` directory)
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Fresh installation test
|
||||
rm -rf /tmp/tfcode-test && mkdir /tmp/tfcode-test
|
||||
cd /tmp/tfcode-test && npm init -y
|
||||
npm install @toothfairyai/tfcode
|
||||
node_modules/.bin/tfcode --version # Should output: 1.0.4
|
||||
```
|
||||
|
||||
## Version History
|
||||
|
||||
- **1.0.4**: Fixed npm installation flow, binary included in main package
|
||||
- **1.0.3**: Initial npm publication (broken installation)
|
||||
- **1.0.2**: Earlier testing versions
|
||||
- **1.0.0**: Initial release
|
||||
|
||||
## Credentials (Testing Only)
|
||||
|
||||
- workspace_id: `6586b7e6-683e-4ee6-a6cf-24c19729b5ff`
|
||||
- api_key: `EWZooLROIS57EVW3BKGu7Pv6LNe4D6m4gkDjukx3`
|
||||
- region: `dev`
|
||||
2
bun.lock
2
bun.lock
@ -381,7 +381,7 @@
|
||||
},
|
||||
"packages/tfcode": {
|
||||
"name": "tfcode",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.5",
|
||||
"bin": {
|
||||
"tfcode": "./bin/tfcode",
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.5",
|
||||
"name": "tfcode",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@ -4,6 +4,10 @@ import fs from "fs"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { spawnSync } from "child_process"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const GITEA_HOST = process.env.TFCODE_GITEA_HOST || "gitea.toothfairyai.com"
|
||||
const GITEA_REPO = process.env.TFCODE_GITEA_REPO || "ToothFairyAI/tf_code"
|
||||
@ -82,7 +86,17 @@ async function downloadBinary() {
|
||||
const { platform, arch, needsBaseline, abi } = detectPlatform()
|
||||
const version = await getVersion()
|
||||
|
||||
// Build filename
|
||||
// Check if binary already exists (included in npm package)
|
||||
const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
|
||||
const binDir = path.join(__dirname, "bin")
|
||||
const existingBinary = path.join(binDir, binaryName)
|
||||
|
||||
if (fs.existsSync(existingBinary)) {
|
||||
console.log(`✓ Binary already exists at ${existingBinary}`)
|
||||
return
|
||||
}
|
||||
|
||||
// Build filename for download
|
||||
let target = `tfcode-${platform}-${arch}`
|
||||
if (needsBaseline) target += "-baseline"
|
||||
if (abi) target += `-${abi}`
|
||||
@ -94,7 +108,6 @@ async function downloadBinary() {
|
||||
console.log(`Downloading tfcode v${version} for ${target}...`)
|
||||
|
||||
// Download
|
||||
const binDir = path.join(__dirname, "bin")
|
||||
if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true })
|
||||
|
||||
const tmpDir = path.join(os.tmpdir(), `tfcode-install-${process.pid}`)
|
||||
@ -110,17 +123,42 @@ async function downloadBinary() {
|
||||
// Fallback to npm optionalDependencies
|
||||
try {
|
||||
const pkgName = `@toothfairyai/${target}`
|
||||
const pkgPath = require.resolve(`${pkgName}/package.json`)
|
||||
const pkgDir = path.dirname(pkgPath)
|
||||
|
||||
// ESM-compatible module resolution
|
||||
let pkgDir
|
||||
try {
|
||||
const pkgUrl = import.meta.resolve(`${pkgName}/package.json`)
|
||||
const pkgPath = fileURLToPath(pkgUrl)
|
||||
pkgDir = path.dirname(pkgPath)
|
||||
} catch (e) {
|
||||
console.error(`Could not resolve ${pkgName}:`, e.message)
|
||||
throw e
|
||||
}
|
||||
|
||||
const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
|
||||
const binaryPath = path.join(pkgDir, "bin", binaryName)
|
||||
|
||||
console.log(`Looking for binary at: ${binaryPath}`)
|
||||
|
||||
if (fs.existsSync(binaryPath)) {
|
||||
console.log(`Found binary at npm package location`)
|
||||
setupBinary(binaryPath, platform)
|
||||
return
|
||||
} else {
|
||||
console.error(`Binary not found at ${binaryPath}`)
|
||||
}
|
||||
} catch {}
|
||||
} catch (e) {
|
||||
console.error("npm package fallback failed:", e.message)
|
||||
}
|
||||
|
||||
console.error("")
|
||||
console.error("Installation failed. The binary could not be downloaded or found.")
|
||||
console.error("")
|
||||
console.error("Possible solutions:")
|
||||
console.error(" 1. If this is a private installation, set TFCODE_GITEA_HOST to an accessible host")
|
||||
console.error(" 2. Manually download the binary and place it in the bin/ directory")
|
||||
console.error(" 3. Contact ToothFairyAI support for assistance")
|
||||
console.error("")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@ -133,7 +171,6 @@ async function downloadBinary() {
|
||||
}
|
||||
|
||||
// Move binary
|
||||
const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
|
||||
const extractedBinary = path.join(tmpDir, "tfcode")
|
||||
const targetBinary = path.join(binDir, binaryName)
|
||||
|
||||
@ -174,6 +211,9 @@ async function main() {
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||
console.log("")
|
||||
|
||||
// Download and setup binary
|
||||
await downloadBinary()
|
||||
|
||||
// Check for Python (needed for TF integration)
|
||||
try {
|
||||
const result = spawnSync("python3", ["--version"], { encoding: "utf8" })
|
||||
|
||||
@ -109,15 +109,29 @@ async function createMainPackage() {
|
||||
await Bun.file(`./dist/tfcode/postinstall.mjs`).write(await Bun.file("./script/postinstall-tfcode.mjs").text())
|
||||
await Bun.file(`./dist/tfcode/LICENSE`).write(await Bun.file("../../LICENSE").text())
|
||||
|
||||
// Copy the current platform's binary to the main package
|
||||
// This makes installation faster (no need to download or copy from optionalDependencies)
|
||||
const currentPlatform = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : "windows"
|
||||
const currentArch = process.arch
|
||||
const platformBinDir = `./dist/tfcode-${currentPlatform}-${currentArch}/bin`
|
||||
const binaryName = process.platform === "win32" ? "tfcode.exe" : "tfcode"
|
||||
|
||||
if (fs.existsSync(`${platformBinDir}/${binaryName}`)) {
|
||||
console.log(`Including ${currentPlatform}-${currentArch} binary in main package`)
|
||||
await $`cp ${platformBinDir}/${binaryName} ./dist/tfcode/bin/`
|
||||
} else {
|
||||
console.log(`Warning: No binary found for current platform (${currentPlatform}-${currentArch})`)
|
||||
console.log(`The postinstall script will need to download or copy from optionalDependencies`)
|
||||
}
|
||||
|
||||
// Create a simple wrapper script that runs the installed binary
|
||||
const wrapper = `#!/usr/bin/env node
|
||||
const { spawn } = require('child_process')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
const binDir = path.join(__dirname, 'bin')
|
||||
const binary = process.platform === 'win32' ? 'tfcode.exe' : 'tfcode'
|
||||
const binaryPath = path.join(binDir, binary)
|
||||
const binaryPath = path.join(__dirname, binary)
|
||||
|
||||
if (!fs.existsSync(binaryPath)) {
|
||||
console.error('tfcode binary not found. Run: npm install @toothfairyai/tfcode')
|
||||
|
||||
@ -348,6 +348,9 @@ export namespace ProviderTransform {
|
||||
)
|
||||
return {}
|
||||
|
||||
// ToothFairyAI doesn't support thinking/reasoning parameters yet
|
||||
if (model.api.npm === "@toothfairyai/sdk") return {}
|
||||
|
||||
// see: https://docs.x.ai/docs/guides/reasoning#control-how-hard-the-model-thinks
|
||||
if (id.includes("grok") && id.includes("grok-3-mini")) {
|
||||
if (model.api.npm === "@openrouter/ai-sdk-provider") {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user