@anh3d0nic/qwen-code-termux-ice 16.0.4 → 16.0.7

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 (69) hide show
  1. package/bin/qwen-ice +25 -5
  2. package/package.json +6 -5
  3. package/scripts/build.js +88 -0
  4. package/scripts/build_package.js +37 -0
  5. package/scripts/build_sandbox.js +174 -0
  6. package/scripts/build_vscode_companion.js +30 -0
  7. package/scripts/check-build-status.js +148 -0
  8. package/scripts/check-i18n.ts +462 -0
  9. package/scripts/check-lockfile.js +74 -0
  10. package/scripts/clean.js +59 -0
  11. package/scripts/copy_bundle_assets.js +90 -0
  12. package/scripts/copy_files.js +86 -0
  13. package/scripts/create_alias.sh +39 -0
  14. package/scripts/dev.js +109 -0
  15. package/scripts/esbuild-shims.js +29 -0
  16. package/scripts/generate-git-commit-info.js +71 -0
  17. package/scripts/generate-settings-schema.ts +146 -0
  18. package/scripts/get-release-version.js +411 -0
  19. package/scripts/ice-mobile.js +5 -0
  20. package/scripts/ice-session.js +6 -0
  21. package/scripts/ice-skills.js +31 -0
  22. package/scripts/ice-teams.js +34 -0
  23. package/scripts/ice-v10.js +276 -0
  24. package/scripts/ice-v11.js +276 -0
  25. package/scripts/ice-v12.js +568 -0
  26. package/scripts/ice-v13.js +824 -0
  27. package/scripts/ice-v14.js +1059 -0
  28. package/scripts/ice-v15.js +1501 -0
  29. package/scripts/ice-v2.js +26 -0
  30. package/scripts/ice-v3-core.js +261 -0
  31. package/scripts/ice-v3.js +46 -0
  32. package/scripts/ice-v4.js +657 -0
  33. package/scripts/ice-v5.js +371 -0
  34. package/scripts/ice-v6.js +305 -0
  35. package/scripts/ice-v7.js +291 -0
  36. package/scripts/ice-v8.js +550 -0
  37. package/scripts/ice-v9.js +546 -0
  38. package/scripts/install-ice.sh +70 -0
  39. package/scripts/install.sh +136 -0
  40. package/scripts/installation/INSTALLATION_GUIDE.md +250 -0
  41. package/scripts/installation/install-qwen-with-source.bat +302 -0
  42. package/scripts/installation/install-qwen-with-source.sh +570 -0
  43. package/scripts/lint.js +205 -0
  44. package/scripts/local_telemetry.js +219 -0
  45. package/scripts/postinstall.cjs +235 -0
  46. package/scripts/pre-commit.js +22 -0
  47. package/scripts/prepare-package.js +186 -0
  48. package/scripts/prepare-termux.cjs +26 -0
  49. package/scripts/sandbox_command.js +128 -0
  50. package/scripts/start.js +86 -0
  51. package/scripts/telemetry.js +85 -0
  52. package/scripts/telemetry_gcp.js +188 -0
  53. package/scripts/telemetry_utils.js +450 -0
  54. package/scripts/test-v10.js +18 -0
  55. package/scripts/test-v11.js +18 -0
  56. package/scripts/test-v12.js +18 -0
  57. package/scripts/test-v13.js +18 -0
  58. package/scripts/test-v14.js +18 -0
  59. package/scripts/test-v3.js +47 -0
  60. package/scripts/test-v4.js +47 -0
  61. package/scripts/test-v6.js +59 -0
  62. package/scripts/test-v8.js +42 -0
  63. package/scripts/test-v9.js +18 -0
  64. package/scripts/test-windows-paths.js +51 -0
  65. package/scripts/tests/get-release-version.test.js +186 -0
  66. package/scripts/tests/test-setup.ts +12 -0
  67. package/scripts/tests/vitest.config.ts +26 -0
  68. package/scripts/unused-keys-only-in-locales.json +62 -0
  69. package/scripts/version.js +112 -0
package/bin/qwen-ice CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/data/data/com.termux/files/usr/bin/node
2
2
  /**
3
- * ❄️ Qwen Code ICE v16.0.0 — Main Binary
3
+ * ❄️ Qwen Code ICE v16.0.6 — Main Binary
4
+ * Fixed: Auto-runs postinstall if core dir missing on fresh install
4
5
  */
5
6
 
6
7
  const fs = require('fs');
@@ -8,8 +9,8 @@ const path = require('path');
8
9
  const readline = require('readline');
9
10
  const { spawn } = require('child_process');
10
11
 
