fraim-framework 2.0.35 โ 2.0.36
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/bin/fraim.js +52 -5
- package/dist/registry/scripts/cleanup-branch.js +62 -33
- package/dist/registry/scripts/generate-engagement-emails.js +119 -44
- package/dist/registry/scripts/newsletter-helpers.js +208 -268
- package/dist/registry/scripts/profile-server.js +387 -0
- package/dist/tests/test-chalk-regression.js +18 -2
- package/dist/tests/test-client-scripts-validation.js +133 -0
- package/dist/tests/test-prep-issue.js +1 -34
- package/dist/tests/test-script-location-independence.js +76 -28
- package/package.json +2 -2
- package/registry/agent-guardrails.md +62 -62
- package/registry/rules/communication.md +121 -121
- package/registry/rules/continuous-learning.md +54 -54
- package/registry/rules/hitl-ppe-record-analysis.md +302 -302
- package/registry/rules/software-development-lifecycle.md +104 -104
- package/registry/scripts/cleanup-branch.ts +341 -0
- package/registry/scripts/code-quality-check.sh +559 -559
- package/registry/scripts/detect-tautological-tests.sh +38 -38
- package/registry/scripts/generate-engagement-emails.ts +830 -0
- package/registry/scripts/markdown-to-pdf.js +7 -3
- package/registry/scripts/newsletter-helpers.ts +777 -0
- package/registry/scripts/prep-issue.sh +30 -61
- package/registry/scripts/profile-server.ts +424 -0
- package/registry/scripts/run-thank-you-workflow.ts +122 -0
- package/registry/scripts/send-newsletter-simple.ts +102 -0
- package/registry/scripts/send-thank-you-emails.ts +57 -0
- package/registry/scripts/validate-openapi-limits.ts +366 -366
- package/registry/scripts/validate-test-coverage.ts +280 -280
- package/registry/scripts/verify-pr-comments.sh +70 -70
- package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +53 -53
- package/registry/templates/evidence/Implementation-BugEvidence.md +85 -85
- package/registry/templates/evidence/Implementation-FeatureEvidence.md +120 -120
- package/registry/workflows/customer-development/insight-analysis.md +156 -156
- package/registry/workflows/customer-development/interview-preparation.md +421 -421
- package/registry/workflows/customer-development/strategic-brainstorming.md +146 -146
- package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +562 -562
- package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +669 -669
- package/dist/registry/scripts/build-scripts-generator.js +0 -205
- package/dist/registry/scripts/fraim-config.js +0 -61
- package/dist/registry/scripts/generic-issues-api.js +0 -100
- package/dist/registry/scripts/openapi-generator.js +0 -664
- package/dist/registry/scripts/performance/profile-server.js +0 -390
- package/dist/test-utils.js +0 -96
- package/dist/tests/esm-compat.js +0 -11
- package/dist/tests/test-chalk-esm-issue.js +0 -159
- package/dist/tests/test-chalk-real-world.js +0 -265
- package/dist/tests/test-chalk-resolution-issue.js +0 -304
- package/dist/tests/test-fraim-install-chalk-issue.js +0 -254
- package/dist/tests/test-npm-resolution-diagnostic.js +0 -140
- package/registry/templates/marketing/STORYTELLING-TEMPLATE.md +0 -130
- package/registry/workflows/marketing/storytelling.md +0 -65
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const child_process_1 = require("child_process");
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const os = __importStar(require("os"));
|
|
40
|
-
const fraim_config_1 = require("../fraim-config");
|
|
41
|
-
const azureConfig = fraim_config_1.fraimConfig.azure;
|
|
42
|
-
const CONFIGS = {
|
|
43
|
-
prod: {
|
|
44
|
-
env: 'prod',
|
|
45
|
-
appName: azureConfig.prodAppName,
|
|
46
|
-
resourceGroup: azureConfig.prodResourceGroup
|
|
47
|
-
},
|
|
48
|
-
preprod: {
|
|
49
|
-
env: 'preprod',
|
|
50
|
-
appName: azureConfig.preprodAppName,
|
|
51
|
-
resourceGroup: azureConfig.preprodResourceGroup
|
|
52
|
-
},
|
|
53
|
-
local: {
|
|
54
|
-
env: 'local',
|
|
55
|
-
appName: azureConfig.localAppName,
|
|
56
|
-
resourceGroup: azureConfig.localResourceGroup
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
async function main() {
|
|
60
|
-
const args = process.argv.slice(2);
|
|
61
|
-
let config = CONFIGS.local;
|
|
62
|
-
const includeLogs = args.includes('--logs');
|
|
63
|
-
if (args.includes('--prod'))
|
|
64
|
-
config = CONFIGS.prod;
|
|
65
|
-
else if (args.includes('--preprod'))
|
|
66
|
-
config = CONFIGS.preprod;
|
|
67
|
-
else if (args.includes('--local')) {
|
|
68
|
-
console.log('๐ Running in local mode (log analysis only)');
|
|
69
|
-
config = CONFIGS.local;
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
console.log('โ ๏ธ No environment specified.');
|
|
73
|
-
console.log('Usage: npx tsx <this-script> [--prod|--preprod|--local] [--logs]');
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
console.log(`\n๐ Starting Profiling for Environment: ${config.env.toUpperCase()}`);
|
|
77
|
-
// 1. Infrastructure (Step 1)
|
|
78
|
-
if (config.env !== 'local') {
|
|
79
|
-
try {
|
|
80
|
-
console.log('\n--- โ๏ธ Step 1: Server Resource Analysis (Plan Level) ---');
|
|
81
|
-
// Get App Service Plan ID
|
|
82
|
-
const planId = (0, child_process_1.execSync)(`az webapp show --name ${config.appName} --resource-group ${config.resourceGroup} --query "appServicePlanId" -o tsv`).toString().trim();
|
|
83
|
-
console.log(`Plan ID: ${planId.split('/').pop()}`);
|
|
84
|
-
// 1a. Overall Metric (Plan Level)
|
|
85
|
-
// Get last 5 minutes of CPU/Memory
|
|
86
|
-
console.log(`> Fetching Plan Metrics (Last 5m)...`);
|
|
87
|
-
const metricCmd = `az monitor metrics list --resource "${planId}" --metrics CpuPercentage MemoryPercentage --interval PT1M --query "value[].{name:name.value, average:timeseries[0].data[-1].average}" -o json`;
|
|
88
|
-
try {
|
|
89
|
-
const metrics = JSON.parse((0, child_process_1.execSync)(metricCmd).toString());
|
|
90
|
-
metrics.forEach((m) => {
|
|
91
|
-
console.log(`${m.name}: ${m.average != null ? m.average.toFixed(2) + '%' : 'N/A'}`);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
catch (e) {
|
|
95
|
-
console.log(`โ ๏ธ Could not fetch plan metrics: ${e.message.split('\n')[0]}`);
|
|
96
|
-
}
|
|
97
|
-
// Prepare for API calls
|
|
98
|
-
// Get Access Token explicitly
|
|
99
|
-
const token = (0, child_process_1.execSync)('az account get-access-token --resource https://management.azure.com/ --query accessToken -o tsv').toString().trim();
|
|
100
|
-
const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
|
|
101
|
-
// --- 1.5: App Level Metrics (CpuTime) ---
|
|
102
|
-
try {
|
|
103
|
-
console.log(`\n> Fetching App Metrics (Last 5m) for ${config.appName}...`);
|
|
104
|
-
const subscriptionId = (0, child_process_1.execSync)(`az account show --query id -o tsv`).toString().trim();
|
|
105
|
-
const siteResourceId = `/subscriptions/${subscriptionId}/resourceGroups/${config.resourceGroup}/providers/Microsoft.Web/sites/${config.appName}`;
|
|
106
|
-
const appResponse = await axios.get(`https://management.azure.com${siteResourceId}/providers/microsoft.insights/metrics?api-version=2018-01-01&metricnames=CpuTime×pan=PT5M&aggregation=Total`, { headers: { Authorization: `Bearer ${token}` } });
|
|
107
|
-
if (appResponse.data && appResponse.data.value) {
|
|
108
|
-
appResponse.data.value.forEach((m) => {
|
|
109
|
-
const val = (m.timeseries[0]?.data[0]?.total);
|
|
110
|
-
const displayVal = val !== undefined ? val.toFixed(2) : 'N/A';
|
|
111
|
-
console.log(`${m.name.value}: ${displayVal}s (Total over 5m)`);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
catch (e) {
|
|
116
|
-
console.log(`โ ๏ธ Could not fetch app metrics: ${e.message}`);
|
|
117
|
-
}
|
|
118
|
-
// 2. Process Metrics (Step 2)
|
|
119
|
-
console.log(`\n--- โ๏ธ Step 2: Per-Process Resource Analysis (Kudu) ---`);
|
|
120
|
-
try {
|
|
121
|
-
// Token and axios already fetched above
|
|
122
|
-
const response = await axios.get(`https://${config.appName}.scm.azurewebsites.net/api/processes`, {
|
|
123
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
124
|
-
});
|
|
125
|
-
const processes = response.data;
|
|
126
|
-
// Shared diagnostics state
|
|
127
|
-
let memInfoOutput = '';
|
|
128
|
-
let psOutput = '';
|
|
129
|
-
let psLines = [];
|
|
130
|
-
// Use Kudu Command API to run 'top' remotely
|
|
131
|
-
try {
|
|
132
|
-
const topCmd = {
|
|
133
|
-
command: "top -b -d 3 -n 2",
|
|
134
|
-
dir: "/home"
|
|
135
|
-
};
|
|
136
|
-
const cmdRes = await axios.post(`https://${config.appName}.scm.azurewebsites.net/api/command`, topCmd, {
|
|
137
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
138
|
-
timeout: 25000
|
|
139
|
-
});
|
|
140
|
-
if (cmdRes.data && cmdRes.data.Output) {
|
|
141
|
-
const lines = cmdRes.data.Output.split('\n');
|
|
142
|
-
// --- Trace System Summary ---
|
|
143
|
-
console.log('System Summary (from top):');
|
|
144
|
-
let summaryLinesCount = 0;
|
|
145
|
-
for (const line of lines) {
|
|
146
|
-
if (line.trim() && summaryLinesCount < 5) {
|
|
147
|
-
console.log(` ${line.trim()}`);
|
|
148
|
-
summaryLinesCount++;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// --- Deep Dive: Missing Memory Investigation ---
|
|
152
|
-
console.log(`\n> Investigating "Invisible" Memory Usage...`);
|
|
153
|
-
try {
|
|
154
|
-
const dfCmd = { command: "df -h | grep -E 'tmpfs|shm'", dir: "/home" };
|
|
155
|
-
const dfRes = await axios.post(`https://${config.appName}.scm.azurewebsites.net/api/command`, dfCmd, { headers: { Authorization: `Bearer ${token}` } });
|
|
156
|
-
console.log(' [Tmpfs/Shm Usage]:');
|
|
157
|
-
console.log(dfRes.data.Output ? ' ' + dfRes.data.Output.replace(/\n/g, '\n ').trim() : ' (No output)');
|
|
158
|
-
const memInfoCmd = { command: "cat /proc/meminfo | grep -E 'MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree|Shmem|Slab|SUnreclaim|Buffers|Cached|AnonPages|Committed_AS'", dir: "/home" };
|
|
159
|
-
const memRes = await axios.post(`https://${config.appName}.scm.azurewebsites.net/api/command`, memInfoCmd, { headers: { Authorization: `Bearer ${token}` } });
|
|
160
|
-
memInfoOutput = memRes.data.Output || '';
|
|
161
|
-
console.log(' [Detailed MemInfo]:');
|
|
162
|
-
console.log(memInfoOutput ? ' ' + memInfoOutput.replace(/\n/g, '\n ').trim() : ' (No output)');
|
|
163
|
-
console.log('\n [Searching for Swap/VM Hogs in /proc...]:');
|
|
164
|
-
const swapHogCmd = {
|
|
165
|
-
command: "for f in /proc/[0-9]*/status; do grep -E '^(Name|Pid|VmSwap|VmSize)' $f 2>/dev/null | tr '\n' ' ' && echo ''; done | sort -k6 -rn | head -n 10",
|
|
166
|
-
dir: "/home"
|
|
167
|
-
};
|
|
168
|
-
const swapRes = await axios.post(`https://${config.appName}.scm.azurewebsites.net/api/command`, swapHogCmd, { headers: { Authorization: `Bearer ${token}` } });
|
|
169
|
-
console.log(' (Format: Name, Pid, VmSize, VmSwap)');
|
|
170
|
-
console.log(swapRes.data.Output ? ' ' + swapRes.data.Output.replace(/\n/g, '\n ').trim() : ' (No output)');
|
|
171
|
-
}
|
|
172
|
-
catch (e) {
|
|
173
|
-
console.log(` Could not inspect storage/meminfo: ${e.message}`);
|
|
174
|
-
}
|
|
175
|
-
let currentSnapshot = [];
|
|
176
|
-
let foundHeader = false;
|
|
177
|
-
let cpuColIndex = -1;
|
|
178
|
-
let memColIndex = -1;
|
|
179
|
-
let cmdColIndex = -1;
|
|
180
|
-
for (const line of lines) {
|
|
181
|
-
const trimmed = line.trim();
|
|
182
|
-
if (!trimmed)
|
|
183
|
-
continue;
|
|
184
|
-
if (trimmed.includes('PID') && trimmed.includes('COMMAND')) {
|
|
185
|
-
foundHeader = true;
|
|
186
|
-
currentSnapshot = [];
|
|
187
|
-
const headers = trimmed.split(/\s+/);
|
|
188
|
-
cpuColIndex = headers.indexOf('%CPU');
|
|
189
|
-
if (cpuColIndex === -1)
|
|
190
|
-
cpuColIndex = headers.indexOf('CPU%');
|
|
191
|
-
memColIndex = headers.indexOf('%MEM');
|
|
192
|
-
if (memColIndex === -1)
|
|
193
|
-
memColIndex = headers.indexOf('MEM%');
|
|
194
|
-
cmdColIndex = headers.indexOf('COMMAND');
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (foundHeader && cpuColIndex >= 0) {
|
|
198
|
-
const parts = trimmed.split(/\s+/);
|
|
199
|
-
if (parts.length >= 9) {
|
|
200
|
-
const pid = parts[0];
|
|
201
|
-
const cpuStr = parts[cpuColIndex];
|
|
202
|
-
const memStr = parts[memColIndex];
|
|
203
|
-
const cmd = parts.slice(cmdColIndex).join(' ');
|
|
204
|
-
const state = parts[7] || '?';
|
|
205
|
-
const time = parts[10] || '?';
|
|
206
|
-
const cpuVal = parseFloat(cpuStr);
|
|
207
|
-
const memVal = parseFloat(memStr);
|
|
208
|
-
if (!isNaN(parseInt(pid))) {
|
|
209
|
-
currentSnapshot.push({ pid, cmd, cpuStr, memStr, cpuVal, memVal, state, time });
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (currentSnapshot.length === 0) {
|
|
215
|
-
console.log('(No processes found or parsing failed)');
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
console.log(`\n--- Cross-Referencing Memory Hogs (ps aux) ---`);
|
|
219
|
-
try {
|
|
220
|
-
const psRes = await axios.post(`https://${config.appName}.scm.azurewebsites.net/api/command`, { command: "ps aux", dir: "/home" }, { headers: { Authorization: `Bearer ${token}` } });
|
|
221
|
-
psOutput = psRes.data.Output || '';
|
|
222
|
-
console.log(`PID\tVSZ\tRSS\tCOMMAND`);
|
|
223
|
-
console.log(`---\t---\t---\t-------`);
|
|
224
|
-
psLines = psOutput.split('\n').filter((l) => l.includes(' '));
|
|
225
|
-
psLines.slice(1, 10).forEach((l) => {
|
|
226
|
-
const p = l.trim().split(/\s+/);
|
|
227
|
-
if (p.length > 10) {
|
|
228
|
-
console.log(`${p[1]}\t${(parseInt(p[4]) / 1024).toFixed(0)}M\t${(parseInt(p[5]) / 1024).toFixed(0)}M\t${p.slice(10).join(' ').padEnd(30).slice(0, 30)}`);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
catch (e) {
|
|
233
|
-
console.log(` Could not fetch ps aux: ${e.message}`);
|
|
234
|
-
}
|
|
235
|
-
console.log(`\n--- Top Processes by CPU (top delta) ---`);
|
|
236
|
-
console.log(`PID\tSTATE\tTIME+\t%CPU\t%MEM\tCOMMAND`);
|
|
237
|
-
console.log(`---\t-----\t-----\t----\t----\t-------`);
|
|
238
|
-
currentSnapshot.sort((a, b) => b.cpuVal - a.cpuVal);
|
|
239
|
-
currentSnapshot.slice(0, 5).forEach(p => {
|
|
240
|
-
console.log(`${p.pid}\t${p.state}\t${p.time}\t${p.cpuStr}%\t${p.memStr}%\t${p.cmd.padEnd(20).slice(0, 20)}`);
|
|
241
|
-
});
|
|
242
|
-
console.log(`\n--- ๐ง Step 4: Automated Diagnosis ---`);
|
|
243
|
-
try {
|
|
244
|
-
let healthy = true;
|
|
245
|
-
if (memInfoOutput.includes('SwapTotal')) {
|
|
246
|
-
const swapTotal = parseInt(memInfoOutput.match(/SwapTotal:\s+(\d+)/)?.[1] || '0');
|
|
247
|
-
const swapFree = parseInt(memInfoOutput.match(/SwapFree:\s+(\d+)/)?.[1] || '0');
|
|
248
|
-
if (swapTotal > 0) {
|
|
249
|
-
const swapUsedPct = ((swapTotal - swapFree) / swapTotal) * 100;
|
|
250
|
-
if (swapUsedPct > 95) {
|
|
251
|
-
console.log(`โ [CRITICAL] Swap Death detected (${swapUsedPct.toFixed(1)}% used).`);
|
|
252
|
-
healthy = false;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
const hasApp = psOutput.includes('server.js') || psOutput.includes('orchestrator.ts');
|
|
257
|
-
if (!hasApp) {
|
|
258
|
-
console.log(`โ [CRITICAL] Application process 'server.js' NOT FOUND in ps aux.`);
|
|
259
|
-
healthy = false;
|
|
260
|
-
}
|
|
261
|
-
const kuduHog = currentSnapshot.find(p => p.pid === '851' && p.memVal > 20);
|
|
262
|
-
if (kuduHog) {
|
|
263
|
-
console.log(`โ ๏ธ [WARNING] Kudu (Azure Agent) is consuming ${kuduHog.memStr}% of physical RAM.`);
|
|
264
|
-
healthy = false;
|
|
265
|
-
}
|
|
266
|
-
const pm2Hogs = psLines.filter((l) => l.includes('God Daemon'));
|
|
267
|
-
if (pm2Hogs.length > 1) {
|
|
268
|
-
console.log(`โ ๏ธ [WARNING] Multiple PM2 God Daemons detected (${pm2Hogs.length}). Potential resource conflict.`);
|
|
269
|
-
healthy = false;
|
|
270
|
-
}
|
|
271
|
-
if (healthy) {
|
|
272
|
-
console.log(`โ
No obvious infrastructure bottlenecks detected.`);
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
console.log(`\nRECOMMENDED ACTIONS:`);
|
|
276
|
-
console.log(`1. Restart the Web App to clear Swap and kill rogue agents.`);
|
|
277
|
-
console.log(`2. Consider upgrading the App Service Plan (B1 -> P1v3) for more RAM.`);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch (e) {
|
|
281
|
-
console.log(` Could not perform automated diagnosis: ${e.message}`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
console.log('Debug: Unexpected response format:', cmdRes.data);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
catch (err) {
|
|
290
|
-
console.log(`โ ๏ธ 'top' failed via Kudu: ${err.message}`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
catch (e) {
|
|
294
|
-
console.log(`โ ๏ธ Could not fetch process metrics: ${e.message}`);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
catch (error) {
|
|
298
|
-
console.error('โ Failed to fetch infrastructure metrics:', error.message);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
// 3. Log Analysis (Step 3)
|
|
302
|
-
if (includeLogs || config.env === 'local') {
|
|
303
|
-
console.log('\n--- ๐ Step 3: Log Analysis ---');
|
|
304
|
-
let logContent = '';
|
|
305
|
-
if (config.env !== 'local') {
|
|
306
|
-
try {
|
|
307
|
-
console.log('> Downloading recent logs from Azure...');
|
|
308
|
-
const fraimTmp = path.join(os.homedir(), '.fraim', 'tmp');
|
|
309
|
-
if (!fs.existsSync(fraimTmp))
|
|
310
|
-
fs.mkdirSync(fraimTmp, { recursive: true });
|
|
311
|
-
const tempDir = fs.mkdtempSync(path.join(fraimTmp, `${fraim_config_1.fraimConfig.personaName.toLowerCase()}-logs-`));
|
|
312
|
-
const zipPath = path.join(tempDir, 'logs.zip');
|
|
313
|
-
(0, child_process_1.execSync)(`az webapp log download --name ${config.appName} --resource-group ${config.resourceGroup} --log-file "${zipPath}"`);
|
|
314
|
-
const originalCwd = process.cwd();
|
|
315
|
-
try {
|
|
316
|
-
process.chdir(tempDir);
|
|
317
|
-
try {
|
|
318
|
-
(0, child_process_1.execSync)(`unzip -o logs.zip`);
|
|
319
|
-
}
|
|
320
|
-
catch (e) {
|
|
321
|
-
try {
|
|
322
|
-
(0, child_process_1.execSync)(`powershell -command "Expand-Archive -Path 'logs.zip' -DestinationPath '.' -Force"`);
|
|
323
|
-
}
|
|
324
|
-
catch (p) { }
|
|
325
|
-
}
|
|
326
|
-
process.chdir(originalCwd);
|
|
327
|
-
}
|
|
328
|
-
catch (e) {
|
|
329
|
-
process.chdir(originalCwd);
|
|
330
|
-
}
|
|
331
|
-
const findLogFile = (dir) => {
|
|
332
|
-
const files = fs.readdirSync(dir);
|
|
333
|
-
for (const file of files) {
|
|
334
|
-
const fullPath = path.join(dir, file);
|
|
335
|
-
const stat = fs.statSync(fullPath);
|
|
336
|
-
if (stat.isDirectory()) {
|
|
337
|
-
const found = findLogFile(fullPath);
|
|
338
|
-
if (found)
|
|
339
|
-
return found;
|
|
340
|
-
}
|
|
341
|
-
else if (file.endsWith('_default_docker.log')) {
|
|
342
|
-
return fullPath;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return null;
|
|
346
|
-
};
|
|
347
|
-
const dockerLog = findLogFile(tempDir);
|
|
348
|
-
if (dockerLog)
|
|
349
|
-
logContent = fs.readFileSync(dockerLog, 'utf-8');
|
|
350
|
-
}
|
|
351
|
-
catch (error) {
|
|
352
|
-
console.error('โ Failed to download logs:', error.message);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
const localLogPath = path.join(process.cwd(), 'test.log');
|
|
357
|
-
if (fs.existsSync(localLogPath))
|
|
358
|
-
logContent = fs.readFileSync(localLogPath, 'utf-8');
|
|
359
|
-
}
|
|
360
|
-
if (logContent) {
|
|
361
|
-
analyzeLogs(logContent);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function analyzeLogs(content) {
|
|
366
|
-
const lines = content.split('\n');
|
|
367
|
-
let indexChecks = 0, decryptions = 0, dbConnections = 0, rssMemory = 0;
|
|
368
|
-
const indexPattern = /Ensured unique index/;
|
|
369
|
-
const decryptPattern = /Token decrypted/;
|
|
370
|
-
const dbConnPattern = /Database connection successful/;
|
|
371
|
-
const memoryPattern = /RSS: (\d+) MB/;
|
|
372
|
-
for (const line of lines) {
|
|
373
|
-
if (indexPattern.test(line))
|
|
374
|
-
indexChecks++;
|
|
375
|
-
if (decryptPattern.test(line))
|
|
376
|
-
decryptions++;
|
|
377
|
-
if (dbConnPattern.test(line))
|
|
378
|
-
dbConnections++;
|
|
379
|
-
const memMatch = line.match(memoryPattern);
|
|
380
|
-
if (memMatch)
|
|
381
|
-
rssMemory = Math.max(rssMemory, parseInt(memMatch[1]));
|
|
382
|
-
}
|
|
383
|
-
console.log('\n--- ๐ Operation Frequency ---');
|
|
384
|
-
console.log(`Ensured Unique Index: ${indexChecks}`);
|
|
385
|
-
console.log(`Token Decryptions: ${decryptions}`);
|
|
386
|
-
console.log(`DB Connections: ${dbConnections}`);
|
|
387
|
-
if (rssMemory > 0)
|
|
388
|
-
console.log(`Max RSS Detected: ${rssMemory} MB`);
|
|
389
|
-
}
|
|
390
|
-
main().catch(console.error);
|
package/dist/test-utils.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.runTests = runTests;
|
|
7
|
-
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
-
dotenv_1.default.config({ override: true });
|
|
9
|
-
const node_test_1 = require("node:test");
|
|
10
|
-
// Global tracker for failed tests across all suites
|
|
11
|
-
const globalFailedTests = [];
|
|
12
|
-
// Generic test runner function that can run any type of test
|
|
13
|
-
async function runTests(testCases, runTestFn, testTitle) {
|
|
14
|
-
console.log(`๐งช Testing ${testTitle}...\n`);
|
|
15
|
-
// Check if we need to filter by tags
|
|
16
|
-
let tagsFilter = [];
|
|
17
|
-
console.log(`Command line arguments: ${process.argv.join(', ')}`);
|
|
18
|
-
// First try command line arguments
|
|
19
|
-
const tagsArg = process.argv.find(arg => arg && typeof arg === 'string' && arg.startsWith('--tags='));
|
|
20
|
-
if (tagsArg) {
|
|
21
|
-
const tagValue = tagsArg.split('=')[1];
|
|
22
|
-
if (tagValue) {
|
|
23
|
-
tagsFilter = tagValue.split(',');
|
|
24
|
-
console.log(`Filtering tests by tags (from CLI): ${tagsFilter.join(', ')}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
// Then try environment variable (for npm scripts)
|
|
28
|
-
if (tagsFilter.length === 0 && process.env.TAGS) {
|
|
29
|
-
tagsFilter = process.env.TAGS.split(',');
|
|
30
|
-
console.log(`Filtering tests by tags (from ENV): ${tagsFilter.join(', ')}`);
|
|
31
|
-
}
|
|
32
|
-
// Check for exclusion tags
|
|
33
|
-
let excludeTags = [];
|
|
34
|
-
if (process.env.EXCLUDE_TAGS) {
|
|
35
|
-
excludeTags = process.env.EXCLUDE_TAGS.split(',');
|
|
36
|
-
console.log(`Excluding tests with tags (from ENV): ${excludeTags.join(', ')}`);
|
|
37
|
-
}
|
|
38
|
-
// Filter test cases by tags if specified
|
|
39
|
-
const testsToRun = testCases.filter(test => {
|
|
40
|
-
// First check inclusion filter
|
|
41
|
-
if (tagsFilter.length > 0) {
|
|
42
|
-
// Ensure test.tags exists before calling .some() on it
|
|
43
|
-
if (!test.tags || !test.tags.some(tag => tagsFilter.includes(tag))) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Then check exclusion filter
|
|
48
|
-
if (excludeTags.length > 0) {
|
|
49
|
-
// Exclude tests with specified tags
|
|
50
|
-
if (test.tags && test.tags.some(tag => excludeTags.includes(tag))) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
});
|
|
56
|
-
if (testsToRun.length === 0) {
|
|
57
|
-
console.log('No tests to run for suite: ' + testTitle);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
console.log(`Running ${testsToRun.length} tests${tagsFilter.length > 0 ? ` with tags: ${tagsFilter.join(', ')}` : ''}\n`);
|
|
61
|
-
// Use Node.js built-in test() function for each test case
|
|
62
|
-
// This allows the TAP reporter to properly aggregate results across all test files
|
|
63
|
-
for (const testCase of testsToRun) {
|
|
64
|
-
await (0, node_test_1.test)(testCase.name, async () => {
|
|
65
|
-
try {
|
|
66
|
-
const success = await runTestFn(testCase);
|
|
67
|
-
if (!success) {
|
|
68
|
-
const failedTestName = `${testTitle}: ${testCase.name}`;
|
|
69
|
-
if (!globalFailedTests.includes(failedTestName)) {
|
|
70
|
-
globalFailedTests.push(failedTestName);
|
|
71
|
-
}
|
|
72
|
-
throw new Error(`Test failed: ${testCase.name}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
const failedTestName = `${testTitle}: ${testCase.name}`;
|
|
77
|
-
if (!globalFailedTests.includes(failedTestName)) {
|
|
78
|
-
globalFailedTests.push(failedTestName);
|
|
79
|
-
}
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
// Display comprehensive final summary
|
|
85
|
-
console.log(`\n๐จ FINAL TEST SUMMARY:`);
|
|
86
|
-
console.log(` โ Total Failed Tests: ${globalFailedTests.length}`);
|
|
87
|
-
if (globalFailedTests.length > 0) {
|
|
88
|
-
console.log(` ๐ Failed Test Names:`);
|
|
89
|
-
globalFailedTests.forEach(testName => {
|
|
90
|
-
console.log(` - ${testName}`);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
if (globalFailedTests.length > 0) {
|
|
94
|
-
process.exitCode = 1;
|
|
95
|
-
}
|
|
96
|
-
}
|
package/dist/tests/esm-compat.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* ESM Compatibility Helper
|
|
4
|
-
* Provides __dirname and __filename for ESM modules
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.__dirname = exports.__filename = void 0;
|
|
8
|
-
const url_1 = require("url");
|
|
9
|
-
const path_1 = require("path");
|
|
10
|
-
exports.__filename = (0, url_1.fileURLToPath)(import.meta.url);
|
|
11
|
-
exports.__dirname = (0, path_1.dirname)(exports.__filename);
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Test to reproduce the ERR_REQUIRE_ESM issue with chalk
|
|
4
|
-
*
|
|
5
|
-
* This test simulates what happens when npm resolves chalk to v5 (ESM-only)
|
|
6
|
-
* while the code tries to use require() (CommonJS)
|
|
7
|
-
*/
|
|
8
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const node_child_process_1 = require("node:child_process");
|
|
13
|
-
const test_utils_1 = require("./test-utils");
|
|
14
|
-
const fs_1 = __importDefault(require("fs"));
|
|
15
|
-
const path_1 = __importDefault(require("path"));
|
|
16
|
-
const os_1 = __importDefault(require("os"));
|
|
17
|
-
async function testChalkESMIssue() {
|
|
18
|
-
console.log(' ๐งช Testing Chalk ESM Issue Reproduction...');
|
|
19
|
-
// Create a temp directory for the test
|
|
20
|
-
const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'chalk-esm-test-'));
|
|
21
|
-
console.log(` ๐ Created temp dir: ${tempDir}`);
|
|
22
|
-
try {
|
|
23
|
-
// 1. Create a minimal package.json that forces chalk v5
|
|
24
|
-
const packageJson = {
|
|
25
|
-
name: 'chalk-esm-test',
|
|
26
|
-
version: '1.0.0',
|
|
27
|
-
type: 'commonjs', // Using CommonJS
|
|
28
|
-
dependencies: {
|
|
29
|
-
'chalk': '^5.0.0' // Force chalk v5 (ESM-only)
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
33
|
-
// 2. Create a test script that uses require('chalk')
|
|
34
|
-
const testScript = `
|
|
35
|
-
const chalk = require('chalk');
|
|
36
|
-
console.log(chalk.blue('This should fail with ERR_REQUIRE_ESM'));
|
|
37
|
-
`;
|
|
38
|
-
fs_1.default.writeFileSync(path_1.default.join(tempDir, 'test.js'), testScript);
|
|
39
|
-
// 3. Install dependencies
|
|
40
|
-
console.log(' ๐ฆ Installing chalk v5...');
|
|
41
|
-
const installResult = await new Promise((resolve) => {
|
|
42
|
-
const proc = (0, node_child_process_1.spawn)('npm', ['install', '--silent'], {
|
|
43
|
-
cwd: tempDir,
|
|
44
|
-
stdio: 'pipe',
|
|
45
|
-
shell: true
|
|
46
|
-
});
|
|
47
|
-
proc.on('close', (code) => {
|
|
48
|
-
resolve({ code });
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
if (installResult.code !== 0) {
|
|
52
|
-
console.log(' โ ๏ธ npm install failed (expected in some environments)');
|
|
53
|
-
return true; // Skip test if npm install fails
|
|
54
|
-
}
|
|
55
|
-
// 4. Try to run the script - should fail with ERR_REQUIRE_ESM
|
|
56
|
-
console.log(' ๐ฅ Attempting to require() chalk v5 (should fail)...');
|
|
57
|
-
const runResult = await new Promise((resolve) => {
|
|
58
|
-
const proc = (0, node_child_process_1.spawn)('node', ['test.js'], {
|
|
59
|
-
cwd: tempDir,
|
|
60
|
-
stdio: 'pipe',
|
|
61
|
-
shell: true
|
|
62
|
-
});
|
|
63
|
-
let stderr = '';
|
|
64
|
-
proc.stderr?.on('data', (data) => {
|
|
65
|
-
stderr += data.toString();
|
|
66
|
-
});
|
|
67
|
-
proc.on('close', (code) => {
|
|
68
|
-
resolve({ code, stderr });
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
// 5. Verify we got the ERR_REQUIRE_ESM error
|
|
72
|
-
console.log(' ๐ Checking for ERR_REQUIRE_ESM error...');
|
|
73
|
-
if (runResult.code === 0) {
|
|
74
|
-
console.log(' โ Script succeeded when it should have failed!');
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
if (!runResult.stderr.includes('ERR_REQUIRE_ESM')) {
|
|
78
|
-
console.log(' โ Got wrong error. Expected ERR_REQUIRE_ESM');
|
|
79
|
-
console.log(` Stderr: ${runResult.stderr.substring(0, 200)}`);
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
console.log(' โ
Successfully reproduced ERR_REQUIRE_ESM error!');
|
|
83
|
-
console.log(' โ
This confirms chalk v5 cannot be used with require()');
|
|
84
|
-
// 6. Now test with chalk v4 (should work)
|
|
85
|
-
console.log(' ๐ Testing with chalk v4 (should work)...');
|
|
86
|
-
const packageJsonV4 = {
|
|
87
|
-
name: 'chalk-esm-test',
|
|
88
|
-
version: '1.0.0',
|
|
89
|
-
type: 'commonjs',
|
|
90
|
-
dependencies: {
|
|
91
|
-
'chalk': '4.1.2' // Exact version 4.1.2
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(packageJsonV4, null, 2));
|
|
95
|
-
// Remove node_modules and reinstall
|
|
96
|
-
fs_1.default.rmSync(path_1.default.join(tempDir, 'node_modules'), { recursive: true, force: true });
|
|
97
|
-
const installV4Result = await new Promise((resolve) => {
|
|
98
|
-
const proc = (0, node_child_process_1.spawn)('npm', ['install', '--silent'], {
|
|
99
|
-
cwd: tempDir,
|
|
100
|
-
stdio: 'pipe',
|
|
101
|
-
shell: true
|
|
102
|
-
});
|
|
103
|
-
proc.on('close', (code) => {
|
|
104
|
-
resolve({ code });
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
if (installV4Result.code !== 0) {
|
|
108
|
-
console.log(' โ ๏ธ npm install v4 failed');
|
|
109
|
-
return true; // Skip this part
|
|
110
|
-
}
|
|
111
|
-
const runV4Result = await new Promise((resolve) => {
|
|
112
|
-
const proc = (0, node_child_process_1.spawn)('node', ['test.js'], {
|
|
113
|
-
cwd: tempDir,
|
|
114
|
-
stdio: 'pipe',
|
|
115
|
-
shell: true
|
|
116
|
-
});
|
|
117
|
-
let stdout = '';
|
|
118
|
-
proc.stdout?.on('data', (data) => {
|
|
119
|
-
stdout += data.toString();
|
|
120
|
-
});
|
|
121
|
-
proc.on('close', (code) => {
|
|
122
|
-
resolve({ code, stdout });
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
if (runV4Result.code !== 0) {
|
|
126
|
-
console.log(' โ Chalk v4 failed when it should have worked!');
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
console.log(' โ
Chalk v4 works correctly with require()');
|
|
130
|
-
console.log(' โ
Test confirms: pinning to 4.1.2 prevents the issue');
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
console.error(' โ Test failed with error:', error);
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
finally {
|
|
138
|
-
// Cleanup
|
|
139
|
-
try {
|
|
140
|
-
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
141
|
-
console.log(' ๐งน Cleaned up temp directory');
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
console.log(' โ ๏ธ Could not clean up temp directory');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
async function runChalkTest(testCase) {
|
|
149
|
-
return await testCase.testFunction();
|
|
150
|
-
}
|
|
151
|
-
const testCases = [
|
|
152
|
-
{
|
|
153
|
-
name: 'Chalk ESM Issue Reproduction',
|
|
154
|
-
description: 'Reproduces the ERR_REQUIRE_ESM error when chalk v5 is used with require()',
|
|
155
|
-
testFunction: testChalkESMIssue,
|
|
156
|
-
tags: ['chalk', 'esm', 'reproduction']
|
|
157
|
-
}
|
|
158
|
-
];
|
|
159
|
-
(0, test_utils_1.runTests)(testCases, runChalkTest, 'Chalk ESM Issue Test');
|