fraim-framework 2.0.63 → 2.0.65

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 (106) hide show
  1. package/bin/fraim-mcp.js +52 -19
  2. package/bin/fraim.js +23 -0
  3. package/dist/src/cli/commands/add-ide.js +53 -14
  4. package/dist/src/cli/commands/doctor.js +12 -24
  5. package/dist/src/cli/commands/init-project.js +0 -3
  6. package/dist/src/cli/commands/init.js +0 -2
  7. package/dist/src/cli/commands/mcp.js +65 -0
  8. package/dist/src/cli/commands/setup.js +17 -1
  9. package/dist/src/cli/commands/sync.js +173 -104
  10. package/dist/src/cli/setup/auto-mcp-setup.js +6 -4
  11. package/dist/src/cli/setup/mcp-config-generator.js +65 -41
  12. package/dist/src/fraim/issue-tracking/ado-provider.js +304 -0
  13. package/dist/src/fraim/issue-tracking/factory.js +63 -0
  14. package/dist/src/fraim/issue-tracking/github-provider.js +200 -0
  15. package/dist/src/fraim/issue-tracking/types.js +7 -0
  16. package/dist/src/fraim/issue-tracking-config.js +83 -0
  17. package/dist/src/local-mcp-server/stdio-server.js +91 -15
  18. package/dist/src/utils/remote-sync.js +130 -0
  19. package/package.json +3 -4
  20. package/dist/src/utils/enforcement-utils.js +0 -239
  21. package/dist/src/utils/validate-workflows.js +0 -101
  22. package/registry/scripts/cleanup-branch.ts +0 -341
  23. package/registry/scripts/code-quality-check.sh +0 -566
  24. package/registry/scripts/comprehensive-explorer.py +0 -297
  25. package/registry/scripts/create-git-labels.sh +0 -49
  26. package/registry/scripts/create-website-structure.js +0 -562
  27. package/registry/scripts/detect-tautological-tests.sh +0 -38
  28. package/registry/scripts/evaluate-code-quality.ts +0 -36
  29. package/registry/scripts/exec-with-timeout.ts +0 -122
  30. package/registry/scripts/generate-engagement-emails.ts +0 -830
  31. package/registry/scripts/interactive-explorer.py +0 -270
  32. package/registry/scripts/markdown-to-pdf.js +0 -395
  33. package/registry/scripts/newsletter-helpers.ts +0 -777
  34. package/registry/scripts/pdf-styles.css +0 -172
  35. package/registry/scripts/prep-issue.sh +0 -548
  36. package/registry/scripts/productivity/build-productivity-csv.mjs +0 -242
  37. package/registry/scripts/productivity/fetch-pr-details.mjs +0 -144
  38. package/registry/scripts/productivity/productivity-report.sh +0 -147
  39. package/registry/scripts/profile-server.ts +0 -426
  40. package/registry/scripts/run-thank-you-workflow.ts +0 -122
  41. package/registry/scripts/scrape-site.py +0 -302
  42. package/registry/scripts/send-newsletter-simple.ts +0 -102
  43. package/registry/scripts/send-thank-you-emails.ts +0 -57
  44. package/registry/scripts/validate-openapi-limits.ts +0 -366
  45. package/registry/scripts/validate-test-coverage.ts +0 -280
  46. package/registry/scripts/verify-pr-comments.sh +0 -74
  47. package/registry/scripts/verify-test-coverage.ts +0 -36
  48. package/registry/stubs/workflows/bootstrap/create-architecture.md +0 -11
  49. package/registry/stubs/workflows/bootstrap/detect-broken-windows.md +0 -11
  50. package/registry/stubs/workflows/bootstrap/evaluate-code-quality.md +0 -11
  51. package/registry/stubs/workflows/bootstrap/verify-test-coverage.md +0 -11
  52. package/registry/stubs/workflows/brainstorming/blue-sky-brainstorming.md +0 -11
  53. package/registry/stubs/workflows/brainstorming/codebase-brainstorming.md +0 -11
  54. package/registry/stubs/workflows/business-development/create-business-plan.md +0 -11
  55. package/registry/stubs/workflows/business-development/ideate-business-opportunity.md +0 -11
  56. package/registry/stubs/workflows/business-development/price-product.md +0 -18
  57. package/registry/stubs/workflows/compliance/detect-compliance-requirements.md +0 -11
  58. package/registry/stubs/workflows/compliance/generate-audit-evidence.md +0 -11
  59. package/registry/stubs/workflows/compliance/soc2-evidence-generator.md +0 -11
  60. package/registry/stubs/workflows/customer-development/insight-analysis.md +0 -11
  61. package/registry/stubs/workflows/customer-development/insight-triage.md +0 -11
  62. package/registry/stubs/workflows/customer-development/interview-preparation.md +0 -11
  63. package/registry/stubs/workflows/customer-development/linkedin-outreach.md +0 -11
  64. package/registry/stubs/workflows/customer-development/strategic-brainstorming.md +0 -11
  65. package/registry/stubs/workflows/customer-development/thank-customers.md +0 -11
  66. package/registry/stubs/workflows/customer-development/user-survey-dispatch.md +0 -11
  67. package/registry/stubs/workflows/customer-development/users-to-target.md +0 -11
  68. package/registry/stubs/workflows/customer-development/weekly-newsletter.md +0 -11
  69. package/registry/stubs/workflows/deploy/cloud-deployment.md +0 -11
  70. package/registry/stubs/workflows/improve-fraim/contribute.md +0 -11
  71. package/registry/stubs/workflows/improve-fraim/file-issue.md +0 -11
  72. package/registry/stubs/workflows/learning/build-skillset.md +0 -11
  73. package/registry/stubs/workflows/learning/synthesize-learnings.md +0 -11
  74. package/registry/stubs/workflows/legal/contract-review-analysis.md +0 -11
  75. package/registry/stubs/workflows/legal/nda.md +0 -11
  76. package/registry/stubs/workflows/legal/patent-filing.md +0 -11
  77. package/registry/stubs/workflows/legal/saas-contract-development.md +0 -11
  78. package/registry/stubs/workflows/legal/trademark-filing.md +0 -11
  79. package/registry/stubs/workflows/marketing/content-creation.md +0 -11
  80. package/registry/stubs/workflows/marketing/convert-to-pdf.md +0 -11
  81. package/registry/stubs/workflows/marketing/create-modern-website.md +0 -11
  82. package/registry/stubs/workflows/marketing/domain-registration.md +0 -11
  83. package/registry/stubs/workflows/marketing/hbr-article.md +0 -11
  84. package/registry/stubs/workflows/marketing/launch-checklist.md +0 -11
  85. package/registry/stubs/workflows/marketing/marketing-strategy.md +0 -11
  86. package/registry/stubs/workflows/marketing/storytelling.md +0 -11
  87. package/registry/stubs/workflows/performance/analyze-performance.md +0 -11
  88. package/registry/stubs/workflows/product-building/design.md +0 -11
  89. package/registry/stubs/workflows/product-building/implement.md +0 -11
  90. package/registry/stubs/workflows/product-building/iterate-on-pr-comments.md +0 -11
  91. package/registry/stubs/workflows/product-building/prep-issue.md +0 -11
  92. package/registry/stubs/workflows/product-building/prototype.md +0 -11
  93. package/registry/stubs/workflows/product-building/resolve.md +0 -11
  94. package/registry/stubs/workflows/product-building/retrospect.md +0 -11
  95. package/registry/stubs/workflows/product-building/spec.md +0 -11
  96. package/registry/stubs/workflows/product-building/test.md +0 -11
  97. package/registry/stubs/workflows/productivity-report/productivity-report.md +0 -11
  98. package/registry/stubs/workflows/quality-assurance/browser-validation.md +0 -11
  99. package/registry/stubs/workflows/quality-assurance/iterative-improvement-cycle.md +0 -11
  100. package/registry/stubs/workflows/replicate/replicate-discovery.md +0 -11
  101. package/registry/stubs/workflows/replicate/replicate-to-issues.md +0 -11
  102. package/registry/stubs/workflows/reviewer/review-implementation-vs-design-spec.md +0 -11
  103. package/registry/stubs/workflows/reviewer/review-implementation-vs-feature-spec.md +0 -11
  104. package/registry/stubs/workflows/startup-credits/aws-activate-application.md +0 -11
  105. package/registry/stubs/workflows/startup-credits/google-cloud-application.md +0 -11
  106. package/registry/stubs/workflows/startup-credits/microsoft-azure-application.md +0 -11