11
- const VERSION = '16.0.0';
12
- const INSTALL_DIR = '/data/data/com.termux/files/.qwen-ice';
12
+ const VERSION = '16.0.6';
13
+ const INSTALL_DIR = process.env.HOME + '/.qwen-ice';
13
14
  const CONFIG_DIR = path.join(INSTALL_DIR, 'config');
14
15
  const MEMORY_DIR = path.join(INSTALL_DIR, 'memory');
15
16
  const LOGS_DIR = path.join(INSTALL_DIR, 'logs');
@@ -280,11 +281,30 @@ function printColdStart() {
280
281
  }
281
282
  }
282
283
 
284
+ function getLatestIceVersion() {
285
+ // Check if core directory exists, run postinstall if not
286
+ if (!fs.existsSync(CORE_DIR)) {
287
+ const { execSync } = require('child_process');
288
+ execSync('node ' + path.join(__dirname, '../scripts/postinstall.cjs'), { stdio: 'inherit' });
289
+ }
290
+ const versions = fs.readdirSync(CORE_DIR)
291
+ .filter(f => f.startsWith('ice-v') && f.endsWith('.js'))
292
+ .sort();
293
+ if (!versions || versions.length === 0) {
294
+ console.error('ICE core not found. Run: node scripts/postinstall.cjs');
295
+ process.exit(1);
296
+ }
297
+ return versions[versions.length - 1] || 'ice-v15.js';
298
+ }
299
+
283
300
  async function processQuery(query) {
284
301
  try {
285
- const { IceV16 } = require(path.join(CORE_DIR, 'ice-v16.js'));
302
+ // Dynamically load latest ICE version
303
+ const latest = getLatestIceVersion();
304
+ const iceModule = require(path.join(CORE_DIR, latest));
305
+ const IceV16 = iceModule.IceV16 || iceModule.UnifiedPipeline;
286
306
  const ice = new IceV16({ yolo, model: selectedModel });
287
- return await ice.processQuery(query);
307
+ return ice.process(query);
288
308
  } catch (err) {
289
309
  return { error: true, message: `Failed to process query: ${err.message}` };
290
310
  }
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@anh3d0nic/qwen-code-termux-ice",
3
- "version": "16.0.4",
4
- "description": "Qwen Code ICE v16.0.0Consolidated from v1-v15. Unified pipeline with 14 steps.",
3
+ "version": "16.0.7",
4
+ "description": "Qwen Code ICE v16.0.5Compounding Intelligence with proper npm install structure",
5
5
  "main": "core/ice-v16.js",
6
6
  "bin": {
7
7
  "qwen-ice": "./bin/qwen-ice",
8
8
  "qwen-ice-api-setup": "./bin/qwen-ice-api-setup"
9
9
  },
10
10
  "scripts": {
11
- "postinstall": "node core/install.js",
11
+ "postinstall": "node scripts/postinstall.cjs",
12
12
  "preuninstall": "node core/uninstall.js",
13
- "test": "echo \"ICE v16.0.0 installed successfully\" && exit 0"
13
+ "test": "echo \"ICE v15.0.0 installed successfully\" && exit 0"
14
14
  },
15
15
  "keywords": [
16
16
  "qwen",
@@ -21,7 +21,7 @@
21
21
  "groq",
22
22
  "gemini",
23
23
  "multi-provider",
24
- "consolidated"
24
+ "compounding-intelligence"
25
25
  ],
26
26
  "author": "anh3d0nic",
27
27
  "license": "MIT",
@@ -49,6 +49,7 @@
49
49
  "config/",
50
50
  "memory/",
51
51
  "logs/",
52
+ "scripts/",
52
53
  "manifest.json"
53
54
  ]
54
55
  }
