fraim-framework 2.0.27 → 2.0.30

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 (98) hide show
  1. package/.github/workflows/deploy-fraim.yml +1 -1
  2. package/dist/registry/scripts/build-scripts-generator.js +205 -0
  3. package/dist/registry/scripts/cleanup-branch.js +258 -0
  4. package/dist/registry/scripts/evaluate-code-quality.js +66 -0
  5. package/dist/registry/scripts/exec-with-timeout.js +142 -0
  6. package/dist/registry/scripts/fraim-config.js +61 -0
  7. package/dist/registry/scripts/generate-engagement-emails.js +630 -0
  8. package/dist/registry/scripts/generic-issues-api.js +100 -0
  9. package/dist/registry/scripts/newsletter-helpers.js +731 -0
  10. package/dist/registry/scripts/openapi-generator.js +664 -0
  11. package/dist/registry/scripts/performance/profile-server.js +390 -0
  12. package/dist/registry/scripts/run-thank-you-workflow.js +92 -0
  13. package/dist/registry/scripts/send-newsletter-simple.js +85 -0
  14. package/dist/registry/scripts/send-thank-you-emails.js +54 -0
  15. package/dist/registry/scripts/validate-openapi-limits.js +311 -0
  16. package/dist/registry/scripts/validate-test-coverage.js +262 -0
  17. package/dist/registry/scripts/verify-test-coverage.js +66 -0
  18. package/dist/src/cli/commands/init.js +14 -14
  19. package/dist/src/cli/commands/sync.js +4 -4
  20. package/dist/src/cli/fraim.js +24 -22
  21. package/dist/src/cli/setup/first-run.js +13 -6
  22. package/dist/src/fraim/db-service.js +26 -15
  23. package/dist/src/fraim/issues.js +67 -0
  24. package/dist/src/fraim-mcp-server.js +272 -18
  25. package/dist/src/utils/git-utils.js +1 -1
  26. package/dist/tests/debug-tools.js +79 -0
  27. package/dist/tests/esm-compat.js +11 -0
  28. package/dist/tests/test-chalk-esm-issue.js +159 -0
  29. package/dist/tests/test-chalk-real-world.js +265 -0
  30. package/dist/tests/test-chalk-regression.js +327 -0
  31. package/dist/tests/test-chalk-resolution-issue.js +304 -0
  32. package/dist/tests/test-fraim-install-chalk-issue.js +254 -0
  33. package/dist/tests/test-fraim-issues.js +59 -0
  34. package/dist/tests/test-genericization.js +1 -1
  35. package/dist/tests/test-mcp-connection.js +166 -0
  36. package/dist/tests/test-mcp-issue-integration.js +144 -0
  37. package/dist/tests/test-mcp-lifecycle-methods.js +312 -0
  38. package/dist/tests/test-node-compatibility.js +71 -0
  39. package/dist/tests/test-npm-install.js +66 -0
  40. package/dist/tests/test-npm-resolution-diagnostic.js +140 -0
  41. package/dist/tests/test-session-rehydration.js +145 -0
  42. package/dist/tests/test-standalone.js +2 -8
  43. package/dist/tests/test-telemetry.js +190 -0
  44. package/package.json +10 -8
  45. package/registry/agent-guardrails.md +62 -54
  46. package/registry/rules/agent-success-criteria.md +52 -0
  47. package/registry/rules/agent-testing-guidelines.md +502 -502
  48. package/registry/rules/communication.md +121 -121
  49. package/registry/rules/continuous-learning.md +54 -54
  50. package/registry/rules/ephemeral-execution.md +10 -5
  51. package/registry/rules/hitl-ppe-record-analysis.md +302 -302
  52. package/registry/rules/local-development.md +251 -251
  53. package/registry/rules/software-development-lifecycle.md +104 -104
  54. package/registry/rules/successful-debugging-patterns.md +482 -478
  55. package/registry/rules/telemetry.md +67 -0
  56. package/registry/scripts/build-scripts-generator.ts +216 -215
  57. package/registry/scripts/cleanup-branch.ts +303 -284
  58. package/registry/scripts/code-quality-check.sh +559 -559
  59. package/registry/scripts/detect-tautological-tests.sh +38 -38
  60. package/registry/scripts/evaluate-code-quality.ts +1 -1
  61. package/registry/scripts/generate-engagement-emails.ts +744 -744
  62. package/registry/scripts/generic-issues-api.ts +110 -150
  63. package/registry/scripts/newsletter-helpers.ts +874 -874
  64. package/registry/scripts/openapi-generator.ts +695 -693
  65. package/registry/scripts/performance/profile-server.ts +5 -3
  66. package/registry/scripts/prep-issue.sh +468 -455
  67. package/registry/scripts/validate-openapi-limits.ts +366 -365
  68. package/registry/scripts/validate-test-coverage.ts +280 -280
  69. package/registry/scripts/verify-pr-comments.sh +70 -70
  70. package/registry/scripts/verify-test-coverage.ts +1 -1
  71. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +53 -53
  72. package/registry/templates/evidence/Implementation-BugEvidence.md +85 -85
  73. package/registry/templates/evidence/Implementation-FeatureEvidence.md +120 -120
  74. package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +66 -0
  75. package/registry/workflows/bootstrap/create-architecture.md +2 -2
  76. package/registry/workflows/bootstrap/evaluate-code-quality.md +3 -3
  77. package/registry/workflows/bootstrap/verify-test-coverage.md +2 -2
  78. package/registry/workflows/customer-development/insight-analysis.md +156 -156
  79. package/registry/workflows/customer-development/interview-preparation.md +421 -421
  80. package/registry/workflows/customer-development/strategic-brainstorming.md +146 -146
  81. package/registry/workflows/customer-development/thank-customers.md +193 -191
  82. package/registry/workflows/customer-development/weekly-newsletter.md +362 -352
  83. package/registry/workflows/improve-fraim/contribute.md +32 -0
  84. package/registry/workflows/improve-fraim/file-issue.md +32 -0
  85. package/registry/workflows/marketing/hbr-article.md +73 -0
  86. package/registry/workflows/performance/analyze-performance.md +63 -59
  87. package/registry/workflows/product-building/design.md +3 -2
  88. package/registry/workflows/product-building/implement.md +4 -3
  89. package/registry/workflows/product-building/prep-issue.md +28 -17
  90. package/registry/workflows/product-building/resolve.md +3 -2
  91. package/registry/workflows/product-building/retrospect.md +3 -2
  92. package/registry/workflows/product-building/spec.md +5 -4
  93. package/registry/workflows/product-building/test.md +3 -2
  94. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +562 -562
  95. package/registry/workflows/replicate/website-discovery-analysis.md +3 -3
  96. package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +632 -632
  97. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +669 -669
  98. package/tsconfig.json +2 -1
