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,129 +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 fs_1 = __importDefault(require("fs"));
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const child_process_1 = require("child_process");
|
|
9
|
-
const assert_1 = __importDefault(require("assert"));
|
|
10
|
-
const test_utils_1 = require("./test-utils");
|
|
11
|
-
// Path to the shell script
|
|
12
|
-
// Handle both source (tests/) and compiled (dist/tests/) execution
|
|
13
|
-
const SCRIPT_PATH = fs_1.default.existsSync(path_1.default.join(__dirname, '../registry/scripts/prep-issue.sh'))
|
|
14
|
-
? path_1.default.join(__dirname, '../registry/scripts/prep-issue.sh')
|
|
15
|
-
: path_1.default.resolve(__dirname, '../../registry/scripts/prep-issue.sh');
|
|
16
|
-
function extractNodeScript() {
|
|
17
|
-
const content = fs_1.default.readFileSync(SCRIPT_PATH, 'utf8');
|
|
18
|
-
// Regex to capture the content inside NODE_SCRIPT="..."
|
|
19
|
-
const match = content.match(/NODE_SCRIPT="([\s\S]*?)"/);
|
|
20
|
-
if (!match || !match[1]) {
|
|
21
|
-
throw new Error('Could not find NODE_SCRIPT variable in prep-issue.sh');
|
|
22
|
-
}
|
|
23
|
-
// Unescape characters that are escaped in Bash double-quoted string
|
|
24
|
-
// specifically: \` \$ \" \\
|
|
25
|
-
return match[1]
|
|
26
|
-
.replace(/\\`/g, '`')
|
|
27
|
-
.replace(/\\\$/g, '$')
|
|
28
|
-
.replace(/\\"/g, '"')
|
|
29
|
-
.replace(/\\\\/g, '\\');
|
|
30
|
-
}
|
|
31
|
-
function runParsingLogic(script, config) {
|
|
32
|
-
const input = JSON.stringify(config);
|
|
33
|
-
const result = (0, child_process_1.spawnSync)('node', ['-e', script], {
|
|
34
|
-
input,
|
|
35
|
-
encoding: 'utf-8'
|
|
36
|
-
});
|
|
37
|
-
if (result.status !== 0) {
|
|
38
|
-
throw new Error(`Script failed to run (status ${result.status}). Stderr: ${result.stderr}`);
|
|
39
|
-
}
|
|
40
|
-
return result.stdout.trim();
|
|
41
|
-
}
|
|
42
|
-
async function verifyPrepIssueConfigParsing() {
|
|
43
|
-
console.log(' 🔍 Verifying prep-issue.sh config parsing logic...');
|
|
44
|
-
try {
|
|
45
|
-
// 1. Verify script exists
|
|
46
|
-
assert_1.default.ok(fs_1.default.existsSync(SCRIPT_PATH), `prep-issue.sh not found at ${SCRIPT_PATH}`);
|
|
47
|
-
// 2. Extract the Node.js parsing logic
|
|
48
|
-
const nodeScript = extractNodeScript();
|
|
49
|
-
assert_1.default.ok(nodeScript.length > 0, 'Extracted script is empty');
|
|
50
|
-
console.log(' ✅ Extracted Node.js parsing logic');
|
|
51
|
-
// 3. Test Valid Configuration
|
|
52
|
-
const validConfig = {
|
|
53
|
-
repository: {
|
|
54
|
-
owner: 'test-owner',
|
|
55
|
-
name: 'test-repo',
|
|
56
|
-
url: 'https://github.com/test-owner/test-repo.git'
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const output = runParsingLogic(nodeScript, validConfig);
|
|
60
|
-
assert_1.default.strictEqual(output, 'test-owner|test-repo|https://github.com/test-owner/test-repo.git|master');
|
|
61
|
-
console.log(' ✅ Valid config parsed correctly');
|
|
62
|
-
// 4. Test Missing Config
|
|
63
|
-
assert_1.default.throws(() => {
|
|
64
|
-
runParsingLogic(nodeScript, { name: 'Create-Project' });
|
|
65
|
-
}, /Script failed/);
|
|
66
|
-
console.log(' ✅ Missing config correctly failed');
|
|
67
|
-
// 5. Test Incomplete Config
|
|
68
|
-
assert_1.default.throws(() => {
|
|
69
|
-
runParsingLogic(nodeScript, { repository: { owner: 'test-owner' } });
|
|
70
|
-
}, /Script failed/);
|
|
71
|
-
console.log(' ✅ Incomplete config correctly failed');
|
|
72
|
-
// 6. Test Default Branch Extraction (git schema)
|
|
73
|
-
const gitConfig = {
|
|
74
|
-
git: {
|
|
75
|
-
repoOwner: 'test-owner',
|
|
76
|
-
repoName: 'test-repo',
|
|
77
|
-
defaultBranch: 'master'
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
const gitOutput = runParsingLogic(nodeScript, gitConfig);
|
|
81
|
-
assert_1.default.strictEqual(gitOutput, 'test-owner|test-repo|https://github.com/test-owner/test-repo.git|master');
|
|
82
|
-
console.log(' ✅ Git config with defaultBranch parsed correctly');
|
|
83
|
-
// 7. Test Default Branch Extraction (repository schema)
|
|
84
|
-
const repoConfig = {
|
|
85
|
-
repository: {
|
|
86
|
-
owner: 'test-owner',
|
|
87
|
-
name: 'test-repo',
|
|
88
|
-
url: 'https://github.com/test-owner/test-repo.git',
|
|
89
|
-
defaultBranch: 'main'
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
const repoOutput = runParsingLogic(nodeScript, repoConfig);
|
|
93
|
-
assert_1.default.strictEqual(repoOutput, 'test-owner|test-repo|https://github.com/test-owner/test-repo.git|main');
|
|
94
|
-
console.log(' ✅ Repository config with defaultBranch parsed correctly');
|
|
95
|
-
// 8. Test Default Branch Fallback
|
|
96
|
-
const noDefaultConfig = {
|
|
97
|
-
git: {
|
|
98
|
-
repoOwner: 'test-owner',
|
|
99
|
-
repoName: 'test-repo'
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
const fallbackOutput = runParsingLogic(nodeScript, noDefaultConfig);
|
|
103
|
-
assert_1.default.strictEqual(fallbackOutput, 'test-owner|test-repo|https://github.com/test-owner/test-repo.git|master');
|
|
104
|
-
console.log(' ✅ Default branch fallback to master works correctly');
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
console.error(' ❌ Test failed:', error);
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// Define test cases
|
|
113
|
-
const testCases = [
|
|
114
|
-
{
|
|
115
|
-
name: 'Prep Issue Config Parsing',
|
|
116
|
-
description: 'Verifies correct parsing of repo config from .fraim/config.json',
|
|
117
|
-
testFn: verifyPrepIssueConfigParsing,
|
|
118
|
-
tags: ['unit', 'scripts']
|
|
119
|
-
}
|
|
120
|
-
];
|
|
121
|
-
// Run strict check if executed directly
|
|
122
|
-
if (require.main === module) {
|
|
123
|
-
(0, test_utils_1.runTests)(testCases, async (testCase) => {
|
|
124
|
-
if (testCase.testFn) {
|
|
125
|
-
return await testCase.testFn();
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
}, 'Prep Issue Script Tests');
|
|
129
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Test suite for productivity report integration
|
|
4
|
-
* Tests the workflow and associated scripts integration
|
|
5
|
-
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const node_test_1 = require("node:test");
|
|
11
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
12
|
-
const fs_1 = __importDefault(require("fs"));
|
|
13
|
-
const path_1 = __importDefault(require("path"));
|
|
14
|
-
// Test configuration
|
|
15
|
-
const WORKFLOW_PATH = 'registry/workflows/productivity-report/productivity-report.md';
|
|
16
|
-
const SCRIPTS_DIR = 'registry/scripts/productivity';
|
|
17
|
-
const EXPECTED_SCRIPTS = [
|
|
18
|
-
'productivity-report.sh',
|
|
19
|
-
'build-productivity-csv.mjs',
|
|
20
|
-
'fetch-pr-details.mjs'
|
|
21
|
-
];
|
|
22
|
-
(0, node_test_1.test)('Productivity Report Workflow Integration', async (t) => {
|
|
23
|
-
await t.test('workflow file exists and is accessible', () => {
|
|
24
|
-
node_assert_1.default.ok(fs_1.default.existsSync(WORKFLOW_PATH), `Workflow file should exist at ${WORKFLOW_PATH}`);
|
|
25
|
-
const content = fs_1.default.readFileSync(WORKFLOW_PATH, 'utf-8');
|
|
26
|
-
node_assert_1.default.ok(content.length > 0, 'Workflow file should not be empty');
|
|
27
|
-
node_assert_1.default.ok(content.includes('# Productivity Report Workflow'), 'Should contain proper workflow header');
|
|
28
|
-
node_assert_1.default.ok(content.includes('**Category:** Performance Analysis'), 'Should be categorized as Performance Analysis');
|
|
29
|
-
});
|
|
30
|
-
await t.test('workflow content is generalized', () => {
|
|
31
|
-
const content = fs_1.default.readFileSync(WORKFLOW_PATH, 'utf-8');
|
|
32
|
-
// Should not contain Ashley-Calendar-AI specific references
|
|
33
|
-
node_assert_1.default.ok(!content.includes('mathursrus/Ashley-Calendar-AI'), 'Should not contain hardcoded Ashley-Calendar-AI repository reference');
|
|
34
|
-
// Should contain generalized instructions
|
|
35
|
-
node_assert_1.default.ok(content.includes('any GitHub repository'), 'Should mention compatibility with any GitHub repository');
|
|
36
|
-
node_assert_1.default.ok(content.includes('automatically detects'), 'Should mention auto-detection capability');
|
|
37
|
-
node_assert_1.default.ok(content.includes('scripts/productivity/'), 'Should reference correct FRAIM script location');
|
|
38
|
-
});
|
|
39
|
-
await t.test('scripts directory exists with correct structure', () => {
|
|
40
|
-
node_assert_1.default.ok(fs_1.default.existsSync(SCRIPTS_DIR), `Scripts directory should exist at ${SCRIPTS_DIR}`);
|
|
41
|
-
const dirStats = fs_1.default.statSync(SCRIPTS_DIR);
|
|
42
|
-
node_assert_1.default.ok(dirStats.isDirectory(), 'Should be a directory');
|
|
43
|
-
});
|
|
44
|
-
await t.test('all expected scripts are present', () => {
|
|
45
|
-
for (const scriptName of EXPECTED_SCRIPTS) {
|
|
46
|
-
const scriptPath = path_1.default.join(SCRIPTS_DIR, scriptName);
|
|
47
|
-
node_assert_1.default.ok(fs_1.default.existsSync(scriptPath), `Script ${scriptName} should exist at ${scriptPath}`);
|
|
48
|
-
const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
|
|
49
|
-
node_assert_1.default.ok(content.length > 0, `Script ${scriptName} should not be empty`);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
await t.test('main script is generalized and repository-agnostic', () => {
|
|
53
|
-
const scriptPath = path_1.default.join(SCRIPTS_DIR, 'productivity-report.sh');
|
|
54
|
-
const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
|
|
55
|
-
// Should not contain hardcoded repository
|
|
56
|
-
node_assert_1.default.ok(!content.includes('mathursrus/Ashley-Calendar-AI'), 'Main script should not contain hardcoded repository reference');
|
|
57
|
-
// Should contain repository detection logic
|
|
58
|
-
node_assert_1.default.ok(content.includes('detect_repository()'), 'Should contain repository detection function');
|
|
59
|
-
node_assert_1.default.ok(content.includes('git remote get-url origin'), 'Should use git remote for auto-detection');
|
|
60
|
-
// Should handle environment variables
|
|
61
|
-
node_assert_1.default.ok(content.includes('REPO_FULL'), 'Should support REPO_FULL environment variable');
|
|
62
|
-
node_assert_1.default.ok(content.includes('REPO_OWNER') && content.includes('REPO_NAME'), 'Should support REPO_OWNER/REPO_NAME environment variables');
|
|
63
|
-
// Should have proper error handling
|
|
64
|
-
node_assert_1.default.ok(content.includes('validate_repo_format'), 'Should validate repository format');
|
|
65
|
-
node_assert_1.default.ok(content.includes('gh auth status'), 'Should check GitHub CLI authentication');
|
|
66
|
-
});
|
|
67
|
-
await t.test('fetch-pr-details script is generalized', () => {
|
|
68
|
-
const scriptPath = path_1.default.join(SCRIPTS_DIR, 'fetch-pr-details.mjs');
|
|
69
|
-
const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
|
|
70
|
-
// Should not contain hardcoded repository
|
|
71
|
-
node_assert_1.default.ok(!content.includes('mathursrus/Ashley-Calendar-AI'), 'PR details script should not contain hardcoded repository');
|
|
72
|
-
// Should contain repository detection
|
|
73
|
-
node_assert_1.default.ok(content.includes('detectRepository()'), 'Should contain repository detection function');
|
|
74
|
-
node_assert_1.default.ok(content.includes('process.env.REPO_FULL'), 'Should check REPO_FULL environment variable');
|
|
75
|
-
// Should have proper error handling
|
|
76
|
-
node_assert_1.default.ok(content.includes('Invalid repository format'), 'Should validate repository format');
|
|
77
|
-
node_assert_1.default.ok(content.includes('timeout:'), 'Should have timeout handling for API calls');
|
|
78
|
-
});
|
|
79
|
-
await t.test('build-csv script is generalized', () => {
|
|
80
|
-
const scriptPath = path_1.default.join(SCRIPTS_DIR, 'build-productivity-csv.mjs');
|
|
81
|
-
const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
|
|
82
|
-
// Should be repository-agnostic (no hardcoded repos)
|
|
83
|
-
node_assert_1.default.ok(!content.includes('mathursrus/Ashley-Calendar-AI'), 'CSV builder should not contain hardcoded repository');
|
|
84
|
-
// Should have proper error handling
|
|
85
|
-
node_assert_1.default.ok(content.includes('Data directory not found'), 'Should handle missing data directory');
|
|
86
|
-
node_assert_1.default.ok(content.includes('Warning:'), 'Should have warning messages for data issues');
|
|
87
|
-
// Should handle file locking
|
|
88
|
-
node_assert_1.default.ok(content.includes('productivity-report-new.csv'), 'Should handle locked files with alternative naming');
|
|
89
|
-
});
|
|
90
|
-
await t.test('scripts have proper Node.js shebang and are executable', () => {
|
|
91
|
-
const nodeScripts = ['build-productivity-csv.mjs', 'fetch-pr-details.mjs'];
|
|
92
|
-
for (const scriptName of nodeScripts) {
|
|
93
|
-
const scriptPath = path_1.default.join(SCRIPTS_DIR, scriptName);
|
|
94
|
-
const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
|
|
95
|
-
node_assert_1.default.ok(content.startsWith('#!/usr/bin/env node'), `${scriptName} should have proper Node.js shebang`);
|
|
96
|
-
}
|
|
97
|
-
// Check bash script shebang
|
|
98
|
-
const bashScriptPath = path_1.default.join(SCRIPTS_DIR, 'productivity-report.sh');
|
|
99
|
-
const bashContent = fs_1.default.readFileSync(bashScriptPath, 'utf-8');
|
|
100
|
-
node_assert_1.default.ok(bashContent.startsWith('#!/bin/bash'), 'Bash script should have proper bash shebang');
|
|
101
|
-
});
|
|
102
|
-
await t.test('workflow references correct script locations', () => {
|
|
103
|
-
const content = fs_1.default.readFileSync(WORKFLOW_PATH, 'utf-8');
|
|
104
|
-
// Should reference FRAIM registry location
|
|
105
|
-
node_assert_1.default.ok(content.includes('~/.fraim/scripts/productivity/'), 'Should reference correct FRAIM script registry location');
|
|
106
|
-
// Should mention all three scripts
|
|
107
|
-
for (const scriptName of EXPECTED_SCRIPTS) {
|
|
108
|
-
node_assert_1.default.ok(content.includes(scriptName), `Should mention script ${scriptName}`);
|
|
109
|
-
}
|
|
110
|
-
// Should have proper usage instructions
|
|
111
|
-
node_assert_1.default.ok(content.includes('bash ~/.fraim/scripts/productivity/productivity-report.sh'), 'Should provide correct usage command');
|
|
112
|
-
});
|
|
113
|
-
await t.test('integration maintains FRAIM patterns', () => {
|
|
114
|
-
// Check that existing FRAIM structure is preserved
|
|
115
|
-
node_assert_1.default.ok(fs_1.default.existsSync('registry/scripts'), 'Existing scripts directory should be preserved');
|
|
116
|
-
node_assert_1.default.ok(fs_1.default.existsSync('registry/workflows'), 'Existing workflows directory should be preserved');
|
|
117
|
-
node_assert_1.default.ok(fs_1.default.existsSync('registry/workflows/productivity-report'), 'Productivity report workflows directory should exist');
|
|
118
|
-
// Check that new structure follows FRAIM patterns
|
|
119
|
-
const workflowContent = fs_1.default.readFileSync(WORKFLOW_PATH, 'utf-8');
|
|
120
|
-
node_assert_1.default.ok(workflowContent.includes('**Category:**'), 'Should follow FRAIM workflow format with category');
|
|
121
|
-
node_assert_1.default.ok(workflowContent.includes('## OVERVIEW'), 'Should follow FRAIM workflow format with OVERVIEW section');
|
|
122
|
-
node_assert_1.default.ok(workflowContent.includes('## WHEN TO USE'), 'Should follow FRAIM workflow format with WHEN TO USE section');
|
|
123
|
-
});
|
|
124
|
-
await t.test('scripts contain proper documentation and help', () => {
|
|
125
|
-
const mainScriptPath = path_1.default.join(SCRIPTS_DIR, 'productivity-report.sh');
|
|
126
|
-
const content = fs_1.default.readFileSync(mainScriptPath, 'utf-8');
|
|
127
|
-
// Should have usage information
|
|
128
|
-
node_assert_1.default.ok(content.includes('Usage:'), 'Main script should contain usage information');
|
|
129
|
-
node_assert_1.default.ok(content.includes('export REPO_FULL'), 'Should document environment variable usage');
|
|
130
|
-
// Should have dependency information
|
|
131
|
-
node_assert_1.default.ok(content.includes('gh CLI'), 'Should mention GitHub CLI dependency');
|
|
132
|
-
node_assert_1.default.ok(content.includes('node'), 'Should mention Node.js dependency');
|
|
133
|
-
node_assert_1.default.ok(content.includes('jq'), 'Should mention jq dependency');
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
// Integration test with MCP server (if available)
|
|
137
|
-
(0, node_test_1.test)('MCP Server Integration', async (t) => {
|
|
138
|
-
await t.test('workflow is accessible via get_fraim_workflow pattern', () => {
|
|
139
|
-
// This test verifies the file is in the correct location for MCP access
|
|
140
|
-
const expectedPath = 'registry/workflows/productivity-report/productivity-report.md';
|
|
141
|
-
node_assert_1.default.ok(fs_1.default.existsSync(expectedPath), 'Workflow should be accessible at expected MCP path');
|
|
142
|
-
// Verify it follows the expected workflow format
|
|
143
|
-
const content = fs_1.default.readFileSync(expectedPath, 'utf-8');
|
|
144
|
-
node_assert_1.default.ok(content.includes('# Productivity Report Workflow'), 'Should have proper workflow header for MCP access');
|
|
145
|
-
});
|
|
146
|
-
await t.test('scripts are in registry location for FRAIM access', () => {
|
|
147
|
-
// Verify scripts are in the correct registry location
|
|
148
|
-
const registryPath = 'registry/scripts/productivity';
|
|
149
|
-
node_assert_1.default.ok(fs_1.default.existsSync(registryPath), 'Scripts should be in FRAIM registry location');
|
|
150
|
-
// Verify all scripts are accessible
|
|
151
|
-
for (const scriptName of EXPECTED_SCRIPTS) {
|
|
152
|
-
const scriptPath = path_1.default.join(registryPath, scriptName);
|
|
153
|
-
node_assert_1.default.ok(fs_1.default.existsSync(scriptPath), `Script ${scriptName} should be accessible in registry`);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
console.log('✅ Productivity integration tests completed');
|
|
@@ -1,198 +0,0 @@
|
|
|
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
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
const test_utils_1 = require("./test-utils");
|
|
40
|
-
const fs_1 = __importDefault(require("fs"));
|
|
41
|
-
const path_1 = __importDefault(require("path"));
|
|
42
|
-
const os_1 = __importDefault(require("os"));
|
|
43
|
-
async function testScriptLocationIndependence() {
|
|
44
|
-
console.log(' 🚀 Testing Script Location Independence...');
|
|
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}`);
|
|
49
|
-
const userScriptsDir = path_1.default.join(userFraimDir, 'scripts');
|
|
50
|
-
console.log(` 📂 Created temp project dir: ${tempProjectDir}`);
|
|
51
|
-
console.log(` 🏠 Using test user dir: ${userFraimDir}`);
|
|
52
|
-
try {
|
|
53
|
-
// Clean up any existing test user directory (with timestamp, should be unique)
|
|
54
|
-
if (fs_1.default.existsSync(userFraimDir)) {
|
|
55
|
-
fs_1.default.rmSync(userFraimDir, { recursive: true, force: true });
|
|
56
|
-
}
|
|
57
|
-
// Create user scripts directory and copy actual registry scripts
|
|
58
|
-
fs_1.default.mkdirSync(userScriptsDir, { recursive: true });
|
|
59
|
-
// Copy a few key scripts to test
|
|
60
|
-
const scriptsToTest = [
|
|
61
|
-
'prep-issue.sh',
|
|
62
|
-
'code-quality-check.sh',
|
|
63
|
-
'detect-tautological-tests.sh'
|
|
64
|
-
];
|
|
65
|
-
for (const scriptName of scriptsToTest) {
|
|
66
|
-
const sourcePath = path_1.default.resolve(__dirname, '../registry/scripts', scriptName);
|
|
67
|
-
const targetPath = path_1.default.join(userScriptsDir, scriptName);
|
|
68
|
-
if (fs_1.default.existsSync(sourcePath)) {
|
|
69
|
-
fs_1.default.copyFileSync(sourcePath, targetPath);
|
|
70
|
-
// Make executable on Unix systems
|
|
71
|
-
if (process.platform !== 'win32') {
|
|
72
|
-
fs_1.default.chmodSync(targetPath, 0o755);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// Set up project directory with .fraim/config.json
|
|
77
|
-
const projectFraimDir = path_1.default.join(tempProjectDir, '.fraim');
|
|
78
|
-
fs_1.default.mkdirSync(projectFraimDir, { recursive: true });
|
|
79
|
-
const testConfig = {
|
|
80
|
-
project: { name: `location-test-${timestamp}` },
|
|
81
|
-
git: {
|
|
82
|
-
repoOwner: 'test',
|
|
83
|
-
repoName: `location-test-${timestamp}`,
|
|
84
|
-
url: `https://github.com/test/location-test-${timestamp}.git`
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
fs_1.default.writeFileSync(path_1.default.join(projectFraimDir, 'config.json'), JSON.stringify(testConfig, null, 2));
|
|
88
|
-
// Test 1: Try to execute prep-issue.sh from user directory
|
|
89
|
-
console.log(' Testing prep-issue.sh execution from user directory...');
|
|
90
|
-
const prepIssueScript = path_1.default.join(userScriptsDir, 'prep-issue.sh');
|
|
91
|
-
if (fs_1.default.existsSync(prepIssueScript)) {
|
|
92
|
-
try {
|
|
93
|
-
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
94
|
-
// On Windows, we need to check if Git Bash is available
|
|
95
|
-
if (process.platform === 'win32') {
|
|
96
|
-
const gitBashPaths = [
|
|
97
|
-
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
98
|
-
'C:\\Program Files (x86)\\Git\\bin\\bash.exe'
|
|
99
|
-
];
|
|
100
|
-
let bashPath = null;
|
|
101
|
-
for (const path of gitBashPaths) {
|
|
102
|
-
if (fs_1.default.existsSync(path)) {
|
|
103
|
-
bashPath = path;
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (!bashPath) {
|
|
108
|
-
console.log(' ⚠️ Git Bash not found on Windows, skipping bash script tests');
|
|
109
|
-
console.log(' ✅ Script location independence test completed (Windows limitation)');
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
const bashCommand = `"${bashPath}" "${prepIssueScript}" --help`;
|
|
113
|
-
const output = execSync(bashCommand, {
|
|
114
|
-
cwd: tempProjectDir,
|
|
115
|
-
encoding: 'utf-8',
|
|
116
|
-
timeout: 15000 // Increased timeout for concurrent runs
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
// Unix systems
|
|
121
|
-
const output = execSync(`"${prepIssueScript}" --help`, {
|
|
122
|
-
cwd: tempProjectDir,
|
|
123
|
-
encoding: 'utf-8',
|
|
124
|
-
timeout: 15000 // Increased timeout for concurrent runs
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
// If we get here, the script at least started successfully
|
|
128
|
-
console.log(' ✅ prep-issue.sh executed successfully from user directory');
|
|
129
|
-
}
|
|
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
|
-
}
|
|
136
|
-
// The script may fail due to missing repo, but as long as it started, that's OK
|
|
137
|
-
if (error.message.includes('Repository not found') ||
|
|
138
|
-
error.message.includes('fatal: repository') ||
|
|
139
|
-
error.message.includes('not a git repository')) {
|
|
140
|
-
// This is expected - the test repo doesn't exist, but the script ran
|
|
141
|
-
console.log(' ✅ prep-issue.sh executed from user directory (repo not found is expected)');
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
console.log(' ❌ prep-issue.sh failed:', error.message);
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
console.log(' ⚠️ prep-issue.sh not found, skipping test');
|
|
151
|
-
}
|
|
152
|
-
// Skip the second test to reduce interference - the first test is sufficient
|
|
153
|
-
console.log(' ✅ Script location independence test completed');
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
catch (error) {
|
|
157
|
-
console.error(' ❌ Script location independence test failed:', error);
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
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
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
await cleanup();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
async function runScriptLocationTest(testCase) {
|
|
188
|
-
return await testCase.testFunction();
|
|
189
|
-
}
|
|
190
|
-
const testCases = [
|
|
191
|
-
{
|
|
192
|
-
name: 'Script Location Independence',
|
|
193
|
-
description: 'Tests that actual registry scripts work when executed from ~/.fraim/scripts/',
|
|
194
|
-
testFunction: testScriptLocationIndependence,
|
|
195
|
-
tags: ['script-location', 'validation']
|
|
196
|
-
}
|
|
197
|
-
];
|
|
198
|
-
(0, test_utils_1.runTests)(testCases, runScriptLocationTest, 'Script Location Independence Tests');
|