fss-link 1.5.7 → 1.6.0
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 +1 -1
- package/bundle/fss-link.js +4785 -3183
- package/package.json +4 -1
- package/scripts/analyze-session-logs.sh +279 -0
- package/scripts/build.js +55 -0
- package/scripts/build_package.js +37 -0
- package/scripts/build_sandbox.js +195 -0
- package/scripts/build_vscode_companion.js +30 -0
- package/scripts/check-build-status.js +148 -0
- package/scripts/check-publish.js +101 -0
- package/scripts/clean.js +55 -0
- package/scripts/copy_bundle_assets.js +40 -0
- package/scripts/copy_files.js +56 -0
- package/scripts/create_alias.sh +39 -0
- package/scripts/emergency-kill-all-tests.sh +95 -0
- package/scripts/emergency-kill-vitest.sh +95 -0
- package/scripts/extract-session-logs.sh +202 -0
- package/scripts/generate-git-commit-info.js +71 -0
- package/scripts/get-previous-tag.js +213 -0
- package/scripts/get-release-version.js +119 -0
- package/scripts/index-session-logs.sh +173 -0
- package/scripts/install-linux.sh +294 -0
- package/scripts/install-macos.sh +343 -0
- package/scripts/install-windows.ps1 +427 -0
- package/scripts/local_telemetry.js +219 -0
- package/scripts/memory-monitor.sh +165 -0
- package/scripts/postinstall-message.js +31 -0
- package/scripts/prepare-package.js +51 -0
- package/scripts/process-session-log.py +302 -0
- package/scripts/quick-install.sh +195 -0
- package/scripts/sandbox_command.js +126 -0
- package/scripts/start.js +76 -0
- package/scripts/telemetry.js +85 -0
- package/scripts/telemetry_gcp.js +188 -0
- package/scripts/telemetry_utils.js +421 -0
- package/scripts/test-windows-paths.js +51 -0
- package/scripts/tests/get-release-version.test.js +110 -0
- package/scripts/tests/test-setup.ts +12 -0
- package/scripts/tests/vitest.config.ts +20 -0
- package/scripts/version.js +83 -0
|
@@ -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 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from '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
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-publish safety check for FSS Link
|
|
4
|
+
* Ensures we're publishing from the correct location with a valid bundle
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
13
|
+
|
|
14
|
+
console.log('🔍 FSS Link Pre-Publish Safety Check');
|
|
15
|
+
console.log('=====================================\n');
|
|
16
|
+
|
|
17
|
+
let errors = 0;
|
|
18
|
+
|
|
19
|
+
// Check 1: Publishing from project root, not packages/
|
|
20
|
+
if (process.cwd().includes('packages')) {
|
|
21
|
+
console.error('❌ ERROR: Must publish from project root, not packages/!');
|
|
22
|
+
console.error(' Current directory: ' + process.cwd());
|
|
23
|
+
console.error(' Run: cd ' + projectRoot + ' && npm publish\n');
|
|
24
|
+
errors++;
|
|
25
|
+
} else {
|
|
26
|
+
console.log('✅ Publishing from project root');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check 2: Bundle exists
|
|
30
|
+
const bundlePath = path.join(projectRoot, 'bundle/fss-link.js');
|
|
31
|
+
if (!fs.existsSync(bundlePath)) {
|
|
32
|
+
console.error('❌ ERROR: bundle/fss-link.js not found');
|
|
33
|
+
console.error(' Run: npm run bundle\n');
|
|
34
|
+
errors++;
|
|
35
|
+
} else {
|
|
36
|
+
console.log('✅ Bundle exists');
|
|
37
|
+
|
|
38
|
+
// Check 3: Bundle is executable
|
|
39
|
+
const stats = fs.statSync(bundlePath);
|
|
40
|
+
if (!(stats.mode & 0o111)) {
|
|
41
|
+
console.error('❌ ERROR: Bundle is not executable');
|
|
42
|
+
console.error(' Run: chmod +x bundle/fss-link.js\n');
|
|
43
|
+
errors++;
|
|
44
|
+
} else {
|
|
45
|
+
console.log('✅ Bundle is executable');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check 4: Bundle has shebang
|
|
49
|
+
const firstLine = fs.readFileSync(bundlePath, 'utf8').split('\n')[0];
|
|
50
|
+
if (firstLine !== '#!/usr/bin/env node') {
|
|
51
|
+
console.error('❌ ERROR: Bundle missing shebang line');
|
|
52
|
+
console.error(' Expected: #!/usr/bin/env node');
|
|
53
|
+
console.error(' Got: ' + firstLine + '\n');
|
|
54
|
+
errors++;
|
|
55
|
+
} else {
|
|
56
|
+
console.log('✅ Bundle has correct shebang');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check 5: Bundle size is reasonable (> 1MB)
|
|
60
|
+
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
61
|
+
if (stats.size < 1024 * 1024) {
|
|
62
|
+
console.error(`❌ ERROR: Bundle suspiciously small (${sizeMB} MB)`);
|
|
63
|
+
console.error(' Expected: > 1 MB');
|
|
64
|
+
console.error(' This may indicate an incomplete build\n');
|
|
65
|
+
errors++;
|
|
66
|
+
} else {
|
|
67
|
+
console.log(`✅ Bundle size reasonable (${sizeMB} MB)`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check 6: Version in bundle matches package.json
|
|
72
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
73
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
74
|
+
if (fs.existsSync(bundlePath)) {
|
|
75
|
+
const bundleContent = fs.readFileSync(bundlePath, 'utf8');
|
|
76
|
+
// Check for version in various formats: "version":"1.2.8", version = "1.2.8", etc.
|
|
77
|
+
const versionPatterns = [
|
|
78
|
+
`"version":"${pkg.version}"`,
|
|
79
|
+
`version = "${pkg.version}"`,
|
|
80
|
+
`'version':'${pkg.version}'`,
|
|
81
|
+
];
|
|
82
|
+
const hasVersion = versionPatterns.some(pattern => bundleContent.includes(pattern));
|
|
83
|
+
|
|
84
|
+
if (!hasVersion) {
|
|
85
|
+
console.error(`❌ ERROR: Bundle version mismatch`);
|
|
86
|
+
console.error(` package.json: ${pkg.version}`);
|
|
87
|
+
console.error(` Bundle may have different version - rebuild with: npm run bundle\n`);
|
|
88
|
+
errors++;
|
|
89
|
+
} else {
|
|
90
|
+
console.log(`✅ Bundle version matches package.json (${pkg.version})`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log('\n=====================================');
|
|
95
|
+
if (errors > 0) {
|
|
96
|
+
console.error(`❌ ${errors} error(s) found - publish blocked\n`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
} else {
|
|
99
|
+
console.log('✅ All checks passed - safe to publish\n');
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
package/scripts/clean.js
ADDED
|
@@ -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 { rmSync, readFileSync } from 'fs';
|
|
21
|
+
import { dirname, join } from 'path';
|
|
22
|
+
import { fileURLToPath } from 'url';
|
|
23
|
+
import { globSync } from 'glob';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const root = join(__dirname, '..');
|
|
27
|
+
|
|
28
|
+
// remove npm install/build artifacts
|
|
29
|
+
rmSync(join(root, 'node_modules'), { recursive: true, force: true });
|
|
30
|
+
rmSync(join(root, 'bundle'), { recursive: true, force: true });
|
|
31
|
+
rmSync(join(root, 'packages/cli/src/generated/'), {
|
|
32
|
+
recursive: true,
|
|
33
|
+
force: true,
|
|
34
|
+
});
|
|
35
|
+
const RMRF_OPTIONS = { recursive: true, force: true };
|
|
36
|
+
rmSync(join(root, 'bundle'), RMRF_OPTIONS);
|
|
37
|
+
// Dynamically clean dist directories in all workspaces
|
|
38
|
+
const rootPackageJson = JSON.parse(
|
|
39
|
+
readFileSync(join(root, 'package.json'), 'utf-8'),
|
|
40
|
+
);
|
|
41
|
+
for (const workspace of rootPackageJson.workspaces) {
|
|
42
|
+
const packages = globSync(join(workspace, 'package.json'), { cwd: root });
|
|
43
|
+
for (const pkgPath of packages) {
|
|
44
|
+
const pkgDir = dirname(join(root, pkgPath));
|
|
45
|
+
rmSync(join(pkgDir, 'dist'), RMRF_OPTIONS);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Clean up vsix files in vscode-ide-companion
|
|
50
|
+
const vsixFiles = globSync('packages/vscode-ide-companion/*.vsix', {
|
|
51
|
+
cwd: root,
|
|
52
|
+
});
|
|
53
|
+
for (const vsixFile of vsixFiles) {
|
|
54
|
+
rmSync(join(root, vsixFile), RMRF_OPTIONS);
|
|
55
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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 { copyFileSync, existsSync, mkdirSync } from 'fs';
|
|
21
|
+
import { dirname, join, basename } from 'path';
|
|
22
|
+
import { fileURLToPath } from 'url';
|
|
23
|
+
import { glob } from 'glob';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const root = join(__dirname, '..');
|
|
27
|
+
const bundleDir = join(root, 'bundle');
|
|
28
|
+
|
|
29
|
+
// Create the bundle directory if it doesn't exist
|
|
30
|
+
if (!existsSync(bundleDir)) {
|
|
31
|
+
mkdirSync(bundleDir);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Find and copy all .sb files from packages to the root of the bundle directory
|
|
35
|
+
const sbFiles = glob.sync('packages/**/*.sb', { cwd: root });
|
|
36
|
+
for (const file of sbFiles) {
|
|
37
|
+
copyFileSync(join(root, file), join(bundleDir, basename(file)));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log('Assets copied to bundle/');
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2025 Google LLC
|
|
6
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Copyright 2025 Google LLC
|
|
10
|
+
//
|
|
11
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
// you may not use this file except in compliance with the License.
|
|
13
|
+
// You may obtain a copy of the License at
|
|
14
|
+
//
|
|
15
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
//
|
|
17
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
// See the License for the specific language governing permissions and
|
|
21
|
+
// limitations under the License.
|
|
22
|
+
|
|
23
|
+
import fs from 'fs';
|
|
24
|
+
import path from 'path';
|
|
25
|
+
|
|
26
|
+
const sourceDir = path.join('src');
|
|
27
|
+
const targetDir = path.join('dist', 'src');
|
|
28
|
+
|
|
29
|
+
const extensionsToCopy = ['.md', '.json', '.sb'];
|
|
30
|
+
|
|
31
|
+
function copyFilesRecursive(source, target) {
|
|
32
|
+
if (!fs.existsSync(target)) {
|
|
33
|
+
fs.mkdirSync(target, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const items = fs.readdirSync(source, { withFileTypes: true });
|
|
37
|
+
|
|
38
|
+
for (const item of items) {
|
|
39
|
+
const sourcePath = path.join(source, item.name);
|
|
40
|
+
const targetPath = path.join(target, item.name);
|
|
41
|
+
|
|
42
|
+
if (item.isDirectory()) {
|
|
43
|
+
copyFilesRecursive(sourcePath, targetPath);
|
|
44
|
+
} else if (extensionsToCopy.includes(path.extname(item.name))) {
|
|
45
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(sourceDir)) {
|
|
51
|
+
console.error(`Source directory ${sourceDir} not found.`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
copyFilesRecursive(sourceDir, targetDir);
|
|
56
|
+
console.log('Successfully copied files.');
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# This script creates an alias for the Gemini CLI
|
|
5
|
+
|
|
6
|
+
# Determine the project directory
|
|
7
|
+
PROJECT_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
|
8
|
+
ALIAS_COMMAND="alias qwen='node "${PROJECT_DIR}/scripts/start.js"'"
|
|
9
|
+
|
|
10
|
+
# Detect shell and set config file path
|
|
11
|
+
if [[ "${SHELL}" == *"/bash" ]]; then
|
|
12
|
+
CONFIG_FILE="${HOME}/.bashrc"
|
|
13
|
+
elif [[ "${SHELL}" == *"/zsh" ]]; then
|
|
14
|
+
CONFIG_FILE="${HOME}/.zshrc"
|
|
15
|
+
else
|
|
16
|
+
echo "Unsupported shell. Only bash and zsh are supported."
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo "This script will add the following alias to your shell configuration file (${CONFIG_FILE}):"
|
|
21
|
+
echo " ${ALIAS_COMMAND}"
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
# Check if the alias already exists
|
|
25
|
+
if grep -q "alias qwen=" "${CONFIG_FILE}"; then
|
|
26
|
+
echo "A 'qwen' alias already exists in ${CONFIG_FILE}. No changes were made."
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
read -p "Do you want to proceed? (y/n) " -n 1 -r
|
|
31
|
+
echo ""
|
|
32
|
+
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
|
|
33
|
+
echo "${ALIAS_COMMAND}" >> "${CONFIG_FILE}"
|
|
34
|
+
echo ""
|
|
35
|
+
echo "Alias added to ${CONFIG_FILE}."
|
|
36
|
+
echo "Please run 'source ${CONFIG_FILE}' or open a new terminal to use the 'qwen' command."
|
|
37
|
+
else
|
|
38
|
+
echo "Aborted. No changes were made."
|
|
39
|
+
fi
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 🚨 NUCLEAR OPTION: Kill ALL test-related processes
|
|
4
|
+
# Purpose: Emergency system recovery when tests cripple the PC
|
|
5
|
+
# Usage: ./scripts/emergency-kill-all-tests.sh
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
NC='\033[0m'
|
|
13
|
+
|
|
14
|
+
echo -e "${RED}💣 NUCLEAR TEST KILLER - EMERGENCY SYSTEM RECOVERY${NC}"
|
|
15
|
+
echo -e "${YELLOW}⚠️ This will kill ALL Node.js test processes immediately${NC}"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# Find all test-related processes
|
|
19
|
+
echo "Scanning for dangerous processes..."
|
|
20
|
+
|
|
21
|
+
# More comprehensive process detection
|
|
22
|
+
VITEST_PIDS=$(pgrep -f "vitest" 2>/dev/null || true)
|
|
23
|
+
NODE_TEST_PIDS=$(pgrep -f "node.*test" 2>/dev/null || true)
|
|
24
|
+
JEST_PIDS=$(pgrep -f "jest" 2>/dev/null || true)
|
|
25
|
+
MOCHA_PIDS=$(pgrep -f "mocha" 2>/dev/null || true)
|
|
26
|
+
NODE_FSS_PIDS=$(pgrep -f "node.*fss-link" 2>/dev/null || true)
|
|
27
|
+
|
|
28
|
+
ALL_PIDS="${VITEST_PIDS} ${NODE_TEST_PIDS} ${JEST_PIDS} ${MOCHA_PIDS} ${NODE_FSS_PIDS}"
|
|
29
|
+
|
|
30
|
+
if [ -z "$(echo $ALL_PIDS | tr -d ' ')" ]; then
|
|
31
|
+
echo -e "${GREEN}✅ No test processes found${NC}"
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo -e "${RED}🎯 TARGETS IDENTIFIED:${NC}"
|
|
36
|
+
echo "$ALL_PIDS" | tr ' ' '\n' | while read -r pid; do
|
|
37
|
+
if [ -n "$pid" ] && [ "$pid" != " " ]; then
|
|
38
|
+
ps -p "$pid" -o pid,%cpu,%mem,cmd 2>/dev/null || true
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
echo ""
|
|
43
|
+
echo -e "${YELLOW}⚡ IMMEDIATE FORCE KILL - NO MERCY${NC}"
|
|
44
|
+
echo "Killing all processes with SIGKILL..."
|
|
45
|
+
|
|
46
|
+
# Nuclear option - kill everything immediately
|
|
47
|
+
for pid in $ALL_PIDS; do
|
|
48
|
+
if [ -n "$pid" ] && [ "$pid" != " " ]; then
|
|
49
|
+
kill -KILL "$pid" 2>/dev/null && echo "💀 KILLED PID $pid" || true
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
# Also kill any node processes using excessive memory (>1GB)
|
|
54
|
+
echo ""
|
|
55
|
+
echo -e "${YELLOW}🔍 Checking for memory hogs (>1GB)...${NC}"
|
|
56
|
+
ps aux --no-headers | awk '$6 > 1000000 && /node/ {print $2, $6/1024 "MB", $11}' | while read -r line; do
|
|
57
|
+
if [ -n "$line" ]; then
|
|
58
|
+
pid=$(echo "$line" | awk '{print $1}')
|
|
59
|
+
echo -e "${RED}Found memory hog: $line${NC}"
|
|
60
|
+
kill -KILL "$pid" 2>/dev/null && echo "💀 KILLED memory hog PID $pid" || true
|
|
61
|
+
fi
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
sleep 2
|
|
65
|
+
|
|
66
|
+
# Final verification
|
|
67
|
+
echo ""
|
|
68
|
+
echo -e "${GREEN}🔍 Final system check...${NC}"
|
|
69
|
+
SURVIVORS=$(pgrep -f "vitest\|jest\|mocha\|node.*test" 2>/dev/null || true)
|
|
70
|
+
if [ -n "$SURVIVORS" ]; then
|
|
71
|
+
echo -e "${RED}❌ SURVIVORS DETECTED:${NC}"
|
|
72
|
+
ps -p $SURVIVORS -o pid,%cpu,%mem,cmd 2>/dev/null || true
|
|
73
|
+
echo ""
|
|
74
|
+
echo -e "${YELLOW}Manual intervention required:${NC}"
|
|
75
|
+
echo "sudo kill -9 $SURVIVORS"
|
|
76
|
+
else
|
|
77
|
+
echo -e "${GREEN}🎉 MISSION ACCOMPLISHED - All test processes eliminated${NC}"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# System recovery commands
|
|
81
|
+
echo ""
|
|
82
|
+
echo -e "${GREEN}🚑 SYSTEM RECOVERY PROTOCOL:${NC}"
|
|
83
|
+
echo "1. Clear memory caches:"
|
|
84
|
+
echo " sync && echo 3 | sudo tee /proc/sys/vm/drop_caches"
|
|
85
|
+
echo ""
|
|
86
|
+
echo "2. Check available memory:"
|
|
87
|
+
echo " free -h"
|
|
88
|
+
echo ""
|
|
89
|
+
echo "3. Check system load:"
|
|
90
|
+
echo " uptime"
|
|
91
|
+
echo ""
|
|
92
|
+
echo "4. Monitor for zombies:"
|
|
93
|
+
echo " ps aux | grep defunct"
|
|
94
|
+
echo ""
|
|
95
|
+
echo -e "${YELLOW}System should be responsive now. Monitor for 30 seconds before resuming work.${NC}"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 🚨 EMERGENCY VITEST KILLER - System Recovery Script
|
|
4
|
+
# Purpose: Kill all vitest processes when they consume excessive memory
|
|
5
|
+
# Usage: ./scripts/emergency-kill-vitest.sh [--force]
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# Colors for output
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
echo -e "${RED}🚨 EMERGENCY VITEST KILLER ACTIVATED${NC}"
|
|
16
|
+
echo "Scanning for vitest processes..."
|
|
17
|
+
|
|
18
|
+
# Find all vitest-related processes
|
|
19
|
+
VITEST_PIDS=$(pgrep -f "vitest\|node.*test" 2>/dev/null || true)
|
|
20
|
+
NODE_TEST_PIDS=$(pgrep -f "node.*\.test\." 2>/dev/null || true)
|
|
21
|
+
ALL_PIDS="${VITEST_PIDS} ${NODE_TEST_PIDS}"
|
|
22
|
+
|
|
23
|
+
if [ -z "$ALL_PIDS" ]; then
|
|
24
|
+
echo -e "${GREEN}✅ No vitest processes found running${NC}"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
echo -e "${YELLOW}Found processes to kill:${NC}"
|
|
29
|
+
echo "$ALL_PIDS" | tr ' ' '\n' | while read -r pid; do
|
|
30
|
+
if [ -n "$pid" ]; then
|
|
31
|
+
ps -p "$pid" -o pid,ppid,%cpu,%mem,cmd 2>/dev/null || true
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
# Check for --force flag
|
|
36
|
+
if [ "$1" = "--force" ]; then
|
|
37
|
+
echo -e "${RED}🔥 FORCE MODE: Killing immediately...${NC}"
|
|
38
|
+
else
|
|
39
|
+
echo ""
|
|
40
|
+
echo -e "${YELLOW}⚠️ WARNING: This will kill ALL vitest and node test processes${NC}"
|
|
41
|
+
echo "Press ENTER to continue, or Ctrl+C to cancel..."
|
|
42
|
+
read -r
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Kill processes gracefully first (SIGTERM)
|
|
46
|
+
echo -e "${YELLOW}🔄 Attempting graceful shutdown (SIGTERM)...${NC}"
|
|
47
|
+
for pid in $ALL_PIDS; do
|
|
48
|
+
if [ -n "$pid" ]; then
|
|
49
|
+
kill -TERM "$pid" 2>/dev/null || true
|
|
50
|
+
echo "Sent SIGTERM to PID $pid"
|
|
51
|
+
fi
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# Wait 3 seconds for graceful shutdown
|
|
55
|
+
echo "Waiting 3 seconds for graceful shutdown..."
|
|
56
|
+
sleep 3
|
|
57
|
+
|
|
58
|
+
# Check what's still running
|
|
59
|
+
REMAINING_PIDS=$(pgrep -f "vitest\|node.*test" 2>/dev/null || true)
|
|
60
|
+
if [ -n "$REMAINING_PIDS" ]; then
|
|
61
|
+
echo -e "${RED}💀 Force killing remaining processes (SIGKILL)...${NC}"
|
|
62
|
+
for pid in $REMAINING_PIDS; do
|
|
63
|
+
if [ -n "$pid" ]; then
|
|
64
|
+
kill -KILL "$pid" 2>/dev/null || true
|
|
65
|
+
echo "Sent SIGKILL to PID $pid"
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
else
|
|
69
|
+
echo -e "${GREEN}✅ All processes terminated gracefully${NC}"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Final verification
|
|
73
|
+
sleep 1
|
|
74
|
+
FINAL_CHECK=$(pgrep -f "vitest\|node.*test" 2>/dev/null || true)
|
|
75
|
+
if [ -n "$FINAL_CHECK" ]; then
|
|
76
|
+
echo -e "${RED}❌ Some processes still running:${NC}"
|
|
77
|
+
echo "$FINAL_CHECK" | tr ' ' '\n' | while read -r pid; do
|
|
78
|
+
if [ -n "$pid" ]; then
|
|
79
|
+
ps -p "$pid" -o pid,ppid,%cpu,%mem,cmd 2>/dev/null || true
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
echo ""
|
|
83
|
+
echo -e "${YELLOW}💡 You may need to run: sudo kill -9 <PID>${NC}"
|
|
84
|
+
else
|
|
85
|
+
echo -e "${GREEN}🎉 SUCCESS: All vitest processes killed${NC}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Memory recovery suggestions
|
|
89
|
+
echo ""
|
|
90
|
+
echo -e "${YELLOW}🔧 Memory Recovery Suggestions:${NC}"
|
|
91
|
+
echo "1. Run: sync && echo 3 | sudo tee /proc/sys/vm/drop_caches"
|
|
92
|
+
echo "2. Check memory: free -h"
|
|
93
|
+
echo "3. Check for zombie processes: ps aux | grep defunct"
|
|
94
|
+
echo ""
|
|
95
|
+
echo -e "${GREEN}Emergency kill complete!${NC}"
|