@@ -0,0 +1,88 @@
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 in dependency order
34
+
35
+
36
+ // Build in dependency order:
37
+ // 1. test-utils (no internal dependencies)
38
+ // 2. core (foundation package)
39
+ // 3. web-templates (embeddable web templates - used by cli)
40
+ // 4. cli (depends on core, test-utils, web-templates)
41
+ // 5. webui (shared UI components - used by vscode companion)
42
+ // 6. sdk (no internal dependencies)
43
+ // 7. vscode-ide-companion (depends on webui) - SKIPPED for Termux
44
+ const buildOrder = [
45
+ 'packages/test-utils',
46
+ 'packages/core',
47
+ 'packages/web-templates',
48
+ 'packages/cli',
49
+ 'packages/webui',
50
+ 'packages/sdk-typescript',
51
+ // 'packages/vscode-ide-companion', // Not needed for Termux
52
+ ];
53
+
54
+ for (const workspace of buildOrder) {
55
+ execSync(`npm run build --workspace=${workspace}`, {
56
+ stdio: 'inherit',
57
+ cwd: root,
58
+ });
59
+
60
+ // After cli is built, generate the JSON Schema for settings
61
+ // so the vscode-ide-companion extension can provide IntelliSense
62
+ if (workspace === 'packages/cli') {
63
+ execSync('npx tsx scripts/generate-settings-schema.ts', {
64
+ stdio: 'inherit',
65
+ cwd: root,
66
+ });
67
+ }
68
+ }
69
+
70
+ // also build container image if sandboxing is enabled
71
+ // skip (-s) npm install + build since we did that above
72
+ try {
73
+ execSync('node scripts/sandbox_command.js -q', {
74
+ stdio: 'inherit',
75
+ cwd: root,
76
+ });
77
+ if (
78
+ process.env.BUILD_SANDBOX === '1' ||
79
+ process.env.BUILD_SANDBOX === 'true'
80
+ ) {
81
+ execSync('node scripts/build_sandbox.js -s', {
82
+ stdio: 'inherit',
83
+ cwd: root,
84
+ });
85
+ }
86
+ } catch {
87
+ // ignore
88
+ }
@@ -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,174 @@
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
+ existsSync,
23
+ readFileSync,
24
+ readdirSync,
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', { stdio: 'inherit' });
91
+
92
+ console.log('bundling...');
93
+ execSync('npm run bundle', { stdio: 'inherit' });
94
+
95
+ console.log('preparing package...');
96
+ execSync('npm run prepare:package', { stdio: 'inherit' });
97
+
98
+ console.log('packing...');
99
+ const distDir = join(process.cwd(), 'dist');
100
+ for (const f of readdirSync(distDir)) {
101
+ if (f.endsWith('.tgz')) {
102
+ rmSync(join(distDir, f), { force: true });
103
+ }
104
+ }
105
+ execSync('npm pack', { stdio: 'ignore', cwd: distDir });
106
+ }
107
+
108
+ const buildStdout = process.env.VERBOSE ? 'inherit' : 'ignore';
109
+
110
+ // Determine the appropriate shell based on OS
111
+ const isWindows = os.platform() === 'win32';
112
+ const shellToUse = isWindows ? 'powershell.exe' : '/bin/bash';
113
+
114
+ function buildImage(imageName, dockerfile) {
115
+ console.log(`building ${imageName} ... (can be slow first time)`);
116
+
117
+ let buildCommandArgs = '';
118
+ let tempAuthFile = '';
119
+
120
+ if (sandboxCommand === 'podman') {
121
+ if (isWindows) {
122
+ // PowerShell doesn't support <() process substitution.
123
+ // Create a temporary auth file that we will clean up after.
124
+ tempAuthFile = join(os.tmpdir(), `qwen-auth-${Date.now()}.json`);
125
+ writeFileSync(tempAuthFile, '{}');
126
+ buildCommandArgs = `--authfile="${tempAuthFile}"`;
127
+ } else {
128
+ // Use bash-specific syntax for Linux/macOS
129
+ buildCommandArgs = `--authfile=<(echo '{}')`;
130
+ }
131
+ }
132
+
133
+ const npmPackageVersion = JSON.parse(
134
+ readFileSync(join(process.cwd(), 'package.json'), 'utf-8'),
135
+ ).version;
136
+
137
+ const imageTag =
138
+ process.env.QWEN_SANDBOX_IMAGE_TAG || imageName.split(':')[1];
139
+ const finalImageName = `${imageName.split(':')[0]}:${imageTag}`;
140
+
141
+ try {
142
+ execSync(
143
+ `${sandboxCommand} build ${buildCommandArgs} ${
144
+ process.env.BUILD_SANDBOX_FLAGS || ''
145
+ } --build-arg CLI_VERSION_ARG=${npmPackageVersion} -f "${dockerfile}" -t "${finalImageName}" .`,
146
+ { stdio: buildStdout, shell: shellToUse },
147
+ );
148
+ console.log(`built ${finalImageName}`);
149
+
150
+ // If an output file path was provided via command-line, write the final image URI to it.
151
+ if (argv.outputFile) {
152
+ console.log(
153
+ `Writing final image URI for CI artifact to: ${argv.outputFile}`,
154
+ );
155
+ // The publish step only supports one image. If we build multiple, only the last one
156
+ // will be published. Throw an error to make this failure explicit if the file already exists.
157
+ if (existsSync(argv.outputFile)) {
158
+ throw new Error(
159
+ `CI artifact file ${argv.outputFile} already exists. Refusing to overwrite.`,
160
+ );
161
+ }
162
+ writeFileSync(argv.outputFile, finalImageName);
163
+ }
164
+ } finally {
165
+ // If we created a temp file, delete it now.
166
+ if (tempAuthFile) {
167
+ rmSync(tempAuthFile, { force: true });
168
+ }
169
+ }
170
+ }
171
+
172
+ buildImage(image, dockerFile);
173
+
174
+ 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