fss-link 1.6.1 → 1.6.12
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/LICENSE +1 -0
- package/README.md +63 -316
- package/bundle/fss-link.js +4038 -134262
- package/docs/CONFIGURATION.md +200 -0
- package/docs/README.md +192 -0
- package/docs/TOOLS.md +268 -0
- package/docs/assets/batch_0001_fss-link-terminal-interface.png +0 -0
- package/docs/assets/batch_0002_multiprovider-connection-hub-a.png +0 -0
- package/docs/assets/batch_0003_database-persistence-system-a.png +0 -0
- package/docs/assets/batch_0004_context-window-compression-a.png +0 -0
- package/docs/assets/batch_0005_file-operations-with-safety.png +0 -0
- package/docs/assets/batch_0006_semantic-search-rag-system.png +0 -0
- package/docs/assets/batch_0008_document-parsing-suite-a.png +0 -0
- package/docs/assets/batch_0009_web-research-tools-a.png +0 -0
- package/docs/assets/batch_0010_texttospeech-voice-output-a.png +0 -0
- package/docs/assets/batch_0011_shell-command-execution-a.png +0 -0
- package/docs/assets/batch_0012_mcp-extension-system-a.png +0 -0
- package/docs/assets/batch_0014_approval-mode-switches-a.png +0 -0
- package/docs/assets/batch_0015_folder-trust-system-a.png +0 -0
- package/package.json +53 -38
- package/scripts/check-publish.js +2 -1
- package/scripts/install-linux.sh +1 -2
- package/scripts/install-macos.sh +1 -2
- package/scripts/install-windows.ps1 +1 -2
- package/scripts/prebundle-sync-dist.js +51 -0
- package/README.pdf +0 -0
- package/scripts/analyze-session-logs.sh +0 -279
- package/scripts/emergency-kill-all-tests.sh +0 -95
- package/scripts/emergency-kill-vitest.sh +0 -95
- package/scripts/extract-session-logs.sh +0 -202
- package/scripts/get-previous-tag.js +0 -213
- package/scripts/get-release-version.js +0 -119
- package/scripts/index-session-logs.sh +0 -173
- package/scripts/local_telemetry.js +0 -219
- package/scripts/memory-monitor.sh +0 -165
- package/scripts/process-session-log.py +0 -302
- package/scripts/quick-install.sh +0 -195
- package/scripts/telemetry_gcp.js +0 -188
- package/scripts/telemetry_utils.js +0 -421
- package/scripts/test-windows-paths.js +0 -51
- package/scripts/tests/get-release-version.test.js +0 -110
- package/scripts/tests/test-setup.ts +0 -12
- package/scripts/tests/vitest.config.ts +0 -20
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# FSS Link Session Log RAG Indexer
|
|
3
|
-
# Indexes processed session logs with FSS-RAG for powerful searching
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
# Configuration
|
|
8
|
-
PROCESSED_DIR="/MASTERFOLDER/Projects/fss-link/fss-live-testing/session-logs/processed"
|
|
9
|
-
COLLECTION_NAME="fss-link-sessions"
|
|
10
|
-
|
|
11
|
-
# Colors
|
|
12
|
-
RED='\033[0;31m'
|
|
13
|
-
GREEN='\033[0;32m'
|
|
14
|
-
YELLOW='\033[1;33m'
|
|
15
|
-
BLUE='\033[0;34m'
|
|
16
|
-
NC='\033[0m'
|
|
17
|
-
|
|
18
|
-
usage() {
|
|
19
|
-
cat << EOF
|
|
20
|
-
Usage: $0 [OPTIONS]
|
|
21
|
-
|
|
22
|
-
Index FSS Link session logs with RAG for semantic searching.
|
|
23
|
-
|
|
24
|
-
OPTIONS:
|
|
25
|
-
-r, --reindex Recreate index from scratch
|
|
26
|
-
-u, --update Add new sessions to existing index
|
|
27
|
-
-s, --status Show index status
|
|
28
|
-
-h, --help Show this help message
|
|
29
|
-
|
|
30
|
-
EXAMPLES:
|
|
31
|
-
$0 --reindex # Create fresh index of all sessions
|
|
32
|
-
$0 --update # Add new sessions to index
|
|
33
|
-
$0 --status # Check index status
|
|
34
|
-
|
|
35
|
-
After indexing, search with:
|
|
36
|
-
rag ${COLLECTION_NAME} "your query"
|
|
37
|
-
rag-all "your query" # Search all collections
|
|
38
|
-
|
|
39
|
-
EOF
|
|
40
|
-
exit 1
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
check_rag() {
|
|
44
|
-
if ! command -v rag-index &> /dev/null; then
|
|
45
|
-
echo -e "${RED}Error: rag-index command not found${NC}"
|
|
46
|
-
echo "FSS-RAG system must be installed and accessible"
|
|
47
|
-
exit 1
|
|
48
|
-
fi
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
show_status() {
|
|
52
|
-
echo -e "${BLUE}=== FSS Link Sessions Index Status ===${NC}\n"
|
|
53
|
-
|
|
54
|
-
# Check if collection exists
|
|
55
|
-
if rag-index list | grep -q "${COLLECTION_NAME}"; then
|
|
56
|
-
echo -e "${GREEN}✓${NC} Collection '${COLLECTION_NAME}' exists"
|
|
57
|
-
|
|
58
|
-
# Get collection details
|
|
59
|
-
rag-index status "${COLLECTION_NAME}" 2>/dev/null || echo " (Status unavailable)"
|
|
60
|
-
else
|
|
61
|
-
echo -e "${YELLOW}○${NC} Collection '${COLLECTION_NAME}' not yet created"
|
|
62
|
-
echo ""
|
|
63
|
-
echo "Run: $0 --reindex to create index"
|
|
64
|
-
fi
|
|
65
|
-
|
|
66
|
-
echo ""
|
|
67
|
-
|
|
68
|
-
# Count processed sessions
|
|
69
|
-
if [[ -d "${PROCESSED_DIR}" ]]; then
|
|
70
|
-
session_count=$(find "${PROCESSED_DIR}" -name "*.md" -type f | wc -l)
|
|
71
|
-
echo "Processed sessions available: ${session_count}"
|
|
72
|
-
else
|
|
73
|
-
echo -e "${RED}No processed sessions directory found${NC}"
|
|
74
|
-
fi
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
reindex_all() {
|
|
78
|
-
echo -e "${BLUE}=== Reindexing FSS Link Sessions ===${NC}\n"
|
|
79
|
-
|
|
80
|
-
if [[ ! -d "${PROCESSED_DIR}" ]]; then
|
|
81
|
-
echo -e "${RED}Error: Processed sessions directory not found: ${PROCESSED_DIR}${NC}"
|
|
82
|
-
exit 1
|
|
83
|
-
fi
|
|
84
|
-
|
|
85
|
-
# Count sessions
|
|
86
|
-
session_count=$(find "${PROCESSED_DIR}" -name "*.md" -type f | wc -l)
|
|
87
|
-
|
|
88
|
-
if [[ ${session_count} -eq 0 ]]; then
|
|
89
|
-
echo -e "${YELLOW}No processed sessions found to index${NC}"
|
|
90
|
-
echo "Run extract-session-logs.sh first to process session logs"
|
|
91
|
-
exit 1
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
echo "Found ${session_count} processed sessions"
|
|
95
|
-
echo ""
|
|
96
|
-
|
|
97
|
-
# Check if collection exists
|
|
98
|
-
if rag-index list | grep -q "${COLLECTION_NAME}"; then
|
|
99
|
-
echo -e "${YELLOW}Warning: Collection '${COLLECTION_NAME}' already exists${NC}"
|
|
100
|
-
echo -n "Delete and recreate? (y/N): "
|
|
101
|
-
read -r confirm
|
|
102
|
-
if [[ ! "${confirm}" =~ ^[Yy]$ ]]; then
|
|
103
|
-
echo "Cancelled"
|
|
104
|
-
exit 0
|
|
105
|
-
fi
|
|
106
|
-
echo ""
|
|
107
|
-
fi
|
|
108
|
-
|
|
109
|
-
# Create index
|
|
110
|
-
echo -e "${BLUE}Creating RAG index...${NC}"
|
|
111
|
-
echo ""
|
|
112
|
-
|
|
113
|
-
cd "${PROCESSED_DIR}" || exit 1
|
|
114
|
-
|
|
115
|
-
# Run rag-index with confirmation flag for non-interactive use
|
|
116
|
-
if rag-index create . --confirm 2>&1; then
|
|
117
|
-
echo ""
|
|
118
|
-
echo -e "${GREEN}✓${NC} Successfully indexed ${session_count} sessions"
|
|
119
|
-
echo ""
|
|
120
|
-
echo -e "${YELLOW}Next steps:${NC}"
|
|
121
|
-
echo " 1. Search sessions: rag ${COLLECTION_NAME} 'your query'"
|
|
122
|
-
echo " 2. Check status: $0 --status"
|
|
123
|
-
echo " 3. Analyze: analyze-session-logs.sh stats"
|
|
124
|
-
else
|
|
125
|
-
echo ""
|
|
126
|
-
echo -e "${RED}✗${NC} Indexing failed"
|
|
127
|
-
exit 1
|
|
128
|
-
fi
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
update_index() {
|
|
132
|
-
echo -e "${BLUE}=== Updating FSS Link Sessions Index ===${NC}\n"
|
|
133
|
-
|
|
134
|
-
# Check if collection exists
|
|
135
|
-
if ! rag-index list | grep -q "${COLLECTION_NAME}"; then
|
|
136
|
-
echo -e "${YELLOW}Collection '${COLLECTION_NAME}' doesn't exist yet${NC}"
|
|
137
|
-
echo "Run: $0 --reindex to create initial index"
|
|
138
|
-
exit 1
|
|
139
|
-
fi
|
|
140
|
-
|
|
141
|
-
echo "This feature requires manual re-indexing currently"
|
|
142
|
-
echo "Run: $0 --reindex to recreate the entire index"
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
# Main execution
|
|
146
|
-
main() {
|
|
147
|
-
check_rag
|
|
148
|
-
|
|
149
|
-
if [[ $# -eq 0 ]]; then
|
|
150
|
-
usage
|
|
151
|
-
fi
|
|
152
|
-
|
|
153
|
-
case "$1" in
|
|
154
|
-
-r|--reindex)
|
|
155
|
-
reindex_all
|
|
156
|
-
;;
|
|
157
|
-
-u|--update)
|
|
158
|
-
update_index
|
|
159
|
-
;;
|
|
160
|
-
-s|--status)
|
|
161
|
-
show_status
|
|
162
|
-
;;
|
|
163
|
-
-h|--help)
|
|
164
|
-
usage
|
|
165
|
-
;;
|
|
166
|
-
*)
|
|
167
|
-
echo -e "${RED}Unknown option: $1${NC}"
|
|
168
|
-
usage
|
|
169
|
-
;;
|
|
170
|
-
esac
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
main "$@"
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @license
|
|
5
|
-
* Copyright 2025 Google LLC
|
|
6
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import fs from 'fs';
|
|
11
|
-
import { spawn, execSync } from 'child_process';
|
|
12
|
-
import { fileURLToPath } from 'url';
|
|
13
|
-
import {
|
|
14
|
-
BIN_DIR,
|
|
15
|
-
OTEL_DIR,
|
|
16
|
-
ensureBinary,
|
|
17
|
-
fileExists,
|
|
18
|
-
manageTelemetrySettings,
|
|
19
|
-
registerCleanup,
|
|
20
|
-
waitForPort,
|
|
21
|
-
} from './telemetry_utils.js';
|
|
22
|
-
|
|
23
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
-
const __dirname = path.dirname(__filename);
|
|
25
|
-
|
|
26
|
-
const OTEL_CONFIG_FILE = path.join(OTEL_DIR, 'collector-local.yaml');
|
|
27
|
-
const OTEL_LOG_FILE = path.join(OTEL_DIR, 'collector.log');
|
|
28
|
-
const JAEGER_LOG_FILE = path.join(OTEL_DIR, 'jaeger.log');
|
|
29
|
-
const JAEGER_PORT = 16686;
|
|
30
|
-
|
|
31
|
-
// This configuration is for the primary otelcol-contrib instance.
|
|
32
|
-
// It receives from the CLI on 4317, exports traces to Jaeger on 14317,
|
|
33
|
-
// and sends metrics/logs to the debug log.
|
|
34
|
-
const OTEL_CONFIG_CONTENT = `
|
|
35
|
-
receivers:
|
|
36
|
-
otlp:
|
|
37
|
-
protocols:
|
|
38
|
-
grpc:
|
|
39
|
-
endpoint: "localhost:4317"
|
|
40
|
-
processors:
|
|
41
|
-
batch:
|
|
42
|
-
timeout: 1s
|
|
43
|
-
exporters:
|
|
44
|
-
otlp:
|
|
45
|
-
endpoint: "localhost:14317"
|
|
46
|
-
tls:
|
|
47
|
-
insecure: true
|
|
48
|
-
debug:
|
|
49
|
-
verbosity: detailed
|
|
50
|
-
service:
|
|
51
|
-
telemetry:
|
|
52
|
-
logs:
|
|
53
|
-
level: "debug"
|
|
54
|
-
metrics:
|
|
55
|
-
level: "none"
|
|
56
|
-
pipelines:
|
|
57
|
-
traces:
|
|
58
|
-
receivers: [otlp]
|
|
59
|
-
processors: [batch]
|
|
60
|
-
exporters: [otlp]
|
|
61
|
-
metrics:
|
|
62
|
-
receivers: [otlp]
|
|
63
|
-
processors: [batch]
|
|
64
|
-
exporters: [debug]
|
|
65
|
-
logs:
|
|
66
|
-
receivers: [otlp]
|
|
67
|
-
processors: [batch]
|
|
68
|
-
exporters: [debug]
|
|
69
|
-
`;
|
|
70
|
-
|
|
71
|
-
async function main() {
|
|
72
|
-
// 1. Ensure binaries are available, downloading if necessary.
|
|
73
|
-
// Binaries are stored in the project's .fss-link/otel/bin directory
|
|
74
|
-
// to avoid modifying the user's system.
|
|
75
|
-
if (!fileExists(BIN_DIR)) fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
76
|
-
|
|
77
|
-
const otelcolPath = await ensureBinary(
|
|
78
|
-
'otelcol-contrib',
|
|
79
|
-
'open-telemetry/opentelemetry-collector-releases',
|
|
80
|
-
(version, platform, arch, ext) =>
|
|
81
|
-
`otelcol-contrib_${version}_${platform}_${arch}.${ext}`,
|
|
82
|
-
'otelcol-contrib',
|
|
83
|
-
false, // isJaeger = false
|
|
84
|
-
).catch((e) => {
|
|
85
|
-
console.error(`��� Error getting otelcol-contrib: ${e.message}`);
|
|
86
|
-
return null;
|
|
87
|
-
});
|
|
88
|
-
if (!otelcolPath) process.exit(1);
|
|
89
|
-
|
|
90
|
-
const jaegerPath = await ensureBinary(
|
|
91
|
-
'jaeger',
|
|
92
|
-
'jaegertracing/jaeger',
|
|
93
|
-
(version, platform, arch, ext) =>
|
|
94
|
-
`jaeger-${version}-${platform}-${arch}.${ext}`,
|
|
95
|
-
'jaeger',
|
|
96
|
-
true, // isJaeger = true
|
|
97
|
-
).catch((e) => {
|
|
98
|
-
console.error(`🛑 Error getting jaeger: ${e.message}`);
|
|
99
|
-
return null;
|
|
100
|
-
});
|
|
101
|
-
if (!jaegerPath) process.exit(1);
|
|
102
|
-
|
|
103
|
-
// 2. Kill any existing processes to ensure a clean start.
|
|
104
|
-
console.log('🧹 Cleaning up old processes and logs...');
|
|
105
|
-
try {
|
|
106
|
-
execSync('pkill -f "otelcol-contrib"');
|
|
107
|
-
console.log('✅ Stopped existing otelcol-contrib process.');
|
|
108
|
-
} catch (_e) {} // eslint-disable-line no-empty
|
|
109
|
-
try {
|
|
110
|
-
execSync('pkill -f "jaeger"');
|
|
111
|
-
console.log('✅ Stopped existing jaeger process.');
|
|
112
|
-
} catch (_e) {} // eslint-disable-line no-empty
|
|
113
|
-
try {
|
|
114
|
-
if (fileExists(OTEL_LOG_FILE)) fs.unlinkSync(OTEL_LOG_FILE);
|
|
115
|
-
console.log('✅ Deleted old collector log.');
|
|
116
|
-
} catch (e) {
|
|
117
|
-
if (e.code !== 'ENOENT') console.error(e);
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
if (fileExists(JAEGER_LOG_FILE)) fs.unlinkSync(JAEGER_LOG_FILE);
|
|
121
|
-
console.log('✅ Deleted old jaeger log.');
|
|
122
|
-
} catch (e) {
|
|
123
|
-
if (e.code !== 'ENOENT') console.error(e);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
let jaegerProcess, collectorProcess;
|
|
127
|
-
let jaegerLogFd, collectorLogFd;
|
|
128
|
-
|
|
129
|
-
const originalSandboxSetting = manageTelemetrySettings(
|
|
130
|
-
true,
|
|
131
|
-
'http://localhost:4317',
|
|
132
|
-
'local',
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
registerCleanup(
|
|
136
|
-
() => [jaegerProcess, collectorProcess],
|
|
137
|
-
() => [jaegerLogFd, collectorLogFd],
|
|
138
|
-
originalSandboxSetting,
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
if (!fileExists(OTEL_DIR)) fs.mkdirSync(OTEL_DIR, { recursive: true });
|
|
142
|
-
fs.writeFileSync(OTEL_CONFIG_FILE, OTEL_CONFIG_CONTENT);
|
|
143
|
-
console.log('📄 Wrote OTEL collector config.');
|
|
144
|
-
|
|
145
|
-
// Start Jaeger
|
|
146
|
-
console.log(`🚀 Starting Jaeger service... Logs: ${JAEGER_LOG_FILE}`);
|
|
147
|
-
jaegerLogFd = fs.openSync(JAEGER_LOG_FILE, 'a');
|
|
148
|
-
jaegerProcess = spawn(
|
|
149
|
-
jaegerPath,
|
|
150
|
-
['--set=receivers.otlp.protocols.grpc.endpoint=localhost:14317'],
|
|
151
|
-
{ stdio: ['ignore', jaegerLogFd, jaegerLogFd] },
|
|
152
|
-
);
|
|
153
|
-
console.log(`⏳ Waiting for Jaeger to start (PID: ${jaegerProcess.pid})...`);
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
await waitForPort(JAEGER_PORT);
|
|
157
|
-
console.log(`✅ Jaeger started successfully.`);
|
|
158
|
-
} catch (_) {
|
|
159
|
-
console.error(`🛑 Error: Jaeger failed to start on port ${JAEGER_PORT}.`);
|
|
160
|
-
if (jaegerProcess && jaegerProcess.pid) {
|
|
161
|
-
process.kill(jaegerProcess.pid, 'SIGKILL');
|
|
162
|
-
}
|
|
163
|
-
if (fileExists(JAEGER_LOG_FILE)) {
|
|
164
|
-
console.error('📄 Jaeger Log Output:');
|
|
165
|
-
console.error(fs.readFileSync(JAEGER_LOG_FILE, 'utf-8'));
|
|
166
|
-
}
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Start the primary OTEL collector
|
|
171
|
-
console.log(`🚀 Starting OTEL collector... Logs: ${OTEL_LOG_FILE}`);
|
|
172
|
-
collectorLogFd = fs.openSync(OTEL_LOG_FILE, 'a');
|
|
173
|
-
collectorProcess = spawn(otelcolPath, ['--config', OTEL_CONFIG_FILE], {
|
|
174
|
-
stdio: ['ignore', collectorLogFd, collectorLogFd],
|
|
175
|
-
});
|
|
176
|
-
console.log(
|
|
177
|
-
`⏳ Waiting for OTEL collector to start (PID: ${collectorProcess.pid})...`,
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
await waitForPort(4317);
|
|
182
|
-
console.log(`✅ OTEL collector started successfully.`);
|
|
183
|
-
} catch (_) {
|
|
184
|
-
console.error(`🛑 Error: OTEL collector failed to start on port 4317.`);
|
|
185
|
-
if (collectorProcess && collectorProcess.pid) {
|
|
186
|
-
process.kill(collectorProcess.pid, 'SIGKILL');
|
|
187
|
-
}
|
|
188
|
-
if (fileExists(OTEL_LOG_FILE)) {
|
|
189
|
-
console.error('📄 OTEL Collector Log Output:');
|
|
190
|
-
console.error(fs.readFileSync(OTEL_LOG_FILE, 'utf-8'));
|
|
191
|
-
}
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
[jaegerProcess, collectorProcess].forEach((proc) => {
|
|
196
|
-
if (proc) {
|
|
197
|
-
proc.on('error', (err) => {
|
|
198
|
-
console.error(`${proc.spawnargs[0]} process error:`, err);
|
|
199
|
-
process.exit(1);
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
console.log(`
|
|
205
|
-
✨ Local telemetry environment is running.`);
|
|
206
|
-
console.log(
|
|
207
|
-
`
|
|
208
|
-
🔎 View traces in the Jaeger UI: http://localhost:${JAEGER_PORT}`,
|
|
209
|
-
);
|
|
210
|
-
console.log(`📊 View metrics in the logs and metrics: ${OTEL_LOG_FILE}`);
|
|
211
|
-
console.log(
|
|
212
|
-
`
|
|
213
|
-
📄 Tail logs and metrics in another terminal: tail -f ${OTEL_LOG_FILE}`,
|
|
214
|
-
);
|
|
215
|
-
console.log(`
|
|
216
|
-
Press Ctrl+C to exit.`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
main();
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# 📊 Memory Monitor for Test Processes
|
|
4
|
-
# Purpose: Monitor memory usage during tests and auto-kill if dangerous
|
|
5
|
-
# Usage: ./scripts/memory-monitor.sh [--auto-kill] [--threshold-gb=8]
|
|
6
|
-
|
|
7
|
-
# Default settings
|
|
8
|
-
AUTO_KILL=false
|
|
9
|
-
THRESHOLD_GB=8
|
|
10
|
-
INTERVAL=5
|
|
11
|
-
|
|
12
|
-
# Colors
|
|
13
|
-
RED='\033[0;31m'
|
|
14
|
-
YELLOW='\033[1;33m'
|
|
15
|
-
GREEN='\033[0;32m'
|
|
16
|
-
BLUE='\033[0;34m'
|
|
17
|
-
NC='\033[0m'
|
|
18
|
-
|
|
19
|
-
# Parse arguments
|
|
20
|
-
for arg in "$@"; do
|
|
21
|
-
case $arg in
|
|
22
|
-
--auto-kill)
|
|
23
|
-
AUTO_KILL=true
|
|
24
|
-
shift
|
|
25
|
-
;;
|
|
26
|
-
--threshold-gb=*)
|
|
27
|
-
THRESHOLD_GB="${arg#*=}"
|
|
28
|
-
shift
|
|
29
|
-
;;
|
|
30
|
-
--interval=*)
|
|
31
|
-
INTERVAL="${arg#*=}"
|
|
32
|
-
shift
|
|
33
|
-
;;
|
|
34
|
-
--help)
|
|
35
|
-
echo "Memory Monitor for Test Processes"
|
|
36
|
-
echo ""
|
|
37
|
-
echo "Usage: $0 [options]"
|
|
38
|
-
echo ""
|
|
39
|
-
echo "Options:"
|
|
40
|
-
echo " --auto-kill Automatically kill processes exceeding threshold"
|
|
41
|
-
echo " --threshold-gb=N Memory threshold in GB (default: 8)"
|
|
42
|
-
echo " --interval=N Check interval in seconds (default: 5)"
|
|
43
|
-
echo " --help Show this help"
|
|
44
|
-
echo ""
|
|
45
|
-
echo "Examples:"
|
|
46
|
-
echo " $0 # Monitor only"
|
|
47
|
-
echo " $0 --auto-kill # Monitor and auto-kill at 8GB"
|
|
48
|
-
echo " $0 --auto-kill --threshold-gb=4 # Auto-kill at 4GB"
|
|
49
|
-
exit 0
|
|
50
|
-
;;
|
|
51
|
-
esac
|
|
52
|
-
done
|
|
53
|
-
|
|
54
|
-
THRESHOLD_KB=$((THRESHOLD_GB * 1024 * 1024))
|
|
55
|
-
|
|
56
|
-
echo -e "${BLUE}📊 FSS Link Memory Monitor${NC}"
|
|
57
|
-
echo -e "${YELLOW}Threshold: ${THRESHOLD_GB}GB | Auto-kill: ${AUTO_KILL} | Interval: ${INTERVAL}s${NC}"
|
|
58
|
-
echo -e "${YELLOW}Press Ctrl+C to stop monitoring${NC}"
|
|
59
|
-
echo ""
|
|
60
|
-
|
|
61
|
-
# Function to format memory
|
|
62
|
-
format_memory() {
|
|
63
|
-
local kb=$1
|
|
64
|
-
if [ $kb -gt 1048576 ]; then
|
|
65
|
-
echo "$((kb / 1024 / 1024))GB"
|
|
66
|
-
elif [ $kb -gt 1024 ]; then
|
|
67
|
-
echo "$((kb / 1024))MB"
|
|
68
|
-
else
|
|
69
|
-
echo "${kb}KB"
|
|
70
|
-
fi
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
# Function to kill dangerous processes
|
|
74
|
-
kill_dangerous_processes() {
|
|
75
|
-
local pids="$1"
|
|
76
|
-
echo -e "${RED}🚨 EMERGENCY: Memory threshold exceeded!${NC}"
|
|
77
|
-
echo -e "${RED}💀 Killing dangerous processes...${NC}"
|
|
78
|
-
|
|
79
|
-
for pid in $pids; do
|
|
80
|
-
if [ -n "$pid" ]; then
|
|
81
|
-
kill -KILL "$pid" 2>/dev/null && echo "Killed PID $pid" || true
|
|
82
|
-
fi
|
|
83
|
-
done
|
|
84
|
-
|
|
85
|
-
# Run the emergency script as backup
|
|
86
|
-
echo -e "${YELLOW}Running emergency cleanup...${NC}"
|
|
87
|
-
./scripts/emergency-kill-vitest.sh --force
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# Monitoring loop
|
|
91
|
-
while true; do
|
|
92
|
-
clear
|
|
93
|
-
echo -e "${BLUE}📊 FSS Link Memory Monitor - $(date)${NC}"
|
|
94
|
-
echo -e "${YELLOW}Threshold: ${THRESHOLD_GB}GB | Auto-kill: ${AUTO_KILL}${NC}"
|
|
95
|
-
echo ""
|
|
96
|
-
|
|
97
|
-
# System memory overview
|
|
98
|
-
echo -e "${GREEN}💻 System Memory:${NC}"
|
|
99
|
-
free -h
|
|
100
|
-
echo ""
|
|
101
|
-
|
|
102
|
-
# Find test processes
|
|
103
|
-
TEST_PIDS=$(pgrep -f "vitest\|node.*test\|jest\|mocha" 2>/dev/null || true)
|
|
104
|
-
|
|
105
|
-
if [ -z "$TEST_PIDS" ]; then
|
|
106
|
-
echo -e "${GREEN}✅ No test processes running${NC}"
|
|
107
|
-
else
|
|
108
|
-
echo -e "${YELLOW}🧪 Test Processes:${NC}"
|
|
109
|
-
printf "%-8s %-8s %-10s %-10s %s\n" "PID" "CPU%" "MEMORY" "STATUS" "COMMAND"
|
|
110
|
-
echo "────────────────────────────────────────────────────────────────"
|
|
111
|
-
|
|
112
|
-
DANGEROUS_PIDS=""
|
|
113
|
-
TOTAL_TEST_MEMORY=0
|
|
114
|
-
|
|
115
|
-
for pid in $TEST_PIDS; do
|
|
116
|
-
if [ -n "$pid" ]; then
|
|
117
|
-
# Get process info
|
|
118
|
-
if ps -p "$pid" > /dev/null 2>&1; then
|
|
119
|
-
INFO=$(ps -p "$pid" -o pid,%cpu,rss,comm --no-headers 2>/dev/null)
|
|
120
|
-
if [ -n "$INFO" ]; then
|
|
121
|
-
MEMORY_KB=$(echo "$INFO" | awk '{print $3}')
|
|
122
|
-
CPU=$(echo "$INFO" | awk '{print $2}')
|
|
123
|
-
COMMAND=$(echo "$INFO" | awk '{print $4}')
|
|
124
|
-
|
|
125
|
-
TOTAL_TEST_MEMORY=$((TOTAL_TEST_MEMORY + MEMORY_KB))
|
|
126
|
-
|
|
127
|
-
# Format memory for display
|
|
128
|
-
MEMORY_DISPLAY=$(format_memory $MEMORY_KB)
|
|
129
|
-
|
|
130
|
-
# Check if dangerous
|
|
131
|
-
STATUS="OK"
|
|
132
|
-
if [ $MEMORY_KB -gt $THRESHOLD_KB ]; then
|
|
133
|
-
STATUS="${RED}DANGER${NC}"
|
|
134
|
-
DANGEROUS_PIDS="$DANGEROUS_PIDS $pid"
|
|
135
|
-
elif [ $MEMORY_KB -gt $((THRESHOLD_KB / 2)) ]; then
|
|
136
|
-
STATUS="${YELLOW}WARNING${NC}"
|
|
137
|
-
else
|
|
138
|
-
STATUS="${GREEN}OK${NC}"
|
|
139
|
-
fi
|
|
140
|
-
|
|
141
|
-
printf "%-8s %-8s %-10s %-20s %s\n" "$pid" "$CPU%" "$MEMORY_DISPLAY" "$STATUS" "$COMMAND"
|
|
142
|
-
fi
|
|
143
|
-
fi
|
|
144
|
-
fi
|
|
145
|
-
done
|
|
146
|
-
|
|
147
|
-
echo ""
|
|
148
|
-
echo -e "${BLUE}📈 Total Test Memory: $(format_memory $TOTAL_TEST_MEMORY)${NC}"
|
|
149
|
-
|
|
150
|
-
# Check for auto-kill
|
|
151
|
-
if [ "$AUTO_KILL" = true ] && [ -n "$DANGEROUS_PIDS" ]; then
|
|
152
|
-
kill_dangerous_processes "$DANGEROUS_PIDS"
|
|
153
|
-
break
|
|
154
|
-
elif [ -n "$DANGEROUS_PIDS" ]; then
|
|
155
|
-
echo ""
|
|
156
|
-
echo -e "${RED}⚠️ DANGEROUS processes detected!${NC}"
|
|
157
|
-
echo -e "${YELLOW}Run with --auto-kill to automatically terminate them${NC}"
|
|
158
|
-
echo -e "${YELLOW}Or manually run: ./scripts/emergency-kill-vitest.sh${NC}"
|
|
159
|
-
fi
|
|
160
|
-
fi
|
|
161
|
-
|
|
162
|
-
echo ""
|
|
163
|
-
echo -e "${BLUE}Next check in ${INTERVAL} seconds... (Ctrl+C to stop)${NC}"
|
|
164
|
-
sleep $INTERVAL
|
|
165
|
-
done
|