fraim-framework 2.0.36 → 2.0.37

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 (165) hide show
  1. package/bin/fraim.js +5 -52
  2. package/dist/registry/scripts/build-scripts-generator.js +205 -0
  3. package/dist/registry/scripts/fraim-config.js +61 -0
  4. package/dist/registry/scripts/generic-issues-api.js +100 -0
  5. package/dist/registry/scripts/openapi-generator.js +664 -0
  6. package/dist/registry/scripts/performance/profile-server.js +390 -0
  7. package/dist/scripts/build-stub-registry.js +108 -0
  8. package/dist/src/cli/commands/doctor.js +5 -5
  9. package/dist/src/cli/commands/sync.js +33 -19
  10. package/dist/test-utils.js +96 -0
  11. package/dist/tests/esm-compat.js +11 -0
  12. package/dist/tests/test-chalk-esm-issue.js +159 -0
  13. package/dist/tests/test-chalk-real-world.js +265 -0
  14. package/dist/tests/test-chalk-regression.js +2 -18
  15. package/dist/tests/test-chalk-resolution-issue.js +304 -0
  16. package/dist/tests/test-fraim-install-chalk-issue.js +254 -0
  17. package/dist/tests/test-npm-resolution-diagnostic.js +140 -0
  18. package/dist/tests/test-package-size.js +88 -0
  19. package/dist/tests/test-prep-issue.js +34 -1
  20. package/dist/tests/test-stub-registry.js +120 -0
  21. package/dist/tests/test-sync-stubs.js +143 -0
  22. package/package.json +6 -8
  23. package/registry/agent-guardrails.md +62 -62
  24. package/registry/scripts/code-quality-check.sh +559 -559
  25. package/registry/scripts/detect-tautological-tests.sh +38 -38
  26. package/registry/scripts/prep-issue.sh +61 -30
  27. package/registry/scripts/validate-openapi-limits.ts +366 -366
  28. package/registry/scripts/validate-test-coverage.ts +280 -280
  29. package/registry/scripts/verify-pr-comments.sh +70 -70
  30. package/registry/stubs/workflows/bootstrap/create-architecture.md +11 -0
  31. package/registry/stubs/workflows/bootstrap/detect-broken-windows.md +11 -0
  32. package/registry/stubs/workflows/bootstrap/evaluate-code-quality.md +11 -0
  33. package/registry/stubs/workflows/bootstrap/verify-test-coverage.md +11 -0
  34. package/registry/stubs/workflows/business-development/create-business-plan.md +11 -0
  35. package/registry/stubs/workflows/business-development/ideate-business-opportunity.md +11 -0
  36. package/registry/stubs/workflows/business-development/price-product.md +18 -0
  37. package/registry/stubs/workflows/convert-to-pdf.md +11 -0
  38. package/registry/stubs/workflows/customer-development/insight-analysis.md +11 -0
  39. package/registry/stubs/workflows/customer-development/insight-triage.md +11 -0
  40. package/registry/stubs/workflows/customer-development/interview-preparation.md +11 -0
  41. package/registry/stubs/workflows/customer-development/linkedin-outreach.md +11 -0
  42. package/registry/stubs/workflows/customer-development/strategic-brainstorming.md +11 -0
  43. package/registry/stubs/workflows/customer-development/thank-customers.md +11 -0
  44. package/registry/stubs/workflows/customer-development/weekly-newsletter.md +11 -0
  45. package/registry/stubs/workflows/deploy/cloud-deployment.md +11 -0
  46. package/registry/stubs/workflows/improve-fraim/contribute.md +11 -0
  47. package/registry/stubs/workflows/improve-fraim/file-issue.md +11 -0
  48. package/registry/stubs/workflows/marketing/content-creation.md +11 -0
  49. package/registry/stubs/workflows/marketing/hbr-article.md +11 -0
  50. package/registry/stubs/workflows/marketing/launch-checklist.md +11 -0
  51. package/registry/stubs/workflows/marketing/marketing-strategy.md +11 -0
  52. package/registry/stubs/workflows/marketing/storytelling.md +11 -0
  53. package/registry/stubs/workflows/performance/analyze-performance.md +11 -0
  54. package/registry/stubs/workflows/product-building/design.md +11 -0
  55. package/registry/stubs/workflows/product-building/implement.md +12 -0
  56. package/registry/stubs/workflows/product-building/iterate-on-pr-comments.md +11 -0
  57. package/registry/stubs/workflows/product-building/prep-issue.md +11 -0
  58. package/registry/stubs/workflows/product-building/prototype.md +11 -0
  59. package/registry/stubs/workflows/product-building/resolve.md +11 -0
  60. package/registry/stubs/workflows/product-building/retrospect.md +11 -0
  61. package/registry/stubs/workflows/product-building/spec.md +11 -0
  62. package/registry/stubs/workflows/product-building/test.md +11 -0
  63. package/registry/stubs/workflows/quality-assurance/browser-validation.md +11 -0
  64. package/registry/stubs/workflows/quality-assurance/iterative-improvement-cycle.md +11 -0
  65. package/registry/stubs/workflows/replicate/replicate-discovery.md +11 -0
  66. package/registry/stubs/workflows/replicate/replicate-to-issues.md +11 -0
  67. package/registry/stubs/workflows/reviewer/review-implementation-vs-design-spec.md +11 -0
  68. package/registry/stubs/workflows/reviewer/review-implementation-vs-feature-spec.md +11 -0
  69. package/registry/stubs/workflows/startup-credits/aws-activate-application.md +11 -0
  70. package/registry/stubs/workflows/startup-credits/google-cloud-application.md +11 -0
  71. package/registry/stubs/workflows/startup-credits/microsoft-azure-application.md +11 -0
  72. package/.github/workflows/ci.yml +0 -65
  73. package/.github/workflows/deploy-fraim.yml +0 -87
  74. package/.github/workflows/phase-change.yml +0 -251
  75. package/.github/workflows/status-change.yml +0 -68
  76. package/.github/workflows/sync-on-pr-review.yml +0 -66
  77. package/examples/simple-webapp/TESTING.md +0 -62
  78. package/examples/simple-webapp/example-test.ts +0 -186
  79. package/registry/github/workflows/ci.yml +0 -51
  80. package/registry/github/workflows/phase-change.yml +0 -251
  81. package/registry/github/workflows/status-change.yml +0 -68
  82. package/registry/github/workflows/sync-on-pr-review.yml +0 -66
  83. package/registry/mcp-template.jsonc +0 -29
  84. package/registry/rules/agent-success-criteria.md +0 -52
  85. package/registry/rules/agent-testing-guidelines.md +0 -502
  86. package/registry/rules/architecture.md +0 -52
  87. package/registry/rules/communication.md +0 -122
  88. package/registry/rules/continuous-learning.md +0 -55
  89. package/registry/rules/debugging-multitenancy-issues.md +0 -85
  90. package/registry/rules/ephemeral-execution.md +0 -57
  91. package/registry/rules/git-safe-commands.md +0 -34
  92. package/registry/rules/hitl-ppe-record-analysis.md +0 -302
  93. package/registry/rules/integrity-and-test-ethics.md +0 -275
  94. package/registry/rules/local-development.md +0 -254
  95. package/registry/rules/merge-requirements.md +0 -231
  96. package/registry/rules/simplicity.md +0 -118
  97. package/registry/rules/software-development-lifecycle.md +0 -105
  98. package/registry/rules/spike-first-development.md +0 -205
  99. package/registry/rules/successful-debugging-patterns.md +0 -491
  100. package/registry/rules/telemetry.md +0 -67
  101. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +0 -53
  102. package/registry/templates/bootstrap/CODE-QUALITY-REPORT-TEMPLATE.md +0 -37
  103. package/registry/templates/bootstrap/TEST-COVERAGE-REPORT-TEMPLATE.md +0 -35
  104. package/registry/templates/business-development/IDEATION-REPORT-TEMPLATE.md +0 -29
  105. package/registry/templates/business-development/PRICING-STRATEGY-TEMPLATE.md +0 -126
  106. package/registry/templates/customer-development/customer-interview-template.md +0 -99
  107. package/registry/templates/customer-development/follow-up-email-templates.md +0 -132
  108. package/registry/templates/customer-development/insight-analysis-template.md +0 -74
  109. package/registry/templates/customer-development/strategic-recommendations-template.md +0 -53
  110. package/registry/templates/customer-development/thank-you-email-template.html +0 -124
  111. package/registry/templates/customer-development/thank-you-note-template.md +0 -16
  112. package/registry/templates/customer-development/triage-log-template.md +0 -278
  113. package/registry/templates/customer-development/weekly-newsletter-template.html +0 -204
  114. package/registry/templates/evidence/Design-Evidence.md +0 -30
  115. package/registry/templates/evidence/Implementation-BugEvidence.md +0 -86
  116. package/registry/templates/evidence/Implementation-FeatureEvidence.md +0 -121
  117. package/registry/templates/evidence/Spec-Evidence.md +0 -19
  118. package/registry/templates/help/HelpNeeded.md +0 -14
  119. package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +0 -66
  120. package/registry/templates/replicate/implementation-checklist.md +0 -39
  121. package/registry/templates/replicate/use-cases-template.md +0 -88
  122. package/registry/templates/retrospective/RETROSPECTIVE-TEMPLATE.md +0 -55
  123. package/registry/templates/specs/BUGSPEC-TEMPLATE.md +0 -37
  124. package/registry/templates/specs/FEATURESPEC-TEMPLATE.md +0 -29
  125. package/registry/templates/specs/TECHSPEC-TEMPLATE.md +0 -39
  126. package/registry/workflows/bootstrap/create-architecture.md +0 -38
  127. package/registry/workflows/bootstrap/evaluate-code-quality.md +0 -36
  128. package/registry/workflows/bootstrap/verify-test-coverage.md +0 -37
  129. package/registry/workflows/business-development/create-business-plan.md +0 -737
  130. package/registry/workflows/business-development/ideate-business-opportunity.md +0 -55
  131. package/registry/workflows/business-development/price-product.md +0 -325
  132. package/registry/workflows/convert-to-pdf.md +0 -235
  133. package/registry/workflows/customer-development/insight-analysis.md +0 -156
  134. package/registry/workflows/customer-development/insight-triage.md +0 -933
  135. package/registry/workflows/customer-development/interview-preparation.md +0 -421
  136. package/registry/workflows/customer-development/linkedin-outreach.md +0 -593
  137. package/registry/workflows/customer-development/strategic-brainstorming.md +0 -146
  138. package/registry/workflows/customer-development/thank-customers.md +0 -203
  139. package/registry/workflows/customer-development/weekly-newsletter.md +0 -366
  140. package/registry/workflows/deploy/cloud-deployment.md +0 -310
  141. package/registry/workflows/improve-fraim/contribute.md +0 -32
  142. package/registry/workflows/improve-fraim/file-issue.md +0 -32
  143. package/registry/workflows/marketing/content-creation.md +0 -37
  144. package/registry/workflows/marketing/hbr-article.md +0 -73
  145. package/registry/workflows/marketing/launch-checklist.md +0 -37
  146. package/registry/workflows/marketing/marketing-strategy.md +0 -45
  147. package/registry/workflows/performance/analyze-performance.md +0 -65
  148. package/registry/workflows/product-building/design.md +0 -130
  149. package/registry/workflows/product-building/implement.md +0 -315
  150. package/registry/workflows/product-building/iterate-on-pr-comments.md +0 -70
  151. package/registry/workflows/product-building/prep-issue.md +0 -43
  152. package/registry/workflows/product-building/prototype.md +0 -60
  153. package/registry/workflows/product-building/resolve.md +0 -164
  154. package/registry/workflows/product-building/retrospect.md +0 -86
  155. package/registry/workflows/product-building/spec.md +0 -117
  156. package/registry/workflows/product-building/test.md +0 -120
  157. package/registry/workflows/quality-assurance/browser-validation.md +0 -221
  158. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +0 -562
  159. package/registry/workflows/replicate/replicate-discovery.md +0 -336
  160. package/registry/workflows/replicate/replicate-to-issues.md +0 -319
  161. package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +0 -632
  162. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +0 -669
  163. package/registry/workflows/startup-credits/aws-activate-application.md +0 -535
  164. package/registry/workflows/startup-credits/google-cloud-application.md +0 -647
  165. package/registry/workflows/startup-credits/microsoft-azure-application.md +0 -538
