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'])
|
? (rawCode as RuntimeProviderManagementErrorDto['code'])
|
||||||
: 'runtime-unhealthy';
|
: 'runtime-unhealthy';
|
||||||
const diagnostics = sanitizeRuntimeProviderDiagnostics(error.diagnostics);
|
const diagnostics = sanitizeRuntimeProviderDiagnostics(error.diagnostics);
|
||||||
|
const message =
|
||||||
|
sanitizeNullableRuntimeProviderText(error.message) ??
|
||||||
|
'Runtime provider management command failed';
|
||||||
return {
|
return {
|
||||||
code,
|
code,
|
||||||
message:
|
message,
|
||||||
sanitizeNullableRuntimeProviderText(error.message) ??
|
|
||||||
'Runtime provider management command failed',
|
|
||||||
recoverable: typeof error.recoverable === 'boolean' ? error.recoverable : true,
|
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;
|
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 {
|
function extractJsonObject<T>(raw: string): T {
|
||||||
const start = raw.indexOf('{');
|
const start = raw.indexOf('{');
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
|
|
|
||||||
|
|
@ -857,6 +857,48 @@ describe('AgentTeamsRuntimeProviderManagementCliClient', () => {
|
||||||
expect(JSON.stringify(response)).not.toContain('sk-secret-value-123456');
|
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 () => {
|
it('does not let non-object error logs shadow a later valid runtime response', async () => {
|
||||||
const validResponse = {
|
const validResponse = {
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue