@toothfairyai/tfcode 2.6.9 → 2.7.1

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 (2) hide show
  1. package/package.json +13 -13
  2. package/postinstall.mjs +46 -188
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toothfairyai/tfcode",
3
- "version": "2.6.9",
3
+ "version": "2.7.1",
4
4
  "bin": {
5
5
  "tfcode": "./bin/tfcode.js"
6
6
  },
@@ -9,18 +9,18 @@
9
9
  },
10
10
  "license": "MIT",
11
11
  "optionalDependencies": {
12
- "@toothfairyai/tfcode-linux-arm64": "2.6.9",
13
- "@toothfairyai/tfcode-windows-x64": "2.6.9",
14
- "@toothfairyai/tfcode-linux-x64-baseline-musl": "2.6.9",
15
- "@toothfairyai/tfcode-darwin-x64-baseline": "2.6.9",
16
- "@toothfairyai/tfcode-linux-x64-musl": "2.6.9",
17
- "@toothfairyai/tfcode-windows-x64-baseline": "2.6.9",
18
- "@toothfairyai/tfcode-linux-arm64-musl": "2.6.9",
19
- "@toothfairyai/tfcode-windows-arm64": "2.6.9",
20
- "@toothfairyai/tfcode-linux-x64": "2.6.9",
21
- "@toothfairyai/tfcode-darwin-x64": "2.6.9",
22
- "@toothfairyai/tfcode-linux-x64-baseline": "2.6.9",
23
- "@toothfairyai/tfcode-darwin-arm64": "2.6.9"
12
+ "@toothfairyai/tfcode-linux-arm64": "2.7.1",
13
+ "@toothfairyai/tfcode-windows-x64": "2.7.1",
14
+ "@toothfairyai/tfcode-linux-x64-baseline-musl": "2.7.1",
15
+ "@toothfairyai/tfcode-darwin-x64-baseline": "2.7.1",
16
+ "@toothfairyai/tfcode-linux-x64-musl": "2.7.1",
17
+ "@toothfairyai/tfcode-windows-x64-baseline": "2.7.1",
18
+ "@toothfairyai/tfcode-linux-arm64-musl": "2.7.1",
19
+ "@toothfairyai/tfcode-windows-arm64": "2.7.1",
20
+ "@toothfairyai/tfcode-linux-x64": "2.7.1",
21
+ "@toothfairyai/tfcode-darwin-x64": "2.7.1",
22
+ "@toothfairyai/tfcode-linux-x64-baseline": "2.7.1",
23
+ "@toothfairyai/tfcode-darwin-arm64": "2.7.1"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=18"
package/postinstall.mjs CHANGED
@@ -9,9 +9,6 @@ import { fileURLToPath } from "url"
9
9
  const __filename = fileURLToPath(import.meta.url)
10
10
  const __dirname = path.dirname(__filename)
11
11
 
12
- const GITEA_HOST = process.env.TFCODE_GITEA_HOST || "gitea.toothfairyai.com"
13
- const GITEA_REPO = process.env.TFCODE_GITEA_REPO || "ToothFairyAI/tf_code"
14
-
15
12
  function detectPlatform() {
16
13
  let platform
17
14
  switch (os.platform()) {
@@ -72,180 +69,12 @@ function detectPlatform() {
72
69
  return { platform, arch, needsBaseline, abi }
73
70
  }
74
71
 
75
- async function getVersion() {
76
- try {
77
- const res = await fetch(`https://${GITEA_HOST}/api/v1/repos/${GITEA_REPO}/releases/latest`)
78
- const data = await res.json()
79
- return data.tag_name?.replace(/^v/, "") || "1.0.0"
80
- } catch {
81
- return "1.0.0"
82
- }
83
- }
84
-
85
- // Detect the machine architecture of an existing binary. Returns "arm64",
86
- // "x64", or null when it can't be determined (null => keep existing binary).
87
- function detectBinaryMachineArch(binaryPath, platform) {
88
- try {
89
- if (platform === "win32") {
90
- const buf = fs.readFileSync(binaryPath)
91
- if (buf.length < 0x40) return null
92
- const pe = buf.readUInt32LE(0x3c)
93
- if (pe + 6 > buf.length) return null
94
- const machine = buf.readUInt16LE(pe + 4)
95
- if (machine === 0x8664) return "x64"
96
- if (machine === 0xaa64) return "arm64"
97
- return null
98
- }
99
- const out = spawnSync("file", [binaryPath], { encoding: "utf8" }).stdout || ""
100
- if (/arm64|aarch64/i.test(out)) return "arm64"
101
- if (/x86-64|x86_64/i.test(out)) return "x64"
102
- return null
103
- } catch {
104
- return null
105
- }
106
- }
107
-
108
- // A missing/unparseable binary is treated as a match so installs never break
109
- // when detection isn't possible; a real mismatch forces a re-download.
110
- function binaryArchMatches(binaryPath, expectedArch, platform) {
111
- const actual = detectBinaryMachineArch(binaryPath, platform)
112
- if (!actual) return true
113
- return actual === expectedArch
114
- }
115
-
116
- async function downloadBinary() {
72
+ function targetName() {
117
73
  const { platform, arch, needsBaseline, abi } = detectPlatform()
118
- const version = await getVersion()
119
-
120
- // Check if binary already exists (included in npm package)
121
- const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
122
- const binDir = path.join(__dirname, "bin")
123
- const existingBinary = path.join(binDir, binaryName)
124
-
125
- if (fs.existsSync(existingBinary) && binaryArchMatches(existingBinary, arch, platform)) {
126
- console.log(`✓ Binary already exists at ${existingBinary}`)
127
- // Still need to copy app dir from platform package if missing
128
- const targetAppDir = path.join(binDir, "app")
129
- if (!fs.existsSync(path.join(targetAppDir, "dist", "index.html"))) {
130
- let target = `tfcode-${platform}-${arch}`
131
- if (needsBaseline) target += "-baseline"
132
- if (abi) target += `-${abi}`
133
- const pkgName = `@toothfairyai/${target}`
134
- try {
135
- const pkgUrl = import.meta.resolve(`${pkgName}/package.json`)
136
- const pkgDir = path.dirname(fileURLToPath(pkgUrl))
137
- const srcAppDir = path.join(pkgDir, "bin", "app")
138
- if (fs.existsSync(path.join(srcAppDir, "dist", "index.html"))) {
139
- fs.cpSync(srcAppDir, targetAppDir, { recursive: true })
140
- console.log("✓ Web app copied from platform package")
141
- }
142
- copyComputerAssets(path.join(pkgDir, "bin"), binDir)
143
- } catch (e) {
144
- console.log(`! Could not copy web app: ${e.message}`)
145
- }
146
- }
147
- return
148
- }
149
-
150
- // Build filename for download
151
74
  let target = `tfcode-${platform}-${arch}`
152
75
  if (needsBaseline) target += "-baseline"
153
76
  if (abi) target += `-${abi}`
154
-
155
- const ext = platform === "linux" ? ".tar.gz" : ".zip"
156
- const filename = `${target}${ext}`
157
- const url = `https://${GITEA_HOST}/${GITEA_REPO}/releases/download/v${version}/${filename}`
158
-
159
- console.log(`Downloading tfcode v${version} for ${target}...`)
160
-
161
- // Download
162
- if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true })
163
-
164
- const tmpDir = path.join(os.tmpdir(), `tfcode-install-${process.pid}`)
165
- fs.mkdirSync(tmpDir, { recursive: true })
166
- const archivePath = path.join(tmpDir, filename)
167
-
168
- // Use curl to download
169
- const curlResult = spawnSync("curl", ["-fsSL", "-o", archivePath, url], { stdio: "inherit" })
170
- if (curlResult.status !== 0) {
171
- console.error(`Failed to download from ${url}`)
172
- console.error("Trying npm package fallback...")
173
-
174
- // Fallback to npm optionalDependencies
175
- try {
176
- const pkgName = `@toothfairyai/${target}`
177
-
178
- // ESM-compatible module resolution
179
- let pkgDir
180
- try {
181
- const pkgUrl = import.meta.resolve(`${pkgName}/package.json`)
182
- const pkgPath = fileURLToPath(pkgUrl)
183
- pkgDir = path.dirname(pkgPath)
184
- } catch (e) {
185
- console.error(`Could not resolve ${pkgName}:`, e.message)
186
- throw e
187
- }
188
-
189
- const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
190
- const binaryPath = path.join(pkgDir, "bin", binaryName)
191
-
192
- console.log(`Looking for binary at: ${binaryPath}`)
193
-
194
- if (fs.existsSync(binaryPath)) {
195
- console.log(`Found binary at npm package location`)
196
- setupBinary(binaryPath, platform)
197
- return
198
- } else {
199
- console.error(`Binary not found at ${binaryPath}`)
200
- }
201
- } catch (e) {
202
- console.error("npm package fallback failed:", e.message)
203
- }
204
-
205
- console.error("")
206
- console.error("Installation failed. The binary could not be downloaded or found.")
207
- console.error("")
208
- console.error("Possible solutions:")
209
- console.error(" 1. If this is a private installation, set TFCODE_GITEA_HOST to an accessible host")
210
- console.error(" 2. Manually download the binary and place it in the bin/ directory")
211
- console.error(" 3. Contact ToothFairyAI support for assistance")
212
- console.error("")
213
- process.exit(1)
214
- }
215
-
216
- // Extract
217
- console.log("Extracting...")
218
- if (platform === "linux") {
219
- spawnSync("tar", ["-xzf", archivePath, "-C", tmpDir], { stdio: "inherit" })
220
- } else {
221
- spawnSync("unzip", ["-q", archivePath, "-d", tmpDir], { stdio: "inherit" })
222
- }
223
-
224
- // Move binary
225
- const extractedBinary = path.join(tmpDir, "tfcode")
226
- const targetBinary = path.join(binDir, binaryName)
227
-
228
- if (fs.existsSync(extractedBinary)) {
229
- if (fs.existsSync(targetBinary)) fs.unlinkSync(targetBinary)
230
- fs.copyFileSync(extractedBinary, targetBinary)
231
- fs.chmodSync(targetBinary, 0o755)
232
- console.log(`Installed tfcode to ${targetBinary}`)
233
- }
234
-
235
- // Move app directory
236
- const extractedAppDir = path.join(tmpDir, "app")
237
- const targetAppDir = path.join(binDir, "app")
238
- if (fs.existsSync(path.join(extractedAppDir, "dist", "index.html"))) {
239
- if (fs.existsSync(targetAppDir)) fs.rmSync(targetAppDir, { recursive: true, force: true })
240
- fs.cpSync(extractedAppDir, targetAppDir, { recursive: true })
241
- console.log("Installed web app")
242
- }
243
-
244
- // Move bundled computer-use helpers (cliclick on macOS, if archived)
245
- copyComputerAssets(tmpDir, binDir)
246
-
247
- // Cleanup
248
- fs.rmSync(tmpDir, { recursive: true, force: true })
77
+ return target
249
78
  }
250
79
 
251
80
  // Copy bundled computer-use helper binaries (e.g. cliclick on macOS) from a
@@ -266,35 +95,64 @@ function copyComputerAssets(srcBinDir, dstBinDir) {
266
95
  console.log("✓ Computer-use helpers copied from platform package")
267
96
  }
268
97
 
269
- function setupBinary(sourcePath, platform) {
270
- const binDir = path.join(__dirname, "bin")
98
+ // The binary ships in the platform-specific optionalDependency
99
+ // (@toothfairyai/tfcode-<platform>-<arch>[-baseline][-musl]). Link it into
100
+ // this package's bin/ dir and copy the web app + computer-use helpers.
101
+ function setupFromPlatformPackage() {
102
+ const { platform } = detectPlatform()
103
+ const pkgName = `@toothfairyai/${targetName()}`
271
104
  const binaryName = platform === "windows" ? "tfcode.exe" : "tfcode"
272
- const targetBinary = path.join(binDir, binaryName)
105
+ const binDir = path.join(__dirname, "bin")
106
+
107
+ // ESM-compatible module resolution
108
+ let pkgDir
109
+ try {
110
+ const pkgUrl = import.meta.resolve(`${pkgName}/package.json`)
111
+ const pkgPath = fileURLToPath(pkgUrl)
112
+ pkgDir = path.dirname(pkgPath)
113
+ } catch (e) {
114
+ console.error(`Could not resolve ${pkgName}: ${e.message}`)
115
+ console.error("")
116
+ console.error("The platform package for your machine was not installed.")
117
+ console.error("")
118
+ console.error("Possible solutions:")
119
+ console.error(` 1. Install it explicitly: npm install ${pkgName}`)
120
+ console.error(" 2. Clear the npm cache and reinstall: npm cache clean --force && npm install @toothfairyai/tfcode")
121
+ console.error(" 3. Contact ToothFairyAI support for assistance")
122
+ console.error("")
123
+ process.exit(1)
124
+ }
125
+
126
+ const sourceBinary = path.join(pkgDir, "bin", binaryName)
127
+ if (!fs.existsSync(sourceBinary)) {
128
+ console.error(`Binary not found at ${sourceBinary}`)
129
+ process.exit(1)
130
+ }
273
131
 
132
+ // Link (or copy) the binary into bin/
274
133
  if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true })
134
+ const targetBinary = path.join(binDir, binaryName)
275
135
  if (fs.existsSync(targetBinary)) fs.unlinkSync(targetBinary)
276
-
277
- // Try hardlink, fall back to copy
278
136
  try {
279
- fs.linkSync(sourcePath, targetBinary)
137
+ fs.linkSync(sourceBinary, targetBinary)
280
138
  } catch {
281
- fs.copyFileSync(sourcePath, targetBinary)
139
+ fs.copyFileSync(sourceBinary, targetBinary)
282
140
  }
283
-
284
141
  fs.chmodSync(targetBinary, 0o755)
285
142
  console.log(`tfcode installed to ${targetBinary}`)
286
143
 
287
- // Also copy app dir from platform package
288
- const sourceDir = path.dirname(sourcePath)
289
- const srcAppDir = path.join(sourceDir, "app")
144
+ // Copy app dir
145
+ const srcAppDir = path.join(pkgDir, "bin", "app")
290
146
  const targetAppDir = path.join(binDir, "app")
291
147
  if (fs.existsSync(path.join(srcAppDir, "dist", "index.html"))) {
292
148
  if (fs.existsSync(targetAppDir)) fs.rmSync(targetAppDir, { recursive: true, force: true })
293
149
  fs.cpSync(srcAppDir, targetAppDir, { recursive: true })
294
150
  console.log("Web app copied from platform package")
151
+ } else {
152
+ console.log("! Web app not found in platform package")
295
153
  }
296
- // Also copy bundled computer-use helpers (cliclick on macOS) if present.
297
- copyComputerAssets(sourceDir, binDir)
154
+
155
+ copyComputerAssets(path.join(pkgDir, "bin"), binDir)
298
156
  }
299
157
 
300
158
  async function main() {
@@ -304,8 +162,8 @@ async function main() {
304
162
  console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
305
163
  console.log("")
306
164
 
307
- // Download and setup binary
308
- await downloadBinary()
165
+ // Setup binary from the npm platform package
166
+ setupFromPlatformPackage()
309
167
 
310
168
  // Check for Python (needed for TF integration)
311
169
  try {