fraim 2.0.100
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/README.md +445 -0
- package/bin/fraim.js +23 -0
- package/dist/src/cli/api/get-provider-client.js +41 -0
- package/dist/src/cli/api/provider-client.js +107 -0
- package/dist/src/cli/commands/add-ide.js +430 -0
- package/dist/src/cli/commands/add-provider.js +233 -0
- package/dist/src/cli/commands/doctor.js +149 -0
- package/dist/src/cli/commands/init-project.js +301 -0
- package/dist/src/cli/commands/list-overridable.js +184 -0
- package/dist/src/cli/commands/list.js +57 -0
- package/dist/src/cli/commands/login.js +84 -0
- package/dist/src/cli/commands/mcp.js +15 -0
- package/dist/src/cli/commands/migrate-project-fraim.js +42 -0
- package/dist/src/cli/commands/override.js +177 -0
- package/dist/src/cli/commands/setup.js +651 -0
- package/dist/src/cli/commands/sync.js +162 -0
- package/dist/src/cli/commands/test-mcp.js +171 -0
- package/dist/src/cli/doctor/check-runner.js +199 -0
- package/dist/src/cli/doctor/checks/global-setup-checks.js +220 -0
- package/dist/src/cli/doctor/checks/ide-config-checks.js +250 -0
- package/dist/src/cli/doctor/checks/mcp-connectivity-checks.js +381 -0
- package/dist/src/cli/doctor/checks/project-setup-checks.js +282 -0
- package/dist/src/cli/doctor/checks/scripts-checks.js +157 -0
- package/dist/src/cli/doctor/checks/workflow-checks.js +251 -0
- package/dist/src/cli/doctor/reporters/console-reporter.js +96 -0
- package/dist/src/cli/doctor/reporters/json-reporter.js +11 -0
- package/dist/src/cli/doctor/types.js +6 -0
- package/dist/src/cli/fraim.js +100 -0
- package/dist/src/cli/internal/device-flow-service.js +83 -0
- package/dist/src/cli/mcp/ide-formats.js +243 -0
- package/dist/src/cli/mcp/mcp-server-builder.js +48 -0
- package/dist/src/cli/mcp/mcp-server-registry.js +160 -0
- package/dist/src/cli/mcp/types.js +3 -0
- package/dist/src/cli/providers/local-provider-registry.js +166 -0
- package/dist/src/cli/providers/provider-registry.js +230 -0
- package/dist/src/cli/setup/auto-mcp-setup.js +331 -0
- package/dist/src/cli/setup/codex-local-config.js +37 -0
- package/dist/src/cli/setup/first-run.js +242 -0
- package/dist/src/cli/setup/ide-detector.js +179 -0
- package/dist/src/cli/setup/mcp-config-generator.js +192 -0
- package/dist/src/cli/setup/provider-prompts.js +339 -0
- package/dist/src/cli/utils/agent-adapters.js +126 -0
- package/dist/src/cli/utils/digest-utils.js +47 -0
- package/dist/src/cli/utils/fraim-gitignore.js +40 -0
- package/dist/src/cli/utils/platform-detection.js +258 -0
- package/dist/src/cli/utils/project-bootstrap.js +93 -0
- package/dist/src/cli/utils/remote-sync.js +315 -0
- package/dist/src/cli/utils/script-sync-utils.js +221 -0
- package/dist/src/cli/utils/version-utils.js +32 -0
- package/dist/src/core/ai-mentor.js +230 -0
- package/dist/src/core/config-loader.js +114 -0
- package/dist/src/core/config-writer.js +75 -0
- package/dist/src/core/types.js +23 -0
- package/dist/src/core/utils/git-utils.js +95 -0
- package/dist/src/core/utils/include-resolver.js +92 -0
- package/dist/src/core/utils/inheritance-parser.js +288 -0
- package/dist/src/core/utils/job-parser.js +176 -0
- package/dist/src/core/utils/local-registry-resolver.js +616 -0
- package/dist/src/core/utils/object-utils.js +11 -0
- package/dist/src/core/utils/project-fraim-migration.js +103 -0
- package/dist/src/core/utils/project-fraim-paths.js +38 -0
- package/dist/src/core/utils/provider-utils.js +18 -0
- package/dist/src/core/utils/server-startup.js +34 -0
- package/dist/src/core/utils/stub-generator.js +147 -0
- package/dist/src/core/utils/workflow-parser.js +174 -0
- package/dist/src/local-mcp-server/learning-context-builder.js +229 -0
- package/dist/src/local-mcp-server/stdio-server.js +1698 -0
- package/dist/src/local-mcp-server/usage-collector.js +264 -0
- package/index.js +85 -0
- package/package.json +139 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Scripts checks for FRAIM doctor command
|
|
4
|
+
* Validates user scripts directory and sync status
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getScriptsChecks = getScriptsChecks;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const SCRIPTS_DIR = path_1.default.join(os_1.default.homedir(), '.fraim', 'scripts');
|
|
16
|
+
/**
|
|
17
|
+
* Check if scripts directory exists
|
|
18
|
+
*/
|
|
19
|
+
function checkScriptsDirectoryExists() {
|
|
20
|
+
return {
|
|
21
|
+
name: 'Scripts directory exists',
|
|
22
|
+
category: 'scripts',
|
|
23
|
+
critical: false,
|
|
24
|
+
run: async () => {
|
|
25
|
+
if (fs_1.default.existsSync(SCRIPTS_DIR)) {
|
|
26
|
+
return {
|
|
27
|
+
status: 'passed',
|
|
28
|
+
message: 'Scripts directory exists',
|
|
29
|
+
details: { path: SCRIPTS_DIR }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
status: 'warning',
|
|
34
|
+
message: 'Scripts directory missing',
|
|
35
|
+
suggestion: 'Run fraim sync to hydrate local scripts for the repo.',
|
|
36
|
+
command: 'fraim sync'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if scripts are synced
|
|
43
|
+
*/
|
|
44
|
+
function checkScriptsSynced() {
|
|
45
|
+
return {
|
|
46
|
+
name: 'Scripts synced',
|
|
47
|
+
category: 'scripts',
|
|
48
|
+
critical: false,
|
|
49
|
+
run: async () => {
|
|
50
|
+
if (!fs_1.default.existsSync(SCRIPTS_DIR)) {
|
|
51
|
+
return {
|
|
52
|
+
status: 'warning',
|
|
53
|
+
message: 'Cannot check scripts - directory missing'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const scripts = fs_1.default.readdirSync(SCRIPTS_DIR).filter(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.sh'));
|
|
58
|
+
if (scripts.length > 0) {
|
|
59
|
+
return {
|
|
60
|
+
status: 'passed',
|
|
61
|
+
message: `${scripts.length} scripts synced`,
|
|
62
|
+
details: { scriptCount: scripts.length }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
status: 'warning',
|
|
67
|
+
message: 'No scripts found',
|
|
68
|
+
suggestion: 'Run fraim sync to hydrate local scripts.',
|
|
69
|
+
command: 'fraim sync'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
status: 'error',
|
|
75
|
+
message: 'Failed to check scripts',
|
|
76
|
+
details: { error: error.message }
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if scripts are executable (Unix/Linux/macOS only)
|
|
84
|
+
*/
|
|
85
|
+
function checkScriptsExecutable() {
|
|
86
|
+
return {
|
|
87
|
+
name: 'Scripts executable',
|
|
88
|
+
category: 'scripts',
|
|
89
|
+
critical: false,
|
|
90
|
+
run: async () => {
|
|
91
|
+
// Skip on Windows
|
|
92
|
+
if (process.platform === 'win32') {
|
|
93
|
+
return {
|
|
94
|
+
status: 'passed',
|
|
95
|
+
message: 'Script permissions check skipped (Windows)',
|
|
96
|
+
details: { platform: 'win32', reason: 'Windows does not use Unix-style executable permissions' }
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (!fs_1.default.existsSync(SCRIPTS_DIR)) {
|
|
100
|
+
return {
|
|
101
|
+
status: 'warning',
|
|
102
|
+
message: 'Cannot check permissions - directory missing'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const scripts = fs_1.default.readdirSync(SCRIPTS_DIR).filter(f => f.endsWith('.sh'));
|
|
107
|
+
if (scripts.length === 0) {
|
|
108
|
+
return {
|
|
109
|
+
status: 'passed',
|
|
110
|
+
message: 'No shell scripts to check',
|
|
111
|
+
details: { scriptCount: 0 }
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
let nonExecutable = 0;
|
|
115
|
+
for (const script of scripts) {
|
|
116
|
+
const scriptPath = path_1.default.join(SCRIPTS_DIR, script);
|
|
117
|
+
const stats = fs_1.default.statSync(scriptPath);
|
|
118
|
+
// Check if executable bit is set (mode & 0o111)
|
|
119
|
+
if ((stats.mode & 0o111) === 0) {
|
|
120
|
+
nonExecutable++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (nonExecutable === 0) {
|
|
124
|
+
return {
|
|
125
|
+
status: 'passed',
|
|
126
|
+
message: `All ${scripts.length} shell scripts executable`,
|
|
127
|
+
details: { scriptCount: scripts.length }
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
status: 'warning',
|
|
132
|
+
message: `${nonExecutable} scripts not executable`,
|
|
133
|
+
suggestion: `Run: chmod +x ${SCRIPTS_DIR}/*.sh`,
|
|
134
|
+
command: `chmod +x ${SCRIPTS_DIR}/*.sh`,
|
|
135
|
+
details: { nonExecutable, total: scripts.length }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
status: 'error',
|
|
141
|
+
message: 'Failed to check script permissions',
|
|
142
|
+
details: { error: error.message }
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get all scripts checks
|
|
150
|
+
*/
|
|
151
|
+
function getScriptsChecks() {
|
|
152
|
+
return [
|
|
153
|
+
checkScriptsDirectoryExists(),
|
|
154
|
+
checkScriptsSynced(),
|
|
155
|
+
checkScriptsExecutable()
|
|
156
|
+
];
|
|
157
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Job checks for FRAIM doctor command
|
|
4
|
+
* Validates job installation and versions
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getJobChecks = getJobChecks;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const inheritance_parser_1 = require("../../../core/utils/inheritance-parser");
|
|
15
|
+
const project_fraim_paths_1 = require("../../../core/utils/project-fraim-paths");
|
|
16
|
+
function getJobStubDirs() {
|
|
17
|
+
return [
|
|
18
|
+
(0, project_fraim_paths_1.getWorkspaceFraimPath)(process.cwd(), 'ai-employee', 'jobs'),
|
|
19
|
+
(0, project_fraim_paths_1.getWorkspaceFraimPath)(process.cwd(), 'ai-manager', 'jobs')
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if jobs directory exists
|
|
24
|
+
*/
|
|
25
|
+
function checkJobsDirectoryExists() {
|
|
26
|
+
return {
|
|
27
|
+
name: 'Jobs directory exists',
|
|
28
|
+
category: 'jobs',
|
|
29
|
+
critical: true,
|
|
30
|
+
run: async () => {
|
|
31
|
+
const jobDirs = getJobStubDirs();
|
|
32
|
+
const existingJobDirs = jobDirs.filter(fs_1.default.existsSync);
|
|
33
|
+
if ((0, project_fraim_paths_1.workspaceFraimExists)(process.cwd()) && existingJobDirs.length > 0) {
|
|
34
|
+
return {
|
|
35
|
+
status: 'passed',
|
|
36
|
+
message: 'Jobs directory exists',
|
|
37
|
+
details: { paths: existingJobDirs }
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
status: 'error',
|
|
42
|
+
message: 'Jobs directory missing',
|
|
43
|
+
suggestion: 'Run fraim sync to hydrate local job stubs. Onboarding can still start through MCP if your agent is already connected.',
|
|
44
|
+
command: 'fraim sync'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if job stubs are present
|
|
51
|
+
*/
|
|
52
|
+
function checkJobStubsPresent() {
|
|
53
|
+
return {
|
|
54
|
+
name: 'Job stubs present',
|
|
55
|
+
category: 'jobs',
|
|
56
|
+
critical: false,
|
|
57
|
+
run: async () => {
|
|
58
|
+
const jobDirs = getJobStubDirs().filter(fs_1.default.existsSync);
|
|
59
|
+
if (jobDirs.length === 0) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'error',
|
|
62
|
+
message: 'Cannot check stubs - jobs directory missing'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
let stubCount = 0;
|
|
67
|
+
const countStubs = (dir) => {
|
|
68
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
countStubs(path_1.default.join(dir, entry.name));
|
|
72
|
+
}
|
|
73
|
+
else if (entry.name.endsWith('.md')) {
|
|
74
|
+
stubCount++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
jobDirs.forEach(countStubs);
|
|
79
|
+
if (stubCount > 0) {
|
|
80
|
+
return {
|
|
81
|
+
status: 'passed',
|
|
82
|
+
message: `${stubCount} job stubs found`,
|
|
83
|
+
details: { stubCount }
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
status: 'warning',
|
|
88
|
+
message: 'No job stubs found',
|
|
89
|
+
suggestion: 'Run fraim sync to hydrate local job stubs. This does not block agent-led onboarding if MCP access is healthy.',
|
|
90
|
+
command: 'fraim sync'
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
status: 'error',
|
|
96
|
+
message: 'Failed to count job stubs',
|
|
97
|
+
details: { error: error.message }
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check if jobs are up to date
|
|
105
|
+
*/
|
|
106
|
+
function checkJobsUpToDate() {
|
|
107
|
+
return {
|
|
108
|
+
name: 'Jobs up to date',
|
|
109
|
+
category: 'jobs',
|
|
110
|
+
critical: false,
|
|
111
|
+
run: async () => {
|
|
112
|
+
const configPath = (0, project_fraim_paths_1.getWorkspaceConfigPath)(process.cwd());
|
|
113
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
114
|
+
return {
|
|
115
|
+
status: 'warning',
|
|
116
|
+
message: 'Cannot check job version - config missing'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const config = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
121
|
+
const possiblePaths = [
|
|
122
|
+
path_1.default.join(__dirname, '../../../../package.json'),
|
|
123
|
+
path_1.default.join(__dirname, '../../../package.json'),
|
|
124
|
+
path_1.default.join(process.cwd(), 'package.json')
|
|
125
|
+
];
|
|
126
|
+
let packageJson = null;
|
|
127
|
+
for (const pkgPath of possiblePaths) {
|
|
128
|
+
if (fs_1.default.existsSync(pkgPath)) {
|
|
129
|
+
packageJson = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!packageJson) {
|
|
134
|
+
return {
|
|
135
|
+
status: 'warning',
|
|
136
|
+
message: 'Cannot determine package version'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const currentVersion = packageJson.version;
|
|
140
|
+
const configVersion = config.version;
|
|
141
|
+
if (configVersion === currentVersion) {
|
|
142
|
+
return {
|
|
143
|
+
status: 'passed',
|
|
144
|
+
message: `Jobs up to date (v${currentVersion})`,
|
|
145
|
+
details: { version: currentVersion }
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
status: 'warning',
|
|
150
|
+
message: `Jobs outdated (v${configVersion} -> v${currentVersion})`,
|
|
151
|
+
suggestion: 'Update local job stubs with fraim sync.',
|
|
152
|
+
command: 'fraim sync',
|
|
153
|
+
details: { configVersion, currentVersion }
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
status: 'error',
|
|
159
|
+
message: 'Failed to check job version',
|
|
160
|
+
details: { error: error.message }
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if override syntax is valid
|
|
168
|
+
*/
|
|
169
|
+
function checkOverrideSyntaxValid() {
|
|
170
|
+
return {
|
|
171
|
+
name: 'Override syntax valid',
|
|
172
|
+
category: 'jobs',
|
|
173
|
+
critical: false,
|
|
174
|
+
run: async () => {
|
|
175
|
+
const personalizedDir = (0, project_fraim_paths_1.getWorkspaceFraimPath)(process.cwd(), 'personalized-employee');
|
|
176
|
+
if (!fs_1.default.existsSync(personalizedDir)) {
|
|
177
|
+
return {
|
|
178
|
+
status: 'passed',
|
|
179
|
+
message: 'No overrides (not required)',
|
|
180
|
+
details: { overrideCount: 0 }
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const parser = new inheritance_parser_1.InheritanceParser();
|
|
185
|
+
const overrides = [];
|
|
186
|
+
let invalidCount = 0;
|
|
187
|
+
const errors = [];
|
|
188
|
+
const scanDir = (dir, base = '') => {
|
|
189
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
const relativePath = path_1.default.join(base, entry.name);
|
|
192
|
+
if (entry.isDirectory()) {
|
|
193
|
+
scanDir(path_1.default.join(dir, entry.name), relativePath);
|
|
194
|
+
}
|
|
195
|
+
else if (entry.name.endsWith('.md')) {
|
|
196
|
+
overrides.push(relativePath);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
scanDir(personalizedDir);
|
|
201
|
+
for (const override of overrides) {
|
|
202
|
+
const overridePath = path_1.default.join(personalizedDir, override);
|
|
203
|
+
const content = fs_1.default.readFileSync(overridePath, 'utf-8');
|
|
204
|
+
const parseResult = parser.parse(content);
|
|
205
|
+
if (parseResult.hasImports) {
|
|
206
|
+
for (const importPath of parseResult.imports) {
|
|
207
|
+
try {
|
|
208
|
+
parser.sanitizePath(importPath);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
invalidCount++;
|
|
212
|
+
errors.push(`${override}: ${error.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (invalidCount === 0) {
|
|
218
|
+
return {
|
|
219
|
+
status: 'passed',
|
|
220
|
+
message: `${overrides.length} overrides valid`,
|
|
221
|
+
details: { overrideCount: overrides.length }
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
status: 'error',
|
|
226
|
+
message: `${invalidCount} invalid overrides found`,
|
|
227
|
+
suggestion: 'Fix override import syntax',
|
|
228
|
+
details: { errors }
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
return {
|
|
233
|
+
status: 'error',
|
|
234
|
+
message: 'Failed to validate overrides',
|
|
235
|
+
details: { error: error.message }
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Get all job checks
|
|
243
|
+
*/
|
|
244
|
+
function getJobChecks() {
|
|
245
|
+
return [
|
|
246
|
+
checkJobsDirectoryExists(),
|
|
247
|
+
checkJobStubsPresent(),
|
|
248
|
+
checkJobsUpToDate(),
|
|
249
|
+
checkOverrideSyntaxValid()
|
|
250
|
+
];
|
|
251
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Console reporter for FRAIM doctor command
|
|
4
|
+
* Formats output with colors and emojis
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.formatConsoleOutput = formatConsoleOutput;
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const CATEGORY_NAMES = {
|
|
14
|
+
globalSetup: 'Global Setup',
|
|
15
|
+
projectSetup: 'Project Setup',
|
|
16
|
+
jobs: 'Jobs',
|
|
17
|
+
ideConfiguration: 'IDE Configuration',
|
|
18
|
+
mcpConnectivity: 'MCP Server Connectivity',
|
|
19
|
+
scripts: 'Scripts'
|
|
20
|
+
};
|
|
21
|
+
function getStatusIcon(status) {
|
|
22
|
+
switch (status) {
|
|
23
|
+
case 'passed': return '✅';
|
|
24
|
+
case 'warning': return '⚠️';
|
|
25
|
+
case 'error': return '❌';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function formatLatency(latency) {
|
|
29
|
+
if (!latency)
|
|
30
|
+
return '';
|
|
31
|
+
return chalk_1.default.gray(` (${latency}ms)`);
|
|
32
|
+
}
|
|
33
|
+
function formatConsoleOutput(result, options) {
|
|
34
|
+
const lines = [];
|
|
35
|
+
// Header
|
|
36
|
+
lines.push(chalk_1.default.blue('🩺 FRAIM Doctor - Comprehensive Health Check\n'));
|
|
37
|
+
// Categories
|
|
38
|
+
for (const [categoryKey, categoryResult] of Object.entries(result.categories)) {
|
|
39
|
+
// Skip empty categories
|
|
40
|
+
if (categoryResult.checks.length === 0)
|
|
41
|
+
continue;
|
|
42
|
+
const categoryName = CATEGORY_NAMES[categoryKey] || categoryKey;
|
|
43
|
+
lines.push(chalk_1.default.bold(`━━━ ${categoryName} ━━━`));
|
|
44
|
+
for (const check of categoryResult.checks) {
|
|
45
|
+
const icon = getStatusIcon(check.status);
|
|
46
|
+
const latency = formatLatency(check.latency);
|
|
47
|
+
lines.push(`${icon} ${check.message}${latency}`);
|
|
48
|
+
// Show details in verbose mode
|
|
49
|
+
if (options.verbose && check.details) {
|
|
50
|
+
for (const [key, value] of Object.entries(check.details)) {
|
|
51
|
+
lines.push(chalk_1.default.gray(` ${key}: ${value}`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Show suggestions for warnings and errors
|
|
55
|
+
if (check.suggestion) {
|
|
56
|
+
lines.push(chalk_1.default.blue(` 💡 ${check.suggestion}`));
|
|
57
|
+
if (check.command) {
|
|
58
|
+
lines.push(chalk_1.default.gray(` Run: ${check.command}`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
lines.push(''); // Empty line between categories
|
|
63
|
+
}
|
|
64
|
+
// Summary
|
|
65
|
+
lines.push(chalk_1.default.bold('━━━ Summary ━━━'));
|
|
66
|
+
lines.push(`${chalk_1.default.green('✅')} ${result.summary.passed} checks passed`);
|
|
67
|
+
if (result.summary.warnings > 0) {
|
|
68
|
+
lines.push(`${chalk_1.default.yellow('⚠️')} ${result.summary.warnings} warnings`);
|
|
69
|
+
}
|
|
70
|
+
if (result.summary.errors > 0) {
|
|
71
|
+
lines.push(`${chalk_1.default.red('❌')} ${result.summary.errors} errors`);
|
|
72
|
+
}
|
|
73
|
+
lines.push('');
|
|
74
|
+
// Final message
|
|
75
|
+
if (result.summary.errors === 0 && result.summary.warnings === 0) {
|
|
76
|
+
lines.push(chalk_1.default.green('✨ Everything looks great! Your FRAIM setup is healthy.'));
|
|
77
|
+
}
|
|
78
|
+
else if (result.summary.errors === 0) {
|
|
79
|
+
lines.push(chalk_1.default.yellow('⚠️ Some warnings found. See suggestions below.'));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
lines.push(chalk_1.default.red('❌ Issues found. See suggestions below.'));
|
|
83
|
+
}
|
|
84
|
+
// Suggestions
|
|
85
|
+
if (result.suggestions && result.suggestions.length > 0) {
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(chalk_1.default.blue('💡 Suggested fixes:'));
|
|
88
|
+
for (const suggestion of result.suggestions.slice(0, 5)) { // Show top 5
|
|
89
|
+
lines.push(chalk_1.default.blue(` ${suggestion.priority}. ${suggestion.message}`));
|
|
90
|
+
if (suggestion.command) {
|
|
91
|
+
lines.push(chalk_1.default.gray(` Run: ${suggestion.command}`));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return lines.join('\n');
|
|
96
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSON reporter for FRAIM doctor command
|
|
4
|
+
* Formats output as JSON for automation
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.formatJsonOutput = formatJsonOutput;
|
|
9
|
+
function formatJsonOutput(result) {
|
|
10
|
+
return JSON.stringify(result, null, 2);
|
|
11
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const commander_1 = require("commander");
|
|
41
|
+
const sync_1 = require("./commands/sync");
|
|
42
|
+
const doctor_1 = require("./commands/doctor");
|
|
43
|
+
const list_1 = require("./commands/list");
|
|
44
|
+
const setup_1 = require("./commands/setup");
|
|
45
|
+
const init_project_1 = require("./commands/init-project");
|
|
46
|
+
const add_ide_1 = require("./commands/add-ide");
|
|
47
|
+
const add_provider_1 = require("./commands/add-provider");
|
|
48
|
+
const override_1 = require("./commands/override");
|
|
49
|
+
const list_overridable_1 = require("./commands/list-overridable");
|
|
50
|
+
const login_1 = require("./commands/login");
|
|
51
|
+
const mcp_1 = require("./commands/mcp");
|
|
52
|
+
const migrate_project_fraim_1 = require("./commands/migrate-project-fraim");
|
|
53
|
+
const fs_1 = __importDefault(require("fs"));
|
|
54
|
+
const path_1 = __importDefault(require("path"));
|
|
55
|
+
const program = new commander_1.Command();
|
|
56
|
+
// Load version from package.json
|
|
57
|
+
// Handle both src/ (dev) and dist/ (prod) execution paths
|
|
58
|
+
let packageJson = { version: 'unknown' };
|
|
59
|
+
try {
|
|
60
|
+
// Robustly find package.json by searching upwards from this file's directory
|
|
61
|
+
let currentDir = __dirname;
|
|
62
|
+
let found = false;
|
|
63
|
+
for (let i = 0; i < 5; i++) { // Max search depth 5
|
|
64
|
+
const pkgPath = path_1.default.join(currentDir, 'package.json');
|
|
65
|
+
if (fs_1.default.existsSync(pkgPath)) {
|
|
66
|
+
packageJson = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
|
|
67
|
+
found = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
console.warn('⚠️ Could not fully resolve package.json version.');
|
|
75
|
+
}
|
|
76
|
+
program
|
|
77
|
+
.name('fraim')
|
|
78
|
+
.description('FRAIM Framework CLI - Manage your AI jobs and rules')
|
|
79
|
+
.version(packageJson.version);
|
|
80
|
+
program.addCommand(sync_1.syncCommand);
|
|
81
|
+
program.addCommand(doctor_1.doctorCommand);
|
|
82
|
+
program.addCommand(list_1.listCommand);
|
|
83
|
+
program.addCommand(setup_1.setupCommand);
|
|
84
|
+
program.addCommand(init_project_1.initProjectCommand);
|
|
85
|
+
program.addCommand(add_ide_1.addIDECommand);
|
|
86
|
+
program.addCommand(add_provider_1.addProviderCommand);
|
|
87
|
+
program.addCommand(override_1.overrideCommand);
|
|
88
|
+
program.addCommand(list_overridable_1.listOverridableCommand);
|
|
89
|
+
program.addCommand(login_1.loginCommand);
|
|
90
|
+
program.addCommand(mcp_1.mcpCommand);
|
|
91
|
+
program.addCommand(migrate_project_fraim_1.migrateProjectFraimCommand);
|
|
92
|
+
// Wait for async command initialization before parsing
|
|
93
|
+
(async () => {
|
|
94
|
+
// Import the initialization promise from setup command
|
|
95
|
+
const { setupCommandInitialization } = await Promise.resolve().then(() => __importStar(require('./commands/setup')));
|
|
96
|
+
if (setupCommandInitialization) {
|
|
97
|
+
await setupCommandInitialization;
|
|
98
|
+
}
|
|
99
|
+
program.parse(process.argv);
|
|
100
|
+
})();
|