@botconnector/bccli 0.5.2 → 0.5.3
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.
- package/bccli-bootstrap.cjs +61 -0
- package/branding.mjs +7 -1
- package/cli.mjs +0 -0
- package/core.mjs +5 -2
- package/package.json +7 -5
- package/session-settings.mjs +26 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
// This small launcher runs before importing the coding engine. npm's Windows
|
|
5
|
+
// shims use the system Node; on affected releases we may select a known-safe
|
|
6
|
+
// owner-installed Node without changing the system-wide PATH.
|
|
7
|
+
const { spawn, spawnSync } = require('node:child_process')
|
|
8
|
+
const { existsSync } = require('node:fs')
|
|
9
|
+
const { join, resolve } = require('node:path')
|
|
10
|
+
const { pathToFileURL } = require('node:url')
|
|
11
|
+
|
|
12
|
+
function unsafeWindowsNode(version, platform = process.platform) {
|
|
13
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(String(version))
|
|
14
|
+
if (!m) return true
|
|
15
|
+
const [major, minor, patch] = m.slice(1).map(Number)
|
|
16
|
+
return platform === 'win32' && major === 24 && (minor < 22 || (minor === 22 && patch < 1))
|
|
17
|
+
}
|
|
18
|
+
function safeRuntime(version) {
|
|
19
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(String(version))
|
|
20
|
+
if (!m) return false
|
|
21
|
+
const [major, minor, patch] = m.slice(1).map(Number)
|
|
22
|
+
return (major === 22 && (minor > 23 || (minor === 23 && patch >= 4))) ||
|
|
23
|
+
(major === 24 && (minor > 22 || (minor === 22 && patch >= 1)))
|
|
24
|
+
}
|
|
25
|
+
function selectRuntime({ platform = process.platform, nodeVersion = process.version,
|
|
26
|
+
execPath = process.execPath, env = process.env,
|
|
27
|
+
probe = (path) => {
|
|
28
|
+
const result = spawnSync(path, ['--version'], { encoding: 'utf8', timeout: 5000, windowsHide: true })
|
|
29
|
+
return result.status === 0 ? result.stdout.trim() : ''
|
|
30
|
+
},
|
|
31
|
+
exists = existsSync } = {}) {
|
|
32
|
+
if (!unsafeWindowsNode(nodeVersion, platform)) return execPath
|
|
33
|
+
const candidates = [
|
|
34
|
+
env.BCCLI_NODE_EXECUTABLE,
|
|
35
|
+
env.LOCALAPPDATA && join(env.LOCALAPPDATA, 'BotConnector', 'BCCLI-Preview', 'runtime', 'node.exe'),
|
|
36
|
+
].filter(Boolean)
|
|
37
|
+
for (const candidate of candidates) {
|
|
38
|
+
const path = resolve(candidate)
|
|
39
|
+
if (path === resolve(execPath) || !exists(path)) continue
|
|
40
|
+
if (safeRuntime(probe(path))) return path
|
|
41
|
+
}
|
|
42
|
+
throw Error('BCCLI requires Node.js 24.22.1+ or 22.23.4+ on Windows. Set BCCLI_NODE_EXECUTABLE to an installed compatible node.exe, or update Node.js. No coding request was sent.')
|
|
43
|
+
}
|
|
44
|
+
async function main() {
|
|
45
|
+
const exe = selectRuntime()
|
|
46
|
+
const entry = join(__dirname, 'cli.mjs')
|
|
47
|
+
if (exe === process.execPath) {
|
|
48
|
+
await import(pathToFileURL(entry).href)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
const child = spawn(exe, [entry, ...process.argv.slice(2)], {
|
|
52
|
+
stdio: 'inherit', cwd: process.cwd(), env: process.env, windowsHide: false, shell: false,
|
|
53
|
+
})
|
|
54
|
+
child.once('error', (error) => { console.error('BCCLI runtime launch failed: ' + error.message); process.exitCode = 1 })
|
|
55
|
+
child.once('exit', (code, signal) => { process.exitCode = code ?? (signal ? 130 : 1) })
|
|
56
|
+
}
|
|
57
|
+
if (require.main === module) main().catch((error) => {
|
|
58
|
+
console.error(error.message)
|
|
59
|
+
process.exitCode = 1
|
|
60
|
+
})
|
|
61
|
+
module.exports = { unsafeWindowsNode, safeRuntime, selectRuntime }
|
package/branding.mjs
CHANGED
|
@@ -33,7 +33,7 @@ const SOURCE_HASHES = Object.freeze({
|
|
|
33
33
|
'chunks/chunk-B3ZFUGTC.js': 'f3f57aafbaeab56ca58f5d3173751d30e5fef815aeaf8dc9b46e6ea9e85eb528',
|
|
34
34
|
'chunks/chunk-GGVWG4SI.js': '945c7f4e9b3697003c165b7bc5d007c9b87140d1fad7be084d7b253d8d2b476c',
|
|
35
35
|
})
|
|
36
|
-
const BRAND_REVISION = 'bccli-
|
|
36
|
+
const BRAND_REVISION = 'bccli-20261031-win-bootstrap-session-v15'
|
|
37
37
|
// Deliberately not Qwen's blue→purple→rose gradient. BotConnector-facing
|
|
38
38
|
// coding CLI uses a distinct teal→green→amber palette in dark/light themes.
|
|
39
39
|
export const BCCLI_COLORS = Object.freeze(['#00AFA0', '#22C55E', '#EAB308'])
|
|
@@ -249,6 +249,12 @@ export function patchUiChunk(file, text) {
|
|
|
249
249
|
'customBannerTitle?customBannerTitle:">_ BCCLI | BotConnector"',
|
|
250
250
|
'Ink banner title',
|
|
251
251
|
)
|
|
252
|
+
if (result.includes('const versionLabel=formatVersionLabel(version);')) {
|
|
253
|
+
result = replaceOnce(result,
|
|
254
|
+
'const versionLabel=formatVersionLabel(version);',
|
|
255
|
+
'const versionLabel="engine "+formatVersionLabel(version);',
|
|
256
|
+
'Clarify upstream engine version in BCCLI banner')
|
|
257
|
+
}
|
|
252
258
|
result = replaceOnce(result,
|
|
253
259
|
'Add a QWEN.md file to give Qwen Code persistent project context.',
|
|
254
260
|
'Use /help to explore BCCLI tools and commands.',
|
package/cli.mjs
CHANGED
|
File without changes
|
package/core.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
8
8
|
import { startGatewayProxy } from './proxy.mjs'
|
|
9
9
|
import { GATEWAY } from './gateway.mjs'
|
|
10
10
|
import { listProviderDefinitions } from './providers.mjs'
|
|
11
|
+
import { ensureIsolatedSessionSettings } from './session-settings.mjs'
|
|
11
12
|
|
|
12
13
|
export { GATEWAY } from './gateway.mjs'
|
|
13
14
|
export const DEFAULT_MODEL = 'ling-3.0-flash'
|
|
@@ -21,7 +22,7 @@ export function assertCandidateRuntimeSupported({ platform = process.platform, n
|
|
|
21
22
|
if (!parts) throw Error('Cannot verify the Node.js version for BCCLI candidate.')
|
|
22
23
|
const major = Number(parts[1]), minor = Number(parts[2]), patch = Number(parts[3])
|
|
23
24
|
if (platform === 'win32' && major === 24 && (minor < 22 || (minor === 22 && patch < 1))) {
|
|
24
|
-
throw Error('Windows Node.js ' + nodeVersion + ' may crash after coding tools. Use Node.js 24.22.1 or newer, or Node.js 22.23.4.
|
|
25
|
+
throw Error('Windows Node.js ' + nodeVersion + ' may crash after coding tools. Use Node.js 24.22.1 or newer, or Node.js 22.23.4. No coding request was sent.')
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
const MODEL_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/+-]{0,255}$/
|
|
@@ -266,8 +267,10 @@ export async function launchQwen({ key, model, prompt, mcpConfig, continueSessio
|
|
|
266
267
|
const proxy = await proxyFactory({ key, endpoint: upstream, liveProvider: true, initialProvider: providerId, searchApiKey })
|
|
267
268
|
try {
|
|
268
269
|
const args = [entrypoint, ...qwenArguments(model, prompt, proxy.baseUrl, { mcpConfig, continueSession, resumeSession, projectDir: process.cwd() })]
|
|
270
|
+
const childEnv = childEnvironment(env, proxy.token, model, { endpoint: proxy.baseUrl, providerId, searchAvailable: Boolean(searchApiKey?.trim()) })
|
|
271
|
+
ensureIsolatedSessionSettings(childEnv.QWEN_HOME)
|
|
269
272
|
const child = spawnImpl(process.execPath, args, {
|
|
270
|
-
cwd: process.cwd(), env:
|
|
273
|
+
cwd: process.cwd(), env: childEnv,
|
|
271
274
|
stdio: 'inherit', windowsHide: false, shell: false,
|
|
272
275
|
})
|
|
273
276
|
return await new Promise((resolve, reject) => {
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botconnector/bccli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "BCCLI | Full coding engine and legacy SDK with verified Apache-2.0 bundled runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"bccli": "./
|
|
7
|
+
"bccli": "./bccli-bootstrap.cjs"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=22"
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"LICENSE",
|
|
37
37
|
"THIRD_PARTY_NOTICES.md",
|
|
38
38
|
"cli.mjs",
|
|
39
|
+
"bccli-bootstrap.cjs",
|
|
40
|
+
"session-settings.mjs",
|
|
39
41
|
"core.mjs",
|
|
40
42
|
"proxy.mjs",
|
|
41
43
|
"gateway.mjs",
|
|
@@ -79,8 +81,8 @@
|
|
|
79
81
|
},
|
|
80
82
|
"bccliRuntimeSource": {
|
|
81
83
|
"repository": "https://github.com/farijarifriyanto-debug/bccli-runtime",
|
|
82
|
-
"commit": "
|
|
83
|
-
"release": "bccli-v0.5.
|
|
84
|
-
"originalSha256": "
|
|
84
|
+
"commit": "eb5e057b3f568e9def717cdc3d8a3b11ce82544f",
|
|
85
|
+
"release": "bccli-v0.5.3",
|
|
86
|
+
"originalSha256": "3a185b33af625ef9df3552e40a9390d4d271b0b977971433357b2f592b5553bc"
|
|
85
87
|
}
|
|
86
88
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// A provider-scoped QWEN_HOME is intentionally separate from ~/.qwen.
|
|
2
|
+
// The upstream engine warns when the isolated directory has no settings.json;
|
|
3
|
+
// create only the minimal blank configuration, never migrate tokens or plugins.
|
|
4
|
+
import { existsSync, lstatSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
5
|
+
import { dirname, join } from 'node:path'
|
|
6
|
+
|
|
7
|
+
export function ensureIsolatedSessionSettings(home) {
|
|
8
|
+
if (typeof home !== 'string' || !home.trim()) throw Error('BCCLI session home missing.')
|
|
9
|
+
mkdirSync(home, { recursive: true, mode: 0o700 })
|
|
10
|
+
for (const dir of [dirname(home), home]) {
|
|
11
|
+
const info = lstatSync(dir)
|
|
12
|
+
if (!info.isDirectory() || info.isSymbolicLink()) throw Error('BCCLI session directory must not be a symlink.')
|
|
13
|
+
}
|
|
14
|
+
const file = join(home, 'settings.json')
|
|
15
|
+
if (existsSync(file)) {
|
|
16
|
+
if (!lstatSync(file).isFile()) throw Error('BCCLI session settings must be a regular file.')
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
writeFileSync(file, '{}\n', { flag: 'wx', mode: 0o600 })
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (error.code !== 'EEXIST' || !lstatSync(file).isFile()) throw error
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
return true
|
|
26
|
+
}
|