@@ -0,0 +1,390 @@
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&timespan=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);
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env tsx
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.buildStubRegistry = buildStubRegistry;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const stub_generator_1 = require("../src/utils/stub-generator");
11
+ /**
12
+ * Build script to generate stub-only registry for npm package
13
+ *
14
+ * This creates a minimal registry containing:
15
+ * - Pre-generated workflow stubs (for IDE discoverability)
16
+ * - Scripts (for local execution)
17
+ *
18
+ * Excludes:
19
+ * - Complete workflows (served by MCP server)
20
+ * - Templates (served by MCP server)
21
+ * - Rules (served by MCP server)
22
+ */
23
+ const SOURCE_REGISTRY = path_1.default.join(__dirname, '..', 'registry');
24
+ const STUB_REGISTRY = path_1.default.join(__dirname, '..', 'registry', 'stubs');
25
+ async function buildStubRegistry() {
26
+ console.log('🔨 Building stub-only registry for npm package...');
27
+ // Clean existing stubs directory
28
+ if (fs_1.default.existsSync(STUB_REGISTRY)) {
29
+ fs_1.default.rmSync(STUB_REGISTRY, { recursive: true, force: true });
30
+ }
31
+ // Create stubs directory structure
32
+ fs_1.default.mkdirSync(STUB_REGISTRY, { recursive: true });
33
+ // Generate workflow stubs
34
+ await generateWorkflowStubs();
35
+ console.log('✅ Stub registry build complete!');
36
+ }
37
+ async function generateWorkflowStubs() {
38
+ const workflowsSourceDir = path_1.default.join(SOURCE_REGISTRY, 'workflows');
39
+ const workflowsStubDir = path_1.default.join(STUB_REGISTRY, 'workflows');
40
+ if (!fs_1.default.existsSync(workflowsSourceDir)) {
41
+ console.warn('⚠️ No workflows directory found in source registry');
42
+ return;
43
+ }
44
+ console.log('📝 Generating workflow stubs...');
45
+ // Get all workflow files recursively
46
+ const workflowFiles = getAllWorkflowFiles(workflowsSourceDir);
47
+ let stubCount = 0;
48
+ for (const workflowFile of workflowFiles) {
49
+ try {
50
+ // Read complete workflow
51
+ const content = fs_1.default.readFileSync(workflowFile.fullPath, 'utf8');
52
+ // Parse intent and principles
53
+ const { intent, principles } = (0, stub_generator_1.parseRegistryWorkflow)(content);
54
+ // Generate stub
55
+ const workflowName = path_1.default.basename(workflowFile.name, '.md');
56
+ const stub = (0, stub_generator_1.generateWorkflowStub)(workflowName, workflowFile.relativePath, intent, principles);
57
+ // Create target directory structure
58
+ const targetDir = path_1.default.join(workflowsStubDir, path_1.default.dirname(workflowFile.relativePath));
59
+ if (!fs_1.default.existsSync(targetDir)) {
60
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
61
+ }
62
+ // Write stub file
63
+ const stubPath = path_1.default.join(workflowsStubDir, workflowFile.relativePath);
64
+ fs_1.default.writeFileSync(stubPath, stub);
65
+ stubCount++;
66
+ console.log(` ✓ ${workflowFile.relativePath}`);
67
+ }
68
+ catch (error) {
69
+ console.error(` ❌ Failed to generate stub for ${workflowFile.relativePath}:`, error);
70
+ }
71
+ }
72
+ console.log(`📝 Generated ${stubCount} workflow stubs`);
73
+ }
74
+ function getAllWorkflowFiles(dir, baseDir = dir) {
75
+ const files = [];
76
+ if (!fs_1.default.existsSync(dir)) {
77
+ return files;
78
+ }
79
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
80
+ for (const entry of entries) {
81
+ const fullPath = path_1.default.join(dir, entry.name);
82
+ if (entry.isDirectory()) {
83
+ // Skip certain directories
84
+ if (entry.name.includes('Issue ') || entry.name.includes('Master')) {
85
+ continue;
86
+ }
87
+ // Recursively process subdirectories
88
+ files.push(...getAllWorkflowFiles(fullPath, baseDir));
89
+ }
90
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
91
+ // Add markdown files
92
+ const relativePath = path_1.default.relative(baseDir, fullPath);
93
+ files.push({
94
+ name: entry.name,
95
+ fullPath,
96
+ relativePath: relativePath.replace(/\\/g, '/') // Normalize path separators
97
+ });
98
+ }
99
+ }
100
+ return files;
101
+ }
102
+ // Run the build if this script is executed directly
103
+ if (require.main === module) {
104
+ buildStubRegistry().catch(error => {
105
+ console.error('❌ Build failed:', error);
106
+ process.exit(1);
107
+ });
108
+ }
@@ -53,20 +53,20 @@ exports.doctorCommand = new commander_1.Command('doctor')
53
53
  // 4. Check registry & sync status
