fraim-framework 2.0.55 â 2.0.57
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/CHANGELOG.md +10 -0
- package/dist/src/cli/commands/init-project.js +10 -4
- package/dist/src/cli/setup/mcp-config-generator.js +23 -15
- package/dist/src/local-mcp-server/stdio-server.js +207 -0
- package/dist/src/utils/validate-workflows.js +101 -0
- package/dist/src/utils/workflow-parser.js +81 -0
- package/package.json +16 -11
- package/registry/scripts/pdf-styles.css +172 -0
- package/registry/scripts/prep-issue.sh +46 -4
- package/registry/scripts/profile-server.ts +131 -130
- package/registry/stubs/workflows/customer-development/user-survey-dispatch.md +1 -1
- package/registry/stubs/workflows/customer-development/users-to-target.md +1 -1
- package/registry/stubs/workflows/product-building/design.md +1 -1
- package/registry/stubs/workflows/product-building/implement.md +1 -1
- package/Claude.md +0 -1
- package/dist/registry/ai-manager-rules/design-phases/design-completeness-review.md +0 -73
- package/dist/registry/ai-manager-rules/design-phases/design-design.md +0 -145
- package/dist/registry/ai-manager-rules/implement-phases/implement-code.md +0 -283
- package/dist/registry/ai-manager-rules/implement-phases/implement-completeness-review.md +0 -120
- package/dist/registry/ai-manager-rules/implement-phases/implement-regression.md +0 -173
- package/dist/registry/ai-manager-rules/implement-phases/implement-repro.md +0 -104
- package/dist/registry/ai-manager-rules/implement-phases/implement-scoping.md +0 -100
- package/dist/registry/ai-manager-rules/implement-phases/implement-smoke.md +0 -237
- package/dist/registry/ai-manager-rules/implement-phases/implement-spike.md +0 -121
- package/dist/registry/ai-manager-rules/implement-phases/implement-validate.md +0 -375
- package/dist/registry/ai-manager-rules/retrospective.md +0 -116
- package/dist/registry/ai-manager-rules/shared-phases/address-pr-feedback.md +0 -188
- package/dist/registry/ai-manager-rules/shared-phases/submit-pr.md +0 -202
- package/dist/registry/ai-manager-rules/shared-phases/wait-for-pr-review.md +0 -170
- package/dist/registry/ai-manager-rules/spec-phases/spec-competitor-analysis.md +0 -105
- package/dist/registry/ai-manager-rules/spec-phases/spec-completeness-review.md +0 -66
- package/dist/registry/ai-manager-rules/spec-phases/spec-spec.md +0 -139
- package/dist/registry/providers/ado.json +0 -19
- package/dist/registry/providers/github.json +0 -19
- package/dist/registry/scripts/cleanup-branch.js +0 -287
- package/dist/registry/scripts/evaluate-code-quality.js +0 -66
- package/dist/registry/scripts/exec-with-timeout.js +0 -142
- package/dist/registry/scripts/generate-engagement-emails.js +0 -705
- package/dist/registry/scripts/newsletter-helpers.js +0 -671
- package/dist/registry/scripts/profile-server.js +0 -388
- package/dist/registry/scripts/run-thank-you-workflow.js +0 -92
- package/dist/registry/scripts/send-newsletter-simple.js +0 -85
- package/dist/registry/scripts/send-thank-you-emails.js +0 -54
- package/dist/registry/scripts/validate-openapi-limits.js +0 -311
- package/dist/registry/scripts/validate-test-coverage.js +0 -262
- package/dist/registry/scripts/verify-test-coverage.js +0 -66
- package/dist/scripts/build-stub-registry.js +0 -108
- package/dist/src/ai-manager/ai-manager.js +0 -482
- package/dist/src/ai-manager/phase-flow.js +0 -357
- package/dist/src/ai-manager/types.js +0 -5
- package/dist/src/fraim-mcp-server.js +0 -1885
- package/dist/tests/debug-tools.js +0 -80
- package/dist/tests/shared-server-utils.js +0 -57
- package/dist/tests/test-add-ide.js +0 -283
- package/dist/tests/test-ai-coach-edge-cases.js +0 -420
- package/dist/tests/test-ai-coach-mcp-integration.js +0 -450
- package/dist/tests/test-ai-coach-performance.js +0 -328
- package/dist/tests/test-ai-coach-phase-content.js +0 -264
- package/dist/tests/test-ai-coach-workflows.js +0 -514
- package/dist/tests/test-cli.js +0 -228
- package/dist/tests/test-client-scripts-validation.js +0 -167
- package/dist/tests/test-complete-setup-flow.js +0 -110
- package/dist/tests/test-config-system.js +0 -279
- package/dist/tests/test-debug-session.js +0 -134
- package/dist/tests/test-end-to-end-hybrid-validation.js +0 -328
- package/dist/tests/test-enhanced-session-init.js +0 -188
- package/dist/tests/test-first-run-journey.js +0 -368
- package/dist/tests/test-fraim-issues.js +0 -59
- package/dist/tests/test-genericization.js +0 -44
- package/dist/tests/test-hybrid-script-execution.js +0 -340
- package/dist/tests/test-ide-detector.js +0 -46
- package/dist/tests/test-improved-setup.js +0 -121
- package/dist/tests/test-mcp-config-generator.js +0 -99
- package/dist/tests/test-mcp-connection.js +0 -107
- package/dist/tests/test-mcp-issue-integration.js +0 -156
- package/dist/tests/test-mcp-lifecycle-methods.js +0 -240
- package/dist/tests/test-mcp-shared-server.js +0 -308
- package/dist/tests/test-mcp-template-processing.js +0 -160
- package/dist/tests/test-modular-issue-tracking.js +0 -165
- package/dist/tests/test-node-compatibility.js +0 -95
- package/dist/tests/test-npm-install.js +0 -68
- package/dist/tests/test-package-size.js +0 -108
- package/dist/tests/test-pr-review-workflow.js +0 -307
- package/dist/tests/test-prep-issue.js +0 -129
- package/dist/tests/test-productivity-integration.js +0 -157
- package/dist/tests/test-script-location-independence.js +0 -198
- package/dist/tests/test-script-sync.js +0 -557
- package/dist/tests/test-server-utils.js +0 -32
- package/dist/tests/test-session-rehydration.js +0 -148
- package/dist/tests/test-setup-integration.js +0 -98
- package/dist/tests/test-setup-scenarios.js +0 -322
- package/dist/tests/test-standalone.js +0 -143
- package/dist/tests/test-stub-registry.js +0 -136
- package/dist/tests/test-sync-stubs.js +0 -143
- package/dist/tests/test-sync-version-update.js +0 -93
- package/dist/tests/test-telemetry.js +0 -193
- package/dist/tests/test-token-validator.js +0 -30
- package/dist/tests/test-user-journey.js +0 -236
- package/dist/tests/test-users-to-target-workflow.js +0 -253
- package/dist/tests/test-utils.js +0 -109
- package/dist/tests/test-wizard.js +0 -71
- package/dist/tests/test-workflow-discovery.js +0 -242
- package/labels.json +0 -52
- package/registry/agent-guardrails.md +0 -63
- package/registry/fraim.md +0 -48
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase1-customer-profiling.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase1-survey-scoping.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase2-platform-discovery.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase2-survey-build-linkedin.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase3-prospect-qualification.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase3-survey-build-reddit.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase4-inventory-compilation.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase4-survey-build-x.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase5-survey-build-facebook.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase6-survey-build-custom.md +0 -11
- package/registry/stubs/workflows/customer-development/ai-coach-phases/phase7-survey-dispatch.md +0 -11
- package/registry/stubs/workflows/customer-development/templates/customer-persona-template.md +0 -11
- package/registry/stubs/workflows/customer-development/templates/search-strategy-template.md +0 -11
- package/setup.js +0 -171
- package/tsconfig.json +0 -23
|
@@ -1,143 +0,0 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const db_service_js_1 = require("../src/fraim/db-service.js");
|
|
9
|
-
const test_utils_1 = require("./test-utils");
|
|
10
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
11
|
-
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
12
|
-
const test_server_utils_1 = require("./test-server-utils");
|
|
13
|
-
async function testServerStartsAndResponds() {
|
|
14
|
-
console.log(' đ Testing Fraim Standalone Server...');
|
|
15
|
-
let fraimProcess;
|
|
16
|
-
let dbService;
|
|
17
|
-
const PORT = Math.floor(Math.random() * 1000) + 10000; // Random port to avoid conflicts
|
|
18
|
-
const TEST_API_KEY = 'test-fraim-key-integration';
|
|
19
|
-
const TEST_ADMIN_KEY = 'test-admin-key-integration';
|
|
20
|
-
const TEST_ADMIN_HEADER = { 'x-admin-key': TEST_ADMIN_KEY };
|
|
21
|
-
const BASE_URL = `http://localhost:${PORT}`;
|
|
22
|
-
try {
|
|
23
|
-
// 1. Seed the test API key in the database
|
|
24
|
-
dbService = new db_service_js_1.FraimDbService();
|
|
25
|
-
await dbService.connect();
|
|
26
|
-
const db = dbService.db;
|
|
27
|
-
await db.collection('fraim_api_keys').updateOne({ key: TEST_API_KEY }, {
|
|
28
|
-
$set: {
|
|
29
|
-
userId: 'test-user@ashley.ai',
|
|
30
|
-
orgId: 'test-org',
|
|
31
|
-
isActive: true,
|
|
32
|
-
createdAt: new Date()
|
|
33
|
-
}
|
|
34
|
-
}, { upsert: true });
|
|
35
|
-
// 2. Start server in standalone mode
|
|
36
|
-
console.log(` Starting server on port ${PORT}...`);
|
|
37
|
-
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
38
|
-
const serverScript = (0, test_server_utils_1.getServerScriptPath)();
|
|
39
|
-
fraimProcess = (0, node_child_process_1.spawn)(npxCommand, ['node', `"${serverScript}"`], {
|
|
40
|
-
env: {
|
|
41
|
-
...process.env,
|
|
42
|
-
FRAIM_MCP_PORT: PORT.toString(),
|
|
43
|
-
FRAIM_ADMIN_KEY: TEST_ADMIN_KEY,
|
|
44
|
-
FRAIM_SKIP_INDEX_ON_START: 'true' // Potential optimization if implemented
|
|
45
|
-
},
|
|
46
|
-
stdio: 'inherit',
|
|
47
|
-
shell: true
|
|
48
|
-
});
|
|
49
|
-
// 3. Wait for server to start
|
|
50
|
-
console.log(' Waiting for server to start...');
|
|
51
|
-
let started = false;
|
|
52
|
-
for (let i = 0; i < 15; i++) {
|
|
53
|
-
try {
|
|
54
|
-
await axios_1.default.get(`${BASE_URL}/health`, { timeout: 1000 });
|
|
55
|
-
started = true;
|
|
56
|
-
console.log(' Server started!');
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (!started) {
|
|
64
|
-
console.error(' â Server failed to start within timeout');
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
// 4. Test health check (public)
|
|
68
|
-
console.log(' Testing public health check...');
|
|
69
|
-
const healthRes = await axios_1.default.get(`${BASE_URL}/health`, { timeout: 2000 });
|
|
70
|
-
node_assert_1.default.strictEqual(healthRes.status, 200);
|
|
71
|
-
node_assert_1.default.strictEqual(healthRes.data.status, 'ok');
|
|
72
|
-
// 5. Test MCP tool list without API key (fail)
|
|
73
|
-
console.log(' Testing MCP without auth (should fail)...');
|
|
74
|
-
try {
|
|
75
|
-
await axios_1.default.post(`${BASE_URL}/mcp`, {
|
|
76
|
-
jsonrpc: '2.0',
|
|
77
|
-
id: 1,
|
|
78
|
-
method: 'tools/list',
|
|
79
|
-
params: {}
|
|
80
|
-
}, { timeout: 2000 });
|
|
81
|
-
console.error(' â Should have failed without API key');
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
node_assert_1.default.ok(error.response, 'Should have a response');
|
|
86
|
-
node_assert_1.default.strictEqual(error.response.status, 401);
|
|
87
|
-
}
|
|
88
|
-
// 6. Test MCP tool list with correct API key (success)
|
|
89
|
-
console.log(' Testing MCP with correct auth...');
|
|
90
|
-
const mcpResponse = await axios_1.default.post(`${BASE_URL}/mcp`, {
|
|
91
|
-
jsonrpc: '2.0',
|
|
92
|
-
id: 1,
|
|
93
|
-
method: 'tools/list',
|
|
94
|
-
params: {}
|
|
95
|
-
}, {
|
|
96
|
-
headers: { 'x-api-key': TEST_API_KEY },
|
|
97
|
-
timeout: 5000
|
|
98
|
-
});
|
|
99
|
-
node_assert_1.default.strictEqual(mcpResponse.status, 200);
|
|
100
|
-
node_assert_1.default.ok(mcpResponse.data.result.tools.length > 0);
|
|
101
|
-
// 7. Test Admin API - List Keys
|
|
102
|
-
console.log(' Testing Admin API - List Keys...');
|
|
103
|
-
const listKeysRes = await axios_1.default.get(`${BASE_URL}/admin/keys`, {
|
|
104
|
-
headers: TEST_ADMIN_HEADER,
|
|
105
|
-
timeout: 2000
|
|
106
|
-
});
|
|
107
|
-
node_assert_1.default.strictEqual(listKeysRes.status, 200);
|
|
108
|
-
node_assert_1.default.ok(Array.isArray(listKeysRes.data));
|
|
109
|
-
node_assert_1.default.ok(listKeysRes.data.some((k) => k.key === TEST_API_KEY));
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
console.error(' â Test failed:', error);
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
finally {
|
|
117
|
-
console.log(' Cleaning up...');
|
|
118
|
-
if (dbService) {
|
|
119
|
-
const db = dbService.db;
|
|
120
|
-
if (db) {
|
|
121
|
-
await db.collection('fraim_api_keys').deleteOne({ key: TEST_API_KEY }).catch(() => { });
|
|
122
|
-
}
|
|
123
|
-
await dbService.close().catch(() => { });
|
|
124
|
-
}
|
|
125
|
-
if (fraimProcess && fraimProcess.pid) {
|
|
126
|
-
const pid = fraimProcess.pid;
|
|
127
|
-
await new Promise((resolve) => (0, tree_kill_1.default)(pid, 'SIGKILL', () => resolve()));
|
|
128
|
-
console.log(` Terminated server process ${pid}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async function runFraimTest(testCase) {
|
|
133
|
-
return await testCase.testFunction();
|
|
134
|
-
}
|
|
135
|
-
const testCases = [
|
|
136
|
-
{
|
|
137
|
-
name: 'Fraim Standalone Server Integration',
|
|
138
|
-
description: 'Tests server startup, public health check, authenticated MCP access, and admin API',
|
|
139
|
-
testFunction: testServerStartsAndResponds,
|
|
140
|
-
tags: ['smoke', 'fraim']
|
|
141
|
-
}
|
|
142
|
-
];
|
|
143
|
-
(0, test_utils_1.runTests)(testCases, runFraimTest, 'Fraim Standalone Server');
|
|
@@ -1,136 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
-
const test_utils_1 = require("./test-utils");
|
|
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 version_utils_1 = require("../src/utils/version-utils");
|
|
13
|
-
const types_1 = require("../src/fraim/types");
|
|
14
|
-
async function testSyncUpdateVersion() {
|
|
15
|
-
console.log(' đ Testing "fraim sync" version update...');
|
|
16
|
-
// Create a temp directory for the test project
|
|
17
|
-
const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-test-sync-'));
|
|
18
|
-
console.log(` đ Created temp dir: ${tempDir}`);
|
|
19
|
-
try {
|
|
20
|
-
const platform = process.platform;
|
|
21
|
-
const npx = platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
22
|
-
const cliScript = (0, test_utils_1.resolveProjectPath)('dist/src/cli/fraim.js');
|
|
23
|
-
// Setup .fraim/config.json with an OLD version
|
|
24
|
-
const fraimDir = path_1.default.join(tempDir, '.fraim');
|
|
25
|
-
fs_1.default.mkdirSync(fraimDir, { recursive: true });
|
|
26
|
-
const oldVersion = '0.0.0';
|
|
27
|
-
const initialConfig = {
|
|
28
|
-
...types_1.DEFAULT_FRAIM_CONFIG,
|
|
29
|
-
version: oldVersion,
|
|
30
|
-
project: { name: 'test-project' },
|
|
31
|
-
git: { repoOwner: 'test', repoName: 'test' }
|
|
32
|
-
};
|
|
33
|
-
fs_1.default.writeFileSync(path_1.default.join(fraimDir, 'config.json'), JSON.stringify(initialConfig, null, 2));
|
|
34
|
-
// Create a fake registry so sync doesn't fail hard
|
|
35
|
-
const registryDir = path_1.default.join(tempDir, 'registry', 'workflows');
|
|
36
|
-
fs_1.default.mkdirSync(registryDir, { recursive: true });
|
|
37
|
-
fs_1.default.writeFileSync(path_1.default.join(registryDir, 'dummy.md'), '---\nintent: test\n---\n# Dummy');
|
|
38
|
-
// Helper to run CLI commands
|
|
39
|
-
const runFraim = (args) => {
|
|
40
|
-
return new Promise((resolve) => {
|
|
41
|
-
const ps = (0, node_child_process_1.spawn)(npx, ['tsx', `"${cliScript}"`, ...args], {
|
|
42
|
-
cwd: tempDir,
|
|
43
|
-
env: { ...process.env, TEST_MODE: 'true' },
|
|
44
|
-
shell: true
|
|
45
|
-
});
|
|
46
|
-
let stdout = '';
|
|
47
|
-
let stderr = '';
|
|
48
|
-
ps.stdout.on('data', d => stdout += d.toString());
|
|
49
|
-
ps.stderr.on('data', d => stderr += d.toString());
|
|
50
|
-
ps.on('close', (code) => resolve({ stdout, stderr, code }));
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
// Run `fraim sync`
|
|
54
|
-
console.log(' Running "fraim sync"...');
|
|
55
|
-
const res = await runFraim(['sync']);
|
|
56
|
-
if (res.code !== 0) {
|
|
57
|
-
console.error(' â Sync failed:', res.stderr);
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
// Verify config.json has the NEW/Current version
|
|
61
|
-
const updatedConfig = JSON.parse(fs_1.default.readFileSync(path_1.default.join(fraimDir, 'config.json'), 'utf-8'));
|
|
62
|
-
const currentPackageVersion = (0, version_utils_1.getFraimVersion)();
|
|
63
|
-
console.log(` âšī¸ Old Version: ${oldVersion}`);
|
|
64
|
-
console.log(` âšī¸ New Version in Config: ${updatedConfig.version}`);
|
|
65
|
-
console.log(` âšī¸ Current Package Version: ${currentPackageVersion}`);
|
|
66
|
-
node_assert_1.default.strictEqual(updatedConfig.version, currentPackageVersion, 'Config version should match package version after sync');
|
|
67
|
-
node_assert_1.default.notStrictEqual(updatedConfig.version, oldVersion, 'Config version should have been updated from 0.0.0');
|
|
68
|
-
console.log(' â
Validated: Version was updated correctly.');
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
console.error(' â Test failed:', error);
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
finally {
|
|
76
|
-
try {
|
|
77
|
-
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
78
|
-
}
|
|
79
|
-
catch (e) { }
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async function runTest(testCase) {
|
|
83
|
-
return await testCase.testFunction();
|
|
84
|
-
}
|
|
85
|
-
const testCases = [
|
|
86
|
-
{
|
|
87
|
-
name: 'Sync Version Update',
|
|
88
|
-
description: 'Verifies that fraim sync updates the version in config.json',
|
|
89
|
-
testFunction: testSyncUpdateVersion,
|
|
90
|
-
tags: ['cli', 'sync']
|
|
91
|
-
},
|
|
92
|
-
];
|
|
93
|
-
(0, test_utils_1.runTests)(testCases, runTest, 'Fraim Sync Update Tests');
|