@@ -8,11 +8,11 @@ const commander_1 = require("commander");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
- const first_run_js_1 = require("../setup/first-run.js");
12
- const sync_js_1 = require("./sync.js");
13
- const types_js_1 = require("../../fraim/types.js");
14
- const git_utils_js_1 = require("../../utils/git-utils.js");
15
- const version_utils_js_1 = require("../../utils/version-utils.js");
11
+ const first_run_1 = require("../setup/first-run");
12
+ const sync_1 = require("./sync");
13
+ const types_1 = require("../../fraim/types");
14
+ const git_utils_1 = require("../../utils/git-utils");
15
+ const version_utils_1 = require("../../utils/version-utils");
16
16
  const runInit = async () => {
17
17
  const projectRoot = process.cwd();
18
18
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
@@ -26,18 +26,18 @@ const runInit = async () => {
26
26
  console.log(chalk_1.default.yellow('ℹ️ .fraim directory already exists'));
27
27
  }
28
28
  if (!fs_1.default.existsSync(configPath)) {
29
- const remoteInfo = (0, git_utils_js_1.getGitRemoteInfo)();
29
+ const remoteInfo = (0, git_utils_1.getGitRemoteInfo)();
30
30
  const config = {
31
- ...types_js_1.DEFAULT_FRAIM_CONFIG,
32
- version: (0, version_utils_js_1.getFraimVersion)(),
31
+ ...types_1.DEFAULT_FRAIM_CONFIG,
32
+ version: (0, version_utils_1.getFraimVersion)(),
33
33
  project: {
34
- ...types_js_1.DEFAULT_FRAIM_CONFIG.project,
34
+ ...types_1.DEFAULT_FRAIM_CONFIG.project,
35
35
  name: path_1.default.basename(projectRoot)
36
36
  },
37
37
  git: {
38
- ...types_js_1.DEFAULT_FRAIM_CONFIG.git,
39
- repoOwner: remoteInfo.owner || types_js_1.DEFAULT_FRAIM_CONFIG.git.repoOwner,
40
- repoName: remoteInfo.repo || types_js_1.DEFAULT_FRAIM_CONFIG.git.repoName
38
+ ...types_1.DEFAULT_FRAIM_CONFIG.git,
39
+ repoOwner: remoteInfo.owner || types_1.DEFAULT_FRAIM_CONFIG.git.repoOwner,
40
+ repoName: remoteInfo.repo || types_1.DEFAULT_FRAIM_CONFIG.git.repoName
41
41
  }
42
42
  };
43
43
  fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
@@ -53,9 +53,9 @@ const runInit = async () => {
53
53
  });
54
54
  console.log(chalk_1.default.blue('\n🎉 FRAIM initialized successfully!'));
55
55
  // Sync workflows from registry
56
- await (0, sync_js_1.runSync)({});
56
+ await (0, sync_1.runSync)({});
57
57
  // Trigger First Run Experience
58
- await (0, first_run_js_1.runFirstRunExperience)();
58
+ await (0, first_run_1.runFirstRunExperience)();
59
59
  process.exit(0);
60
60
  };
