freebuff 0.1.4 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/launcher.js +73 -9
  3. package/package.json +9 -9
package/README.md CHANGED
@@ -33,7 +33,7 @@ and keep the extracted `freebuff` binary and `tree-sitter.wasm` together.
33
33
 
34
34
  ## Why Freebuff?
35
35
 
36
- **Choice of leading models** — The regular CLI picker includes GLM 5.3 Flash, DeepSeek, GPT-6 Luna, MiMo 2.6 Flash, MiMo 2.6 Pro, Solar Mini 4, Solar Pro 4, Space Bunny Alpha, Gemini 3.8 Flash, and Muse Spark 1.2, with GLM 5.3 Flash selected by default.
36
+ **Choice of leading models** — The regular CLI picker includes GLM 5.3 Flash, DeepSeek, GPT-6 Luna, MiMo 2.6 Flash, MiMo 2.6 Pro, Solar Mini 4, Solar Pro 4, Space Bunny Alpha, Gemini 3.8 Flash, and Muse Spark 1.3, with GLM 5.3 Flash selected by default.
37
37
 
38
38
  **Fast** — 5–10× speed up. 3–5× tokens per second compared to Claude, plus context gathering in seconds.
39
39
 
@@ -43,7 +43,7 @@ and keep the extracted `freebuff` binary and `tree-sitter.wasm` together.
43
43
 
44
44
  **How can it be free?** Freebuff is supported by text ads.
45
45
 
46
- **What models do you use?** In full mode, the regular picker includes GLM 5.3 Flash, DeepSeek V4.1 Flash, GPT-6 Luna, MiMo 2.6 Flash, MiMo 2.6 Pro, Solar Mini 4, Solar Pro 4, Space Bunny Alpha, Gemini 3.8 Flash, and Muse Spark 1.2. Space Bunny Alpha is a beta stealth model from an anonymous provider that retains prompts. Gemini 3.8 Flash requires a paid plan: without one it is listed but locked, and selecting it opens the plans page. GPT-6 Luna and MiMo 2.6 Pro are open to every full-access account. Muse Spark 1.2 has a 1M-token context and is rate limited across all users, so at busy times it queues and then answers on DeepSeek V4 Flash instead of leaving you waiting. GLM 5.3 Flash is the CLI default, and it costs no session at all, so the default is always available no matter how much you have used. Limited mode uses GLM 5.3 Flash, DeepSeek V4.1 Flash, MiMo 2.6 Flash, Solar Mini 4, and Solar Pro 4. Most models draw on your normal daily sessions rather than a separate limit; GLM 5.3 Flash, DeepSeek V4.1 Flash, MiMo 2.6 Flash, Solar Mini 4, and Solar Pro 4 are unmetered at full access. Models may still serve from a quantized (Q8_0) build.
46
+ **What models do you use?** In full mode, the regular picker includes GLM 5.3 Flash, DeepSeek V4.1 Flash, GPT-6 Luna, MiMo 2.6 Flash, MiMo 2.6 Pro, Solar Mini 4, Solar Pro 4, Space Bunny Alpha, Gemini 3.8 Flash, and Muse Spark 1.3. Space Bunny Alpha is a beta stealth model from an anonymous provider that retains prompts. Gemini 3.8 Flash and Muse Spark 1.3 require a paid plan: without one they are listed but locked, and selecting one opens the plans page. GPT-6 Luna and MiMo 2.6 Pro are open to every full-access account. Muse Spark 1.3 has a 1M-token context and is rate limited across all users, so at busy times it queues and then answers on DeepSeek V4 Flash instead of leaving you waiting. GLM 5.3 Flash is the CLI default, and it costs no session at all, so the default is always available no matter how much you have used. Limited mode uses GLM 5.3 Flash, DeepSeek V4.1 Flash, MiMo 2.6 Flash, Solar Mini 4, and Solar Pro 4. Most models draw on your normal daily sessions rather than a separate limit; GLM 5.3 Flash, DeepSeek V4.1 Flash, MiMo 2.6 Flash, Solar Mini 4, and Solar Pro 4 are unmetered at full access. Models may still serve from a quantized (Q8_0) build.
47
47
 
48
48
  **Which countries is Freebuff available in?** All countries. Freebuff runs in "full" mode in the US, Canada, UK, EU, and other select countries, and in "limited" mode everywhere else (or while using a VPN). See [freebuff.com](https://freebuff.com) for the full list.
49
49
 
package/launcher.js CHANGED
@@ -35,15 +35,51 @@ const PLATFORM_TARGET_KEYS = [
35
35
 
36
36
  const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '[::1]'])
