fraim-framework 2.0.36 → 2.0.38
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.
- package/bin/fraim.js +5 -52
- package/dist/registry/scripts/build-scripts-generator.js +205 -0
- package/dist/registry/scripts/fraim-config.js +61 -0
- package/dist/registry/scripts/generic-issues-api.js +100 -0
- package/dist/registry/scripts/openapi-generator.js +664 -0
- package/dist/registry/scripts/performance/profile-server.js +390 -0
- package/dist/scripts/build-stub-registry.js +108 -0
- package/dist/src/cli/commands/doctor.js +5 -5
- package/dist/src/cli/commands/init-project.js +74 -0
- package/dist/src/cli/commands/setup.js +176 -0
- package/dist/src/cli/commands/sync.js +33 -19
- package/dist/src/cli/commands/test-mcp.js +135 -0
- package/dist/src/cli/fraim.js +6 -0
- package/dist/src/cli/setup/auto-mcp-setup.js +367 -0
- package/dist/src/cli/setup/ide-detector.js +163 -0
- package/dist/src/cli/setup/mcp-config-generator.js +115 -0
- package/dist/src/cli/setup/token-validator.js +49 -0
- package/dist/test-utils.js +96 -0
- package/dist/tests/debug-tools.js +2 -2
- package/dist/tests/esm-compat.js +11 -0
- package/dist/tests/shared-server-utils.js +57 -0
- package/dist/tests/test-chalk-esm-issue.js +159 -0
- package/dist/tests/test-chalk-real-world.js +265 -0
- package/dist/tests/test-chalk-regression.js +2 -18
- package/dist/tests/test-chalk-resolution-issue.js +304 -0
- package/dist/tests/test-client-scripts-validation.js +27 -5
- package/dist/tests/test-complete-setup-flow.js +110 -0
- package/dist/tests/test-fraim-install-chalk-issue.js +254 -0
- package/dist/tests/test-ide-detector.js +46 -0
- package/dist/tests/test-improved-setup.js +121 -0
- package/dist/tests/test-mcp-config-generator.js +70 -0
- package/dist/tests/test-mcp-connection.js +58 -117
- package/dist/tests/test-mcp-issue-integration.js +2 -2
- package/dist/tests/test-mcp-lifecycle-methods.js +34 -100
- package/dist/tests/test-mcp-shared-server.js +308 -0
- package/dist/tests/test-npm-resolution-diagnostic.js +140 -0
- package/dist/tests/test-package-size.js +101 -0
- package/dist/tests/test-prep-issue.js +34 -1
- package/dist/tests/test-script-location-independence.js +39 -62
- package/dist/tests/test-server-utils.js +32 -0
- package/dist/tests/test-session-rehydration.js +2 -2
- package/dist/tests/test-setup-integration.js +98 -0
- package/dist/tests/test-standalone.js +2 -2
- package/dist/tests/test-stub-registry.js +136 -0
- package/dist/tests/test-sync-stubs.js +143 -0
- package/dist/tests/test-telemetry.js +2 -2
- package/dist/tests/test-token-validator.js +30 -0
- package/dist/tests/test-user-journey.js +2 -1
- package/package.json +7 -9
- package/registry/agent-guardrails.md +62 -62
- package/registry/scripts/code-quality-check.sh +559 -559
- package/registry/scripts/detect-tautological-tests.sh +38 -38
- package/registry/scripts/prep-issue.sh +61 -30
- package/registry/scripts/validate-openapi-limits.ts +366 -366
- package/registry/scripts/validate-test-coverage.ts +280 -280
- package/registry/scripts/verify-pr-comments.sh +70 -70
- package/registry/stubs/workflows/bootstrap/create-architecture.md +11 -0
- package/registry/stubs/workflows/bootstrap/detect-broken-windows.md +11 -0
- package/registry/stubs/workflows/bootstrap/evaluate-code-quality.md +11 -0
- package/registry/stubs/workflows/bootstrap/verify-test-coverage.md +11 -0
- package/registry/stubs/workflows/business-development/create-business-plan.md +11 -0
- package/registry/stubs/workflows/business-development/ideate-business-opportunity.md +11 -0
- package/registry/stubs/workflows/business-development/price-product.md +18 -0
- package/registry/stubs/workflows/convert-to-pdf.md +11 -0
- package/registry/stubs/workflows/customer-development/insight-analysis.md +11 -0
- package/registry/stubs/workflows/customer-development/insight-triage.md +11 -0
- package/registry/stubs/workflows/customer-development/interview-preparation.md +11 -0
- package/registry/stubs/workflows/customer-development/linkedin-outreach.md +11 -0
- package/registry/stubs/workflows/customer-development/strategic-brainstorming.md +11 -0
- package/registry/stubs/workflows/customer-development/thank-customers.md +11 -0
- package/registry/stubs/workflows/customer-development/weekly-newsletter.md +11 -0
- package/registry/stubs/workflows/deploy/cloud-deployment.md +11 -0
- package/registry/stubs/workflows/improve-fraim/contribute.md +11 -0
- package/registry/stubs/workflows/improve-fraim/file-issue.md +11 -0
- package/registry/stubs/workflows/marketing/content-creation.md +11 -0
- package/registry/stubs/workflows/marketing/hbr-article.md +11 -0
- package/registry/stubs/workflows/marketing/launch-checklist.md +11 -0
- package/registry/stubs/workflows/marketing/marketing-strategy.md +11 -0
- package/registry/stubs/workflows/marketing/storytelling.md +11 -0
- package/registry/stubs/workflows/performance/analyze-performance.md +11 -0
- package/registry/stubs/workflows/product-building/design.md +11 -0
- package/registry/stubs/workflows/product-building/implement.md +12 -0
- package/registry/stubs/workflows/product-building/iterate-on-pr-comments.md +11 -0
- package/registry/stubs/workflows/product-building/prep-issue.md +11 -0
- package/registry/stubs/workflows/product-building/prototype.md +11 -0
- package/registry/stubs/workflows/product-building/resolve.md +11 -0
- package/registry/stubs/workflows/product-building/retrospect.md +11 -0
- package/registry/stubs/workflows/product-building/spec.md +11 -0
- package/registry/stubs/workflows/product-building/test.md +11 -0
- package/registry/stubs/workflows/quality-assurance/browser-validation.md +11 -0
- package/registry/stubs/workflows/quality-assurance/iterative-improvement-cycle.md +11 -0
- package/registry/stubs/workflows/replicate/replicate-discovery.md +11 -0
- package/registry/stubs/workflows/replicate/replicate-to-issues.md +11 -0
- package/registry/stubs/workflows/reviewer/review-implementation-vs-design-spec.md +11 -0
- package/registry/stubs/workflows/reviewer/review-implementation-vs-feature-spec.md +11 -0
- package/registry/stubs/workflows/startup-credits/aws-activate-application.md +11 -0
- package/registry/stubs/workflows/startup-credits/google-cloud-application.md +11 -0
- package/registry/stubs/workflows/startup-credits/microsoft-azure-application.md +11 -0
- package/.github/workflows/ci.yml +0 -65
- package/.github/workflows/deploy-fraim.yml +0 -87
- package/.github/workflows/phase-change.yml +0 -251
- package/.github/workflows/status-change.yml +0 -68
- package/.github/workflows/sync-on-pr-review.yml +0 -66
- package/examples/simple-webapp/TESTING.md +0 -62
- package/examples/simple-webapp/example-test.ts +0 -186
- package/registry/github/workflows/ci.yml +0 -51
- package/registry/github/workflows/phase-change.yml +0 -251
- package/registry/github/workflows/status-change.yml +0 -68
- package/registry/github/workflows/sync-on-pr-review.yml +0 -66
- package/registry/mcp-template.jsonc +0 -29
- package/registry/rules/agent-success-criteria.md +0 -52
- package/registry/rules/agent-testing-guidelines.md +0 -502
- package/registry/rules/architecture.md +0 -52
- package/registry/rules/communication.md +0 -122
- package/registry/rules/continuous-learning.md +0 -55
- package/registry/rules/debugging-multitenancy-issues.md +0 -85
- package/registry/rules/ephemeral-execution.md +0 -57
- package/registry/rules/git-safe-commands.md +0 -34
- package/registry/rules/hitl-ppe-record-analysis.md +0 -302
- package/registry/rules/integrity-and-test-ethics.md +0 -275
- package/registry/rules/local-development.md +0 -254
- package/registry/rules/merge-requirements.md +0 -231
- package/registry/rules/simplicity.md +0 -118
- package/registry/rules/software-development-lifecycle.md +0 -105
- package/registry/rules/spike-first-development.md +0 -205
- package/registry/rules/successful-debugging-patterns.md +0 -491
- package/registry/rules/telemetry.md +0 -67
- package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +0 -53
- package/registry/templates/bootstrap/CODE-QUALITY-REPORT-TEMPLATE.md +0 -37
- package/registry/templates/bootstrap/TEST-COVERAGE-REPORT-TEMPLATE.md +0 -35
- package/registry/templates/business-development/IDEATION-REPORT-TEMPLATE.md +0 -29
- package/registry/templates/business-development/PRICING-STRATEGY-TEMPLATE.md +0 -126
- package/registry/templates/customer-development/customer-interview-template.md +0 -99
- package/registry/templates/customer-development/follow-up-email-templates.md +0 -132
- package/registry/templates/customer-development/insight-analysis-template.md +0 -74
- package/registry/templates/customer-development/strategic-recommendations-template.md +0 -53
- package/registry/templates/customer-development/thank-you-email-template.html +0 -124
- package/registry/templates/customer-development/thank-you-note-template.md +0 -16
- package/registry/templates/customer-development/triage-log-template.md +0 -278
- package/registry/templates/customer-development/weekly-newsletter-template.html +0 -204
- package/registry/templates/evidence/Design-Evidence.md +0 -30
- package/registry/templates/evidence/Implementation-BugEvidence.md +0 -86
- package/registry/templates/evidence/Implementation-FeatureEvidence.md +0 -121
- package/registry/templates/evidence/Spec-Evidence.md +0 -19
- package/registry/templates/help/HelpNeeded.md +0 -14
- package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +0 -66
- package/registry/templates/replicate/implementation-checklist.md +0 -39
- package/registry/templates/replicate/use-cases-template.md +0 -88
- package/registry/templates/retrospective/RETROSPECTIVE-TEMPLATE.md +0 -55
- package/registry/templates/specs/BUGSPEC-TEMPLATE.md +0 -37
- package/registry/templates/specs/FEATURESPEC-TEMPLATE.md +0 -29
- package/registry/templates/specs/TECHSPEC-TEMPLATE.md +0 -39
- package/registry/workflows/bootstrap/create-architecture.md +0 -38
- package/registry/workflows/bootstrap/evaluate-code-quality.md +0 -36
- package/registry/workflows/bootstrap/verify-test-coverage.md +0 -37
- package/registry/workflows/business-development/create-business-plan.md +0 -737
- package/registry/workflows/business-development/ideate-business-opportunity.md +0 -55
- package/registry/workflows/business-development/price-product.md +0 -325
- package/registry/workflows/convert-to-pdf.md +0 -235
- package/registry/workflows/customer-development/insight-analysis.md +0 -156
- package/registry/workflows/customer-development/insight-triage.md +0 -933
- package/registry/workflows/customer-development/interview-preparation.md +0 -421
- package/registry/workflows/customer-development/linkedin-outreach.md +0 -593
- package/registry/workflows/customer-development/strategic-brainstorming.md +0 -146
- package/registry/workflows/customer-development/thank-customers.md +0 -203
- package/registry/workflows/customer-development/weekly-newsletter.md +0 -366
- package/registry/workflows/deploy/cloud-deployment.md +0 -310
- package/registry/workflows/improve-fraim/contribute.md +0 -32
- package/registry/workflows/improve-fraim/file-issue.md +0 -32
- package/registry/workflows/marketing/content-creation.md +0 -37
- package/registry/workflows/marketing/hbr-article.md +0 -73
- package/registry/workflows/marketing/launch-checklist.md +0 -37
- package/registry/workflows/marketing/marketing-strategy.md +0 -45
- package/registry/workflows/performance/analyze-performance.md +0 -65
- package/registry/workflows/product-building/design.md +0 -130
- package/registry/workflows/product-building/implement.md +0 -315
- package/registry/workflows/product-building/iterate-on-pr-comments.md +0 -70
- package/registry/workflows/product-building/prep-issue.md +0 -43
- package/registry/workflows/product-building/prototype.md +0 -60
- package/registry/workflows/product-building/resolve.md +0 -164
- package/registry/workflows/product-building/retrospect.md +0 -86
- package/registry/workflows/product-building/spec.md +0 -117
- package/registry/workflows/product-building/test.md +0 -120
- package/registry/workflows/quality-assurance/browser-validation.md +0 -221
- package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +0 -562
- package/registry/workflows/replicate/replicate-discovery.md +0 -336
- package/registry/workflows/replicate/replicate-to-issues.md +0 -319
- package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +0 -632
- package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +0 -669
- package/registry/workflows/startup-credits/aws-activate-application.md +0 -535
- package/registry/workflows/startup-credits/google-cloud-application.md +0 -647
- package/registry/workflows/startup-credits/microsoft-azure-application.md +0 -538
|
@@ -42,13 +42,15 @@ const path_1 = __importDefault(require("path"));
|
|
|
42
42
|
const os_1 = __importDefault(require("os"));
|
|
43
43
|
async function testScriptLocationIndependence() {
|
|
44
44
|
console.log(' 🚀 Testing Script Location Independence...');
|
|
45
|
-
|
|
46
|
-
const
|
|
45
|
+
// Use timestamp to ensure unique directories even in concurrent runs
|
|
46
|
+
const timestamp = Date.now();
|
|
47
|
+
const tempProjectDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), `fraim-location-test-${timestamp}-`));
|
|
48
|
+
const userFraimDir = path_1.default.join(os_1.default.homedir(), `.fraim-location-test-${timestamp}`);
|
|
47
49
|
const userScriptsDir = path_1.default.join(userFraimDir, 'scripts');
|
|
48
50
|
console.log(` 📂 Created temp project dir: ${tempProjectDir}`);
|
|
49
51
|
console.log(` 🏠 Using test user dir: ${userFraimDir}`);
|
|
50
52
|
try {
|
|
51
|
-
// Clean up any existing test user directory
|
|
53
|
+
// Clean up any existing test user directory (with timestamp, should be unique)
|
|
52
54
|
if (fs_1.default.existsSync(userFraimDir)) {
|
|
53
55
|
fs_1.default.rmSync(userFraimDir, { recursive: true, force: true });
|
|
54
56
|
}
|
|
@@ -75,11 +77,11 @@ async function testScriptLocationIndependence() {
|
|
|
75
77
|
const projectFraimDir = path_1.default.join(tempProjectDir, '.fraim');
|
|
76
78
|
fs_1.default.mkdirSync(projectFraimDir, { recursive: true });
|
|
77
79
|
const testConfig = {
|
|
78
|
-
project: { name:
|
|
80
|
+
project: { name: `location-test-${timestamp}` },
|
|
79
81
|
git: {
|
|
80
82
|
repoOwner: 'test',
|
|
81
|
-
repoName:
|
|
82
|
-
url:
|
|
83
|
+
repoName: `location-test-${timestamp}`,
|
|
84
|
+
url: `https://github.com/test/location-test-${timestamp}.git`
|
|
83
85
|
}
|
|
84
86
|
};
|
|
85
87
|
fs_1.default.writeFileSync(path_1.default.join(projectFraimDir, 'config.json'), JSON.stringify(testConfig, null, 2));
|
|
@@ -111,7 +113,7 @@ async function testScriptLocationIndependence() {
|
|
|
111
113
|
const output = execSync(bashCommand, {
|
|
112
114
|
cwd: tempProjectDir,
|
|
113
115
|
encoding: 'utf-8',
|
|
114
|
-
timeout:
|
|
116
|
+
timeout: 15000 // Increased timeout for concurrent runs
|
|
115
117
|
});
|
|
116
118
|
}
|
|
117
119
|
else {
|
|
@@ -119,13 +121,18 @@ async function testScriptLocationIndependence() {
|
|
|
119
121
|
const output = execSync(`"${prepIssueScript}" --help`, {
|
|
120
122
|
cwd: tempProjectDir,
|
|
121
123
|
encoding: 'utf-8',
|
|
122
|
-
timeout:
|
|
124
|
+
timeout: 15000 // Increased timeout for concurrent runs
|
|
123
125
|
});
|
|
124
126
|
}
|
|
125
127
|
// If we get here, the script at least started successfully
|
|
126
128
|
console.log(' ✅ prep-issue.sh executed successfully from user directory');
|
|
127
129
|
}
|
|
128
130
|
catch (error) {
|
|
131
|
+
// Check for timeout specifically
|
|
132
|
+
if (error.message.includes('ETIMEDOUT') || error.signal === 'SIGTERM') {
|
|
133
|
+
console.log(' ❌ prep-issue.sh failed: spawnSync', error.syscall, 'ETIMEDOUT');
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
129
136
|
// The script may fail due to missing repo, but as long as it started, that's OK
|
|
130
137
|
if (error.message.includes('Repository not found') ||
|
|
131
138
|
error.message.includes('fatal: repository') ||
|
|
@@ -142,54 +149,7 @@ async function testScriptLocationIndependence() {
|
|
|
142
149
|
else {
|
|
143
150
|
console.log(' ⚠️ prep-issue.sh not found, skipping test');
|
|
144
151
|
}
|
|
145
|
-
//
|
|
146
|
-
console.log(' Testing code-quality-check.sh execution from user directory...');
|
|
147
|
-
const qualityCheckScript = path_1.default.join(userScriptsDir, 'code-quality-check.sh');
|
|
148
|
-
if (fs_1.default.existsSync(qualityCheckScript)) {
|
|
149
|
-
try {
|
|
150
|
-
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
151
|
-
if (process.platform === 'win32') {
|
|
152
|
-
const gitBashPaths = [
|
|
153
|
-
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
154
|
-
'C:\\Program Files (x86)\\Git\\bin\\bash.exe'
|
|
155
|
-
];
|
|
156
|
-
let bashPath = null;
|
|
157
|
-
for (const path of gitBashPaths) {
|
|
158
|
-
if (fs_1.default.existsSync(path)) {
|
|
159
|
-
bashPath = path;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (!bashPath) {
|
|
164
|
-
console.log(' ⚠️ Git Bash not found on Windows, skipping quality check test');
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
const bashCommand = `"${bashPath}" "${qualityCheckScript}" --help`;
|
|
168
|
-
const output = execSync(bashCommand, {
|
|
169
|
-
cwd: tempProjectDir,
|
|
170
|
-
encoding: 'utf-8',
|
|
171
|
-
timeout: 10000
|
|
172
|
-
});
|
|
173
|
-
console.log(' ✅ code-quality-check.sh executed successfully from user directory');
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
const output = execSync(`"${qualityCheckScript}" --help`, {
|
|
178
|
-
cwd: tempProjectDir,
|
|
179
|
-
encoding: 'utf-8',
|
|
180
|
-
timeout: 10000
|
|
181
|
-
});
|
|
182
|
-
console.log(' ✅ code-quality-check.sh executed successfully from user directory');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
console.log(' ❌ code-quality-check.sh failed (expected due to dependencies):', error.message);
|
|
187
|
-
// This is expected to fail - we'll document this as a known issue
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
console.log(' ⚠️ code-quality-check.sh not found, skipping test');
|
|
192
|
-
}
|
|
152
|
+
// Skip the second test to reduce interference - the first test is sufficient
|
|
193
153
|
console.log(' ✅ Script location independence test completed');
|
|
194
154
|
return true;
|
|
195
155
|
}
|
|
@@ -198,13 +158,30 @@ async function testScriptLocationIndependence() {
|
|
|
198
158
|
return false;
|
|
199
159
|
}
|
|
200
160
|
finally {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
161
|
+
// Enhanced cleanup with retry logic
|
|
162
|
+
const cleanup = async (retries = 3) => {
|
|
163
|
+
for (let i = 0; i < retries; i++) {
|
|
164
|
+
try {
|
|
165
|
+
if (fs_1.default.existsSync(tempProjectDir)) {
|
|
166
|
+
fs_1.default.rmSync(tempProjectDir, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
if (fs_1.default.existsSync(userFraimDir)) {
|
|
169
|
+
fs_1.default.rmSync(userFraimDir, { recursive: true, force: true });
|
|
170
|
+
}
|
|
171
|
+
break; // Success
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
if (i === retries - 1) {
|
|
175
|
+
console.warn(' ⚠️ Cleanup failed after retries:', e);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Wait a bit before retry
|
|
179
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
205
182
|
}
|
|
206
|
-
}
|
|
207
|
-
|
|
183
|
+
};
|
|
184
|
+
await cleanup();
|
|
208
185
|
}
|
|
209
186
|
}
|
|
210
187
|
async function runScriptLocationTest(testCase) {
|
|
@@ -0,0 +1,32 @@
|
|
|
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.getServerScriptPath = getServerScriptPath;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
/**
|
|
10
|
+
* Utility function to get the correct server script path
|
|
11
|
+
* Handles different execution contexts (running from project root, tests directory, etc.)
|
|
12
|
+
*/
|
|
13
|
+
function getServerScriptPath() {
|
|
14
|
+
// Try to find the server script from various possible locations
|
|
15
|
+
const possiblePaths = [
|
|
16
|
+
path_1.default.resolve(__dirname, '../dist/src/fraim-mcp-server.js'),
|
|
17
|
+
path_1.default.resolve(process.cwd(), 'dist/src/fraim-mcp-server.js'),
|
|
18
|
+
path_1.default.resolve(__dirname, '../../dist/src/fraim-mcp-server.js'),
|
|
19
|
+
path_1.default.resolve(__dirname, '../../../dist/src/fraim-mcp-server.js')
|
|
20
|
+
];
|
|
21
|
+
for (const scriptPath of possiblePaths) {
|
|
22
|
+
if (fs_1.default.existsSync(scriptPath)) {
|
|
23
|
+
console.log(` 📍 Found server script at: ${scriptPath}`);
|
|
24
|
+
return scriptPath;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// If none found, log all attempted paths and use the first one
|
|
28
|
+
console.warn(' ⚠️ Server script not found at any of these paths:');
|
|
29
|
+
possiblePaths.forEach(p => console.warn(` ${p}`));
|
|
30
|
+
console.warn(' Using first path (may fail)...');
|
|
31
|
+
return possiblePaths[0];
|
|
32
|
+
}
|
|
@@ -9,7 +9,7 @@ const db_service_js_1 = require("../src/fraim/db-service.js");
|
|
|
9
9
|
const test_utils_1 = require("./test-utils");
|
|
10
10
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
11
11
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
12
|
-
const
|
|
12
|
+
const test_server_utils_1 = require("./test-server-utils");
|
|
13
13
|
async function testRehydrationAndExemptions() {
|
|
14
14
|
console.log(' 🚀 Testing Session Re-hydration and Initialization Exemptions...');
|
|
15
15
|
let fraimProcess;
|
|
@@ -21,7 +21,7 @@ async function testRehydrationAndExemptions() {
|
|
|
21
21
|
const startServer = async () => {
|
|
22
22
|
console.log(` Starting server on port ${PORT}...`);
|
|
23
23
|
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
24
|
-
const serverScript =
|
|
24
|
+
const serverScript = (0, test_server_utils_1.getServerScriptPath)();
|
|
25
25
|
const proc = (0, node_child_process_1.spawn)(npxCommand, ['node', `"${serverScript}"`], {
|
|
26
26
|
env: {
|
|
27
27
|
...process.env,
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const ide_detector_1 = require("../src/cli/setup/ide-detector");
|
|
12
|
+
const mcp_config_generator_1 = require("../src/cli/setup/mcp-config-generator");
|
|
13
|
+
const token_validator_1 = require("../src/cli/setup/token-validator");
|
|
14
|
+
(0, node_test_1.test)('Setup integration - token validation flow', async () => {
|
|
15
|
+
// Test valid tokens
|
|
16
|
+
const validFraimKey = 'fraim_test123456789012345';
|
|
17
|
+
const validGithubToken = 'ghp_test123456789012345';
|
|
18
|
+
(0, node_assert_1.default)((0, token_validator_1.isValidTokenFormat)(validFraimKey, 'fraim'), 'Valid FRAIM key format should pass');
|
|
19
|
+
(0, node_assert_1.default)((0, token_validator_1.isValidTokenFormat)(validGithubToken, 'github'), 'Valid GitHub token format should pass');
|
|
20
|
+
(0, node_assert_1.default)(await (0, token_validator_1.validateFraimKey)(validFraimKey), 'Valid FRAIM key should validate');
|
|
21
|
+
// Test invalid tokens
|
|
22
|
+
(0, node_assert_1.default)(!(0, token_validator_1.isValidTokenFormat)('invalid_key', 'fraim'), 'Invalid FRAIM key should fail');
|
|
23
|
+
(0, node_assert_1.default)(!(0, token_validator_1.isValidTokenFormat)('invalid_token', 'github'), 'Invalid GitHub token should fail');
|
|
24
|
+
(0, node_assert_1.default)(!await (0, token_validator_1.validateFraimKey)('invalid_key'), 'Invalid FRAIM key should not validate');
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.test)('Setup integration - MCP config generation for all IDE types', () => {
|
|
27
|
+
const testFraimKey = 'fraim_test123456789012345';
|
|
28
|
+
const testGithubToken = 'ghp_test123456789012345';
|
|
29
|
+
// Test all config types
|
|
30
|
+
const standardConfig = (0, mcp_config_generator_1.generateMCPConfig)('standard', testFraimKey, testGithubToken);
|
|
31
|
+
const kiroConfig = (0, mcp_config_generator_1.generateMCPConfig)('kiro', testFraimKey, testGithubToken);
|
|
32
|
+
const codexConfig = (0, mcp_config_generator_1.generateMCPConfig)('codex', testFraimKey, testGithubToken);
|
|
33
|
+
const windsurfConfig = (0, mcp_config_generator_1.generateMCPConfig)('windsurf', testFraimKey, testGithubToken);
|
|
34
|
+
// Verify standard config structure
|
|
35
|
+
(0, node_assert_1.default)(standardConfig.mcpServers, 'Standard config should have mcpServers');
|
|
36
|
+
(0, node_assert_1.default)(standardConfig.mcpServers.fraim.serverUrl, 'Standard should use serverUrl');
|
|
37
|
+
(0, node_assert_1.default)(standardConfig.mcpServers.fraim.headers['x-api-key'] === testFraimKey, 'Should contain FRAIM key');
|
|
38
|
+
// Verify kiro config structure
|
|
39
|
+
(0, node_assert_1.default)(kiroConfig.mcpServers.fraim.url, 'Kiro should use url');
|
|
40
|
+
(0, node_assert_1.default)(!kiroConfig.mcpServers.fraim.serverUrl, 'Kiro should not have serverUrl');
|
|
41
|
+
// Verify codex config is TOML string
|
|
42
|
+
(0, node_assert_1.default)(typeof codexConfig === 'string', 'Codex should return TOML string');
|
|
43
|
+
(0, node_assert_1.default)(codexConfig.includes('[mcp_servers.fraim]'), 'Should contain FRAIM section');
|
|
44
|
+
(0, node_assert_1.default)(codexConfig.includes(testFraimKey), 'Should contain FRAIM key');
|
|
45
|
+
// Verify windsurf config structure
|
|
46
|
+
(0, node_assert_1.default)(windsurfConfig.mcpServers.fraim.command, 'Windsurf should use command');
|
|
47
|
+
(0, node_assert_1.default)(windsurfConfig.mcpServers.fraim.env.FRAIM_API_KEY === testFraimKey, 'Should contain FRAIM key in env');
|
|
48
|
+
});
|
|
49
|
+
(0, node_test_1.test)('Setup integration - IDE detection works', () => {
|
|
50
|
+
const detectedIDEs = (0, ide_detector_1.detectInstalledIDEs)();
|
|
51
|
+
// Should return an array (might be empty in test environment)
|
|
52
|
+
(0, node_assert_1.default)(Array.isArray(detectedIDEs), 'Should return an array');
|
|
53
|
+
// If any IDEs are detected, they should have the correct structure
|
|
54
|
+
detectedIDEs.forEach(ide => {
|
|
55
|
+
(0, node_assert_1.default)(typeof ide.name === 'string', 'IDE should have name');
|
|
56
|
+
(0, node_assert_1.default)(typeof ide.configPath === 'string', 'IDE should have configPath');
|
|
57
|
+
(0, node_assert_1.default)(['json', 'toml'].includes(ide.configFormat), 'IDE should have valid configFormat');
|
|
58
|
+
(0, node_assert_1.default)(['standard', 'kiro', 'codex', 'windsurf'].includes(ide.configType), 'IDE should have valid configType');
|
|
59
|
+
(0, node_assert_1.default)(typeof ide.detectMethod === 'function', 'IDE should have detectMethod');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
(0, node_test_1.test)('Setup integration - global config directory creation', () => {
|
|
63
|
+
const testConfigDir = path_1.default.join(os_1.default.tmpdir(), 'fraim-test-' + Date.now());
|
|
64
|
+
// Simulate creating global config directory
|
|
65
|
+
if (!fs_1.default.existsSync(testConfigDir)) {
|
|
66
|
+
fs_1.default.mkdirSync(testConfigDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(testConfigDir), 'Config directory should be created');
|
|
69
|
+
// Test config file creation
|
|
70
|
+
const testConfig = {
|
|
71
|
+
version: '2.0.37',
|
|
72
|
+
apiKey: 'fraim_test123456789012345',
|
|
73
|
+
configuredAt: new Date().toISOString()
|
|
74
|
+
};
|
|
75
|
+
const configPath = path_1.default.join(testConfigDir, 'config.json');
|
|
76
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify(testConfig, null, 2));
|
|
77
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(configPath), 'Config file should be created');
|
|
78
|
+
const savedConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
79
|
+
(0, node_assert_1.default)(savedConfig.apiKey === testConfig.apiKey, 'Config should contain API key');
|
|
80
|
+
(0, node_assert_1.default)(savedConfig.version === testConfig.version, 'Config should contain version');
|
|
81
|
+
// Cleanup
|
|
82
|
+
fs_1.default.rmSync(testConfigDir, { recursive: true, force: true });
|
|
83
|
+
});
|
|
84
|
+
(0, node_test_1.test)('Setup integration - backup functionality', () => {
|
|
85
|
+
const testDir = path_1.default.join(os_1.default.tmpdir(), 'fraim-backup-test-' + Date.now());
|
|
86
|
+
fs_1.default.mkdirSync(testDir, { recursive: true });
|
|
87
|
+
const originalConfigPath = path_1.default.join(testDir, 'test-config.json');
|
|
88
|
+
const originalConfig = { existing: 'config' };
|
|
89
|
+
fs_1.default.writeFileSync(originalConfigPath, JSON.stringify(originalConfig, null, 2));
|
|
90
|
+
// Simulate backup creation
|
|
91
|
+
const backupPath = `${originalConfigPath}.fraim-backup-${Date.now()}`;
|
|
92
|
+
fs_1.default.copyFileSync(originalConfigPath, backupPath);
|
|
93
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(backupPath), 'Backup file should be created');
|
|
94
|
+
const backupConfig = JSON.parse(fs_1.default.readFileSync(backupPath, 'utf8'));
|
|
95
|
+
node_assert_1.default.deepStrictEqual(backupConfig, originalConfig, 'Backup should match original');
|
|
96
|
+
// Cleanup
|
|
97
|
+
fs_1.default.rmSync(testDir, { recursive: true, force: true });
|
|
98
|
+
});
|
|
@@ -9,7 +9,7 @@ const db_service_js_1 = require("../src/fraim/db-service.js");
|
|
|
9
9
|
const test_utils_1 = require("./test-utils");
|
|
10
10
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
11
11
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
12
|
-
const
|
|
12
|
+
const test_server_utils_1 = require("./test-server-utils");
|
|
13
13
|
async function testServerStartsAndResponds() {
|
|
14
14
|
console.log(' 🚀 Testing Fraim Standalone Server...');
|
|
15
15
|
let fraimProcess;
|
|
@@ -35,7 +35,7 @@ async function testServerStartsAndResponds() {
|
|
|
35
35
|
// 2. Start server in standalone mode
|
|
36
36
|
console.log(` Starting server on port ${PORT}...`);
|
|
37
37
|
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
38
|
-
const serverScript =
|
|
38
|
+
const serverScript = (0, test_server_utils_1.getServerScriptPath)();
|
|
39
39
|
fraimProcess = (0, node_child_process_1.spawn)(npxCommand, ['node', `"${serverScript}"`], {
|
|
40
40
|
env: {
|
|
41
41
|
...process.env,
|
|
@@ -0,0 +1,136 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
8
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const build_stub_registry_1 = require("../scripts/build-stub-registry");
|
|
12
|
+
/**
|
|
13
|
+
* Tests for stub registry build process
|
|
14
|
+
* Ensures that the npm package contains only stubs and scripts, not full workflows
|
|
15
|
+
*/
|
|
16
|
+
// Find project root by looking for package.json
|
|
17
|
+
function findProjectRoot() {
|
|
18
|
+
let currentDir = __dirname;
|
|
19
|
+
while (currentDir !== path_1.default.dirname(currentDir)) {
|
|
20
|
+
if (fs_1.default.existsSync(path_1.default.join(currentDir, 'package.json'))) {
|
|
21
|
+
return currentDir;
|
|
22
|
+
}
|
|
23
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
24
|
+
}
|
|
25
|
+
throw new Error('Could not find project root (package.json not found)');
|
|
26
|
+
}
|
|
27
|
+
(0, node_test_1.test)('Stub registry build generates correct structure', async () => {
|
|
28
|
+
// Clean up any existing stubs
|
|
29
|
+
const projectRoot = findProjectRoot();
|
|
30
|
+
const stubsPath = path_1.default.join(projectRoot, 'registry', 'stubs');
|
|
31
|
+
if (fs_1.default.existsSync(stubsPath)) {
|
|
32
|
+
fs_1.default.rmSync(stubsPath, { recursive: true, force: true });
|
|
33
|
+
}
|
|
34
|
+
// Build stub registry
|
|
35
|
+
await (0, build_stub_registry_1.buildStubRegistry)();
|
|
36
|
+
// Verify stubs directory exists
|
|
37
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(stubsPath), 'Stubs directory should exist');
|
|
38
|
+
// Verify workflows stubs directory exists
|
|
39
|
+
const workflowsStubsPath = path_1.default.join(stubsPath, 'workflows');
|
|
40
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(workflowsStubsPath), 'Workflows stubs directory should exist');
|
|
41
|
+
// Verify at least some stubs were generated
|
|
42
|
+
const stubFiles = getAllFiles(workflowsStubsPath, '.md');
|
|
43
|
+
(0, node_assert_1.default)(stubFiles.length > 0, 'Should generate at least one workflow stub');
|
|
44
|
+
console.log(`✅ Generated ${stubFiles.length} workflow stubs`);
|
|
45
|
+
});
|
|
46
|
+
(0, node_test_1.test)('Generated stubs are lightweight and contain correct format', async () => {
|
|
47
|
+
const projectRoot = findProjectRoot();
|
|
48
|
+
const stubsPath = path_1.default.join(projectRoot, 'registry', 'stubs', 'workflows');
|
|
49
|
+
// Find a stub file to test
|
|
50
|
+
const stubFiles = getAllFiles(stubsPath, '.md');
|
|
51
|
+
(0, node_assert_1.default)(stubFiles.length > 0, 'Should have stub files to test');
|
|
52
|
+
const testStubPath = stubFiles[0];
|
|
53
|
+
const stubContent = fs_1.default.readFileSync(testStubPath, 'utf8');
|
|
54
|
+
// Verify stub format
|
|
55
|
+
(0, node_assert_1.default)(stubContent.includes('# FRAIM Workflow:'), 'Stub should have workflow title');
|
|
56
|
+
(0, node_assert_1.default)(stubContent.includes('FRAIM-managed workflow stub'), 'Stub should identify itself as a stub');
|
|
57
|
+
(0, node_assert_1.default)(stubContent.includes('get_fraim_workflow('), 'Stub should contain MCP call instruction');
|
|
58
|
+
(0, node_assert_1.default)(stubContent.includes('## Intent'), 'Stub should contain intent section');
|
|
59
|
+
(0, node_assert_1.default)(stubContent.includes('DO NOT EXECUTE'), 'Stub should contain execution warning');
|
|
60
|
+
// Verify stub is lightweight (should be much smaller than full workflow)
|
|
61
|
+
const stubLines = stubContent.split('\n').length;
|
|
62
|
+
(0, node_assert_1.default)(stubLines < 20, `Stub should be lightweight (${stubLines} lines), not a full workflow`);
|
|
63
|
+
console.log(`✅ Stub format verified (${stubLines} lines)`);
|
|
64
|
+
});
|
|
65
|
+
(0, node_test_1.test)('Stubs do not contain full workflow content', async () => {
|
|
66
|
+
const projectRoot = findProjectRoot();
|
|
67
|
+
const stubsPath = path_1.default.join(projectRoot, 'registry', 'stubs', 'workflows');
|
|
68
|
+
const fullWorkflowsPath = path_1.default.join(projectRoot, 'registry', 'workflows');
|
|
69
|
+
const stubFiles = getAllFiles(stubsPath, '.md');
|
|
70
|
+
(0, node_assert_1.default)(stubFiles.length > 0, 'Should have stub files to test');
|
|
71
|
+
for (const stubFile of stubFiles.slice(0, 3)) { // Test first 3 stubs
|
|
72
|
+
const stubContent = fs_1.default.readFileSync(stubFile, 'utf8');
|
|
73
|
+
// Find corresponding full workflow
|
|
74
|
+
const relativePath = path_1.default.relative(stubsPath, stubFile);
|
|
75
|
+
const fullWorkflowPath = path_1.default.join(fullWorkflowsPath, relativePath);
|
|
76
|
+
if (fs_1.default.existsSync(fullWorkflowPath)) {
|
|
77
|
+
const fullContent = fs_1.default.readFileSync(fullWorkflowPath, 'utf8');
|
|
78
|
+
// Stub should be much smaller than full workflow
|
|
79
|
+
(0, node_assert_1.default)(stubContent.length < fullContent.length * 0.5, `Stub should be <50% size of full workflow (stub: ${stubContent.length}, full: ${fullContent.length})`);
|
|
80
|
+
// More importantly, stub should not contain full workflow sections
|
|
81
|
+
(0, node_assert_1.default)(!stubContent.includes('## WORKFLOW TRIGGER'), 'Stub should not contain WORKFLOW TRIGGER section');
|
|
82
|
+
(0, node_assert_1.default)(!stubContent.includes('## AI AGENT PROCESS'), 'Stub should not contain AI AGENT PROCESS section');
|
|
83
|
+
(0, node_assert_1.default)(!stubContent.includes('## EXAMPLES'), 'Stub should not contain EXAMPLES section');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.log('✅ Stubs are properly lightweight');
|
|
87
|
+
});
|
|
88
|
+
(0, node_test_1.test)('Package.json files array excludes full workflows', () => {
|
|
89
|
+
const projectRoot = findProjectRoot();
|
|
90
|
+
const packageJsonPath = path_1.default.join(projectRoot, 'package.json');
|
|
91
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
|
|
92
|
+
const files = packageJson.files || [];
|
|
93
|
+
// Should include stubs
|
|
94
|
+
(0, node_assert_1.default)(files.includes('registry/stubs/'), 'Should include registry/stubs/');
|
|
95
|
+
// Should include scripts
|
|
96
|
+
(0, node_assert_1.default)(files.includes('registry/scripts/'), 'Should include registry/scripts/');
|
|
97
|
+
// Should NOT include full registry
|
|
98
|
+
(0, node_assert_1.default)(!files.includes('registry/'), 'Should NOT include full registry/');
|
|
99
|
+
(0, node_assert_1.default)(!files.includes('registry/workflows/'), 'Should NOT include registry/workflows/');
|
|
100
|
+
(0, node_assert_1.default)(!files.includes('registry/templates/'), 'Should NOT include registry/templates/');
|
|
101
|
+
(0, node_assert_1.default)(!files.includes('registry/rules/'), 'Should NOT include registry/rules/');
|
|
102
|
+
console.log('✅ Package.json correctly excludes full workflows');
|
|
103
|
+
});
|
|
104
|
+
(0, node_test_1.test)('Scripts are still included in package', () => {
|
|
105
|
+
const projectRoot = findProjectRoot();
|
|
106
|
+
const scriptsPath = path_1.default.join(projectRoot, 'registry', 'scripts');
|
|
107
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(scriptsPath), 'Scripts directory should exist');
|
|
108
|
+
const scriptFiles = getAllFiles(scriptsPath);
|
|
109
|
+
(0, node_assert_1.default)(scriptFiles.length > 0, 'Should have script files');
|
|
110
|
+
// Verify package.json includes scripts
|
|
111
|
+
const packageJsonPath = path_1.default.join(projectRoot, 'package.json');
|
|
112
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
|
|
113
|
+
const files = packageJson.files || [];
|
|
114
|
+
(0, node_assert_1.default)(files.includes('registry/scripts/'), 'Package should include scripts');
|
|
115
|
+
console.log(`✅ ${scriptFiles.length} scripts are included in package`);
|
|
116
|
+
});
|
|
117
|
+
// Helper function to get all files recursively
|
|
118
|
+
function getAllFiles(dir, extension) {
|
|
119
|
+
const files = [];
|
|
120
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
121
|
+
return files;
|
|
122
|
+
}
|
|
123
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
126
|
+
if (entry.isDirectory()) {
|
|
127
|
+
files.push(...getAllFiles(fullPath, extension));
|
|
128
|
+
}
|
|
129
|
+
else if (entry.isFile()) {
|
|
130
|
+
if (!extension || entry.name.endsWith(extension)) {
|
|
131
|
+
files.push(fullPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return files;
|
|
136
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
8
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const os_1 = __importDefault(require("os"));
|
|
12
|
+
const sync_1 = require("../src/cli/commands/sync");
|
|
13
|
+
/**
|
|
14
|
+
* Tests for sync command with stub registry
|
|
15
|
+
* Ensures sync works correctly with pre-generated stubs
|
|
16
|
+
*/
|
|
17
|
+
// Use a temporary directory for testing
|
|
18
|
+
const TEST_PROJECT_DIR = path_1.default.join(os_1.default.tmpdir(), 'fraim-test-sync-' + Date.now());
|
|
19
|
+
const TEST_FRAIM_DIR = path_1.default.join(TEST_PROJECT_DIR, '.fraim');
|
|
20
|
+
const TEST_WORKFLOWS_DIR = path_1.default.join(TEST_FRAIM_DIR, 'workflows');
|
|
21
|
+
(0, node_test_1.test)('Sync command works with stub registry', async () => {
|
|
22
|
+
// Setup test environment
|
|
23
|
+
setupTestProject();
|
|
24
|
+
// Change to test directory
|
|
25
|
+
const originalCwd = process.cwd();
|
|
26
|
+
process.chdir(TEST_PROJECT_DIR);
|
|
27
|
+
try {
|
|
28
|
+
// Run sync
|
|
29
|
+
await (0, sync_1.runSync)({ force: true });
|
|
30
|
+
// Verify workflows directory was created
|
|
31
|
+
(0, node_assert_1.default)(fs_1.default.existsSync(TEST_WORKFLOWS_DIR), 'Workflows directory should be created');
|
|
32
|
+
// Verify stubs were copied
|
|
33
|
+
const stubFiles = getAllFiles(TEST_WORKFLOWS_DIR, '.md');
|
|
34
|
+
(0, node_assert_1.default)(stubFiles.length > 0, 'Should copy workflow stubs');
|
|
35
|
+
// Verify stubs have correct format
|
|
36
|
+
const testStub = fs_1.default.readFileSync(stubFiles[0], 'utf8');
|
|
37
|
+
(0, node_assert_1.default)(testStub.includes('FRAIM-managed workflow stub'), 'Copied files should be stubs');
|
|
38
|
+
(0, node_assert_1.default)(testStub.includes('get_fraim_workflow('), 'Stubs should contain MCP call instruction');
|
|
39
|
+
console.log(`✅ Sync copied ${stubFiles.length} workflow stubs`);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
// Restore original directory
|
|
43
|
+
process.chdir(originalCwd);
|
|
44
|
+
// Cleanup test directory
|
|
45
|
+
if (fs_1.default.existsSync(TEST_PROJECT_DIR)) {
|
|
46
|
+
fs_1.default.rmSync(TEST_PROJECT_DIR, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
(0, node_test_1.test)('Sync uses stub registry, not full workflows', async () => {
|
|
51
|
+
// Setup test environment
|
|
52
|
+
setupTestProject();
|
|
53
|
+
const originalCwd = process.cwd();
|
|
54
|
+
process.chdir(TEST_PROJECT_DIR);
|
|
55
|
+
try {
|
|
56
|
+
// Run sync
|
|
57
|
+
await (0, sync_1.runSync)({ force: true });
|
|
58
|
+
// Verify synced files are stubs, not full workflows
|
|
59
|
+
const stubFiles = getAllFiles(TEST_WORKFLOWS_DIR, '.md');
|
|
60
|
+
(0, node_assert_1.default)(stubFiles.length > 0, 'Should have synced files');
|
|
61
|
+
for (const stubFile of stubFiles.slice(0, 3)) { // Test first 3 files
|
|
62
|
+
const content = fs_1.default.readFileSync(stubFile, 'utf8');
|
|
63
|
+
const lines = content.split('\n').length;
|
|
64
|
+
// Should be lightweight stubs
|
|
65
|
+
(0, node_assert_1.default)(lines < 20, `File should be a stub (${lines} lines), not a full workflow`);
|
|
66
|
+
(0, node_assert_1.default)(content.includes('DO NOT EXECUTE'), 'Should contain stub warning');
|
|
67
|
+
(0, node_assert_1.default)(!content.includes('## WORKFLOW TRIGGER'), 'Should not contain full workflow sections');
|
|
68
|
+
(0, node_assert_1.default)(!content.includes('## AI AGENT PROCESS'), 'Should not contain full workflow sections');
|
|
69
|
+
}
|
|
70
|
+
console.log('✅ Sync correctly uses stubs, not full workflows');
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
process.chdir(originalCwd);
|
|
74
|
+
if (fs_1.default.existsSync(TEST_PROJECT_DIR)) {
|
|
75
|
+
fs_1.default.rmSync(TEST_PROJECT_DIR, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
(0, node_test_1.test)('Sync preserves directory structure from stub registry', async () => {
|
|
80
|
+
setupTestProject();
|
|
81
|
+
const originalCwd = process.cwd();
|
|
82
|
+
process.chdir(TEST_PROJECT_DIR);
|
|
83
|
+
try {
|
|
84
|
+
await (0, sync_1.runSync)({ force: true });
|
|
85
|
+
// Verify directory structure is preserved
|
|
86
|
+
const expectedDirs = [
|
|
87
|
+
'bootstrap',
|
|
88
|
+
'product-building',
|
|
89
|
+
'customer-development',
|
|
90
|
+
'marketing'
|
|
91
|
+
];
|
|
92
|
+
for (const expectedDir of expectedDirs) {
|
|
93
|
+
const dirPath = path_1.default.join(TEST_WORKFLOWS_DIR, expectedDir);
|
|
94
|
+
if (fs_1.default.existsSync(dirPath)) {
|
|
95
|
+
(0, node_assert_1.default)(fs_1.default.statSync(dirPath).isDirectory(), `${expectedDir} should be a directory`);
|
|
96
|
+
// Should contain stub files
|
|
97
|
+
const files = fs_1.default.readdirSync(dirPath).filter(f => f.endsWith('.md'));
|
|
98
|
+
(0, node_assert_1.default)(files.length > 0, `${expectedDir} should contain workflow stubs`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
console.log('✅ Directory structure preserved correctly');
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
process.chdir(originalCwd);
|
|
105
|
+
if (fs_1.default.existsSync(TEST_PROJECT_DIR)) {
|
|
106
|
+
fs_1.default.rmSync(TEST_PROJECT_DIR, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
function setupTestProject() {
|
|
111
|
+
// Create test project directory
|
|
112
|
+
if (fs_1.default.existsSync(TEST_PROJECT_DIR)) {
|
|
113
|
+
fs_1.default.rmSync(TEST_PROJECT_DIR, { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
fs_1.default.mkdirSync(TEST_PROJECT_DIR, { recursive: true });
|
|
116
|
+
// Create .fraim directory
|
|
117
|
+
fs_1.default.mkdirSync(TEST_FRAIM_DIR, { recursive: true });
|
|
118
|
+
// Create basic config.json
|
|
119
|
+
const config = {
|
|
120
|
+
version: "2.0.36",
|
|
121
|
+
customizations: {}
|
|
122
|
+
};
|
|
123
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_FRAIM_DIR, 'config.json'), JSON.stringify(config, null, 2));
|
|
124
|
+
}
|
|
125
|
+
function getAllFiles(dir, extension) {
|
|
126
|
+
const files = [];
|
|
127
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
128
|
+
return files;
|
|
129
|
+
}
|
|
130
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
133
|
+
if (entry.isDirectory()) {
|
|
134
|
+
files.push(...getAllFiles(fullPath, extension));
|
|
135
|
+
}
|
|
136
|
+
else if (entry.isFile()) {
|
|
137
|
+
if (!extension || entry.name.endsWith(extension)) {
|
|
138
|
+
files.push(fullPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
@@ -9,7 +9,7 @@ const db_service_js_1 = require("../src/fraim/db-service.js");
|
|
|
9
9
|
const test_utils_1 = require("./test-utils");
|
|
10
10
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
11
11
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
12
|
-
const
|
|
12
|
+
const test_server_utils_1 = require("./test-server-utils");
|
|
13
13
|
async function testTelemetryFlow() {
|
|
14
14
|
console.log(' 🚀 Testing Fraim Telemetry System...');
|
|
15
15
|
let fraimProcess;
|
|
@@ -39,7 +39,7 @@ async function testTelemetryFlow() {
|
|
|
39
39
|
// 2. Start Server
|
|
40
40
|
console.log(` Starting server on port ${PORT}...`);
|
|
41
41
|
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
42
|
-
const serverScript =
|
|
42
|
+
const serverScript = (0, test_server_utils_1.getServerScriptPath)();
|
|
43
43
|
fraimProcess = (0, node_child_process_1.spawn)(npxCommand, ['node', `"${serverScript}"`], {
|
|
44
44
|
env: {
|
|
45
45
|
...process.env,
|