fraim-framework 2.0.64 → 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 (107) 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 +23 -3
  18. package/dist/src/utils/remote-sync.js +130 -0
  19. package/package.json +2 -3
  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/azure/cost-optimization.md +0 -11
  49. package/registry/stubs/workflows/bootstrap/create-architecture.md +0 -11
  50. package/registry/stubs/workflows/bootstrap/detect-broken-windows.md +0 -11
  51. package/registry/stubs/workflows/bootstrap/evaluate-code-quality.md +0 -11
  52. package/registry/stubs/workflows/bootstrap/verify-test-coverage.md +0 -11
  53. package/registry/stubs/workflows/brainstorming/blue-sky-brainstorming.md +0 -11
  54. package/registry/stubs/workflows/brainstorming/codebase-brainstorming.md +0 -11
  55. package/registry/stubs/workflows/business-development/create-business-plan.md +0 -11
  56. package/registry/stubs/workflows/business-development/ideate-business-opportunity.md +0 -11
  57. package/registry/stubs/workflows/business-development/price-product.md +0 -18
  58. package/registry/stubs/workflows/compliance/detect-compliance-requirements.md +0 -11
  59. package/registry/stubs/workflows/compliance/generate-audit-evidence.md +0 -11
  60. package/registry/stubs/workflows/compliance/soc2-evidence-generator.md +0 -11
  61. package/registry/stubs/workflows/customer-development/insight-analysis.md +0 -11
  62. package/registry/stubs/workflows/customer-development/insight-triage.md +0 -11
  63. package/registry/stubs/workflows/customer-development/interview-preparation.md +0 -11
  64. package/registry/stubs/workflows/customer-development/linkedin-outreach.md +0 -11
  65. package/registry/stubs/workflows/customer-development/strategic-brainstorming.md +0 -11
  66. package/registry/stubs/workflows/customer-development/thank-customers.md +0 -11
  67. package/registry/stubs/workflows/customer-development/user-survey-dispatch.md +0 -11
  68. package/registry/stubs/workflows/customer-development/users-to-target.md +0 -11
  69. package/registry/stubs/workflows/customer-development/weekly-newsletter.md +0 -11
  70. package/registry/stubs/workflows/deploy/cloud-deployment.md +0 -11
  71. package/registry/stubs/workflows/improve-fraim/contribute.md +0 -11
  72. package/registry/stubs/workflows/improve-fraim/file-issue.md +0 -11
  73. package/registry/stubs/workflows/learning/build-skillset.md +0 -11
  74. package/registry/stubs/workflows/learning/synthesize-learnings.md +0 -11
  75. package/registry/stubs/workflows/legal/contract-review-analysis.md +0 -11
  76. package/registry/stubs/workflows/legal/nda.md +0 -11
  77. package/registry/stubs/workflows/legal/patent-filing.md +0 -11
  78. package/registry/stubs/workflows/legal/saas-contract-development.md +0 -11
  79. package/registry/stubs/workflows/legal/trademark-filing.md +0 -11
  80. package/registry/stubs/workflows/marketing/content-creation.md +0 -11
  81. package/registry/stubs/workflows/marketing/convert-to-pdf.md +0 -11
  82. package/registry/stubs/workflows/marketing/create-modern-website.md +0 -11
  83. package/registry/stubs/workflows/marketing/domain-registration.md +0 -11
  84. package/registry/stubs/workflows/marketing/hbr-article.md +0 -11
  85. package/registry/stubs/workflows/marketing/launch-checklist.md +0 -11
  86. package/registry/stubs/workflows/marketing/marketing-strategy.md +0 -11
  87. package/registry/stubs/workflows/marketing/storytelling.md +0 -11
  88. package/registry/stubs/workflows/performance/analyze-performance.md +0 -11
  89. package/registry/stubs/workflows/product-building/design.md +0 -11
  90. package/registry/stubs/workflows/product-building/implement.md +0 -11
  91. package/registry/stubs/workflows/product-building/iterate-on-pr-comments.md +0 -11
  92. package/registry/stubs/workflows/product-building/prep-issue.md +0 -11
  93. package/registry/stubs/workflows/product-building/prototype.md +0 -11
  94. package/registry/stubs/workflows/product-building/resolve.md +0 -11
  95. package/registry/stubs/workflows/product-building/retrospect.md +0 -11
  96. package/registry/stubs/workflows/product-building/spec.md +0 -11
  97. package/registry/stubs/workflows/product-building/test.md +0 -11
  98. package/registry/stubs/workflows/productivity-report/productivity-report.md +0 -11
  99. package/registry/stubs/workflows/quality-assurance/browser-validation.md +0 -11
  100. package/registry/stubs/workflows/quality-assurance/iterative-improvement-cycle.md +0 -11
  101. package/registry/stubs/workflows/replicate/replicate-discovery.md +0 -11
  102. package/registry/stubs/workflows/replicate/replicate-to-issues.md +0 -11
  103. package/registry/stubs/workflows/reviewer/review-implementation-vs-design-spec.md +0 -11
  104. package/registry/stubs/workflows/reviewer/review-implementation-vs-feature-spec.md +0 -11
  105. package/registry/stubs/workflows/startup-credits/aws-activate-application.md +0 -11
  106. package/registry/stubs/workflows/startup-credits/google-cloud-application.md +0 -11
  107. package/registry/stubs/workflows/startup-credits/microsoft-azure-application.md +0 -11
