fix(opencode): explain managed profile link failures
Co-authored-by: iliya <iliyazelenkog@gmail.com>
This commit is contained in:
parent
7e5fa14b75
commit
bf41db266d
2 changed files with 83 additions and 4 deletions
|
|
@ -151,13 +151,17 @@ function sanitizeRuntimeProviderError(error: unknown): RuntimeProviderManagement
|
|||
? (rawCode as RuntimeProviderManagementErrorDto['code'])
|
||||
: 'runtime-unhealthy';
|
||||
const diagnostics = sanitizeRuntimeProviderDiagnostics(error.diagnostics);
|
||||
const message =
|
||||
sanitizeNullableRuntimeProviderText(error.message) ??
|
||||
'Runtime provider management command failed';
|
||||
return {
|
||||
code,
|
||||
message:
|
||||
sanitizeNullableRuntimeProviderText(error.message) ??
|
||||
'Runtime provider management command failed',
|
||||
message,
|
||||
recoverable: typeof error.recoverable === 'boolean' ? error.recoverable : true,
|
||||
diagnostics: withRuntimeProviderErrorCode(code, diagnostics),
|
||||
diagnostics: withRuntimeProviderErrorCode(
|
||||
code,
|
||||
diagnostics ?? buildOpenCodeProfileNodeModulesLinkDiagnostics(message)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +221,39 @@ function sanitizeNullableRuntimeProviderText(value: unknown): string | null {
|
|||
return typeof value === 'string' ? sanitizeRuntimeProviderText(value) : null;
|
||||
}
|
||||
|
||||
function buildOpenCodeProfileNodeModulesLinkDiagnostics(
|
||||
message: string
|
||||
): RuntimeProviderManagementErrorDto['diagnostics'] {
|
||||
const normalized = message.toLowerCase();
|
||||
const isAccessDeniedLinkFailure =
|
||||
(normalized.includes('eperm') || normalized.includes('eacces')) &&
|
||||
normalized.includes('symlink') &&
|
||||
normalized.includes('opencode') &&
|
||||
normalized.includes('node_modules');
|
||||
if (!isAccessDeniedLinkFailure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const summary = 'OpenCode managed profile node_modules link was blocked.';
|
||||
const likelyCause =
|
||||
'Windows denied creating the managed OpenCode profile node_modules link. Newer Agent Teams runtimes fall back to a junction or local profile directory.';
|
||||
return {
|
||||
summary,
|
||||
likelyCause,
|
||||
binaryPath: null,
|
||||
command: null,
|
||||
projectPath: null,
|
||||
exitCode: null,
|
||||
stderrPreview: message,
|
||||
stdoutPreview: null,
|
||||
hints: [
|
||||
'Update the Agent Teams runtime and refresh the OpenCode provider catalog.',
|
||||
'If you must use an older runtime, enable Windows Developer Mode or run Agent Teams AI as Administrator.',
|
||||
'If the error persists after updating, refresh again so the runtime can rebuild the managed OpenCode profile node_modules path.',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function extractJsonObject<T>(raw: string): T {
|
||||
const start = raw.indexOf('{');
|
||||
if (start < 0) {
|
||||
|
|
|
|||
|
|
@ -857,6 +857,48 @@ describe('AgentTeamsRuntimeProviderManagementCliClient', () => {
|
|||
expect(JSON.stringify(response)).not.toContain('sk-secret-value-123456');
|
||||
});
|
||||
|
||||
it('adds actionable diagnostics for OpenCode managed profile node_modules symlink failures', async () => {
|
||||
const runtimeMessage = [
|
||||
'Runtime provider management command failed unexpectedly:',
|
||||
"EPERM: operation not permitted, symlink 'C:\\Users\\Swarog\\AppData\\Local\\claude-multimodel-nodejs\\Cache\\opencode\\shared-cache\\config-node_modules'",
|
||||
"-> 'C:\\Users\\Swarog\\AppData\\Local\\claude-multimodel-nodejs\\Data\\opencode\\profiles\\abc123\\config\\opencode\\node_modules'",
|
||||
].join(' ');
|
||||
const error = new Error('Command failed: /repo/cli-dev runtime providers view');
|
||||
Object.assign(error, {
|
||||
stdout: JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
runtimeId: 'opencode',
|
||||
error: {
|
||||
code: 'runtime-unhealthy',
|
||||
message: runtimeMessage,
|
||||
recoverable: true,
|
||||
},
|
||||
}),
|
||||
stderr: '',
|
||||
});
|
||||
execCliMock.mockRejectedValue(error);
|
||||
|
||||
const client = new AgentTeamsRuntimeProviderManagementCliClient();
|
||||
const response = await client.loadView({
|
||||
runtimeId: 'opencode',
|
||||
});
|
||||
|
||||
expect(response.error?.message).toBe(runtimeMessage);
|
||||
expect(response.error?.diagnostics?.summary).toBe(
|
||||
'OpenCode managed profile node_modules link was blocked.'
|
||||
);
|
||||
expect(response.error?.diagnostics?.likelyCause).toContain(
|
||||
'Windows denied creating the managed OpenCode profile node_modules link'
|
||||
);
|
||||
expect(response.error?.diagnostics?.stderrPreview).toBe(runtimeMessage);
|
||||
expect(response.error?.diagnostics?.hints).toEqual(
|
||||
expect.arrayContaining([
|
||||
'Update the Agent Teams runtime and refresh the OpenCode provider catalog.',
|
||||
'If you must use an older runtime, enable Windows Developer Mode or run Agent Teams AI as Administrator.',
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('does not let non-object error logs shadow a later valid runtime response', async () => {
|
||||
const validResponse = {
|
||||
schemaVersion: 1,
|
||||
|
|
|
|||
Loading…
Reference in a new issue