praxis-agent 0.43.1 → 0.45.0
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/README.md +45 -13
- package/dist/application/session-service.js +84 -4
- package/dist/application/top-level-agent-manager.d.ts +7 -0
- package/dist/application/top-level-agent-manager.js +21 -3
- package/dist/cli/controls.js +4 -0
- package/dist/cli/interactive.js +3 -1
- package/dist/cli/protocol.d.ts +5 -0
- package/dist/cli/protocol.js +45 -0
- package/dist/cli/provider-auth-command.d.ts +32 -0
- package/dist/cli/provider-auth-command.js +249 -0
- package/dist/cli/tui/quiet-frame.js +4 -4
- package/dist/cli/tui/transcript-viewport.js +3 -3
- package/dist/cli/workspace-trust-prompt.js +2 -2
- package/dist/cli-runtime.d.ts +34 -1
- package/dist/cli-runtime.js +587 -184
- package/dist/maintenance/doctor.js +100 -22
- package/dist/persistence/provider-credential-vault.d.ts +72 -0
- package/dist/persistence/provider-credential-vault.js +498 -0
- package/dist/providers/codex-oauth.d.ts +104 -0
- package/dist/providers/codex-oauth.js +770 -0
- package/dist/providers/codex-subscription.d.ts +33 -0
- package/dist/providers/codex-subscription.js +849 -0
- package/dist/providers/provider-auth.d.ts +71 -0
- package/dist/providers/provider-auth.js +149 -0
- package/dist/providers/provider-registry.d.ts +52 -0
- package/dist/providers/provider-registry.js +187 -0
- package/dist/providers/provider-settings.d.ts +38 -0
- package/dist/providers/provider-settings.js +334 -0
- package/dist/security/workspace-trust.d.ts +4 -3
- package/dist/security/workspace-trust.js +35 -1
- package/package.json +6 -3
|
@@ -7,9 +7,13 @@ import { validateClaudeHooks } from '../hooks/claude-hooks.js';
|
|
|
7
7
|
import { validateClaudeMcpConfiguration } from '../mcp/claude-mcp-tools.js';
|
|
8
8
|
import { loadClaudeAutoModeConfig } from '../permissions/claude-auto-classifier.js';
|
|
9
9
|
import { ClaudePermissionResolver, validateClaudePermissionSettings, } from '../permissions/claude-permission-resolver.js';
|
|
10
|
-
import { readPluginRegistry, validateClaudePlugin, } from '../plugins/claude-plugin-runtime.js';
|
|
10
|
+
import { loadClaudePlugins, readPluginRegistry, validateClaudePlugin, } from '../plugins/claude-plugin-runtime.js';
|
|
11
|
+
import { assessWorkspaceTrust, hasWorkspaceProviderSelection, workspaceTrustInventory, } from '../security/workspace-trust.js';
|
|
11
12
|
import { loadNativeContextResources, loadNativeSettings, loadNativeSharedResources, } from '../persistence/native-resources.js';
|
|
12
13
|
import { parseContextEnvironment, parseProviderEnvironment, } from '../providers/environment.js';
|
|
14
|
+
import { resolveProviderCredential } from '../providers/provider-auth.js';
|
|
15
|
+
import { ProviderCredentialVault } from '../persistence/provider-credential-vault.js';
|
|
16
|
+
import { resolveProviderTarget } from '../providers/provider-settings.js';
|
|
13
17
|
import { ContextBudget } from '../core/context-budget.js';
|
|
14
18
|
import { ModelPricingRegistry } from '../core/usage.js';
|
|
15
19
|
import { redactSensitiveText, sensitiveEnvironmentValues, } from '../platform/sensitive-data.js';
|
|
@@ -127,6 +131,7 @@ async function capture(id, operation) {
|
|
|
127
131
|
export async function runDoctor(options) {
|
|
128
132
|
const configRoot = resolve(options.configRoot);
|
|
129
133
|
const cwd = resolve(options.cwd);
|
|
134
|
+
const claudeStatePath = resolve(options.claudeStatePath ?? resolve(configRoot, 'state.json'));
|
|
130
135
|
const sensitiveValues = sensitiveEnvironmentValues(options.environment);
|
|
131
136
|
const diagnosticOptions = {
|
|
132
137
|
version: options.version,
|
|
@@ -163,6 +168,32 @@ export async function runDoctor(options) {
|
|
|
163
168
|
});
|
|
164
169
|
return nativeResources;
|
|
165
170
|
};
|
|
171
|
+
const providerTrustAssessment = async () => {
|
|
172
|
+
const shared = await loadNativeSharedResources({
|
|
173
|
+
root: configRoot,
|
|
174
|
+
cwd,
|
|
175
|
+
environment: options.environment,
|
|
176
|
+
includeProjectMemory: false,
|
|
177
|
+
});
|
|
178
|
+
const plugins = await loadClaudePlugins({
|
|
179
|
+
configRoot,
|
|
180
|
+
cwd,
|
|
181
|
+
pluginDirectories: [],
|
|
182
|
+
pluginUrls: [],
|
|
183
|
+
loadInstalled: true,
|
|
184
|
+
readOnlyExecutables: true,
|
|
185
|
+
environment: options.environment,
|
|
186
|
+
});
|
|
187
|
+
const settings = [...shared.settings, ...plugins.settings];
|
|
188
|
+
if (!hasWorkspaceProviderSelection(settings))
|
|
189
|
+
return false;
|
|
190
|
+
const assessment = await assessWorkspaceTrust(await workspaceTrustInventory({
|
|
191
|
+
cwd,
|
|
192
|
+
settings,
|
|
193
|
+
mcp: [...shared.mcp, ...plugins.mcp],
|
|
194
|
+
}), claudeStatePath);
|
|
195
|
+
return assessment.status === 'trusted';
|
|
196
|
+
};
|
|
166
197
|
const checks = [];
|
|
167
198
|
checks.push(await capture('installation', async () => {
|
|
168
199
|
const executablePath = await canonicalExecutable(options.executablePath);
|
|
@@ -197,17 +228,19 @@ export async function runDoctor(options) {
|
|
|
197
228
|
};
|
|
198
229
|
}));
|
|
199
230
|
checks.push(await capture('provider', async () => {
|
|
200
|
-
const
|
|
231
|
+
const target = await resolveProviderTarget({
|
|
232
|
+
configRoot,
|
|
233
|
+
cwd,
|
|
234
|
+
environment: options.environment,
|
|
235
|
+
includeProjectSettings: await providerTrustAssessment(),
|
|
236
|
+
});
|
|
237
|
+
const controlsEnvironment = {
|
|
238
|
+
...options.environment,
|
|
239
|
+
PRAXIS_PROVIDER: target.protocol === 'anthropic-messages' ? 'anthropic' : 'openai',
|
|
240
|
+
PRAXIS_BASE_URL: target.baseUrl,
|
|
241
|
+
};
|
|
242
|
+
const provider = parseProviderEnvironment(controlsEnvironment);
|
|
201
243
|
parseContextEnvironment(options.environment);
|
|
202
|
-
const apiKey = options.environment.PRAXIS_API_KEY;
|
|
203
|
-
const model = options.environment.PRAXIS_MODEL;
|
|
204
|
-
if (!apiKey || apiKey.trim().length === 0) {
|
|
205
|
-
throw new Error('PRAXIS_API_KEY is required');
|
|
206
|
-
}
|
|
207
|
-
if (!model || model.trim().length === 0) {
|
|
208
|
-
throw new Error('PRAXIS_MODEL is required');
|
|
209
|
-
}
|
|
210
|
-
const baseUrl = safeBaseUrl(provider.baseUrl);
|
|
211
244
|
const contextWindow = options.environment.PRAXIS_CONTEXT_WINDOW_TOKENS;
|
|
212
245
|
const contextReserve = options.environment.PRAXIS_CONTEXT_RESERVE_TOKENS;
|
|
213
246
|
if (contextWindow !== undefined) {
|
|
@@ -220,19 +253,64 @@ export async function runDoctor(options) {
|
|
|
220
253
|
: { reserveTokens: parsedReserve }),
|
|
221
254
|
});
|
|
222
255
|
}
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
256
|
+
const vault = new ProviderCredentialVault({
|
|
257
|
+
configRoot,
|
|
258
|
+
environment: options.environment,
|
|
259
|
+
});
|
|
260
|
+
const credential = await resolveProviderCredential({
|
|
261
|
+
target,
|
|
262
|
+
environment: options.environment,
|
|
263
|
+
vault,
|
|
264
|
+
commandRunner: async () => ({
|
|
265
|
+
stdout: '__praxis_doctor_credential_placeholder__',
|
|
266
|
+
exitCode: 0,
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
const pricingDiagnosis = (() => {
|
|
270
|
+
if (target.billingMode !== 'api')
|
|
271
|
+
return undefined;
|
|
272
|
+
return ModelPricingRegistry.fromEnvironment(options.environment.PRAXIS_PRICING_JSON).diagnose(target.modelId);
|
|
273
|
+
})();
|
|
274
|
+
const helperSkipped = credential.source.source === 'command';
|
|
275
|
+
const safeCredential = {
|
|
276
|
+
type: credential.type,
|
|
277
|
+
source: credential.source.source,
|
|
278
|
+
...(credential.source.source === 'env'
|
|
279
|
+
? { name: credential.source.name }
|
|
280
|
+
: {}),
|
|
281
|
+
...(credential.type === 'oauth'
|
|
282
|
+
? {
|
|
283
|
+
expiry: credential.expiresAt > Date.now()
|
|
284
|
+
? 'valid'
|
|
285
|
+
: 'expired',
|
|
286
|
+
}
|
|
287
|
+
: {}),
|
|
288
|
+
};
|
|
289
|
+
const warnings = [
|
|
290
|
+
...(helperSkipped
|
|
291
|
+
? ['credential helper execution was intentionally skipped']
|
|
292
|
+
: []),
|
|
293
|
+
...(pricingDiagnosis?.source === 'unknown'
|
|
294
|
+
? ['model pricing is unavailable and fail-closed']
|
|
295
|
+
: []),
|
|
296
|
+
];
|
|
226
297
|
return {
|
|
227
|
-
...(
|
|
228
|
-
summary:
|
|
229
|
-
? `${
|
|
230
|
-
: `${
|
|
298
|
+
...(warnings.length === 0 ? {} : { status: 'warn' }),
|
|
299
|
+
summary: warnings.length === 0
|
|
300
|
+
? `${target.providerId} provider target is valid`
|
|
301
|
+
: `${target.providerId} provider target is valid; ${warnings.join('; ')}`,
|
|
231
302
|
details: {
|
|
232
|
-
provider:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
303
|
+
provider: target.providerId,
|
|
304
|
+
profile: target.profileId,
|
|
305
|
+
model: target.modelId,
|
|
306
|
+
protocol: target.protocol,
|
|
307
|
+
baseUrl: safeBaseUrl(provider.baseUrl),
|
|
308
|
+
billingMode: target.billingMode,
|
|
309
|
+
experimental: target.experimental,
|
|
310
|
+
credential: safeCredential,
|
|
311
|
+
...(pricingDiagnosis === undefined
|
|
312
|
+
? {}
|
|
313
|
+
: { pricing: pricingDiagnosis }),
|
|
236
314
|
},
|
|
237
315
|
};
|
|
238
316
|
}));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export declare class ProviderKeychainUnavailableError extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
export interface ProviderCredentialKey {
|
|
5
|
+
providerId: string;
|
|
6
|
+
profileId: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiKeyCredential {
|
|
9
|
+
type: 'api-key';
|
|
10
|
+
secret: string;
|
|
11
|
+
revision: number;
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiKeyCredentialInput {
|
|
15
|
+
type: 'api-key';
|
|
16
|
+
secret: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OAuthCredential {
|
|
19
|
+
type: 'oauth';
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
expiresAt: number;
|
|
23
|
+
accountId?: string;
|
|
24
|
+
revision: number;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
}
|
|
27
|
+
export interface OAuthCredentialInput {
|
|
28
|
+
type: 'oauth';
|
|
29
|
+
accessToken: string;
|
|
30
|
+
refreshToken: string;
|
|
31
|
+
expiresAt: number;
|
|
32
|
+
accountId?: string;
|
|
33
|
+
}
|
|
34
|
+
export type ProviderCredentialRecord = ApiKeyCredential | OAuthCredential;
|
|
35
|
+
export type ProviderCredentialInput = ApiKeyCredentialInput | OAuthCredentialInput;
|
|
36
|
+
export interface ProviderCredentialMetadata {
|
|
37
|
+
key: ProviderCredentialKey;
|
|
38
|
+
type: ProviderCredentialRecord['type'];
|
|
39
|
+
revision: number;
|
|
40
|
+
updatedAt: string;
|
|
41
|
+
expiresAt?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ProviderCredentialKeychainAdapter {
|
|
44
|
+
read(service: string): Promise<string | undefined>;
|
|
45
|
+
write(service: string, serializedEnvelope: string): Promise<void>;
|
|
46
|
+
delete(service: string): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export interface ProviderCredentialVaultOptions {
|
|
49
|
+
configRoot: string;
|
|
50
|
+
useKeychain?: boolean;
|
|
51
|
+
keychain?: ProviderCredentialKeychainAdapter;
|
|
52
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
53
|
+
}
|
|
54
|
+
export declare function providerCredentialFilePath(configRoot: string): string;
|
|
55
|
+
export declare function providerCredentialService(configRoot: string): string;
|
|
56
|
+
export declare class ProviderCredentialVault {
|
|
57
|
+
private readonly root;
|
|
58
|
+
private readonly file;
|
|
59
|
+
private readonly useKeychain;
|
|
60
|
+
private readonly service;
|
|
61
|
+
private readonly keychain;
|
|
62
|
+
private readonly lease;
|
|
63
|
+
constructor(options: ProviderCredentialVaultOptions);
|
|
64
|
+
read(key: ProviderCredentialKey): Promise<ProviderCredentialRecord | undefined>;
|
|
65
|
+
list(): Promise<ProviderCredentialMetadata[]>;
|
|
66
|
+
modify(key: ProviderCredentialKey, callback: (current: ProviderCredentialRecord | undefined) => ProviderCredentialInput | undefined | Promise<ProviderCredentialInput | undefined>): Promise<ProviderCredentialRecord | undefined>;
|
|
67
|
+
delete(key: ProviderCredentialKey): Promise<void>;
|
|
68
|
+
private readReconciled;
|
|
69
|
+
private persist;
|
|
70
|
+
private acquire;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=provider-credential-vault.d.ts.map
|