-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Expand file tree
/
Copy pathdiagnostics.ts
More file actions
110 lines (104 loc) · 4.31 KB
/
Copy pathdiagnostics.ts
File metadata and controls
110 lines (104 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { agentBinEnvKey, agentSearchDirs } from './executables.js';
import type { AgentLaunchResolution } from './launch.js';
import type { AgentAuthProbeResult } from './auth.js';
import type { AgentDiagnostic, RuntimeAgentDef } from './types.js';
import type { AgentFixIntent } from '@open-design/contracts';
// Cap on how many searched dirs we attach to a `not-on-path` diagnostic.
// The resolver walks PATH + the user-toolchain whitelist, which can run to
// dozens of entries; the UI only needs enough to make "we looked here" land
// without ballooning the /api/agents payload.
const MAX_SEARCHED_DIRS = 24;
function setEnvIntent(agentId: string): AgentFixIntent[] {
const envKey = agentBinEnvKey(agentId);
return envKey ? [{ kind: 'setEnv', envKey }] : [];
}
// The agent is not resolvable at all: either nothing matched on PATH, or a
// user-supplied `*_BIN` override points at a missing/invalid file. The two
// cases get different copy + fix affordances because the remedy differs
// (install / point us at the binary vs. fix or clear the override).
export function buildExecutableDiagnostic(
def: Pick<RuntimeAgentDef, 'id' | 'name' | 'bin'>,
configuredEnv: Record<string, string> = {},
): AgentDiagnostic {
const envKey = agentBinEnvKey(def.id);
const overrideRaw = envKey ? configuredEnv?.[envKey]?.trim() : '';
if (envKey && overrideRaw) {
return {
reason: 'configured-bin-invalid',
severity: 'error',
message: `${def.name}'s configured binary (${envKey}) was not found or is not executable.`,
detail: overrideRaw,
fixActions: [
{ kind: 'setEnv', envKey },
{ kind: 'clearEnv', envKey },
{ kind: 'rescan' },
],
};
}
return {
reason: 'not-on-path',
severity: 'error',
message: `${def.name} (\`${def.bin}\`) was not found on your PATH.`,
searchedDirs: agentSearchDirs().slice(0, MAX_SEARCHED_DIRS),
fixActions: [
{ kind: 'openInstall' },
...setEnvIntent(def.id),
{ kind: 'rescan' },
],
};
}
export type NotInvocableCause = 'not-executable' | 'missing-target';
// A file matched but `--version` could not spawn it. Permission failures are
// real binaries that need their executable bit restored; missing-target
// failures are usually leftover npm/nvm/mise shims whose underlying target was
// uninstalled.
export function buildNotInvocableDiagnostic(
def: Pick<RuntimeAgentDef, 'id' | 'name'>,
launch: Pick<AgentLaunchResolution, 'selectedPath' | 'launchPath'>,
cause: NotInvocableCause,
): AgentDiagnostic {
if (cause === 'not-executable') {
return {
reason: 'not-executable',
severity: 'error',
message: `${def.name} was found but is not executable. Restore its execute permission or choose a different binary, then rescan.`,
...(launch.launchPath ? { detail: launch.launchPath } : {}),
fixActions: [...setEnvIntent(def.id), { kind: 'rescan' }],
};
}
return {
reason: 'shim-broken',
severity: 'error',
message: `${def.name} was found but could not be launched — its wrapper or shim points at a missing target.`,
...(launch.launchPath ? { detail: launch.launchPath } : {}),
fixActions: [...setEnvIntent(def.id), { kind: 'openDocs' }, { kind: 'rescan' }],
};
}
// The agent is installed and invocable but its auth probe reported a
// missing / unverifiable credential. Detection only reaches this helper for
// adapters that declare a cheap, side-effect-free authProbe; until an adapter
// also declares a daemon-safe OAuth producer, diagnostics point at docs.
export function buildAuthDiagnostic(
def: Pick<RuntimeAgentDef, 'id' | 'name'>,
auth: AgentAuthProbeResult,
): AgentDiagnostic | null {
if (auth.status === 'ok') return null;
const signInIntent: AgentFixIntent = { kind: 'openDocs' };
if (auth.status === 'missing') {
return {
reason: 'auth-missing',
severity: 'error',
message: auth.message || `${def.name} is installed but not authenticated.`,
...(auth.stderrTail ? { detail: auth.stderrTail } : {}),
fixActions: [signInIntent, { kind: 'rescan' }],
};
}
return {
reason: 'auth-unknown',
severity: 'warning',
message:
auth.message || `${def.name} authentication status could not be verified.`,
...(auth.stderrTail ? { detail: auth.stderrTail } : {}),
fixActions: [signInIntent, { kind: 'rescan' }],
};
}