@gakim-digital/dexter-bridge 0.11.6 → 0.11.9
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/package.json +1 -1
- package/src/agent.js +137 -22
- package/src/agentOutput.js +5 -0
- package/src/api.js +9 -0
- package/src/cli.js +126 -23
- package/src/config.js +1 -0
- package/src/framerAgentTools.js +182 -17
- package/src/harnessMcpServer.js +13 -5
- package/src/harnessTools.js +114 -1
- package/src/protocol.js +6 -3
- package/src/providers/codexAppServer.js +16 -5
- package/src/runtimeProfiles.js +127 -2
package/src/runtimeProfiles.js
CHANGED
|
@@ -71,6 +71,20 @@ function normalizeCapabilities(value = {}) {
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
function normalizeModelCatalog(value = {}) {
|
|
75
|
+
const source = ['runtime', 'fallback', 'stale', 'error'].includes(value.source)
|
|
76
|
+
? value.source
|
|
77
|
+
: 'fallback';
|
|
78
|
+
return {
|
|
79
|
+
source,
|
|
80
|
+
refreshedAt: text(value.refreshedAt, 80) || new Date().toISOString(),
|
|
81
|
+
modelCount: Number.isFinite(Number(value.modelCount))
|
|
82
|
+
? Math.max(0, Math.floor(Number(value.modelCount)))
|
|
83
|
+
: 0,
|
|
84
|
+
...(text(value.error, 500) ? { error: text(value.error, 500) } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
export function normalizeRuntimeProfile(value, { includeSecret = false } = {}) {
|
|
75
89
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
76
90
|
const driver = text(value.driver, 80);
|
|
@@ -110,6 +124,10 @@ export function normalizeRuntimeProfile(value, { includeSecret = false } = {}) {
|
|
|
110
124
|
continuationIdentity: text(value.continuationIdentity, 180) || stableIdentity(driver, instanceId),
|
|
111
125
|
capabilities: normalizeCapabilities(value.capabilities),
|
|
112
126
|
models,
|
|
127
|
+
modelCatalog: normalizeModelCatalog({
|
|
128
|
+
...(value.modelCatalog || {}),
|
|
129
|
+
modelCount: models.length,
|
|
130
|
+
}),
|
|
113
131
|
...(text(value.keyLast4, 16) ? { keyLast4: text(value.keyLast4, 16) } : {}),
|
|
114
132
|
...(text(value.command, 2048) ? { command: text(value.command, 2048) } : {}),
|
|
115
133
|
...(Array.isArray(value.args)
|
|
@@ -121,6 +139,9 @@ export function normalizeRuntimeProfile(value, { includeSecret = false } = {}) {
|
|
|
121
139
|
}
|
|
122
140
|
: {}),
|
|
123
141
|
...(text(value.cwd, 2048) ? { cwd: text(value.cwd, 2048) } : {}),
|
|
142
|
+
...(normalizeDiagnostics(value.diagnostics)
|
|
143
|
+
? { diagnostics: normalizeDiagnostics(value.diagnostics) }
|
|
144
|
+
: {}),
|
|
124
145
|
};
|
|
125
146
|
if (includeSecret && value.credentials) profile.credentials = value.credentials;
|
|
126
147
|
return profile;
|
|
@@ -133,7 +154,104 @@ export function publicRuntimeProfile(value) {
|
|
|
133
154
|
return publicProfile;
|
|
134
155
|
}
|
|
135
156
|
|
|
136
|
-
|
|
157
|
+
const DIAGNOSTIC_LEVELS = new Set(['info', 'warn', 'error']);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Structured environment checks for one local agent, shaped so the builder
|
|
161
|
+
* can show exactly what works and what to fix (installed, signed in, which
|
|
162
|
+
* credential is billed, and whether the model list came from the agent).
|
|
163
|
+
*/
|
|
164
|
+
export function diagnosticsFromAgentCheck(check, env = process.env) {
|
|
165
|
+
const label = check?.label || check?.agent || 'Agent';
|
|
166
|
+
const checks = [];
|
|
167
|
+
const add = (level, code, message, hint) =>
|
|
168
|
+
checks.push({ level, code, message, ...(hint ? { hint } : {}) });
|
|
169
|
+
if (!check || check.installed === false || check.status === 'unavailable') {
|
|
170
|
+
add(
|
|
171
|
+
'error',
|
|
172
|
+
'cli_missing',
|
|
173
|
+
check?.error || `${label} is not installed on this computer.`,
|
|
174
|
+
check?.agent === 'codex'
|
|
175
|
+
? 'Install Codex (npm i -g @openai/codex), then restart the bridge.'
|
|
176
|
+
: 'Install Claude Code (npm i -g @anthropic-ai/claude-code), then restart the bridge.',
|
|
177
|
+
);
|
|
178
|
+
} else {
|
|
179
|
+
add(
|
|
180
|
+
'info',
|
|
181
|
+
'cli_detected',
|
|
182
|
+
`${label}${check.version ? ` ${check.version}` : ''} detected.`,
|
|
183
|
+
);
|
|
184
|
+
if (check.signedIn === false) {
|
|
185
|
+
add(
|
|
186
|
+
'error',
|
|
187
|
+
'sign_in_required',
|
|
188
|
+
check.error || `${label} is not signed in.`,
|
|
189
|
+
check.agent === 'codex'
|
|
190
|
+
? 'Run `codex login` in a terminal, then restart the bridge.'
|
|
191
|
+
: 'Run `claude` in a terminal and sign in, then restart the bridge.',
|
|
192
|
+
);
|
|
193
|
+
} else {
|
|
194
|
+
const method = text(check.authMethod || check.authMode, 80);
|
|
195
|
+
add('info', 'signed_in', `Signed in${method ? ` (${method})` : ''}.`);
|
|
196
|
+
if (check.agent === 'claude-code' && text(env?.ANTHROPIC_API_KEY, 8)) {
|
|
197
|
+
add(
|
|
198
|
+
'warn',
|
|
199
|
+
'api_key_billing',
|
|
200
|
+
'ANTHROPIC_API_KEY is set, so Claude Code bills that API key instead of your Claude plan.',
|
|
201
|
+
'Unset ANTHROPIC_API_KEY in the bridge terminal to use your plan.',
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if (check.agent === 'codex' && check.fallbackProviderUsed) {
|
|
205
|
+
add(
|
|
206
|
+
'warn',
|
|
207
|
+
'provider_fallback',
|
|
208
|
+
`Codex is using ${check.providerName || check.providerId || 'a fallback provider'} because the configured provider is not ready.`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const modelCount = Array.isArray(check.modelDetails) ? check.modelDetails.length : 0;
|
|
213
|
+
if (check.modelCatalogSource === 'runtime') {
|
|
214
|
+
add('info', 'models_discovered', `${modelCount} model${modelCount === 1 ? '' : 's'} available.`);
|
|
215
|
+
} else if (check.signedIn !== false) {
|
|
216
|
+
add(
|
|
217
|
+
'warn',
|
|
218
|
+
'model_catalog_fallback',
|
|
219
|
+
`Could not read the model list from ${label}; showing the default list.`,
|
|
220
|
+
check.modelCatalogError ? text(check.modelCatalogError, 300) : undefined,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
status: checks.some((item) => item.level === 'error')
|
|
226
|
+
? 'fail'
|
|
227
|
+
: checks.some((item) => item.level === 'warn')
|
|
228
|
+
? 'warn'
|
|
229
|
+
: 'pass',
|
|
230
|
+
checks,
|
|
231
|
+
testedAt: new Date().toISOString(),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function normalizeDiagnostics(value) {
|
|
236
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
237
|
+
const checks = (Array.isArray(value.checks) ? value.checks : [])
|
|
238
|
+
.slice(0, 12)
|
|
239
|
+
.flatMap((item) => {
|
|
240
|
+
const level = DIAGNOSTIC_LEVELS.has(item?.level) ? item.level : null;
|
|
241
|
+
const code = text(item?.code, 80);
|
|
242
|
+
const message = text(item?.message, 500);
|
|
243
|
+
if (!level || !code || !message) return [];
|
|
244
|
+
const hint = text(item?.hint, 300);
|
|
245
|
+
return [{ level, code, message, ...(hint ? { hint } : {}) }];
|
|
246
|
+
});
|
|
247
|
+
return {
|
|
248
|
+
status: ['pass', 'warn', 'fail'].includes(value.status) ? value.status : 'warn',
|
|
249
|
+
checks,
|
|
250
|
+
testedAt: text(value.testedAt, 40) || new Date().toISOString(),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function profileFromAgentCheck(check, env) {
|
|
137
255
|
if (!check || check.installed === false) return null;
|
|
138
256
|
const driver =
|
|
139
257
|
check.agent === 'codex' ? 'codex-app-server' : check.agent === 'claude-code' ? 'claude-code-cli' : null;
|
|
@@ -169,6 +287,13 @@ function profileFromAgentCheck(check) {
|
|
|
169
287
|
cancellation: true,
|
|
170
288
|
},
|
|
171
289
|
models: check.modelDetails || [],
|
|
290
|
+
modelCatalog: {
|
|
291
|
+
source: check.modelCatalogSource || 'fallback',
|
|
292
|
+
refreshedAt: check.modelCatalogRefreshedAt,
|
|
293
|
+
modelCount: check.modelDetails?.length || 0,
|
|
294
|
+
...(check.modelCatalogError ? { error: check.modelCatalogError } : {}),
|
|
295
|
+
},
|
|
296
|
+
diagnostics: diagnosticsFromAgentCheck(check, env),
|
|
172
297
|
});
|
|
173
298
|
}
|
|
174
299
|
|
|
@@ -239,7 +364,7 @@ export async function discoverRuntimeProfiles({
|
|
|
239
364
|
const selectedRuntime = normalizeRuntimeSelection(runtimeSelection);
|
|
240
365
|
const selectedDriver = runtimeDriver(selectedRuntime);
|
|
241
366
|
const profiles = agentChecks
|
|
242
|
-
.map(profileFromAgentCheck)
|
|
367
|
+
.map((check) => profileFromAgentCheck(check, env))
|
|
243
368
|
.filter(Boolean)
|
|
244
369
|
.filter((profile) => !selectedDriver || profile.driver === selectedDriver);
|
|
245
370
|
if (!selectedRuntime) {
|