54
54
  const digestPath = path_1.default.join(fraimDir, '.digest');
55
55
  // Try 4 levels up (dist/src/cli/commands -> root)
56
- let registryPath = path_1.default.join(__dirname, '../../../../registry');
56
+ let registryPath = path_1.default.join(__dirname, '../../../../registry/stubs');
57
57
  if (!fs_1.default.existsSync(registryPath)) {
58
58
  // Try 3 levels up (src/cli/commands -> root)
59
- registryPath = path_1.default.join(__dirname, '../../../registry');
59
+ registryPath = path_1.default.join(__dirname, '../../../registry/stubs');
60
60
  }
61
61
  // Fallback for local development if running from within the framework repo itself (and CWD is root)
62
62
  if (!fs_1.default.existsSync(registryPath)) {
63
- registryPath = path_1.default.join(projectRoot, 'registry');
63
+ registryPath = path_1.default.join(projectRoot, 'registry/stubs');
64
64
  }
65
65
  if (!fs_1.default.existsSync(registryPath)) {
66
- console.log(chalk_1.default.yellow('⚠️ Could not locate framework registry. (Expected in node_modules/@fraim/framework/registry)'));
66
+ console.log(chalk_1.default.yellow('⚠️ Could not locate framework stub registry. (Expected in node_modules/@fraim/framework/registry/stubs)'));
67
67
  }
