fraim-framework 2.0.35 → 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 (159) hide show
  1. package/dist/registry/scripts/cleanup-branch.js +62 -33
  2. package/dist/registry/scripts/generate-engagement-emails.js +119 -44
  3. package/dist/registry/scripts/newsletter-helpers.js +208 -268
  4. package/dist/registry/scripts/profile-server.js +387 -0
  5. package/dist/scripts/build-stub-registry.js +108 -0
  6. package/dist/src/cli/commands/doctor.js +5 -5
  7. package/dist/src/cli/commands/sync.js +33 -19
  8. package/dist/tests/test-client-scripts-validation.js +133 -0
  9. package/dist/tests/test-package-size.js +88 -0
  10. package/dist/tests/test-script-location-independence.js +76 -28
  11. package/dist/tests/test-stub-registry.js +120 -0
  12. package/dist/tests/test-sync-stubs.js +143 -0
  13. package/package.json +7 -9
  14. package/registry/scripts/cleanup-branch.ts +341 -0
  15. package/registry/scripts/generate-engagement-emails.ts +830 -0
  16. package/registry/scripts/markdown-to-pdf.js +7 -3
  17. package/registry/scripts/newsletter-helpers.ts +777 -0
  18. package/registry/scripts/profile-server.ts +424 -0
  19. package/registry/scripts/run-thank-you-workflow.ts +122 -0
  20. package/registry/scripts/send-newsletter-simple.ts +102 -0
  21. package/registry/scripts/send-thank-you-emails.ts +57 -0
  22. package/registry/stubs/workflows/bootstrap/create-architecture.md +11 -0
  23. package/registry/stubs/workflows/bootstrap/detect-broken-windows.md +11 -0
  24. package/registry/stubs/workflows/bootstrap/evaluate-code-quality.md +11 -0
  25. package/registry/stubs/workflows/bootstrap/verify-test-coverage.md +11 -0
  26. package/registry/stubs/workflows/business-development/create-business-plan.md +11 -0
  27. package/registry/stubs/workflows/business-development/ideate-business-opportunity.md +11 -0
  28. package/registry/stubs/workflows/business-development/price-product.md +18 -0
  29. package/registry/stubs/workflows/convert-to-pdf.md +11 -0
  30. package/registry/stubs/workflows/customer-development/insight-analysis.md +11 -0
  31. package/registry/stubs/workflows/customer-development/insight-triage.md +11 -0
  32. package/registry/stubs/workflows/customer-development/interview-preparation.md +11 -0
  33. package/registry/stubs/workflows/customer-development/linkedin-outreach.md +11 -0
  34. package/registry/stubs/workflows/customer-development/strategic-brainstorming.md +11 -0
  35. package/registry/stubs/workflows/customer-development/thank-customers.md +11 -0
  36. package/registry/stubs/workflows/customer-development/weekly-newsletter.md +11 -0
  37. package/registry/stubs/workflows/deploy/cloud-deployment.md +11 -0
  38. package/registry/stubs/workflows/improve-fraim/contribute.md +11 -0
  39. package/registry/stubs/workflows/improve-fraim/file-issue.md +11 -0
  40. package/registry/stubs/workflows/marketing/content-creation.md +11 -0
  41. package/registry/stubs/workflows/marketing/hbr-article.md +11 -0
  42. package/registry/stubs/workflows/marketing/launch-checklist.md +11 -0
  43. package/registry/stubs/workflows/marketing/marketing-strategy.md +11 -0
  44. package/registry/stubs/workflows/marketing/storytelling.md +11 -0
  45. package/registry/stubs/workflows/performance/analyze-performance.md +11 -0
  46. package/registry/stubs/workflows/product-building/design.md +11 -0
  47. package/registry/stubs/workflows/product-building/implement.md +12 -0
  48. package/registry/stubs/workflows/product-building/iterate-on-pr-comments.md +11 -0
  49. package/registry/stubs/workflows/product-building/prep-issue.md +11 -0
  50. package/registry/stubs/workflows/product-building/prototype.md +11 -0
  51. package/registry/stubs/workflows/product-building/resolve.md +11 -0
  52. package/registry/stubs/workflows/product-building/retrospect.md +11 -0
  53. package/registry/stubs/workflows/product-building/spec.md +11 -0
  54. package/registry/stubs/workflows/product-building/test.md +11 -0
  55. package/registry/stubs/workflows/quality-assurance/browser-validation.md +11 -0
  56. package/registry/stubs/workflows/quality-assurance/iterative-improvement-cycle.md +11 -0
  57. package/registry/stubs/workflows/replicate/replicate-discovery.md +11 -0
  58. package/registry/stubs/workflows/replicate/replicate-to-issues.md +11 -0
  59. package/registry/stubs/workflows/reviewer/review-implementation-vs-design-spec.md +11 -0
  60. package/registry/stubs/workflows/reviewer/review-implementation-vs-feature-spec.md +11 -0
  61. package/registry/stubs/workflows/startup-credits/aws-activate-application.md +11 -0
  62. package/registry/stubs/workflows/startup-credits/google-cloud-application.md +11 -0
  63. package/registry/stubs/workflows/startup-credits/microsoft-azure-application.md +11 -0
  64. package/.github/workflows/ci.yml +0 -65
  65. package/.github/workflows/deploy-fraim.yml +0 -87
  66. package/.github/workflows/phase-change.yml +0 -251
  67. package/.github/workflows/status-change.yml +0 -68
  68. package/.github/workflows/sync-on-pr-review.yml +0 -66
  69. package/examples/simple-webapp/TESTING.md +0 -62
  70. package/examples/simple-webapp/example-test.ts +0 -186
  71. package/registry/github/workflows/ci.yml +0 -51
  72. package/registry/github/workflows/phase-change.yml +0 -251
  73. package/registry/github/workflows/status-change.yml +0 -68
  74. package/registry/github/workflows/sync-on-pr-review.yml +0 -66
  75. package/registry/mcp-template.jsonc +0 -29
  76. package/registry/rules/agent-success-criteria.md +0 -52
  77. package/registry/rules/agent-testing-guidelines.md +0 -502
  78. package/registry/rules/architecture.md +0 -52
  79. package/registry/rules/communication.md +0 -122
  80. package/registry/rules/continuous-learning.md +0 -55
  81. package/registry/rules/debugging-multitenancy-issues.md +0 -85
  82. package/registry/rules/ephemeral-execution.md +0 -57
  83. package/registry/rules/git-safe-commands.md +0 -34
  84. package/registry/rules/hitl-ppe-record-analysis.md +0 -302
  85. package/registry/rules/integrity-and-test-ethics.md +0 -275
  86. package/registry/rules/local-development.md +0 -254
  87. package/registry/rules/merge-requirements.md +0 -231
  88. package/registry/rules/simplicity.md +0 -118
  89. package/registry/rules/software-development-lifecycle.md +0 -105
  90. package/registry/rules/spike-first-development.md +0 -205
  91. package/registry/rules/successful-debugging-patterns.md +0 -491
  92. package/registry/rules/telemetry.md +0 -67
  93. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +0 -53
  94. package/registry/templates/bootstrap/CODE-QUALITY-REPORT-TEMPLATE.md +0 -37
  95. package/registry/templates/bootstrap/TEST-COVERAGE-REPORT-TEMPLATE.md +0 -35
  96. package/registry/templates/business-development/IDEATION-REPORT-TEMPLATE.md +0 -29
  97. package/registry/templates/business-development/PRICING-STRATEGY-TEMPLATE.md +0 -126
  98. package/registry/templates/customer-development/customer-interview-template.md +0 -99
  99. package/registry/templates/customer-development/follow-up-email-templates.md +0 -132
  100. package/registry/templates/customer-development/insight-analysis-template.md +0 -74
  101. package/registry/templates/customer-development/strategic-recommendations-template.md +0 -53
  102. package/registry/templates/customer-development/thank-you-email-template.html +0 -124
  103. package/registry/templates/customer-development/thank-you-note-template.md +0 -16
  104. package/registry/templates/customer-development/triage-log-template.md +0 -278
  105. package/registry/templates/customer-development/weekly-newsletter-template.html +0 -204
  106. package/registry/templates/evidence/Design-Evidence.md +0 -30
  107. package/registry/templates/evidence/Implementation-BugEvidence.md +0 -86
  108. package/registry/templates/evidence/Implementation-FeatureEvidence.md +0 -121
  109. package/registry/templates/evidence/Spec-Evidence.md +0 -19
  110. package/registry/templates/help/HelpNeeded.md +0 -14
  111. package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +0 -66
  112. package/registry/templates/marketing/STORYTELLING-TEMPLATE.md +0 -130
  113. package/registry/templates/replicate/implementation-checklist.md +0 -39
  114. package/registry/templates/replicate/use-cases-template.md +0 -88
  115. package/registry/templates/retrospective/RETROSPECTIVE-TEMPLATE.md +0 -55
  116. package/registry/templates/specs/BUGSPEC-TEMPLATE.md +0 -37
  117. package/registry/templates/specs/FEATURESPEC-TEMPLATE.md +0 -29
  118. package/registry/templates/specs/TECHSPEC-TEMPLATE.md +0 -39
  119. package/registry/workflows/bootstrap/create-architecture.md +0 -38
  120. package/registry/workflows/bootstrap/evaluate-code-quality.md +0 -36
  121. package/registry/workflows/bootstrap/verify-test-coverage.md +0 -37
  122. package/registry/workflows/business-development/create-business-plan.md +0 -737
  123. package/registry/workflows/business-development/ideate-business-opportunity.md +0 -55
  124. package/registry/workflows/business-development/price-product.md +0 -325
  125. package/registry/workflows/convert-to-pdf.md +0 -235
  126. package/registry/workflows/customer-development/insight-analysis.md +0 -156
  127. package/registry/workflows/customer-development/insight-triage.md +0 -933
  128. package/registry/workflows/customer-development/interview-preparation.md +0 -421
  129. package/registry/workflows/customer-development/linkedin-outreach.md +0 -593
  130. package/registry/workflows/customer-development/strategic-brainstorming.md +0 -146
  131. package/registry/workflows/customer-development/thank-customers.md +0 -203
  132. package/registry/workflows/customer-development/weekly-newsletter.md +0 -366
  133. package/registry/workflows/deploy/cloud-deployment.md +0 -310
  134. package/registry/workflows/improve-fraim/contribute.md +0 -32
  135. package/registry/workflows/improve-fraim/file-issue.md +0 -32
  136. package/registry/workflows/marketing/content-creation.md +0 -37
  137. package/registry/workflows/marketing/hbr-article.md +0 -73
  138. package/registry/workflows/marketing/launch-checklist.md +0 -37
  139. package/registry/workflows/marketing/marketing-strategy.md +0 -45
  140. package/registry/workflows/marketing/storytelling.md +0 -65
  141. package/registry/workflows/performance/analyze-performance.md +0 -65
  142. package/registry/workflows/product-building/design.md +0 -130
  143. package/registry/workflows/product-building/implement.md +0 -315
  144. package/registry/workflows/product-building/iterate-on-pr-comments.md +0 -70
  145. package/registry/workflows/product-building/prep-issue.md +0 -43
  146. package/registry/workflows/product-building/prototype.md +0 -60
  147. package/registry/workflows/product-building/resolve.md +0 -164
  148. package/registry/workflows/product-building/retrospect.md +0 -86
  149. package/registry/workflows/product-building/spec.md +0 -117
  150. package/registry/workflows/product-building/test.md +0 -120
  151. package/registry/workflows/quality-assurance/browser-validation.md +0 -221
  152. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +0 -562
  153. package/registry/workflows/replicate/replicate-discovery.md +0 -336
  154. package/registry/workflows/replicate/replicate-to-issues.md +0 -319
  155. package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +0 -632
  156. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +0 -669
  157. package/registry/workflows/startup-credits/aws-activate-application.md +0 -535
  158. package/registry/workflows/startup-credits/google-cloud-application.md +0 -647
  159. package/registry/workflows/startup-credits/microsoft-azure-application.md +0 -538
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env npx tsx
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const child_process_1 = require("child_process");
38
+ const fs_1 = require("fs");
39
+ const path_1 = require("path");
40
+ function loadClientConfig() {
41
+ const configPath = (0, path_1.join)(process.cwd(), '.fraim', 'config.json');
42
+ if (!(0, fs_1.existsSync)(configPath)) {
43
+ throw new Error('.fraim/config.json not found. Run fraim init first.');
44
+ }
45
+ return JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
46
+ }
47
+ function getEnvOr(keys, fallback) {
48
+ for (const key of keys) {
49
+ const value = process.env[key];
50
+ if (value && value.length)
51
+ return value;
52
+ }
53
+ return fallback;
54
+ }
55
+ function checkAzureCLI() {
56
+ try {
57
+ (0, child_process_1.execSync)('az --version', { stdio: 'pipe' });
58
+ return true;
59
+ }
60
+ catch (error) {
61
+ return false;
62
+ }
63
+ }
64
+ function checkAzureAuth() {
65
+ try {
66
+ (0, child_process_1.execSync)('az account show', { stdio: 'pipe' });
67
+ return true;
68
+ }
69
+ catch (error) {
70
+ return false;
71
+ }
72
+ }
73
+ async function getAppServicePlanMetrics(appName, resourceGroup) {
74
+ try {
75
+ console.log('\n--- ☁️ App Service Plan Metrics ---');
76
+ // Get App Service Plan ID
77
+ const planIdCmd = `az webapp show --name ${appName} --resource-group ${resourceGroup} --query "appServicePlanId" -o tsv`;
78
+ const planId = (0, child_process_1.execSync)(planIdCmd, { encoding: 'utf8' }).trim();
79
+ const planName = planId.split('/').pop();
80
+ console.log(`📋 Plan: ${planName}`);
81
+ // Get CPU and Memory metrics for last 5 minutes
82
+ console.log('📊 Fetching CPU and Memory metrics (last 5 minutes)...');
83
+ const metricsCmd = `az monitor metrics list --resource "${planId}" --metrics CpuPercentage MemoryPercentage --interval PT1M --query "value[].{name:name.value, data:timeseries[0].data}" -o json`;
84
+ const metricsOutput = (0, child_process_1.execSync)(metricsCmd, { encoding: 'utf8' });
85
+ const metrics = JSON.parse(metricsOutput);
86
+ for (const metric of metrics) {
87
+ const latestData = metric.data[metric.data.length - 1];
88
+ const value = latestData?.average || latestData?.total || 'N/A';
89
+ console.log(` ${metric.name}: ${typeof value === 'number' ? value.toFixed(2) + '%' : value}`);
90
+ }
91
+ }
92
+ catch (error) {
93
+ console.log(`⚠️ Could not fetch App Service Plan metrics: ${error.message.split('\n')[0]}`);
94
+ }
95
+ }
96
+ async function getAppServiceMetrics(appName, resourceGroup) {
97
+ try {
98
+ console.log('\n--- 🖥️ App Service Metrics ---');
99
+ // Get subscription ID
100
+ const subscriptionId = (0, child_process_1.execSync)('az account show --query id -o tsv', { encoding: 'utf8' }).trim();
101
+ // Get app-level metrics using Azure CLI
102
+ console.log('📊 Fetching App Service metrics (last 5 minutes)...');
103
+ const appResourceId = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.Web/sites/${appName}`;
104
+ const appMetricsCmd = `az monitor metrics list --resource "${appResourceId}" --metrics CpuTime Requests Http2xx Http4xx Http5xx --interval PT1M --query "value[].{name:name.value, data:timeseries[0].data}" -o json`;
105
+ const appMetricsOutput = (0, child_process_1.execSync)(appMetricsCmd, { encoding: 'utf8' });
106
+ const appMetrics = JSON.parse(appMetricsOutput);
107
+ for (const metric of appMetrics) {
108
+ const latestData = metric.data[metric.data.length - 1];
109
+ const value = latestData?.total || latestData?.average || 'N/A';
110
+ let displayValue = value;
111
+ if (typeof value === 'number') {
112
+ if (metric.name === 'CpuTime') {
113
+ displayValue = `${value.toFixed(2)}s`;
114
+ }
115
+ else {
116
+ displayValue = value.toString();
117
+ }
118
+ }
119
+ console.log(` ${metric.name}: ${displayValue}`);
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.log(`⚠️ Could not fetch App Service metrics: ${error.message.split('\n')[0]}`);
124
+ }
125
+ }
126
+ async function getProcessInformation(appName) {
127
+ try {
128
+ console.log('\n--- ⚙️ Process Information (Kudu API) ---');
129
+ // Get access token for Kudu API
130
+ const token = (0, child_process_1.execSync)('az account get-access-token --resource https://management.azure.com/ --query accessToken -o tsv', { encoding: 'utf8' }).trim();
131
+ // Import axios dynamically
132
+ const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
133
+ // Get process list from Kudu
134
+ console.log('📋 Fetching running processes...');
135
+ const processResponse = await axios.get(`https://${appName}.scm.azurewebsites.net/api/processes`, {
136
+ headers: { Authorization: `Bearer ${token}` },
137
+ timeout: 10000
138
+ });
139
+ const processes = processResponse.data;
140
+ // Sort by CPU usage and show top processes
141
+ const sortedProcesses = processes
142
+ .filter((p) => p.cpu_usage !== undefined)
143
+ .sort((a, b) => (b.cpu_usage || 0) - (a.cpu_usage || 0))
144
+ .slice(0, 10);
145
+ console.log('\n🔥 Top 10 Processes by CPU Usage:');
146
+ console.log('PID\tCPU%\tMemory(MB)\tName');
147
+ console.log('---\t----\t---------\t----');
148
+ for (const process of sortedProcesses) {
149
+ const pid = process.id || 'N/A';
150
+ const cpu = process.cpu_usage ? process.cpu_usage.toFixed(2) : '0.00';
151
+ const memory = process.working_set ? (process.working_set / 1024 / 1024).toFixed(1) : 'N/A';
152
+ const name = process.name || 'Unknown';
153
+ console.log(`${pid}\t${cpu}\t${memory}\t\t${name.substring(0, 30)}`);
154
+ }
155
+ }
156
+ catch (error) {
157
+ console.log(`⚠️ Could not fetch process information: ${error.message.split('\n')[0]}`);
158
+ console.log(' This might be due to authentication issues or Kudu API being unavailable.');
159
+ }
160
+ }
161
+ async function getSystemInformation(appName) {
162
+ try {
163
+ console.log('\n--- 🖥️ System Information ---');
164
+ const token = (0, child_process_1.execSync)('az account get-access-token --resource https://management.azure.com/ --query accessToken -o tsv', { encoding: 'utf8' }).trim();
165
+ const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
166
+ // Get system info using Kudu command API
167
+ console.log('📊 Fetching system information...');
168
+ const commands = [
169
+ { name: 'Memory Info', cmd: 'cat /proc/meminfo | head -10' },
170
+ { name: 'CPU Info', cmd: 'cat /proc/cpuinfo | grep "model name" | head -1' },
171
+ { name: 'Disk Usage', cmd: 'df -h | head -5' },
172
+ { name: 'Load Average', cmd: 'uptime' }
173
+ ];
174
+ for (const command of commands) {
175
+ try {
176
+ const response = await axios.post(`https://${appName}.scm.azurewebsites.net/api/command`, {
177
+ command: command.cmd,
178
+ dir: '/home'
179
+ }, {
180
+ headers: { Authorization: `Bearer ${token}` },
181
+ timeout: 5000
182
+ });
183
+ console.log(`\n${command.name}:`);
184
+ const output = response.data.Output || response.data.Error || 'No output';
185
+ console.log(output.split('\n').map((line) => ` ${line}`).join('\n'));
186
+ }
187
+ catch (cmdError) {
188
+ console.log(`\n${command.name}: Could not retrieve (${cmdError.message.split('\n')[0]})`);
189
+ }
190
+ }
191
+ }
192
+ catch (error) {
193
+ console.log(`⚠️ Could not fetch system information: ${error.message.split('\n')[0]}`);
194
+ }
195
+ }
196
+ async function getApplicationLogs(appName, resourceGroup) {
197
+ try {
198
+ console.log('\n--- 📋 Recent Application Logs ---');
199
+ // Get recent logs using Azure CLI
200
+ console.log('📄 Fetching recent application logs...');
201
+ const logsCmd = `az webapp log tail --name ${appName} --resource-group ${resourceGroup} --provider application --timeout 5`;
202
+ try {
203
+ const logs = (0, child_process_1.execSync)(logsCmd, { encoding: 'utf8', timeout: 10000 });
204
+ console.log('Recent logs:');
205
+ console.log(logs.split('\n').slice(-20).map(line => ` ${line}`).join('\n'));
206
+ }
207
+ catch (logError) {
208
+ console.log('⚠️ Could not fetch logs - they may not be enabled or available');
209
+ console.log(' Enable application logging in Azure portal for better diagnostics');
210
+ }
211
+ }
212
+ catch (error) {
213
+ console.log(`⚠️ Could not fetch application logs: ${error.message.split('\n')[0]}`);
214
+ }
215
+ }
216
+ async function profileLocalEnvironment() {
217
+ console.log('\n--- 🏠 Local Environment Profiling ---');
218
+ try {
219
+ // Basic system information
220
+ console.log('💻 System Information:');
221
+ if (process.platform === 'win32') {
222
+ try {
223
+ const systemInfo = (0, child_process_1.execSync)('systeminfo | findstr /C:"Total Physical Memory" /C:"Available Physical Memory" /C:"Processor"', { encoding: 'utf8' });
224
+ console.log(systemInfo.split('\n').map(line => ` ${line.trim()}`).filter(line => line).join('\n'));
225
+ }
226
+ catch {
227
+ console.log(' Could not retrieve Windows system info');
228
+ }
229
+ }
230
+ else {
231
+ try {
232
+ const memInfo = (0, child_process_1.execSync)('free -h', { encoding: 'utf8' });
233
+ const cpuInfo = (0, child_process_1.execSync)('cat /proc/cpuinfo | grep "model name" | head -1', { encoding: 'utf8' });
234
+ console.log(' Memory:');
235
+ console.log(memInfo.split('\n').map(line => ` ${line}`).join('\n'));
236
+ console.log(' CPU:');
237
+ console.log(` ${cpuInfo.trim()}`);
238
+ }
239
+ catch {
240
+ console.log(' Could not retrieve Linux system info');
241
+ }
242
+ }
243
+ // Node.js process information
244
+ console.log('\n🟢 Node.js Process Information:');
245
+ console.log(` Node Version: ${process.version}`);
246
+ console.log(` Platform: ${process.platform}`);
247
+ console.log(` Architecture: ${process.arch}`);
248
+ console.log(` Memory Usage:`);
249
+ const memUsage = process.memoryUsage();
250
+ console.log(` RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)} MB`);
251
+ console.log(` Heap Used: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
252
+ console.log(` Heap Total: ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
253
+ console.log(` External: ${(memUsage.external / 1024 / 1024).toFixed(2)} MB`);
254
+ }
255
+ catch (error) {
256
+ console.log(`⚠️ Error profiling local environment: ${error.message}`);
257
+ }
258
+ }
259
+ async function main() {
260
+ const config = loadClientConfig();
261
+ // Azure configuration with environment variable fallbacks
262
+ const azureConfig = {
263
+ prodAppName: config.azure?.prodAppName || getEnvOr(['FRAIM_AZURE_PROD_APP_NAME'], 'fraim-app-prod'),
264
+ prodResourceGroup: config.azure?.prodResourceGroup || getEnvOr(['FRAIM_AZURE_PROD_RESOURCE_GROUP'], 'fraim-prod-rg'),
265
+ preprodAppName: config.azure?.preprodAppName || getEnvOr(['FRAIM_AZURE_PREPROD_APP_NAME'], 'fraim-app-pre-prod'),
266
+ preprodResourceGroup: config.azure?.preprodResourceGroup || getEnvOr(['FRAIM_AZURE_PREPROD_RESOURCE_GROUP'], 'fraim-pre-prod-rg'),
267
+ localAppName: config.azure?.localAppName || getEnvOr(['FRAIM_AZURE_LOCAL_APP_NAME'], 'local'),
268
+ localResourceGroup: config.azure?.localResourceGroup || getEnvOr(['FRAIM_AZURE_LOCAL_RESOURCE_GROUP'], 'local')
269
+ };
270
+ const CONFIGS = {
271
+ prod: {
272
+ env: 'prod',
273
+ appName: azureConfig.prodAppName,
274
+ resourceGroup: azureConfig.prodResourceGroup
275
+ },
276
+ preprod: {
277
+ env: 'preprod',
278
+ appName: azureConfig.preprodAppName,
279
+ resourceGroup: azureConfig.preprodResourceGroup
280
+ },
281
+ local: {
282
+ env: 'local',
283
+ appName: azureConfig.localAppName,
284
+ resourceGroup: azureConfig.localResourceGroup
285
+ }
286
+ };
287
+ const args = process.argv.slice(2);
288
+ let profileConfig = CONFIGS.local;
289
+ const includeLogs = args.includes('--logs');
290
+ if (args.includes('--help') || args.includes('-h')) {
291
+ console.log(`
292
+ 🔍 Azure App Service Profiler
293
+
294
+ Usage:
295
+ npx tsx profile-server.ts [options]
296
+
297
+ Options:
298
+ --prod Profile production environment
299
+ --preprod Profile pre-production environment
300
+ --local Profile local environment (default)
301
+ --logs Include application logs in analysis
302
+ --help, -h Show this help message
303
+
304
+ Examples:
305
+ # Profile production server
306
+ npx tsx profile-server.ts --prod
307
+
308
+ # Profile with logs
309
+ npx tsx profile-server.ts --prod --logs
310
+
311
+ # Profile local environment
312
+ npx tsx profile-server.ts --local
313
+
314
+ Requirements:
315
+ - Azure CLI (az) installed and authenticated
316
+ - Proper permissions to access App Service resources
317
+ - For Kudu API access: Contributor role on the App Service
318
+
319
+ Configuration:
320
+ Reads Azure settings from .fraim/config.json or environment variables:
321
+ - FRAIM_AZURE_PROD_APP_NAME
322
+ - FRAIM_AZURE_PROD_RESOURCE_GROUP
323
+ - FRAIM_AZURE_PREPROD_APP_NAME
324
+ - FRAIM_AZURE_PREPROD_RESOURCE_GROUP
325
+ `);
326
+ return;
327
+ }
328
+ if (args.includes('--prod'))
329
+ profileConfig = CONFIGS.prod;
330
+ else if (args.includes('--preprod'))
331
+ profileConfig = CONFIGS.preprod;
332
+ else if (args.includes('--local'))
333
+ profileConfig = CONFIGS.local;
334
+ console.log(`\n🚀 Starting Server Profiling`);
335
+ console.log(`📊 Environment: ${profileConfig.env.toUpperCase()}`);
336
+ console.log(`🏷️ App: ${profileConfig.appName}`);
337
+ console.log(`📁 Resource Group: ${profileConfig.resourceGroup}`);
338
+ if (profileConfig.env === 'local') {
339
+ await profileLocalEnvironment();
340
+ console.log('\n✅ Local profiling completed');
341
+ return;
342
+ }
343
+ // Check prerequisites for Azure profiling
344
+ console.log('\n🔍 Checking prerequisites...');
345
+ if (!checkAzureCLI()) {
346
+ console.error('❌ Azure CLI not found. Please install Azure CLI first.');
347
+ console.error(' Download from: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli');
348
+ process.exit(1);
349
+ }
350
+ console.log('✅ Azure CLI found');
351
+ if (!checkAzureAuth()) {
352
+ console.error('❌ Not authenticated with Azure. Please run: az login');
353
+ process.exit(1);
354
+ }
355
+ console.log('✅ Azure authentication verified');
356
+ try {
357
+ // Verify app exists
358
+ console.log(`\n🔍 Verifying App Service: ${profileConfig.appName}`);
359
+ (0, child_process_1.execSync)(`az webapp show --name ${profileConfig.appName} --resource-group ${profileConfig.resourceGroup} --query name -o tsv`, { stdio: 'pipe' });
360
+ console.log('✅ App Service found');
361
+ // Run profiling analysis
362
+ await getAppServicePlanMetrics(profileConfig.appName, profileConfig.resourceGroup);
363
+ await getAppServiceMetrics(profileConfig.appName, profileConfig.resourceGroup);
364
+ await getProcessInformation(profileConfig.appName);
365
+ await getSystemInformation(profileConfig.appName);
366
+ if (includeLogs) {
367
+ await getApplicationLogs(profileConfig.appName, profileConfig.resourceGroup);
368
+ }
369
+ console.log('\n✅ Server profiling completed successfully');
370
+ console.log('\n💡 Tips:');
371
+ console.log(' - Use --logs flag to include application logs');
372
+ console.log(' - High CPU usage may indicate performance bottlenecks');
373
+ console.log(' - High memory usage may indicate memory leaks');
374
+ console.log(' - Check process list for unexpected or resource-heavy processes');
375
+ }
376
+ catch (error) {
377
+ console.error(`\n❌ Profiling failed: ${error.message}`);
378
+ console.error('\nTroubleshooting:');
379
+ console.error(' - Verify app name and resource group are correct');
380
+ console.error(' - Ensure you have proper permissions (Contributor role)');
381
+ console.error(' - Check if the App Service is running');
382
+ console.error(' - Try: az webapp list --query "[].{name:name, resourceGroup:resourceGroup}"');
383
+ process.exit(1);
384
+ }
385
+ }
386
+ // Run the main function
387
+ 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
  }