@@ -1,426 +0,0 @@
1
- #!/usr/bin/env npx tsx
2
-
3
- import { execSync } from 'child_process';
4
- import { readFileSync, existsSync } from 'fs';
5
- import { join } from 'path';
6
- import * as path from 'path';
7
-
8
- /**
9
- * Production Server Profiler
10
- * Automates the analysis of Azure App Service performance for coding agents.
11
- *
12
- * Usage: npx tsx profile-server.ts [--prod|--preprod|--local] [--logs]
13
- *
14
- * Self-contained script - reads configuration from .fraim/config.json
15
- * Requires: Azure CLI (az) installed and authenticated
16
- */
17
-
18
- // Self-contained configuration loading
19
- interface FraimConfig {
20
- persona: { name: string };
21
- azure?: {
22
- prodAppName?: string;
23
- prodResourceGroup?: string;
24
- preprodAppName?: string;
25
- preprodResourceGroup?: string;
26
- localAppName?: string;
27
- localResourceGroup?: string;
28
- };
29
- }
30
-
31
- function loadClientConfig(): FraimConfig {
32
- const configPath = join(process.cwd(), '.fraim', 'config.json');
33
- if (!existsSync(configPath)) {
34
- throw new Error('.fraim/config.json not found. Run fraim init first.');
35
- }
36
- return JSON.parse(readFileSync(configPath, 'utf-8'));
37
- }
38
-
39
- function getEnvOr(keys: string[], fallback: string): string {
40
- for (const key of keys) {
41
- const value = process.env[key];
42
- if (value && value.length) return value;
43
- }
44
- return fallback;
45
- }
46
-
47
- interface ProfilingConfig {
48
- env: 'prod' | 'preprod' | 'local';
49
- appName: string;
50
- resourceGroup: string;
51
- }
52
-
53
- function checkAzureCLI(): boolean {
54
- try {
55
- execSync('az --version', { stdio: 'pipe' });
56
- return true;
57
- } catch (error) {
58
- return false;
59
- }
60
- }
61
-
62
- function checkAzureAuth(): boolean {
63
- try {
64
- execSync('az account show', { stdio: 'pipe' });
65
- return true;
66
- } catch (error) {
67
- return false;
68
- }
69
- }
70
-
71
- async function getAppServicePlanMetrics(appName: string, resourceGroup: string): Promise<void> {
72
- try {
73
- console.log('\n--- ā˜ļø App Service Plan Metrics ---');
74
-
75
- // Get App Service Plan ID
76
- const planIdCmd = `az webapp show --name ${appName} --resource-group ${resourceGroup} --query "appServicePlanId" -o tsv`;
77
- const planId = execSync(planIdCmd, { encoding: 'utf8' }).trim();
78
- const planName = planId.split('/').pop();
79
- console.log(`šŸ“‹ Plan: ${planName}`);
80
-
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
-
85
- const metricsOutput = execSync(metricsCmd, { encoding: 'utf8' });
86
- const metrics = JSON.parse(metricsOutput);
87
-
88
- for (const metric of metrics) {
89
- const latestData = metric.data[metric.data.length - 1];
90
- const value = latestData?.average || latestData?.total || 'N/A';
91
- console.log(` ${metric.name}: ${typeof value === 'number' ? value.toFixed(2) + '%' : value}`);
92
- }
93
- } catch (error: any) {
94
- console.log(`āš ļø Could not fetch App Service Plan metrics: ${error.message.split('\n')[0]}`);
95
- }
96
- }
97
-
98
- async function getAppServiceMetrics(appName: string, resourceGroup: string): Promise<void> {
99
- try {
100
- console.log('\n--- šŸ–„ļø App Service Metrics ---');
101
-
102
- // Get subscription ID
103
- const subscriptionId = execSync('az account show --query id -o tsv', { encoding: 'utf8' }).trim();
104
-
105
- // Get app-level metrics using Azure CLI
106
- console.log('šŸ“Š Fetching App Service metrics (last 5 minutes)...');
107
- const root = '/';
108
- const appResourceId = `${root}subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.Web/sites/${appName}`;
109
-
110
- 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`;
111
-
112
- const appMetricsOutput = execSync(appMetricsCmd, { encoding: 'utf8' });
113
- const appMetrics = JSON.parse(appMetricsOutput);
114
-
115
- for (const metric of appMetrics) {
116
- const latestData = metric.data[metric.data.length - 1];
117
- const value = latestData?.total || latestData?.average || 'N/A';
118
- let displayValue = value;
119
-
120
- if (typeof value === 'number') {
121
- if (metric.name === 'CpuTime') {
122
- displayValue = `${value.toFixed(2)}s`;
123
- } else {
124
- displayValue = value.toString();
125
- }
126
- }
127
-
128
- console.log(` ${metric.name}: ${displayValue}`);
129
- }
130
- } catch (error: any) {
131
- console.log(`āš ļø Could not fetch App Service metrics: ${error.message.split('\n')[0]}`);
132
- }
133
- }
134
-
135
- async function getProcessInformation(appName: string): Promise<void> {
136
- try {
137
- console.log('\n--- āš™ļø Process Information (Kudu API) ---');
138
-
139
- // Get access token for Kudu API
140
- const token = execSync('az account get-access-token --resource https://management.azure.com/ --query accessToken -o tsv', { encoding: 'utf8' }).trim();
141
-
142
- // Import axios dynamically
143
- const axios = (await import('axios')).default;
144
-
145
- // Get process list from Kudu
146
- console.log('šŸ“‹ Fetching running processes...');
147
- const processResponse = await axios.get(`https://${appName}.scm.azurewebsites.net/api/processes`, {
148
- headers: { Authorization: `Bearer ${token}` },
149
- timeout: 10000
150
- });
151
-
152
- const processes = processResponse.data;
153
-
154
- // Sort by CPU usage and show top processes
155
- const sortedProcesses = processes
156
- .filter((p: any) => p.cpu_usage !== undefined)
157
- .sort((a: any, b: any) => (b.cpu_usage || 0) - (a.cpu_usage || 0))
158
- .slice(0, 10);
159
-
160
- console.log('\nšŸ”„ Top 10 Processes by CPU Usage:');
161
- console.log('PID\tCPU%\tMemory(MB)\tName');
162
- console.log('---\t----\t---------\t----');
163
-
164
- for (const process of sortedProcesses) {
165
- const pid = process.id || 'N/A';
166
- const cpu = process.cpu_usage ? process.cpu_usage.toFixed(2) : '0.00';
167
- const memory = process.working_set ? (process.working_set / 1024 / 1024).toFixed(1) : 'N/A';
168
- const name = process.name || 'Unknown';
169
-
170
- console.log(`${pid}\t${cpu}\t${memory}\t\t${name.substring(0, 30)}`);
171
- }
172
-
173
- } catch (error: any) {
174
- console.log(`āš ļø Could not fetch process information: ${error.message.split('\n')[0]}`);
175
- console.log(' This might be due to authentication issues or Kudu API being unavailable.');
176
- }
177
- }
178
-
179
- async function getSystemInformation(appName: string): Promise<void> {
180
- try {
181
- console.log('\n--- šŸ–„ļø System Information ---');
182
-
183
- const token = execSync('az account get-access-token --resource https://management.azure.com/ --query accessToken -o tsv', { encoding: 'utf8' }).trim();
184
- const axios = (await import('axios')).default;
185
-
186
- // Get system info using Kudu command API
187
- console.log('šŸ“Š Fetching system information...');
188
-
189
- const commands = [
190
- { name: 'Memory Info', cmd: 'cat /proc/meminfo | head -10' },
191
- { name: 'CPU Info', cmd: 'cat /proc/cpuinfo | grep "model name" | head -1' },
192
- { name: 'Disk Usage', cmd: 'df -h | head -5' },
193
- { name: 'Load Average', cmd: 'uptime' }
194
- ];
195
-
196
- for (const command of commands) {
197
- try {
198
- const response = await axios.post(`https://${appName}.scm.azurewebsites.net/api/command`, {
199
- command: command.cmd,
200
- dir: path.join(path.sep, 'home')
201
- }, {
202
- headers: { Authorization: `Bearer ${token}` },
203
- timeout: 5000
204
- });
205
-
206
- console.log(`\n${command.name}:`);
207
- const output = response.data.Output || response.data.Error || 'No output';
208
- console.log(output.split('\n').map((line: string) => ` ${line}`).join('\n'));
209
-
210
- } catch (cmdError: any) {
211
- console.log(`\n${command.name}: Could not retrieve (${cmdError.message.split('\n')[0]})`);
212
- }
213
- }
214
-
215
- } catch (error: any) {
216
- console.log(`āš ļø Could not fetch system information: ${error.message.split('\n')[0]}`);
217
- }
218
- }
219
-
220
- async function getApplicationLogs(appName: string, resourceGroup: string): Promise<void> {
221
- try {
222
- console.log('\n--- šŸ“‹ Recent Application Logs ---');
223
-
224
- // Get recent logs using Azure CLI
225
- console.log('šŸ“„ Fetching recent application logs...');
226
- const logsCmd = `az webapp log tail --name ${appName} --resource-group ${resourceGroup} --provider application --timeout 5`;
227
-
228
- try {
229
- const logs = execSync(logsCmd, { encoding: 'utf8', timeout: 10000 });
230
- console.log('Recent logs:');
231
- console.log(logs.split('\n').slice(-20).map(line => ` ${line}`).join('\n'));
232
- } catch (logError) {
233
- console.log('āš ļø Could not fetch logs - they may not be enabled or available');
234
- console.log(' Enable application logging in Azure portal for better diagnostics');
235
- }
236
-
237
- } catch (error: any) {
238
- console.log(`āš ļø Could not fetch application logs: ${error.message.split('\n')[0]}`);
239
- }
240
- }
241
-
242
- async function profileLocalEnvironment(): Promise<void> {
243
- console.log('\n--- šŸ  Local Environment Profiling ---');
244
-
245
- try {
246
- // Basic system information
247
- console.log('šŸ’» System Information:');
248
-
249
- if (process.platform === 'win32') {
250
- try {
251
- const systemInfo = execSync('systeminfo | findstr /C:"Total Physical Memory" /C:"Available Physical Memory" /C:"Processor"', { encoding: 'utf8' });
252
- console.log(systemInfo.split('\n').map(line => ` ${line.trim()}`).filter(line => line).join('\n'));
253
- } catch {
254
- console.log(' Could not retrieve Windows system info');
255
- }
256
- } else {
257
- try {
258
- const memInfo = execSync('free -h', { encoding: 'utf8' });
259
- const cpuInfo = execSync('cat /proc/cpuinfo | grep "model name" | head -1', { encoding: 'utf8' });
260
- console.log(' Memory:');
261
- console.log(memInfo.split('\n').map(line => ` ${line}`).join('\n'));
262
- console.log(' CPU:');
263
- console.log(` ${cpuInfo.trim()}`);
264
- } catch {
265
- console.log(' Could not retrieve Linux system info');
266
- }
267
- }
268
-
269
- // Node.js process information
270
- console.log('\n🟢 Node.js Process Information:');
271
- console.log(` Node Version: ${process.version}`);
272
- console.log(` Platform: ${process.platform}`);
273
- console.log(` Architecture: ${process.arch}`);
274
- console.log(` Memory Usage:`);
275
- const memUsage = process.memoryUsage();
276
- console.log(` RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)} MB`);
277
- console.log(` Heap Used: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
278
- console.log(` Heap Total: ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
279
- console.log(` External: ${(memUsage.external / 1024 / 1024).toFixed(2)} MB`);
280
-
281
- } catch (error: any) {
282
- console.log(`āš ļø Error profiling local environment: ${error.message}`);
283
- }
284
- }
285
-
286
- async function main() {
287
- const config = loadClientConfig();
288
-
289
- // Azure configuration with environment variable fallbacks
290
- const azureConfig = {
291
- prodAppName: config.azure?.prodAppName || getEnvOr(['FRAIM_AZURE_PROD_APP_NAME'], 'fraim-app-prod'),
292
- prodResourceGroup: config.azure?.prodResourceGroup || getEnvOr(['FRAIM_AZURE_PROD_RESOURCE_GROUP'], 'fraim-prod-rg'),
293
- preprodAppName: config.azure?.preprodAppName || getEnvOr(['FRAIM_AZURE_PREPROD_APP_NAME'], 'fraim-app-pre-prod'),
294
- preprodResourceGroup: config.azure?.preprodResourceGroup || getEnvOr(['FRAIM_AZURE_PREPROD_RESOURCE_GROUP'], 'fraim-pre-prod-rg'),
295
- localAppName: config.azure?.localAppName || getEnvOr(['FRAIM_AZURE_LOCAL_APP_NAME'], 'local'),
296
- localResourceGroup: config.azure?.localResourceGroup || getEnvOr(['FRAIM_AZURE_LOCAL_RESOURCE_GROUP'], 'local')
297
- };
298
-
299
- const CONFIGS: Record<string, ProfilingConfig> = {
300
- prod: {
301
- env: 'prod',
302
- appName: azureConfig.prodAppName,
303
- resourceGroup: azureConfig.prodResourceGroup
304
- },
305
- preprod: {
306
- env: 'preprod',
307
- appName: azureConfig.preprodAppName,
308
- resourceGroup: azureConfig.preprodResourceGroup
309
- },
310
- local: {
311
- env: 'local',
312
- appName: azureConfig.localAppName,
313
- resourceGroup: azureConfig.localResourceGroup
314
- }
315
- };
316
-
317
- const args = process.argv.slice(2);
318
- let profileConfig: ProfilingConfig = CONFIGS.local;
319
- const includeLogs = args.includes('--logs');
320
-
321
- if (args.includes('--help') || args.includes('-h')) {
322
- console.log(`
323
- šŸ” Azure App Service Profiler
324
-
325
- Usage:
326
- npx tsx profile-server.ts [options]
327
-
328
- Options:
329
- --prod Profile production environment
330
- --preprod Profile pre-production environment
331
- --local Profile local environment (default)
332
- --logs Include application logs in analysis
333
- --help, -h Show this help message
334
-
335
- Examples:
336
- # Profile production server
337
- npx tsx profile-server.ts --prod
338
-
339
- # Profile with logs
340
- npx tsx profile-server.ts --prod --logs
341
-
342
- # Profile local environment
343
- npx tsx profile-server.ts --local
344
-
345
- Requirements:
346
- - Azure CLI (az) installed and authenticated
347
- - Proper permissions to access App Service resources
348
- - For Kudu API access: Contributor role on the App Service
349
-
350
- Configuration:
351
- Reads Azure settings from .fraim/config.json or environment variables:
352
- - FRAIM_AZURE_PROD_APP_NAME
353
- - FRAIM_AZURE_PROD_RESOURCE_GROUP
354
- - FRAIM_AZURE_PREPROD_APP_NAME
355
- - FRAIM_AZURE_PREPROD_RESOURCE_GROUP
356
- `);
357
- return;
358
- }
359
-
360
- if (args.includes('--prod')) profileConfig = CONFIGS.prod;
361
- else if (args.includes('--preprod')) profileConfig = CONFIGS.preprod;
362
- else if (args.includes('--local')) profileConfig = CONFIGS.local;
363
-
364
- console.log(`\nšŸš€ Starting Server Profiling`);
365
- console.log(`šŸ“Š Environment: ${profileConfig.env.toUpperCase()}`);
366
- console.log(`šŸ·ļø App: ${profileConfig.appName}`);
367
- console.log(`šŸ“ Resource Group: ${profileConfig.resourceGroup}`);
368
-
369
- if (profileConfig.env === 'local') {
370
- await profileLocalEnvironment();
371
- console.log('\nāœ… Local profiling completed');
372
- return;
373
- }
374
-
375
- // Check prerequisites for Azure profiling
376
- console.log('\nšŸ” Checking prerequisites...');
377
-
378
- if (!checkAzureCLI()) {
379
- console.error('āŒ Azure CLI not found. Please install Azure CLI first.');
380
- console.error(' Download from: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli');
381
- process.exit(1);
382
- }
383
- console.log('āœ… Azure CLI found');
384
-
385
- if (!checkAzureAuth()) {
386
- console.error('āŒ Not authenticated with Azure. Please run: az login');
387
- process.exit(1);
388
- }
389
- console.log('āœ… Azure authentication verified');
390
-
391
- try {
392
- // Verify app exists
393
- console.log(`\nšŸ” Verifying App Service: ${profileConfig.appName}`);
394
- execSync(`az webapp show --name ${profileConfig.appName} --resource-group ${profileConfig.resourceGroup} --query name -o tsv`, { stdio: 'pipe' });
395
- console.log('āœ… App Service found');
396
-
397
- // Run profiling analysis
398
- await getAppServicePlanMetrics(profileConfig.appName, profileConfig.resourceGroup);
399
- await getAppServiceMetrics(profileConfig.appName, profileConfig.resourceGroup);
400
- await getProcessInformation(profileConfig.appName);
401
- await getSystemInformation(profileConfig.appName);
402
-
403
- if (includeLogs) {
404
- await getApplicationLogs(profileConfig.appName, profileConfig.resourceGroup);
405
- }
406
-
407
- console.log('\nāœ… Server profiling completed successfully');
408
- console.log('\nšŸ’” Tips:');
409
- console.log(' - Use --logs flag to include application logs');
410
- console.log(' - High CPU usage may indicate performance bottlenecks');
411
- console.log(' - High memory usage may indicate memory leaks');
412
- console.log(' - Check process list for unexpected or resource-heavy processes');
413
-
414
- } catch (error: any) {
415
- console.error(`\nāŒ Profiling failed: ${error.message}`);
416
- console.error('\nTroubleshooting:');
417
- console.error(' - Verify app name and resource group are correct');
418
- console.error(' - Ensure you have proper permissions (Contributor role)');
419
- console.error(' - Check if the App Service is running');
420
- console.error(' - Try: az webapp list --query "[].{name:name, resourceGroup:resourceGroup}"');
421
- process.exit(1);
422
- }
423
- }
424
-
425
- // Run the main function
426
- main().catch(console.error);
@@ -1,122 +0,0 @@
1
- #!/usr/bin/env tsx
2
-
3
- /**
4
- * Runner script for thank-you email workflow
5
- * Called by AI agents to generate thank-you emails
6
- */
7
-
8
- import { getResolvedIssues, findExecutiveByEmail, getPersonaEmailForExecutive } from './generate-engagement-emails';
9
- import { writeFileSync, mkdirSync } from 'fs';
10
- import { join } from 'path';
11
-
12
- interface CustomerData {
13
- email: string;
14
- name: string;
15
- issues: Array<{
16
- number: number;
17
- title: string;
18
- body: string;
19
- }>;
20
- executiveId?: string;
21
- executiveName?: string;
22
- personaEmail?: string;
23
- }
24
-
25
- async function main() {
26
- console.log('šŸŽÆ Starting thank-you email generation workflow...\n');
27
-
28
- // Step 1: Get resolved issues
29
- console.log('šŸ“‹ Step 1: Retrieving resolved issues...');
30
- const issues = await getResolvedIssues();
31
-
32
- console.log(`\nāœ… Found ${issues.length} resolved issues\n`);
33
-
34
- // Step 2: Extract customer information
35
- console.log('šŸ“§ Step 2: Extracting customer information...\n');
36
-
37
- const customerMap = new Map<string, CustomerData>();
38
-
39
- for (const issue of issues) {
40
- // Extract email and name from issue body or title
41
- let customerEmail: string | null = null;
42
- let customerName: string | null = null;
43
-
44
- // Try to extract from body first
45
- const bodyEmailMatch = issue.body?.match(/\*\*Reported by:\*\*\s+(.+?)\s+\((.+?)\)/);
46
- if (bodyEmailMatch) {
47
- customerName = bodyEmailMatch[1].trim();
48
- customerEmail = bodyEmailMatch[2].trim();
49
- }
50
-
51
- // Try to extract from title (format: "email: summary")
52
- if (!customerEmail) {
53
- const titleEmailMatch = issue.title.match(/^([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}):/);
54
- if (titleEmailMatch) {
55
- customerEmail = titleEmailMatch[1];
56
- }
57
- }
58
-
59
- if (!customerEmail) {
60
- console.log(`āš ļø Issue #${issue.number}: Could not extract customer email, skipping`);
61
- continue;
62
- }
63
-
64
- // Normalize email to lowercase for consistent matching
65
- const normalizedEmail = customerEmail.toLowerCase();
66
-
67
- // Add or update customer data
68
- if (!customerMap.has(normalizedEmail)) {
69
- customerMap.set(normalizedEmail, {
70
- email: normalizedEmail,
71
- name: customerName || 'Valued Customer',
72
- issues: []
73
- });
74
- }
75
-
76
- const customerData = customerMap.get(normalizedEmail)!;
77
- customerData.issues.push({
78
- number: issue.number,
79
- title: issue.title,
80
- body: issue.body || ''
81
- });
82
- }
83
-
84
- console.log(`šŸ“Š Found ${customerMap.size} unique customers\n`);
85
-
86
- // Step 3: Lookup executive data for each customer
87
- console.log('šŸ” Step 3: Looking up executive data...\n');
88
-
89
- const entries = Array.from(customerMap.entries());
90
- for (const [email, customerData] of entries) {
91
- try {
92
- const executive = await findExecutiveByEmail(email);
93
-
94
- if (executive) {
95
- customerData.executiveId = executive.id;
96
- customerData.executiveName = executive.name;
97
-
98
- if (executive.id) {
99
- const personaEmail = await getPersonaEmailForExecutive(executive.id);
100
- customerData.personaEmail = personaEmail;
101
- console.log(`āœ… ${email}: Found executive ${executive.name} (${executive.id}), Persona email: ${personaEmail}`);
102
- } else {
103
- console.log(`āš ļø ${email}: Found executive ${executive.name} but no ID`);
104
- }
105
- } else {
106
- console.log(`āš ļø ${email}: No executive record found in database`);
107
- }
108
- } catch (error) {
109
- console.error(`āŒ ${email}: Error looking up executive:`, error);
110
- }
111
- }
112
-
113
- console.log('\nšŸ“ Customer Data Summary:\n');
114
- console.log(JSON.stringify(Array.from(customerMap.values()), null, 2));
115
-
116
- // Save to temp file for AI agent to process
117
- const outputPath = join(process.cwd(), 'temp-customer-data.json');
118
- writeFileSync(outputPath, JSON.stringify(Array.from(customerMap.values()), null, 2));
119
- console.log(`\nšŸ’¾ Customer data saved to: ${outputPath}`);
120
- }
121
-
122
- main().catch(console.error);