68
68
  else {
69
- console.log(chalk_1.default.green('✅ Framework registry found.'));
69
+ console.log(chalk_1.default.green('✅ Framework stub registry found.'));
70
70
  const currentDigest = await (0, digest_utils_1.generateDigest)(registryPath);
71
71
  const existingDigest = fs_1.default.existsSync(digestPath) ? fs_1.default.readFileSync(digestPath, 'utf8') : '';
72
72
  if (currentDigest !== existingDigest) {
@@ -9,7 +9,6 @@ const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
11
  const digest_utils_1 = require("../../utils/digest-utils");
12
- const stub_generator_1 = require("../../utils/stub-generator");
13
12
  const config_loader_1 = require("../../fraim/config-loader");
14
13
  const version_utils_1 = require("../../utils/version-utils");
15
14
  const script_sync_utils_1 = require("../../utils/script-sync-utils");
@@ -20,20 +19,20 @@ const runSync = async (options) => {
20
19
  const workflowsRelativePath = config.customizations?.workflowsPath || '.fraim/workflows';
21
20
  const workflowsDir = path_1.default.resolve(projectRoot, workflowsRelativePath);
22
21
  const digestPath = path_1.default.join(fraimDir, '.digest');
23
- // In a real npm package, registry would be in node_modules/@fraim/framework/registry
22
+ // In npm package, stubs are in node_modules/@fraim/framework/registry/stubs/workflows
24
23
  // We need to handle both "running from source" (src/cli/commands) and "running from dist" (dist/src/cli/commands)
25
24
  // Try 4 levels up (dist/src/cli/commands -> root)
26
- let registryPath = path_1.default.join(__dirname, '../../../../registry');
25
+ let registryPath = path_1.default.join(__dirname, '../../../../registry/stubs');
27
26
  if (!fs_1.default.existsSync(registryPath)) {
28
27
  // Try 3 levels up (src/cli/commands -> root)
29
- registryPath = path_1.default.join(__dirname, '../../../registry');
28
+ registryPath = path_1.default.join(__dirname, '../../../registry/stubs');
30
29
  }
31
30
  // Fallback for local development if running from within the framework repo itself
32
31
  if (!fs_1.default.existsSync(registryPath)) {
33
- registryPath = path_1.default.join(projectRoot, 'registry');
32
+ registryPath = path_1.default.join(projectRoot, 'registry/stubs');
34
33
  }
35
34
  if (!fs_1.default.existsSync(registryPath)) {
36
- console.error(chalk_1.default.red('❌ Registry not found. Ensure @fraim/framework is installed.'));
35
+ console.error(chalk_1.default.red('❌ Stub registry not found. Ensure @fraim/framework is installed and built.'));
37
36
  process.exit(1);
38
37
  }
39
38
  if (!fs_1.default.existsSync(workflowsDir)) {
@@ -64,10 +63,10 @@ const runSync = async (options) => {
64
63
  else {
65
64
  const registryWorkflowsPath = path_1.default.join(registryPath, 'workflows');
66
65
  if (!fs_1.default.existsSync(registryWorkflowsPath)) {
67
- console.log(chalk_1.default.yellow('⚠️ No workflows found in registry.'));
66
+ console.log(chalk_1.default.yellow('⚠️ No workflow stubs found in registry.'));
68
67
  }
69
68
  else {
70
- // Get all workflows from registry (recursive)
69
+ // Get all workflow stubs from registry (recursive)
71
70
  const getFiles = (dir) => {
72
71
  const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
73
72
  const files = entries
@@ -80,13 +79,12 @@ const runSync = async (options) => {
80
79
  return files;
81
80
  };
82
81
  const registryFiles = getFiles(registryWorkflowsPath);
83
- const generatedStubs = [];
82
+ const copiedStubs = [];
84
83
  for (const file of registryFiles) {
85
- const content = fs_1.default.readFileSync(file, 'utf8');
86
- const { intent, principles } = (0, stub_generator_1.parseRegistryWorkflow)(content);
84
+ // These are already stubs, just copy them directly
87
85
  const fileName = path_1.default.basename(file);
88
86
  const workflowName = fileName.replace('.md', '');
89
- // Calculate relative path from registry/workflows to preserve structure
87
+ // Calculate relative path from registry/stubs/workflows to preserve structure
90
88
  const relativePath = path_1.default.relative(registryWorkflowsPath, file);
91
89
  const relativeDir = path_1.default.dirname(relativePath);
92
90
  // Ensure target directory exists
@@ -94,10 +92,11 @@ const runSync = async (options) => {
94
92
  if (!fs_1.default.existsSync(targetDir)) {
95
93
  fs_1.default.mkdirSync(targetDir, { recursive: true });
96
94
  }
97
- const stubContent = (0, stub_generator_1.generateWorkflowStub)(workflowName, file, intent, principles);
95
+ // Copy stub file directly
96
+ const stubContent = fs_1.default.readFileSync(file, 'utf8');
98
97
  const stubPath = path_1.default.join(targetDir, fileName);
99
98
  fs_1.default.writeFileSync(stubPath, stubContent);
100
- generatedStubs.push(relativePath); // Store relative path for cleanup tracking
99
+ copiedStubs.push(relativePath); // Store relative path for cleanup tracking
101
100
  console.log(chalk_1.default.gray(` + ${workflowName} (${relativeDir === '.' ? 'root' : relativeDir})`));
102
101
  }
103
102
  // Cleanup stubs that no longer exist in registry
@@ -119,8 +118,8 @@ const runSync = async (options) => {
119
118
  for (const stub of localStubs) {
120
119
  // standardise path separators for comparison
121
120
  const normalizedStub = stub.replace(/\\/g, '/');
122
- const normalizedGenerated = generatedStubs.map(s => s.replace(/\\/g, '/'));
123
- if (!normalizedGenerated.includes(normalizedStub)) {
121
+ const normalizedCopied = copiedStubs.map(s => s.replace(/\\/g, '/'));
122
+ if (!normalizedCopied.includes(normalizedStub)) {
124
123
  fs_1.default.unlinkSync(path_1.default.join(workflowsDir, stub));
125
124
  console.log(chalk_1.default.yellow(` - ${stub} (removed from registry)`));
126
125
  // Cleanup empty directories
@@ -134,13 +133,28 @@ const runSync = async (options) => {
134
133
  }
135
134
  }
136
135
  fs_1.default.writeFileSync(digestPath, currentDigest);
137
- console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Generated ${generatedStubs.length} stubs.`));
136
+ console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Copied ${copiedStubs.length} stubs.`));
138
137
  }
139
138
  }
140
139
  // Always sync scripts, regardless of workflow sync status
141
140
  console.log(chalk_1.default.blue('\n🔄 Syncing FRAIM scripts to user directory...'));
142
- const syncResult = (0, script_sync_utils_1.syncScriptsToUserDirectory)(registryPath);
143
- const cleanedScriptCount = (0, script_sync_utils_1.cleanupObsoleteUserScripts)(registryPath);
141
+ // Scripts are packaged separately from stubs, find the correct registry path
142
+ // Try 4 levels up (dist/src/cli/commands -> root)
143
+ let scriptsRegistryPath = path_1.default.join(__dirname, '../../../../registry');
144
+ if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
145
+ // Try 3 levels up (src/cli/commands -> root)
146
+ scriptsRegistryPath = path_1.default.join(__dirname, '../../../registry');
147
+ }
148
+ // Fallback for local development if running from within the framework repo itself
149
+ if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
150
+ scriptsRegistryPath = path_1.default.join(projectRoot, 'registry');
151
+ }
152
+ if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
153
+ console.error(chalk_1.default.red('❌ Scripts registry not found. Ensure @fraim/framework is installed and built.'));
154
+ process.exit(1);
155
+ }
156
+ const syncResult = (0, script_sync_utils_1.syncScriptsToUserDirectory)(scriptsRegistryPath);
157
+ const cleanedScriptCount = (0, script_sync_utils_1.cleanupObsoleteUserScripts)(scriptsRegistryPath);
144
158
  if (syncResult.synced > 0 || cleanedScriptCount > 0) {
145
159
  console.log(chalk_1.default.green(`✅ Script sync complete. Updated ${syncResult.synced} scripts, removed ${cleanedScriptCount} obsolete scripts.`));
146
160
  }