61
61
  exports.runInit = runInit;
@@ -10,11 +10,11 @@ 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
12
  const stub_generator_1 = require("../../utils/stub-generator");
13
- const config_loader_js_1 = require("../../fraim/config-loader.js");
14
- const version_utils_js_1 = require("../../utils/version-utils.js");
13
+ const config_loader_1 = require("../../fraim/config-loader");
14
+ const version_utils_1 = require("../../utils/version-utils");
15
15
  const runSync = async (options) => {
16
16
  const projectRoot = process.cwd();
17
- const config = (0, config_loader_js_1.loadFraimConfig)();
17
+ const config = (0, config_loader_1.loadFraimConfig)();
18
18
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
19
19
  const workflowsRelativePath = config.customizations?.workflowsPath || '.fraim/workflows';
20
20
  const workflowsDir = path_1.default.resolve(projectRoot, workflowsRelativePath);
@@ -43,7 +43,7 @@ const runSync = async (options) => {
43
43
  if (fs_1.default.existsSync(configPath)) {
44
44
  try {
45
45
  const currentConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
46
- const newVersion = (0, version_utils_js_1.getFraimVersion)();
46
+ const newVersion = (0, version_utils_1.getFraimVersion)();
47
47
  if (currentConfig.version !== newVersion) {
48
48
  currentConfig.version = newVersion;
49
49
  fs_1.default.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
@@ -5,39 +5,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
- const init_js_1 = require("./commands/init.js");
9
- const sync_js_1 = require("./commands/sync.js");
10
- const doctor_js_1 = require("./commands/doctor.js");
11
- const list_js_1 = require("./commands/list.js");
12
- const wizard_js_1 = require("./commands/wizard.js");
8
+ const init_1 = require("./commands/init");
9
+ const sync_1 = require("./commands/sync");
10
+ const doctor_1 = require("./commands/doctor");
11
+ const list_1 = require("./commands/list");
12
+ const wizard_1 = require("./commands/wizard");
13
13
  const fs_1 = __importDefault(require("fs"));
14
14
  const path_1 = __importDefault(require("path"));
15
15
  const program = new commander_1.Command();
16
16
  // Load version from package.json
17
17
  // Handle both src/ (dev) and dist/ (prod) execution paths
18
- let packageJson;
18
+ let packageJson = { version: 'unknown' };
19
19
  try {
20
- // Try 2 levels up (src/cli -> root) - for tsx dev
21
- packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', 'package.json'), 'utf8'));
20
+ // Robustly find package.json by searching upwards from this file's directory
21
+ let currentDir = __dirname;
22
+ let found = false;
23
+ for (let i = 0; i < 5; i++) { // Max search depth 5
24
+ const pkgPath = path_1.default.join(currentDir, 'package.json');
25
+ if (fs_1.default.existsSync(pkgPath)) {
26
+ packageJson = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
27
+ found = true;
28
+ break;
29
+ }
30
+ currentDir = path_1.default.dirname(currentDir);
31
+ }
22
32
  }
23
33
  catch (e) {
24
- try {
25
- // Try 3 levels up (dist/src/cli -> root) - for compiled js
26
- packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', '..', 'package.json'), 'utf8'));
27
- }
28
- catch (e2) {
29
- // Fallback or throw
30
- console.error('Could not locate package.json');
31
- process.exit(1);
32
- }
34
+ console.warn('⚠️ Could not fully resolve package.json version.');
33
35
  }
34
36
  program
35
37
  .name('fraim')
36
38
  .description('FRAIM Framework CLI - Manage your AI workflows and rules')
37
39
  .version(packageJson.version);
38
- program.addCommand(init_js_1.initCommand);
39
- program.addCommand(sync_js_1.syncCommand);
40
- program.addCommand(doctor_js_1.doctorCommand);
41
- program.addCommand(list_js_1.listCommand);
42
- program.addCommand(wizard_js_1.wizardCommand);
40
+ program.addCommand(init_1.initCommand);
41
+ program.addCommand(sync_1.syncCommand);
42
+ program.addCommand(doctor_1.doctorCommand);
43
+ program.addCommand(list_1.listCommand);
44
+ program.addCommand(wizard_1.wizardCommand);
43
45
  program.parse(process.argv);
@@ -47,12 +47,19 @@ const runFirstRunExperience = async () => {
47
47
  }
48
48
  console.log(chalk_1.default.blue('\n👋 Welcome to FRAIM! Let\'s get you set up.\n'));
49
49
  // 1. Ask for FRAIM key
50
- const response = await (0, prompts_1.default)({
51
- type: 'text',
52
- name: 'fraimKey',
53
- message: 'Do you have a FRAIM key? (Input key or press Enter to skip)',
54
- validate: (value) => true // Optional input
55
- });
50
+ let response;
51
+ try {
52
+ response = await (0, prompts_1.default)({
53
+ type: 'text',
54
+ name: 'fraimKey',
55
+ message: 'Do you have a FRAIM key? (Input key or press Enter to skip)',
56
+ validate: (value) => true // Optional input
57
+ });
58
+ }
59
+ catch (e) {
60
+ console.warn(chalk_1.default.yellow('\n⚠️ Interactive prompts experienced an issue. Skipping setup.\n'));
61
+ return;
62
+ }
56
63
  if (response.fraimKey && response.fraimKey.trim().length > 0) {
57
64
  const key = response.fraimKey.trim();
58
65
  console.log(chalk_1.default.green('\n✅ Key received.'));
@@ -17,32 +17,43 @@ class FraimDbService {
17
17
  this.db = this.client.db(dbName);
18
18
  // Use fraim_ prefix for standalone server collections
19
19
  this.keysCollection = this.db.collection('fraim_api_keys');
20
- this.logsCollection = this.db.collection('fraim_usage_logs');
20
+ this.sessionsCollection = this.db.collection('fraim_telemetry_sessions');
21
21
  // Create indexes
22
22
  await this.keysCollection.createIndex({ key: 1 }, { unique: true });
23
- await this.logsCollection.createIndex({ keyId: 1 });
24
- await this.logsCollection.createIndex({ timestamp: -1 });
23
+ await this.sessionsCollection.createIndex({ sessionId: 1 }, { unique: true });
24
+ await this.sessionsCollection.createIndex({ userId: 1 });
25
+ await this.sessionsCollection.createIndex({ lastActive: -1 });
25
26
  console.log(`✅ Connected to Fraim DB: ${dbName}`);
26
27
  }
28
+ async createSession(session) {
29
+ if (!this.sessionsCollection)
30
+ throw new Error('DB not connected');
31
+ await this.sessionsCollection.insertOne(session);
32
+ }
33
+ async updateSessionActivity(sessionId, lastActive) {
34
+ if (!this.sessionsCollection)
35
+ return; // Fail silently
36
+ await this.sessionsCollection.updateOne({ sessionId }, { $set: { lastActive } });
37
+ }
27
38
  async verifyApiKey(key) {
28
39
  if (!this.keysCollection)
29
40
  throw new Error('DB not connected');
30
41
  const apiKey = await this.keysCollection.findOne({ key, isActive: true });
31
42
  return apiKey;
32
43
  }
33
- async logUsage(log) {
34
- if (!this.logsCollection)
35
- return; // Fail silently for logs
36
- try {
37
- await this.logsCollection.insertOne({
38
- ...log,
39
- timestamp: new Date()
40
- });
41
- }
42
- catch (e) {
43
- console.error('⚠️ Failed to log usage:', e.message);
44
- }
44
+ async getActiveSessionByApiKey(key) {
45
+ if (!this.keysCollection || !this.sessionsCollection)
46
+ throw new Error('DB not connected');
47
+ // 1. Get user for this key
48
+ const apiKeyData = await this.verifyApiKey(key);
49
+ if (!apiKeyData)
50
+ return null;
51
+ // 2. Get latest session for this user (within last 24h)
52
+ const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
53
+ const session = await this.sessionsCollection.findOne({ userId: apiKeyData.userId, lastActive: { $gt: dayAgo } }, { sort: { lastActive: -1 } });
54
+ return session;
45
55
  }
56
+ // ... (rest of methods)
46
57
  async listApiKeys() {
47
58
  if (!this.keysCollection)
48
59
  throw new Error('DB not connected');
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fileFraimIssue = fileFraimIssue;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const config_loader_1 = require("./config-loader");
9
+ /**
10
+ * File a GitHub issue in the configured FRAIM repository
11
+ */
12
+ async function fileFraimIssue(params) {
13
+ const { title, body, labels, dryRun } = params;
14
+ // Load config
15
+ const config = (0, config_loader_1.loadFraimConfig)();
16
+ const owner = config.git?.repoOwner || 'mathursrus';
17
+ const repo = config.git?.repoName || 'FRAIM';
18
+ const url = `https://api.github.com/repos/${owner}/${repo}/issues`;
19
+ const payload = {
20
+ title,
21
+ body
22
+ };
23
+ if (labels && labels.length > 0) {
24
+ payload.labels = labels;
25
+ }
26
+ if (dryRun) {
27
+ return {
28
+ success: true,
29
+ dryRun: true,
30
+ message: `[DRY RUN] Would POST to ${url} with title: "${title}"`
31
+ };
32
+ }
33
+ const token = process.env.GITHUB_TOKEN;
34
+ if (!token) {
35
+ return {
36
+ success: false,
37
+ message: 'GITHUB_TOKEN environment variable is required'
38
+ };
39
+ }
40
+ try {
41
+ const response = await axios_1.default.post(url, payload, {
42
+ headers: {
43
+ 'Authorization': `Bearer ${token}`,
44
+ 'Accept': 'application/vnd.github.v3+json',
45
+ 'Content-Type': 'application/json',
46
+ },
47
+ });
48
+ return {
49
+ success: true,
50
+ issueNumber: response.data.number,
51
+ htmlUrl: response.data.html_url
52
+ };
53
+ }
54
+ catch (error) {
55
+ let errorMessage = 'Unknown error';
56
+ if (axios_1.default.isAxiosError(error)) {
57
+ errorMessage = `Status: ${error.response?.status} - ${JSON.stringify(error.response?.data)}`;
58
+ }
59
+ else if (error instanceof Error) {
60
+ errorMessage = error.message;
61
+ }
62
+ return {
63
+ success: false,
64
+ message: errorMessage
65
+ };
66
+ }
67
+ }