37
37
 
38
+ /**
39
+ * Registrable domains that serve release downloads. An https override must
40
+ * name one of these or a subdomain of one.
41
+ */
42
+ const RELEASE_ORIGIN_DOMAINS = ['codebuff.com', 'freebuff.com']
43
+
44
+ function isReleaseOriginHost(hostname) {
45
+ const host = hostname.toLowerCase()
46
+ return RELEASE_ORIGIN_DOMAINS.some(
47
+ (domain) => host === domain || host.endsWith(`.${domain}`),
48
+ )
49
+ }
50
+
51
+ /**
52
+ * A release version the launcher will put into a download URL or a file
53
+ * name: strict `MAJOR.MINOR.PATCH` with an optional dot-separated
54
+ * alphanumeric prerelease, and nothing else — no build metadata, no
55
+ * leading `v`, no whitespace, `/`, `..`, `%` or `?`. The version reaches
56
+ * `/api/releases/download/<version>/<file>` and the partial-archive path
57
+ * from the npm registry document or the local metadata file, and neither
58
+ * is a place that should be able to rewrite a URL path or escape a
59
+ * directory.
60
+ */
61
+ const STRICT_RELEASE_VERSION =
62
+ /^(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})(?:-(?:0|[1-9]\d{0,8}|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d{0,8}|\d*[A-Za-z-][0-9A-Za-z-]*))*)?$/
63
+
64
+ function isStrictReleaseVersion(version) {
65
+ return (
66
+ typeof version === 'string' &&
67
+ version.length <= 64 &&
68
+ STRICT_RELEASE_VERSION.test(version)
69
+ )
70
+ }
71
+
38
72
  /**
39
73
  * Decide where release archives are downloaded from.
40
74
  *
41
75
  * NEXT_PUBLIC_CODEBUFF_APP_URL is read at runtime, so anyone able to set an
42
- * environment variable could point the launcher at a plain-http origin and
43
- * let a network attacker substitute the archive. The override is honoured
44
- * only over https, or over http on a loopback host (local release servers in
45
- * development and tests). Anything else is ignored with a warning and the
46
- * default origin is used.
76
+ * environment variable could point the launcher at another origin. The
77
+ * archive's sha256 comes from npm, not from that origin, so a substituted
78
+ * archive is refused either way; the origin is still held to the hosts that
79
+ * actually serve releases. The override is honoured only over https to a
80
+ * codebuff.com / freebuff.com host, or over http/https on a loopback host
81
+ * (local release servers in development and tests). Anything else is
82
+ * ignored with a warning and the default origin is used.
47
83
  */
