fraim 2.0.229 → 2.0.232
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.
|
@@ -12,6 +12,7 @@ exports.getScriptsChecks = getScriptsChecks;
|
|
|
12
12
|
const fs_1 = __importDefault(require("fs"));
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
14
|
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
15
16
|
const SCRIPTS_DIR = path_1.default.join(os_1.default.homedir(), '.fraim', 'scripts');
|
|
16
17
|
/**
|
|
17
18
|
* Check if scripts directory exists
|
|
@@ -145,6 +146,71 @@ function checkScriptsExecutable() {
|
|
|
145
146
|
}
|
|
146
147
|
};
|
|
147
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Check Python availability, guarding against the Windows App Execution Alias.
|
|
151
|
+
* On Windows, bare `python`/`python3` are aliased to the Microsoft Store installer
|
|
152
|
+
* when Python is not installed. This check uses the `py` launcher (not aliased)
|
|
153
|
+
* as the primary probe, with a fallback path filter for non-standard installs.
|
|
154
|
+
*/
|
|
155
|
+
function checkPythonAvailability() {
|
|
156
|
+
return {
|
|
157
|
+
name: 'Python runtime available',
|
|
158
|
+
category: 'scripts',
|
|
159
|
+
critical: false,
|
|
160
|
+
run: async () => {
|
|
161
|
+
const hasPyScripts = fs_1.default.existsSync(SCRIPTS_DIR) &&
|
|
162
|
+
fs_1.default.readdirSync(SCRIPTS_DIR).some(f => f.endsWith('.py'));
|
|
163
|
+
if (!hasPyScripts) {
|
|
164
|
+
return {
|
|
165
|
+
status: 'passed',
|
|
166
|
+
message: 'No Python scripts synced — Python check skipped'
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (process.platform === 'win32') {
|
|
170
|
+
// Primary probe: py launcher (not subject to App Execution Alias)
|
|
171
|
+
const pyResult = (0, child_process_1.spawnSync)('py', ['--version'], { timeout: 1500, encoding: 'utf8' });
|
|
172
|
+
if (pyResult.status === 0) {
|
|
173
|
+
const version = (pyResult.stdout || pyResult.stderr || '').trim();
|
|
174
|
+
return {
|
|
175
|
+
status: 'passed',
|
|
176
|
+
message: `Python available via py launcher (${version})`
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// Fallback: check if python.exe resolves to a real install (not WindowsApps)
|
|
180
|
+
const whereResult = (0, child_process_1.spawnSync)('where', ['python'], { timeout: 1500, encoding: 'utf8' });
|
|
181
|
+
const paths = (whereResult.stdout || '').split('\n').map(p => p.trim()).filter(Boolean);
|
|
182
|
+
const realPython = paths.find(p => !p.toLowerCase().includes('windowsapps'));
|
|
183
|
+
if (realPython) {
|
|
184
|
+
return {
|
|
185
|
+
status: 'passed',
|
|
186
|
+
message: `Python available at ${realPython} (non-standard install without py launcher)`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
status: 'warning',
|
|
191
|
+
message: 'Python not available on Windows — Microsoft Store alias detected or Python not installed',
|
|
192
|
+
suggestion: 'Install Python from https://www.python.org/downloads/windows/ (the official installer registers the py launcher). Python scripts in ~/.fraim/scripts/ will not run until Python is installed.',
|
|
193
|
+
details: { platform: 'win32', pyLauncherFound: false }
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Mac / Linux: probe python3
|
|
197
|
+
const py3Result = (0, child_process_1.spawnSync)('python3', ['--version'], { timeout: 1500, encoding: 'utf8' });
|
|
198
|
+
if (py3Result.status === 0) {
|
|
199
|
+
const version = (py3Result.stdout || py3Result.stderr || '').trim();
|
|
200
|
+
return {
|
|
201
|
+
status: 'passed',
|
|
202
|
+
message: `Python available (${version})`
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
status: 'warning',
|
|
207
|
+
message: 'python3 not found',
|
|
208
|
+
suggestion: 'Install Python 3 to enable FRAIM script accelerators. On macOS: brew install python3. On Linux: sudo apt install python3.',
|
|
209
|
+
details: { platform: process.platform }
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
148
214
|
/**
|
|
149
215
|
* Get all scripts checks
|
|
150
216
|
*/
|
|
@@ -152,6 +218,7 @@ function getScriptsChecks() {
|
|
|
152
218
|
return [
|
|
153
219
|
checkScriptsDirectoryExists(),
|
|
154
220
|
checkScriptsSynced(),
|
|
155
|
-
checkScriptsExecutable()
|
|
221
|
+
checkScriptsExecutable(),
|
|
222
|
+
checkPythonAvailability()
|
|
156
223
|
];
|
|
157
224
|
}
|
|
@@ -76,6 +76,8 @@ const guiAppDetect = (configSurfaceCheck, appName, options = {}) => {
|
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
78
|
const availableByVersionProbe = (command) => {
|
|
79
|
+
if (process.env.FRAIM_DETECT_DISABLE_CLI_PROBES === '1')
|
|
80
|
+
return false;
|
|
79
81
|
const result = process.platform === 'win32'
|
|
80
82
|
? (0, child_process_1.spawnSync)('cmd.exe', ['/d', '/s', '/c', `${command} --version`], { encoding: 'utf8', timeout: 1500 })
|
|
81
83
|
: (0, child_process_1.spawnSync)(command, ['--version'], { encoding: 'utf8', timeout: 1500 });
|
|
@@ -58,6 +58,15 @@ exports.FIRST_RUN_AGENT_OPTIONS = [
|
|
|
58
58
|
launchCommand: 'copilot',
|
|
59
59
|
installPackage: '@github/copilot',
|
|
60
60
|
},
|
|
61
|
+
{
|
|
62
|
+
id: 'antigravity-cli',
|
|
63
|
+
label: 'Antigravity CLI',
|
|
64
|
+
detectAliases: ['agy', 'antigravity', 'antigravity-cli'],
|
|
65
|
+
loginCommand: 'agy auth login',
|
|
66
|
+
launchCommand: 'agy',
|
|
67
|
+
// agy has no npm package — install via https://antigravity.google/cli/
|
|
68
|
+
installPackage: '',
|
|
69
|
+
},
|
|
61
70
|
];
|
|
62
71
|
/**
|
|
63
72
|
* The canonical row set, in display order. Each row starts in `pending`;
|
|
@@ -46,23 +46,6 @@ const project_fraim_paths_1 = require("../core/utils/project-fraim-paths");
|
|
|
46
46
|
const quality_evidence_1 = require("../core/quality-evidence");
|
|
47
47
|
const feature_flags_1 = require("../config/feature-flags");
|
|
48
48
|
const persona_entitlement_service_1 = require("./persona-entitlement-service");
|
|
49
|
-
const FRAIM_PROMPT_TEXT = `You are running in FRAIM mode. Follow this process:
|
|
50
|
-
|
|
51
|
-
0. **Preload deferred FRAIM tools when needed**: If FRAIM MCP tools are unavailable because this host lazily loads deferred tool schemas, call ToolSearch once to load fraim_connect, list_fraim_jobs, get_fraim_job, get_fraim_file, seekMentoring. Do the preload as one batched discovery step, not one search per tool.
|
|
52
|
-
|
|
53
|
-
1. **Confirm FRAIM activation**: Use FRAIM only when the user explicitly invokes FRAIM, names a FRAIM job, asks what FRAIM job to run, or the active surface has already selected a FRAIM job. For ordinary requests, answer or work normally; do not scan FRAIM stubs first.
|
|
54
|
-
|
|
55
|
-
2. **If the user did not specify a FRAIM job or topic after activation**: If local FRAIM job stubs are present in the workspace, inspect those first and match the request locally. Also inspect fraim/personalized-employee/jobs/ for local overrides or repo-specific jobs. If local files are missing, you cannot inspect workspace files, the user asks for available jobs, or recommendations require full catalog context, call list_fraim_jobs() to view the catalog.
|
|
56
|
-
|
|
57
|
-
3. **Find the match**: If the user names an exact FRAIM job, call get_fraim_job({ job: "<job-name>" }) directly. Otherwise, match the user's request to a FRAIM job from the local stub catalog, fraim/personalized-employee/jobs/, or the full list_fraim_jobs() response. If no exact or high-confidence job match exists, say that no FRAIM job matches and continue with normal tools or ask one concise clarification. Do not pick the nearest catalog job.
|
|
58
|
-
|
|
59
|
-
4. **Load the full content**:
|
|
60
|
-
- For jobs, call get_fraim_job({ job: "<matched-job-name>" }).
|
|
61
|
-
- For skills, use the content returned by get_fraim_file(...).
|
|
62
|
-
|
|
63
|
-
5. **Execute**:
|
|
64
|
-
- For jobs, follow the phased instructions and use seekMentoring when the job requires phase transitions.
|
|
65
|
-
- For skills, apply the skill steps directly to the user's current context.`;
|
|
66
49
|
exports.DEFAULT_LAUNCH_PHRASE_MAPPINGS = {
|
|
67
50
|
'Onboard this project': 'get_fraim_job({ job: "project-onboarding" })',
|
|
68
51
|
'sleep on learnings': 'get_fraim_job({ job: "sleep-on-learnings" })',
|
|
@@ -184,43 +167,17 @@ class McpService {
|
|
|
184
167
|
return { resources: [] };
|
|
185
168
|
}
|
|
186
169
|
handleListPrompts() {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
description: 'Activate a FRAIM job or skill. Use this prompt only for explicit FRAIM work, job recommendations, or known FRAIM job execution.',
|
|
192
|
-
arguments: [
|
|
193
|
-
{
|
|
194
|
-
name: 'task',
|
|
195
|
-
description: 'Job, skill, or task to run (e.g. "feature-specification", "sleep on learnings"). Omit to let FRAIM match from context.',
|
|
196
|
-
required: false
|
|
197
|
-
}
|
|
198
|
-
]
|
|
199
|
-
}
|
|
200
|
-
]
|
|
201
|
-
};
|
|
170
|
+
// Issue #928: fraim prompt removed — the CLAUDE.md job-routing instructions
|
|
171
|
+
// in the repo's workspace already wire FRAIM correctly. A separate MCP prompt
|
|
172
|
+
// creates duplicate activation paths that confuse agents on non-FRAIM repos.
|
|
173
|
+
return { prompts: [] };
|
|
202
174
|
}
|
|
203
175
|
handleGetPrompt(params) {
|
|
204
|
-
const { name
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
const task = promptArgs?.task ? String(promptArgs.task) : '';
|
|
211
|
-
const taskSuffix = task ? `\n\nTask: ${task}` : '';
|
|
212
|
-
return {
|
|
213
|
-
description: 'Activate a FRAIM job or skill',
|
|
214
|
-
messages: [
|
|
215
|
-
{
|
|
216
|
-
role: 'user',
|
|
217
|
-
content: {
|
|
218
|
-
type: 'text',
|
|
219
|
-
text: FRAIM_PROMPT_TEXT + taskSuffix
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
]
|
|
223
|
-
};
|
|
176
|
+
const { name } = params ?? {};
|
|
177
|
+
// Issue #928: fraim prompt removed; all names now return not-found.
|
|
178
|
+
const err = new Error(`Prompt not found: ${name}`);
|
|
179
|
+
err.code = -32602;
|
|
180
|
+
throw err;
|
|
224
181
|
}
|
|
225
182
|
async handleToolCall(params, context) {
|
|
226
183
|
let result = await this.handleToolCallInternal(params, context);
|