@@ -1,4 +1,37 @@
1
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
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -9,17 +42,32 @@ const fs_1 = __importDefault(require("fs"));
9
42
  const path_1 = __importDefault(require("path"));
10
43
  const chalk_1 = __importDefault(require("chalk"));
11
44
  const child_process_1 = require("child_process");
12
- const digest_utils_1 = require("../../utils/digest-utils");
13
45
  const config_loader_1 = require("../../fraim/config-loader");
14
46
  const version_utils_1 = require("../../utils/version-utils");
15
47
  const script_sync_utils_1 = require("../../utils/script-sync-utils");
48
+ /**
49
+ * Load API key from user-level config (~/.fraim/config.json)
50
+ */
51
+ function loadUserApiKey() {
52
+ const userConfigPath = path_1.default.join((0, script_sync_utils_1.getUserFraimDir)(), 'config.json');
53
+ if (!fs_1.default.existsSync(userConfigPath)) {
54
+ return undefined;
55
+ }
56
+ try {
57
+ const userConfig = JSON.parse(fs_1.default.readFileSync(userConfigPath, 'utf8'));
58
+ return userConfig.apiKey;
59
+ }
60
+ catch (error) {
61
+ console.warn(chalk_1.default.yellow('⚠️ Failed to read user-level config for API key'));
62
+ return undefined;
63
+ }
64
+ }
16
65
  const runSync = async (options) => {
17
66
  const projectRoot = process.cwd();
18
67
  const config = (0, config_loader_1.loadFraimConfig)();
19
68
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
20
69
  const workflowsRelativePath = config.customizations?.workflowsPath || '.fraim/workflows';
21
70
  const workflowsDir = path_1.default.resolve(projectRoot, workflowsRelativePath);
22
- const digestPath = path_1.default.join(fraimDir, '.digest');
23
71
  // Check for CLI updates first (but skip during installation to prevent loops)
24
72
  const isPostInstall = process.env.npm_lifecycle_event === 'postinstall' ||
25
73
  process.env.npm_lifecycle_script === 'postinstall';
@@ -29,138 +77,143 @@ const runSync = async (options) => {
29
77
  else if (isPostInstall) {
30
78
  console.log(chalk_1.default.gray('⏭️ Skipping auto-update check during installation to prevent loops.'));
31
79
  }
32
- // In npm package, stubs are in node_modules/@fraim/framework/registry/stubs/workflows
33
- // We need to handle both "running from source" (src/cli/commands) and "running from dist" (dist/src/cli/commands)
34
- // Try 4 levels up (dist/src/cli/commands -> root)
80
+ // Try remote sync first if API key is available (from user config, project config, or env)
81
+ const apiKey = loadUserApiKey() || config.apiKey || process.env.FRAIM_API_KEY;
82
+ if (apiKey) {
83
+ console.log(chalk_1.default.blue('🔄 Syncing FRAIM workflows from remote server...'));
84
+ try {
85
+ const { syncFromRemote } = await Promise.resolve().then(() => __importStar(require('../../utils/remote-sync.js')));
86
+ const result = await syncFromRemote({
87
+ remoteUrl: config.remoteUrl, // Will use default if not set
88
+ apiKey: apiKey,
89
+ projectRoot,
90
+ skipUpdates: options.skipUpdates || false
91
+ });
92
+ if (result.success) {
93
+ console.log(chalk_1.default.green(`✅ Successfully synced ${result.workflowsSynced} workflows and ${result.scriptsSynced} scripts from remote`));
94
+ // Update version in config.json
95
+ const configPath = path_1.default.join(fraimDir, 'config.json');
96
+ if (fs_1.default.existsSync(configPath)) {
97
+ try {
98
+ const currentConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
99
+ const newVersion = (0, version_utils_1.getFraimVersion)();
100
+ if (currentConfig.version !== newVersion) {
101
+ currentConfig.version = newVersion;
102
+ fs_1.default.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
103
+ console.log(chalk_1.default.green(`✅ Updated FRAIM version to ${newVersion} in config.`));
104
+ }
105
+ }
106
+ catch (e) {
107
+ console.warn(chalk_1.default.yellow('⚠️ Could not update version in config.json.'));
108
+ }
109
+ }
110
+ return;
111
+ }
112
+ else {
113
+ console.warn(chalk_1.default.yellow(`⚠️ Remote sync failed: ${result.error}, falling back to local sync`));
114
+ }
115
+ }
116
+ catch (error) {
117
+ console.warn(chalk_1.default.yellow(`⚠️ Remote sync failed: ${error.message}, falling back to local sync`));
118
+ }
119
+ }
120
+ // Fallback to local sync (for development/testing or when remote is not configured)
121
+ console.log(chalk_1.default.blue('🔄 Syncing FRAIM workflows from local package...'));
122
+ // Find local stubs directory
35
123
  let registryPath = path_1.default.join(__dirname, '../../../../registry/stubs');
36
124
  if (!fs_1.default.existsSync(registryPath)) {
37
- // Try 3 levels up (src/cli/commands -> root)
38
125
  registryPath = path_1.default.join(__dirname, '../../../registry/stubs');
39
126
  }
40
- // Fallback for local development if running from within the framework repo itself
41
127
  if (!fs_1.default.existsSync(registryPath)) {
42
128
  registryPath = path_1.default.join(projectRoot, 'registry/stubs');
43
129
  }
44
130
  if (!fs_1.default.existsSync(registryPath)) {
45
- console.error(chalk_1.default.red('❌ Stub registry not found. Ensure @fraim/framework is installed and built.'));
131
+ console.error(chalk_1.default.red('❌ Stub registry not found locally and no remote server configured.'));
132
+ console.error(chalk_1.default.yellow('💡 Configure remoteUrl and apiKey in .fraim/config.json to sync from remote server.'));
46
133
  process.exit(1);
47
134
  }
48
135
  if (!fs_1.default.existsSync(workflowsDir)) {
49
136
  fs_1.default.mkdirSync(workflowsDir, { recursive: true });
50
137
  }
51
- // Update version in config.json
52
- const configPath = path_1.default.join(fraimDir, 'config.json');
53
- if (fs_1.default.existsSync(configPath)) {
54
- try {
55
- const currentConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
56
- const newVersion = (0, version_utils_1.getFraimVersion)();
57
- if (currentConfig.version !== newVersion) {
58
- currentConfig.version = newVersion;
59
- fs_1.default.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
60
- console.log(chalk_1.default.green(`✅ Updated FRAIM version to ${newVersion} in config.`));
61
- }
138
+ const registryWorkflowsPath = path_1.default.join(registryPath, 'workflows');
139
+ if (!fs_1.default.existsSync(registryWorkflowsPath)) {
140
+ console.log(chalk_1.default.yellow('⚠️ No workflow stubs found in local registry.'));
141
+ return;
142
+ }
143
+ // Get all workflow stubs from registry (recursive)
144
+ const getFiles = (dir) => {
145
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
146
+ const files = entries
147
+ .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
148
+ .map(e => path_1.default.join(dir, e.name));
149
+ const folders = entries.filter(e => e.isDirectory());
150
+ for (const folder of folders) {
151
+ files.push(...getFiles(path_1.default.join(dir, folder.name)));
62
152
  }
63
- catch (e) {
64
- console.warn(chalk_1.default.yellow('⚠️ Could not update version in config.json.'));
153
+ return files;
154
+ };
155
+ const registryFiles = getFiles(registryWorkflowsPath);
156
+ const copiedStubs = [];
157
+ for (const file of registryFiles) {
158
+ const fileName = path_1.default.basename(file);
159
+ const workflowName = fileName.replace('.md', '');
160
+ // Calculate relative path from registry/stubs/workflows to preserve structure
161
+ const relativePath = path_1.default.relative(registryWorkflowsPath, file);
162
+ const relativeDir = path_1.default.dirname(relativePath);
163
+ // Ensure target directory exists
164
+ const targetDir = path_1.default.join(workflowsDir, relativeDir);
165
+ if (!fs_1.default.existsSync(targetDir)) {
166
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
65
167
  }
168
+ // Copy stub file directly
169
+ const stubContent = fs_1.default.readFileSync(file, 'utf8');
170
+ const stubPath = path_1.default.join(targetDir, fileName);
171
+ fs_1.default.writeFileSync(stubPath, stubContent);
172
+ copiedStubs.push(relativePath);
173
+ console.log(chalk_1.default.gray(` + ${workflowName} (${relativeDir === '.' ? 'root' : relativeDir})`));
66
174
  }
67
- console.log(chalk_1.default.blue('🔄 Syncing FRAIM workflows...'));
68
- const currentDigest = await (0, digest_utils_1.generateDigest)(registryPath);
69
- const existingDigest = fs_1.default.existsSync(digestPath) ? fs_1.default.readFileSync(digestPath, 'utf8') : '';
70
- if (currentDigest === existingDigest && !options.force) {
71
- console.log(chalk_1.default.green('✅ Workflows are already in sync.'));
72
- }
73
- else {
74
- const registryWorkflowsPath = path_1.default.join(registryPath, 'workflows');
75
- if (!fs_1.default.existsSync(registryWorkflowsPath)) {
76
- console.log(chalk_1.default.yellow('⚠️ No workflow stubs found in registry.'));
175
+ // Cleanup stubs that no longer exist in registry
176
+ const getLocalStubs = (dir) => {
177
+ if (!fs_1.default.existsSync(dir))
178
+ return [];
179
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
180
+ const files = entries
181
+ .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
182
+ .map(e => path_1.default.relative(workflowsDir, path_1.default.join(dir, e.name)));
183
+ const folders = entries.filter(e => e.isDirectory());
184
+ for (const folder of folders) {
185
+ files.push(...getLocalStubs(path_1.default.join(dir, folder.name)));
77
186
  }
78
- else {
79
- // Get all workflow stubs from registry (recursive)
80
- const getFiles = (dir) => {
81
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
82
- const files = entries
83
- .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
84
- .map(e => path_1.default.join(dir, e.name));
85
- const folders = entries.filter(e => e.isDirectory());
86
- for (const folder of folders) {
87
- files.push(...getFiles(path_1.default.join(dir, folder.name)));
88
- }
89
- return files;
90
- };
91
- const registryFiles = getFiles(registryWorkflowsPath);
92
- const copiedStubs = [];
93
- for (const file of registryFiles) {
94
- // These are already stubs, just copy them directly
95
- const fileName = path_1.default.basename(file);
96
- const workflowName = fileName.replace('.md', '');
97
- // Calculate relative path from registry/stubs/workflows to preserve structure
98
- const relativePath = path_1.default.relative(registryWorkflowsPath, file);
99
- const relativeDir = path_1.default.dirname(relativePath);
100
- // Ensure target directory exists
101
- const targetDir = path_1.default.join(workflowsDir, relativeDir);
102
- if (!fs_1.default.existsSync(targetDir)) {
103
- fs_1.default.mkdirSync(targetDir, { recursive: true });
187
+ return files;
188
+ };
189
+ const localStubs = getLocalStubs(workflowsDir);
190
+ for (const stub of localStubs) {
191
+ const normalizedStub = stub.replace(/\\/g, '/');
192
+ const normalizedCopied = copiedStubs.map(s => s.replace(/\\/g, '/'));
193
+ if (!normalizedCopied.includes(normalizedStub)) {
194
+ fs_1.default.unlinkSync(path_1.default.join(workflowsDir, stub));
195
+ console.log(chalk_1.default.yellow(` - ${stub} (removed from registry)`));
196
+ try {
197
+ const dir = path_1.default.dirname(path_1.default.join(workflowsDir, stub));
198
+ if (fs_1.default.readdirSync(dir).length === 0) {
199
+ fs_1.default.rmdirSync(dir);
104
200
  }
105
- // Copy stub file directly
106
- const stubContent = fs_1.default.readFileSync(file, 'utf8');
107
- const stubPath = path_1.default.join(targetDir, fileName);
108
- fs_1.default.writeFileSync(stubPath, stubContent);
109
- copiedStubs.push(relativePath); // Store relative path for cleanup tracking
110
- console.log(chalk_1.default.gray(` + ${workflowName} (${relativeDir === '.' ? 'root' : relativeDir})`));
111
201
  }
112
- // Cleanup stubs that no longer exist in registry
113
- // Helper to get all local stubs recursively
114
- const getLocalStubs = (dir) => {
115
- if (!fs_1.default.existsSync(dir))
116
- return [];
117
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
118
- const files = entries
119
- .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
120
- .map(e => path_1.default.relative(workflowsDir, path_1.default.join(dir, e.name)));
121
- const folders = entries.filter(e => e.isDirectory());
122
- for (const folder of folders) {
123
- files.push(...getLocalStubs(path_1.default.join(dir, folder.name)));
124
- }
125
- return files;
126
- };
127
- const localStubs = getLocalStubs(workflowsDir);
128
- for (const stub of localStubs) {
129
- // standardise path separators for comparison
130
- const normalizedStub = stub.replace(/\\/g, '/');
131
- const normalizedCopied = copiedStubs.map(s => s.replace(/\\/g, '/'));
132
- if (!normalizedCopied.includes(normalizedStub)) {
133
- fs_1.default.unlinkSync(path_1.default.join(workflowsDir, stub));
134
- console.log(chalk_1.default.yellow(` - ${stub} (removed from registry)`));
135
- // Cleanup empty directories
136
- try {
137
- const dir = path_1.default.dirname(path_1.default.join(workflowsDir, stub));
138
- if (fs_1.default.readdirSync(dir).length === 0) {
139
- fs_1.default.rmdirSync(dir);
140
- }
141
- }
142
- catch (e) { }
143
- }
144
- }
145
- fs_1.default.writeFileSync(digestPath, currentDigest);
146
- console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Copied ${copiedStubs.length} stubs.`));
202
+ catch (e) { }
147
203
  }
148
204
  }
149
- // Always sync scripts, regardless of workflow sync status
205
+ console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Copied ${copiedStubs.length} stubs.`));
206
+ // Sync scripts
150
207
  console.log(chalk_1.default.blue('\n🔄 Syncing FRAIM scripts to user directory...'));
151
- // Scripts are packaged separately from stubs, find the correct registry path
152
- // Try 4 levels up (dist/src/cli/commands -> root)
153
208
  let scriptsRegistryPath = path_1.default.join(__dirname, '../../../../registry');
154
209
  if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
155
- // Try 3 levels up (src/cli/commands -> root)
156
210
  scriptsRegistryPath = path_1.default.join(__dirname, '../../../registry');
157
211
  }
158
- // Fallback for local development if running from within the framework repo itself
159
212
  if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
160
213
  scriptsRegistryPath = path_1.default.join(projectRoot, 'registry');
161
214
  }
162
215
  if (!fs_1.default.existsSync(path_1.default.join(scriptsRegistryPath, 'scripts'))) {
163
- console.error(chalk_1.default.red('❌ Scripts registry not found. Ensure @fraim/framework is installed and built.'));
216
+ console.error(chalk_1.default.red('❌ Scripts registry not found.'));
164
217
  process.exit(1);
165
218
  }
166
219
  const syncResult = (0, script_sync_utils_1.syncScriptsToUserDirectory)(scriptsRegistryPath);
@@ -171,6 +224,22 @@ const runSync = async (options) => {
171
224
  else {
172
225
  console.log(chalk_1.default.green('✅ Scripts are already in sync.'));
173
226
  }
227
+ // Update version in config.json
228
+ const configPath = path_1.default.join(fraimDir, 'config.json');
229
+ if (fs_1.default.existsSync(configPath)) {
230
+ try {
231
+ const currentConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
232
+ const newVersion = (0, version_utils_1.getFraimVersion)();
233
+ if (currentConfig.version !== newVersion) {
234
+ currentConfig.version = newVersion;
235
+ fs_1.default.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
236
+ console.log(chalk_1.default.green(`✅ Updated FRAIM version to ${newVersion} in config.`));
237
+ }
238
+ }
239
+ catch (e) {
240
+ console.warn(chalk_1.default.yellow('⚠️ Could not update version in config.json.'));
241
+ }
242
+ }
174
243
  };
175
244
  exports.runSync = runSync;
176
245
  async function checkAndUpdateCLI() {
@@ -11,7 +11,7 @@ const prompts_1 = __importDefault(require("prompts"));
11
11
  const ide_detector_1 = require("./ide-detector");
12
12
  const mcp_config_generator_1 = require("./mcp-config-generator");
13
13
  const token_validator_1 = require("./token-validator");
14
- const promptForIDESelection = async (detectedIDEs) => {
14
+ const promptForIDESelection = async (detectedIDEs, githubToken) => {
15
15
  console.log(chalk_1.default.green(`✅ Found ${detectedIDEs.length} IDEs that can be configured with FRAIM:\n`));
16
16
  detectedIDEs.forEach((ide, index) => {
17
17
  const configExists = fs_1.default.existsSync((0, ide_detector_1.expandPath)(ide.configPath));
@@ -20,10 +20,12 @@ const promptForIDESelection = async (detectedIDEs) => {
20
20
  console.log(chalk_1.default.white(` ${index + 1}. ${ide.name} ${statusIcon} (${statusText})`));
21
21
  console.log(chalk_1.default.gray(` Config: ${ide.configPath}`));
22
22
  });
23
- console.log(chalk_1.default.blue('\nFRAIM will add these MCP servers to selected IDEs:'));
23
+ console.log(chalk_1.default.blue('FRAIM will add these MCP servers to selected IDEs:'));
24
24
  console.log(chalk_1.default.gray(' • fraim (required for FRAIM workflows)'));
25
25
  console.log(chalk_1.default.gray(' • git (version control integration)'));
26
- console.log(chalk_1.default.gray(' • github (GitHub API access)'));
26
+ if (githubToken) {
27
+ console.log(chalk_1.default.gray(' • github (GitHub API access)'));
28
+ }
27
29
  console.log(chalk_1.default.gray(' • playwright (browser automation)'));
28
30
  console.log(chalk_1.default.yellow('\n💡 Existing MCP servers will be preserved - only missing servers will be added.'));
29
31
  const response = await (0, prompts_1.default)({
@@ -314,7 +316,7 @@ const autoConfigureMCP = async (fraimKey, githubToken, selectedIDEs) => {
314
316
  }
315
317
  else {
316
318
  // Interactive selection
317
- idesToConfigure = await (0, exports.promptForIDESelection)(detectedIDEs);
319
+ idesToConfigure = await (0, exports.promptForIDESelection)(detectedIDEs, githubToken);
318
320
  }
319
321
  if (idesToConfigure.length === 0) {
320
322
  console.log(chalk_1.default.yellow('⚠️ No IDEs selected for configuration.'));
@@ -1,18 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateMCPConfig = exports.generateWindsurfMCPServers = exports.generateCodexMCPServers = exports.generateKiroMCPServers = exports.generateClaudeMCPServers = exports.generateStandardMCPServers = void 0;
4
- const generateStandardMCPServers = (fraimKey, githubToken) => ({
5
- mcpServers: {
4
+ const generateStandardMCPServers = (fraimKey, githubToken) => {
5
+ const servers = {
6
6
  git: {
7
7
  command: "npx",
8
8
  args: ["-y", "@cyanheads/git-mcp-server"]
9
9
  },
10
- github: {
11
- serverUrl: "https://api.githubcopilot.com/mcp/",
12
- headers: {
13
- Authorization: `Bearer ${githubToken}`
14
- }
15
- },
16
10
  playwright: {
17
11
  command: "npx",
18
12
  args: ["-y", "@playwright/mcp"]
@@ -24,22 +18,25 @@ const generateStandardMCPServers = (fraimKey, githubToken) => ({
24
18
  FRAIM_REMOTE_URL: "https://fraim.wellnessatwork.me"
25
19
  }
26
20
  }
21
+ };
22
+ // Only add GitHub server if token is provided
23
+ if (githubToken) {
24
+ servers.github = {
25
+ serverUrl: "https://api.githubcopilot.com/mcp/",
26
+ headers: {
27
+ Authorization: `Bearer ${githubToken}`
28
+ }
29
+ };
27
30
  }
28
- });
31
+ return { mcpServers: servers };
32
+ };
29
33
  exports.generateStandardMCPServers = generateStandardMCPServers;
30
- const generateClaudeMCPServers = (fraimKey, githubToken) => ({
31
- mcpServers: {
34
+ const generateClaudeMCPServers = (fraimKey, githubToken) => {
35
+ const servers = {
32
36
  git: {
33
37
  command: "npx",
34
38
  args: ["-y", "@cyanheads/git-mcp-server"]
35
39
  },
36
- github: {
37
- type: "http",
38
- url: "https://api.githubcopilot.com/mcp/",
39
- headers: {
40
- Authorization: `Bearer ${githubToken}`
41
- }
42
- },
43
40
  playwright: {
44
41
  command: "npx",
45
42
  args: ["-y", "@playwright/mcp"]
@@ -51,21 +48,26 @@ const generateClaudeMCPServers = (fraimKey, githubToken) => ({
51
48
  FRAIM_REMOTE_URL: "https://fraim.wellnessatwork.me"
52
49
  }
53
50
  }
51
+ };
52
+ // Only add GitHub server if token is provided
53
+ if (githubToken) {
54
+ servers.github = {
55
+ type: "http",
56
+ url: "https://api.githubcopilot.com/mcp/",
57
+ headers: {
58
+ Authorization: `Bearer ${githubToken}`
59
+ }
60
+ };
54
61
  }
55
- });
62
+ return { mcpServers: servers };
63
+ };
56
64
  exports.generateClaudeMCPServers = generateClaudeMCPServers;
57
- const generateKiroMCPServers = (fraimKey, githubToken) => ({
58
- mcpServers: {
65
+ const generateKiroMCPServers = (fraimKey, githubToken) => {
66
+ const servers = {
59
67
  git: {
60
68
  command: "npx",
61
69
  args: ["-y", "@cyanheads/git-mcp-server"]
62
70
  },
63
- github: {
64
- url: "https://api.githubcopilot.com/mcp/",
65
- headers: {
66
- Authorization: `Bearer ${githubToken}`
67
- }
68
- },
69
71
  playwright: {
70
72
  command: "npx",
71
73
  args: ["-y", "@playwright/mcp"]
@@ -77,18 +79,34 @@ const generateKiroMCPServers = (fraimKey, githubToken) => ({
77
79
  FRAIM_REMOTE_URL: "https://fraim.wellnessatwork.me"
78
80
  }
79
81
  }
82
+ };
83
+ // Only add GitHub server if token is provided
84
+ if (githubToken) {
85
+ servers.github = {
86
+ url: "https://api.githubcopilot.com/mcp/",
87
+ headers: {
88
+ Authorization: `Bearer ${githubToken}`
89
+ }
90
+ };
80
91
  }
81
- });
92
+ return { mcpServers: servers };
93
+ };
82
94
  exports.generateKiroMCPServers = generateKiroMCPServers;
83
- const generateCodexMCPServers = (fraimKey, githubToken) => `
95
+ const generateCodexMCPServers = (fraimKey, githubToken) => {
96
+ let config = `
84
97
  [mcp_servers.git]
85
98
  command = "npx"
86
99
  args = ["-y", "@cyanheads/git-mcp-server"]
87
-
100
+ `;
101
+ // Only add GitHub server if token is provided
102
+ if (githubToken) {
103
+ config += `
88
104
  [mcp_servers.github]
89
105
  url = "https://api.githubcopilot.com/mcp/"
90
106
  bearer_token_env_var = "GIT_TOKEN"
91
-
107
+ `;
108
+ }
109
+ config += `
92
110
  [mcp_servers.playwright]
93
111
  command = "npx"
94
112
  args = ["-y", "@playwright/mcp"]
@@ -100,20 +118,15 @@ command = "fraim-mcp"
100
118
  FRAIM_API_KEY = "${fraimKey}"
101
119
  FRAIM_REMOTE_URL = "https://fraim.wellnessatwork.me"
102
120
  `;
121
+ return config;
122
+ };
103
123
  exports.generateCodexMCPServers = generateCodexMCPServers;
104
- const generateWindsurfMCPServers = (fraimKey, githubToken) => ({
105
- mcpServers: {
124
+ const generateWindsurfMCPServers = (fraimKey, githubToken) => {
125
+ const servers = {
106
126
  git: {
107
127
  command: "npx",
108
128
  args: ["-y", "@cyanheads/git-mcp-server"]
109
129
  },
110
- github: {
111
- command: "npx",
112
- args: ["-y", "@modelcontextprotocol/server-fetch", "https://api.githubcopilot.com/mcp/"],
113
- env: {
114
- GITHUB_TOKEN: githubToken
115
- }
116
- },
117
130
  playwright: {
118
131
  command: "npx",
119
132
  args: ["-y", "@playwright/mcp"]
@@ -125,8 +138,19 @@ const generateWindsurfMCPServers = (fraimKey, githubToken) => ({
125
138
  FRAIM_REMOTE_URL: "https://fraim.wellnessatwork.me"
126
139
  }
127
140
  }
141
+ };
142
+ // Only add GitHub server if token is provided
143
+ if (githubToken) {
144
+ servers.github = {
145
+ command: "npx",
146
+ args: ["-y", "@modelcontextprotocol/server-fetch", "https://api.githubcopilot.com/mcp/"],
147
+ env: {
148
+ GITHUB_TOKEN: githubToken
149
+ }
150
+ };
128
151
  }
129
- });
152
+ return { mcpServers: servers };
153
+ };
130
154
  exports.generateWindsurfMCPServers = generateWindsurfMCPServers;
131
155
  const generateMCPConfig = (configType, fraimKey, githubToken) => {
132
156
  switch (configType) {