48
84
  function resolveDownloadOrigin(configuredOrigin, { warn = () => {} } = {}) {
49
85
  if (typeof configuredOrigin !== 'string' || configuredOrigin.trim() === '') {
@@ -62,15 +98,25 @@ function resolveDownloadOrigin(configuredOrigin, { warn = () => {} } = {}) {
62
98
  }
63
99
 
64
100
  const isLocal = LOCAL_HOSTNAMES.has(parsed.hostname.toLowerCase())
101
+ const isHttp = parsed.protocol === 'http:' || parsed.protocol === 'https:'
102
+ // Only an origin: credentials or a query would ride along on every request.
103
+ const isBareOrigin =
104
+ !parsed.username && !parsed.password && !parsed.search && !parsed.hash
105
+ if (isHttp && isLocal && isBareOrigin) {
106
+ return trimmed
107
+ }
65
108
  if (
66
- parsed.protocol === 'https:' ||
67
- (parsed.protocol === 'http:' && isLocal)
109
+ parsed.protocol === 'https:' &&
110
+ isReleaseOriginHost(parsed.hostname) &&
111
+ isBareOrigin
68
112
  ) {
69
113
  return trimmed
70
114
  }
71
115
 
72
116
  warn(
73
- `Ignoring NEXT_PUBLIC_CODEBUFF_APP_URL=${configuredOrigin}: release downloads must use https (http is allowed only for localhost). Downloading from ${DEFAULT_DOWNLOAD_ORIGIN}.`,
117
+ parsed.protocol === 'https:'
118
+ ? `Ignoring NEXT_PUBLIC_CODEBUFF_APP_URL=${parsed.protocol}//${parsed.host}: release downloads come only from codebuff.com or freebuff.com (or localhost). Downloading from ${DEFAULT_DOWNLOAD_ORIGIN}.`
119
+ : `Ignoring NEXT_PUBLIC_CODEBUFF_APP_URL=${parsed.protocol}//${parsed.host}: release downloads must use https (http is allowed only for localhost). Downloading from ${DEFAULT_DOWNLOAD_ORIGIN}.`,
74
120
  )
75
121
  return DEFAULT_DOWNLOAD_ORIGIN
76
122
  }
@@ -747,7 +793,7 @@ function createLauncher(productConfig) {
747
793
 
748
794
  const body = await streamToString(res)
749
795
  const packageData = JSON.parse(body)
750
- if (typeof packageData.version !== 'string' || !packageData.version) {
796
+ if (!isStrictReleaseVersion(packageData.version)) {
751
797
  return null
752
798
  }
753
799
 
@@ -936,6 +982,9 @@ function createLauncher(productConfig) {
936
982
  }
937
983
 
938
984
  function getPartialArchivePath(version, targetKey) {
985
+ if (!isStrictReleaseVersion(version)) {
986
+ throw new Error(`Invalid release version for an archive path: ${version}`)
987
+ }
939
988
  return path.join(
940
989
  CONFIG.configDir,
941
990
  `.${packageName}-${version}-${targetKey}.tar.gz.part`,
@@ -1168,6 +1217,21 @@ function createLauncher(productConfig) {
1168
1217
  ) {
1169
1218
  const fileName = PLATFORM_TARGETS[targetKey]
1170
1219
 
1220
+ // Before anything is built from it: the version becomes a URL path
1221
+ // segment and part of a file name below.
1222
+ if (!isStrictReleaseVersion(version)) {
1223
+ const error = new Error(
1224
+ `Refusing to download ${packageName}: ${JSON.stringify(String(version)).slice(0, 80)} is not a release version.`,
1225
+ )
1226
+ error.code = 'EBADVERSION'
1227
+ error.retryable = false
1228
+ trackUpdateFailed(error.message, 'invalid', {
1229
+ stage: 'version_check',
1230
+ target: targetKey,
1231
+ })
1232
+ throw error
1233
+ }
1234
+
1171
1235
  if (!fileName) {
1172
1236
  const error = new Error(
1173
1237
  `Unsupported platform: ${process.platform} ${process.arch}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freebuff",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "The world's strongest free coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -41,13 +41,13 @@
41
41
  "provenance": false
42
42
  },
43
43
  "binaryChecksums": {
44
- "linux-x64": "02645c1354b0f72ae3ae6c138fd34b2f74afdf4552f17008713ff2f00f4af1ef",
45
- "linux-x64-baseline": "5b758c46c3fb289fbd8ae04ce42c304a91e87a20ff5eab338e17cbc03e937831",
46
- "linux-arm64": "9f40b2b4d76cacaa1f0d598cdfe3a5534e8f3e787803c604319dee569e08d923",
47
- "darwin-x64": "ef2e71cd81b3166d6449e04221cc547a499bef90ba07c5087783650f63c72854",
48
- "darwin-x64-baseline": "0d860e9b5cfb178f989fc5c23695d1c5f2328175683f2046775d59df77259f9c",
49
- "darwin-arm64": "5c40f26c55f11b3395eae3d509ebbed9ffceaf1b06b929cfc90a4860cf64ac35",
50
- "win32-x64": "826dd49fd9b412aaa87f023901a16872813832b84cda0bad0d97f14eb5ab63eb",
51
- "win32-x64-baseline": "588cd19c2cdbfd9d323e1b1b737ae9e802404231293a2208a66494fc8ea93e5a"
44
+ "linux-x64": "2c0f5b23b563830cbfb99f4fcc57e2657524f77159f2a8088b67f8279f7db3f9",
45
+ "linux-x64-baseline": "194b9ea6667ef7503412f4edca2d0e256cf8dc592e658bc147a46105f15aa44e",
46
+ "linux-arm64": "7609d2cad1055d0df2c9d73b95a10c98439eee77a78d739084af408c33d8e6b4",
47
+ "darwin-x64": "a1c7aa7fc361d1f5095d5c50dab409101a411b14951933c55b8f03d777600f5f",
48
+ "darwin-x64-baseline": "165d9077f04af2d30063d06445f0ddc2aa1feafadb034140d2f66435df4ae1c6",
49
+ "darwin-arm64": "2e99d58f7805c5ff8975e94ee6c31d23bfd2d0dd1094806659a1fa6c4c9c68e0",
50
+ "win32-x64": "ba239c2aae754927e11655cbc534c6c5dcfc3c41e6f8a8e9c4ede256acf23fc3",
51
+ "win32-x64-baseline": "cb1d911d296d481ffb1165bda1999c6e5633bb0d183c584fc121da2db7cf8abc"
52
52
  }
53
53
  }