@mmmbuto/qwen-code-termux 0.6.4-termux → 0.6.402

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/README.md CHANGED
@@ -24,7 +24,7 @@ pkg update && pkg upgrade -y
24
24
  pkg install nodejs-lts -y
25
25
  npm install -g @mmmbuto/qwen-code-termux
26
26
 
27
- qwen --version # expected: 0.6.3-termux
27
+ qwen --version # expected: 0.6.402
28
28
  ```
29
29
 
30
30
  Build from source:
@@ -82,7 +82,7 @@ export OPENAI_MODEL="gpt-4o" # optional
82
82
  ## Documentation & Fixes
83
83
 
84
84
  - **Test Suite**: [`QWEN_TEST_SUITE.md`](./QWEN_TEST_SUITE.md)
85
- - **Test Report**: [`QWEN_TEST_REPORT_v0.6.3.md`](./QWEN_TEST_REPORT_v0.6.3.md)
85
+ - **Test Report**: [`QWEN_TEST_REPORT_v0.6.402.md`](./QWEN_TEST_REPORT_v0.6.402.md)
86
86
  - **Patches**: [`docs/patches/README.md`](./docs/patches/README.md)
87
87
  - **Termux Fixes**: [`docs/patches/TERMUX_FIXES.md`](./docs/patches/TERMUX_FIXES.md)
88
88
 
@@ -153,7 +153,7 @@ npm install -g @mmmbuto/qwen-code-termux@latest
153
153
 
154
154
  ### Versions
155
155
 
156
- - **latest / stable**: 0.6.3-termux
156
+ - **latest / stable**: 0.6.402
157
157
 
158
158
  ## Benchmark Results
159
159
 
@@ -168,8 +168,7 @@ npm install -g @mmmbuto/qwen-code-termux@latest
168
168
 
169
169
  Looking for a graphical interface?
170
170
 
171
- - [**AionUi**](https://github.com/iOfficeAI/AionUi) A modern GUI for command-line AI tools including Qwen Code
172
- - [**Gemini CLI Desktop**](https://github.com/Piebald-AI/gemini-cli-desktop) A cross-platform desktop/web/mobile UI for Qwen Code
171
+ - Web UI: [NexusCLI](https://github.com/DioNanos/nexuscli) - Optional web interface for Codex/Claude/Gemini
173
172
 
174
173
  ## Troubleshooting
175
174
 
package/dist/cli.js CHANGED
@@ -155008,7 +155008,7 @@ __export(geminiContentGenerator_exports, {
155008
155008
  createGeminiContentGenerator: () => createGeminiContentGenerator
155009
155009
  });
155010
155010
  function createGeminiContentGenerator(config2, gcConfig) {
155011
- const version2 = "0.6.4-termux";
155011
+ const version2 = "0.6.402";
155012
155012
  const userAgent2 = config2.userAgent || `QwenCode/${version2} (${process.platform}; ${process.arch})`;
155013
155013
  const baseHeaders = {
155014
155014
  "User-Agent": userAgent2
@@ -356998,7 +356998,7 @@ __name(getPackageJson, "getPackageJson");
356998
356998
  // packages/cli/src/utils/version.ts
356999
356999
  async function getCliVersion() {
357000
357000
  const pkgJson = await getPackageJson();
357001
- return "0.6.4-termux";
357001
+ return "0.6.402";
357002
357002
  }
357003
357003
  __name(getCliVersion, "getCliVersion");
357004
357004
 
@@ -365081,7 +365081,7 @@ var formatDuration = /* @__PURE__ */ __name((milliseconds) => {
365081
365081
 
365082
365082
  // packages/cli/src/generated/git-commit.ts
365083
365083
  init_esbuild_shims();
365084
- var GIT_COMMIT_INFO2 = "3b146e8f";
365084
+ var GIT_COMMIT_INFO2 = "89e3ec25";
365085
365085
 
365086
365086
  // packages/cli/src/utils/systemInfo.ts
365087
365087
  async function getNpmVersion() {
@@ -416299,7 +416299,7 @@ var GeminiAgent = class {
416299
416299
  name: APPROVAL_MODE_INFO[mode].name,
416300
416300
  description: APPROVAL_MODE_INFO[mode].description
416301
416301
  }));
416302
- const version2 = "0.6.4-termux";
416302
+ const version2 = "0.6.402";
416303
416303
  return {
416304
416304
  protocolVersion: PROTOCOL_VERSION,
416305
416305
  agentInfo: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmmbuto/qwen-code-termux",
3
- "version": "0.6.4-termux",
3
+ "version": "0.6.402",
4
4
  "engines": {
5
5
  "node": ">=20.0.0"
6
6
  },
@@ -13,7 +13,7 @@
13
13
  "url": "git+https://github.com/DioNanos/qwen-code-termux.git"
14
14
  },
15
15
  "config": {
16
- "sandboxImageUri": "ghcr.io/mmmbuto/qwen-code-termux:0.6.3-termux"
16
+ "sandboxImageUri": "ghcr.io/mmmbuto/qwen-code-termux:0.6.402"
17
17
  },
18
18
  "scripts": {
19
19
  "start": "cross-env node scripts/start.js",
@@ -69,6 +69,7 @@
69
69
  "qwen": "dist/cli.js"
70
70
  },
71
71
  "files": [
72
+ "scripts",
72
73
  "dist/",
73
74
  "README.md",
74
75
  "LICENSE"
@@ -121,7 +122,7 @@
121
122
  "@lydell/node-pty-linux-x64": "1.1.0",
122
123
  "@lydell/node-pty-win32-arm64": "1.1.0",
123
124
  "@lydell/node-pty-win32-x64": "1.1.0",
124
- "node-pty": "^1.0.0"
125
+ "@lydell/node-pty-linux-arm64": "1.2.0-beta.2"
125
126
  },
126
127
  "lint-staged": {
127
128
  "*.{js,jsx,ts,tsx}": [
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ //
8
+ // Licensed under the Apache License, Version 2.0 (the "License");
9
+ // you may not use this file except in compliance with the License.
10
+ // You may obtain a copy of the License at
11
+ //
12
+ // http://www.apache.org/licenses/LICENSE-2.0
13
+ //
14
+ // Unless required by applicable law or agreed to in writing, software
15
+ // distributed under the License is distributed on an "AS IS" BASIS,
16
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ // See the License for the specific language governing permissions and
18
+ // limitations under the License.
19
+
20
+ import { execSync } from 'node:child_process';
21
+ import { existsSync } from 'node:fs';
22
+ import { dirname, join } from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+
25
+ const __dirname = dirname(fileURLToPath(import.meta.url));
26
+ const root = join(__dirname, '..');
27
+
28
+ // npm install if node_modules was removed (e.g. via npm run clean or scripts/clean.js)
29
+ if (!existsSync(join(root, 'node_modules'))) {
30
+ execSync('npm install', { stdio: 'inherit', cwd: root });
31
+ }
32
+
33
+ // build all workspaces/packages
34
+ execSync('npm run generate', { stdio: 'inherit', cwd: root });
35
+ execSync('npm run build --workspaces', { stdio: 'inherit', cwd: root });
36
+
37
+ // also build container image if sandboxing is enabled
38
+ // skip (-s) npm install + build since we did that above
39
+ try {
40
+ execSync('node scripts/sandbox_command.js -q', {
41
+ stdio: 'inherit',
42
+ cwd: root,
43
+ });
44
+ if (
45
+ process.env.BUILD_SANDBOX === '1' ||
46
+ process.env.BUILD_SANDBOX === 'true'
47
+ ) {
48
+ execSync('node scripts/build_sandbox.js -s', {
49
+ stdio: 'inherit',
50
+ cwd: root,
51
+ });
52
+ }
53
+ } catch {
54
+ // ignore
55
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ //
8
+ // Licensed under the Apache License, Version 2.0 (the "License");
9
+ // you may not use this file except in compliance with the License.
10
+ // You may obtain a copy of the License at
11
+ //
12
+ // http://www.apache.org/licenses/LICENSE-2.0
13
+ //
14
+ // Unless required by applicable law or agreed to in writing, software
15
+ // distributed under the License is distributed on an "AS IS" BASIS,
16
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ // See the License for the specific language governing permissions and
18
+ // limitations under the License.
19
+
20
+ import { execSync } from 'node:child_process';
21
+ import { writeFileSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+
24
+ if (!process.cwd().includes('packages')) {
25
+ console.error('must be invoked from a package directory');
26
+ process.exit(1);
27
+ }
28
+
29
+ // build typescript files
30
+ execSync('tsc --build', { stdio: 'inherit' });
31
+
32
+ // copy .{md,json} files
33
+ execSync('node ../../scripts/copy_files.js', { stdio: 'inherit' });
34
+
35
+ // touch dist/.last_build
36
+ writeFileSync(join(process.cwd(), 'dist', '.last_build'), '');
37
+ process.exit(0);
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ //
8
+ // Licensed under the Apache License, Version 2.0 (the "License");
9
+ // you may not use this file except in compliance with the License.
10
+ // You may obtain a copy of the License at
11
+ //
12
+ // http://www.apache.org/licenses/LICENSE-2.0
13
+ //
14
+ // Unless required by applicable law or agreed to in writing, software
15
+ // distributed under the License is distributed on an "AS IS" BASIS,
16
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ // See the License for the specific language governing permissions and
18
+ // limitations under the License.
19
+
20
+ import { execSync } from 'node:child_process';
21
+ import {
22
+ chmodSync,
23
+ existsSync,
24
+ readFileSync,
25
+ rmSync,
26
+ writeFileSync,
27
+ } from 'node:fs';
28
+ import { join } from 'node:path';
29
+ import os from 'node:os';
30
+ import yargs from 'yargs';
31
+ import { hideBin } from 'yargs/helpers';
32
+ import cliPkgJson from '../packages/cli/package.json' with { type: 'json' };
33
+
34
+ const argv = yargs(hideBin(process.argv))
35
+ .option('s', {
36
+ alias: 'skip-npm-install-build',
37
+ type: 'boolean',
38
+ default: false,
39
+ description: 'skip npm install + npm run build',
40
+ })
41
+ .option('f', {
42
+ alias: 'dockerfile',
43
+ type: 'string',
44
+ default: 'Dockerfile',
45
+ description: 'use <dockerfile> for custom image',
46
+ })
47
+ .option('i', {
48
+ alias: 'image',
49
+ type: 'string',
50
+ default: cliPkgJson.config.sandboxImageUri,
51
+ description: 'use <image> name for custom image',
52
+ })
53
+ .option('output-file', {
54
+ type: 'string',
55
+ description:
56
+ 'Path to write the final image URI. Used for CI/CD pipeline integration.',
57
+ }).argv;
58
+
59
+ let sandboxCommand;
60
+ try {
61
+ sandboxCommand = execSync('node scripts/sandbox_command.js')
62
+ .toString()
63
+ .trim();
64
+ } catch (e) {
65
+ console.warn('ERROR: could not detect sandbox container command');
66
+ console.error(e);
67
+ process.exit(process.env.CI ? 1 : 0);
68
+ }
69
+
70
+ if (sandboxCommand === 'sandbox-exec') {
71
+ console.warn(
72
+ 'WARNING: container-based sandboxing is disabled (see README.md#sandboxing)',
73
+ );
74
+ process.exit(0);
75
+ }
76
+
77
+ console.log(`using ${sandboxCommand} for sandboxing`);
78
+
79
+ const image = argv.i;
80
+ const dockerFile = argv.f;
81
+
82
+ if (!image.length) {
83
+ console.warn(
84
+ 'No default image tag specified in gemini-cli/packages/cli/package.json',
85
+ );
86
+ }
87
+
88
+ if (!argv.s) {
89
+ execSync('npm install', { stdio: 'inherit' });
90
+ execSync('npm run build --workspaces', { stdio: 'inherit' });
91
+ }
92
+
93
+ console.log('packing @qwen-code/qwen-code ...');
94
+ const cliPackageDir = join('packages', 'cli');
95
+ rmSync(join(cliPackageDir, 'dist', 'qwen-code-*.tgz'), { force: true });
96
+ execSync(
97
+ `npm pack -w @qwen-code/qwen-code --pack-destination ./packages/cli/dist`,
98
+ {
99
+ stdio: 'ignore',
100
+ },
101
+ );
102
+
103
+ console.log('packing @qwen-code/qwen-code-core ...');
104
+ const corePackageDir = join('packages', 'core');
105
+ rmSync(join(corePackageDir, 'dist', 'qwen-code-core-*.tgz'), {
106
+ force: true,
107
+ });
108
+ execSync(
109
+ `npm pack -w @qwen-code/qwen-code-core --pack-destination ./packages/core/dist`,
110
+ { stdio: 'ignore' },
111
+ );
112
+
113
+ const packageVersion = JSON.parse(
114
+ readFileSync(join(process.cwd(), 'package.json'), 'utf-8'),
115
+ ).version;
116
+
117
+ chmodSync(
118
+ join(cliPackageDir, 'dist', `qwen-code-qwen-code-${packageVersion}.tgz`),
119
+ 0o755,
120
+ );
121
+ chmodSync(
122
+ join(
123
+ corePackageDir,
124
+ 'dist',
125
+ `qwen-code-qwen-code-core-${packageVersion}.tgz`,
126
+ ),
127
+ 0o755,
128
+ );
129
+
130
+ const buildStdout = process.env.VERBOSE ? 'inherit' : 'ignore';
131
+
132
+ // Determine the appropriate shell based on OS
133
+ const isWindows = os.platform() === 'win32';
134
+ const shellToUse = isWindows ? 'powershell.exe' : '/bin/bash';
135
+
136
+ function buildImage(imageName, dockerfile) {
137
+ console.log(`building ${imageName} ... (can be slow first time)`);
138
+
139
+ let buildCommandArgs = '';
140
+ let tempAuthFile = '';
141
+
142
+ if (sandboxCommand === 'podman') {
143
+ if (isWindows) {
144
+ // PowerShell doesn't support <() process substitution.
145
+ // Create a temporary auth file that we will clean up after.
146
+ tempAuthFile = join(os.tmpdir(), `qwen-auth-${Date.now()}.json`);
147
+ writeFileSync(tempAuthFile, '{}');
148
+ buildCommandArgs = `--authfile="${tempAuthFile}"`;
149
+ } else {
150
+ // Use bash-specific syntax for Linux/macOS
151
+ buildCommandArgs = `--authfile=<(echo '{}')`;
152
+ }
153
+ }
154
+
155
+ const npmPackageVersion = JSON.parse(
156
+ readFileSync(join(process.cwd(), 'package.json'), 'utf-8'),
157
+ ).version;
158
+
159
+ const imageTag =
160
+ process.env.GEMINI_SANDBOX_IMAGE_TAG || imageName.split(':')[1];
161
+ const finalImageName = `${imageName.split(':')[0]}:${imageTag}`;
162
+
163
+ try {
164
+ execSync(
165
+ `${sandboxCommand} build ${buildCommandArgs} ${
166
+ process.env.BUILD_SANDBOX_FLAGS || ''
167
+ } --build-arg CLI_VERSION_ARG=${npmPackageVersion} -f "${dockerfile}" -t "${finalImageName}" .`,
168
+ { stdio: buildStdout, shell: shellToUse },
169
+ );
170
+ console.log(`built ${finalImageName}`);
171
+
172
+ // If an output file path was provided via command-line, write the final image URI to it.
173
+ if (argv.outputFile) {
174
+ console.log(
175
+ `Writing final image URI for CI artifact to: ${argv.outputFile}`,
176
+ );
177
+ // The publish step only supports one image. If we build multiple, only the last one
178
+ // will be published. Throw an error to make this failure explicit if the file already exists.
179
+ if (existsSync(argv.outputFile)) {
180
+ throw new Error(
181
+ `CI artifact file ${argv.outputFile} already exists. Refusing to overwrite.`,
182
+ );
183
+ }
184
+ writeFileSync(argv.outputFile, finalImageName);
185
+ }
186
+ } finally {
187
+ // If we created a temp file, delete it now.
188
+ if (tempAuthFile) {
189
+ rmSync(tempAuthFile, { force: true });
190
+ }
191
+ }
192
+ }
193
+
194
+ buildImage(image, dockerFile);
195
+
196
+ execSync(`${sandboxCommand} image prune -f`, { stdio: 'ignore' });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ //
8
+ // Licensed under the Apache License, Version 2.0 (the "License");
9
+ // you may not use this file except in compliance with the License.
10
+ // You may obtain a copy of the License at
11
+ //
12
+ // http://www.apache.org/licenses/LICENSE-2.0
13
+ //
14
+ // Unless required by applicable law or agreed to in writing, software
15
+ // distributed under the License is distributed on an "AS IS" BASIS,
16
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ // See the License for the specific language governing permissions and
18
+ // limitations under the License.
19
+
20
+ import { execSync } from 'node:child_process';
21
+ import { dirname, join } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const root = join(__dirname, '..');
26
+
27
+ execSync('npm --workspace=qwen-code-vscode-ide-companion run package', {
28
+ stdio: 'inherit',
29
+ cwd: root,
30
+ });
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import os from 'node:os'; // Import os module
10
+
11
+ // --- Configuration ---
12
+ const cliPackageDir = path.resolve('packages', 'cli'); // Base directory for the CLI package
13
+ const buildTimestampPath = path.join(cliPackageDir, 'dist', '.last_build'); // Path to the timestamp file within the CLI package
14
+ const sourceDirs = [path.join(cliPackageDir, 'src')]; // Source directory within the CLI package
15
+ const filesToWatch = [
16
+ path.join(cliPackageDir, 'package.json'),
17
+ path.join(cliPackageDir, 'tsconfig.json'),
18
+ ]; // Specific files within the CLI package
19
+ const buildDir = path.join(cliPackageDir, 'dist'); // Build output directory within the CLI package
20
+ const warningsFilePath = path.join(os.tmpdir(), 'qwen-code-warnings.txt'); // Temp file for warnings
21
+ // ---------------------
22
+
23
+ function getMtime(filePath) {
24
+ try {
25
+ return fs.statSync(filePath).mtimeMs; // Use mtimeMs for higher precision
26
+ } catch (err) {
27
+ if (err.code === 'ENOENT') {
28
+ return null; // File doesn't exist
29
+ }
30
+ console.error(`Error getting stats for ${filePath}:`, err);
31
+ process.exit(1); // Exit on unexpected errors getting stats
32
+ }
33
+ }
34
+
35
+ function findSourceFiles(dir, allFiles = []) {
36
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
37
+ for (const entry of entries) {
38
+ const fullPath = path.join(dir, entry.name);
39
+ // Simple check to avoid recursing into node_modules or build dir itself
40
+ if (
41
+ entry.isDirectory() &&
42
+ entry.name !== 'node_modules' &&
43
+ fullPath !== buildDir
44
+ ) {
45
+ findSourceFiles(fullPath, allFiles);
46
+ } else if (entry.isFile()) {
47
+ allFiles.push(fullPath);
48
+ }
49
+ }
50
+ return allFiles;
51
+ }
52
+
53
+ console.log('Checking build status...');
54
+
55
+ // Clean up old warnings file before check
56
+ try {
57
+ if (fs.existsSync(warningsFilePath)) {
58
+ fs.unlinkSync(warningsFilePath);
59
+ }
60
+ } catch (err) {
61
+ console.warn(
62
+ `[Check Script] Warning: Could not delete previous warnings file: ${err.message}`,
63
+ );
64
+ }
65
+
66
+ const buildMtime = getMtime(buildTimestampPath);
67
+ if (!buildMtime) {
68
+ // If build is missing, write that as a warning and exit(0) so app can display it
69
+ const errorMessage = `ERROR: Build timestamp file (${path.relative(process.cwd(), buildTimestampPath)}) not found. Run \`npm run build\` first.`;
70
+ console.error(errorMessage); // Still log error here
71
+ try {
72
+ fs.writeFileSync(warningsFilePath, errorMessage);
73
+ } catch (writeErr) {
74
+ console.error(
75
+ `[Check Script] Error writing missing build warning file: ${writeErr.message}`,
76
+ );
77
+ }
78
+ process.exit(0); // Allow app to start and show the error
79
+ }
80
+
81
+ let newerSourceFileFound = false;
82
+ const warningMessages = []; // Collect warnings here
83
+ const allSourceFiles = [];
84
+
85
+ // Collect files from specified directories
86
+ sourceDirs.forEach((dir) => {
87
+ const dirPath = path.resolve(dir);
88
+ if (fs.existsSync(dirPath)) {
89
+ findSourceFiles(dirPath, allSourceFiles);
90
+ } else {
91
+ console.warn(`Warning: Source directory "${dir}" not found.`);
92
+ }
93
+ });
94
+
95
+ // Add specific files
96
+ filesToWatch.forEach((file) => {
97
+ const filePath = path.resolve(file);
98
+ if (fs.existsSync(filePath)) {
99
+ allSourceFiles.push(filePath);
100
+ } else {
101
+ console.warn(`Warning: Watched file "${file}" not found.`);
102
+ }
103
+ });
104
+
105
+ // Check modification times
106
+ for (const file of allSourceFiles) {
107
+ const sourceMtime = getMtime(file);
108
+ const relativePath = path.relative(process.cwd(), file);
109
+ const isNewer = sourceMtime && sourceMtime > buildMtime;
110
+
111
+ if (isNewer) {
112
+ const warning = `Warning: Source file "${relativePath}" has been modified since the last build.`;
113
+ console.warn(warning); // Keep console warning for script debugging
114
+ warningMessages.push(warning);
115
+ newerSourceFileFound = true;
116
+ // break; // Uncomment to stop checking after the first newer file
117
+ }
118
+ }
119
+
120
+ if (newerSourceFileFound) {
121
+ const finalWarning =
122
+ '\nRun "npm run build" to incorporate changes before starting.';
123
+ warningMessages.push(finalWarning);
124
+ console.warn(finalWarning);
125
+
126
+ // Write warnings to the temp file
127
+ try {
128
+ fs.writeFileSync(warningsFilePath, warningMessages.join('\n'));
129
+ // Removed debug log
130
+ } catch (err) {
131
+ console.error(`[Check Script] Error writing warnings file: ${err.message}`);
132
+ // Proceed without writing, app won't show warnings
133
+ }
134
+ } else {
135
+ console.log('Build is up-to-date.');
136
+ // Ensure no stale warning file exists if build is ok
137
+ try {
138
+ if (fs.existsSync(warningsFilePath)) {
139
+ fs.unlinkSync(warningsFilePath);
140
+ }
141
+ } catch (err) {
142
+ console.warn(
143
+ `[Check Script] Warning: Could not delete previous warnings file: ${err.message}`,
144
+ );
145
+ }
146
+ }
147
+
148
+ process.exit(0); // Always exit successfully so the app starts