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
package/README.md
CHANGED
|
@@ -27,7 +27,9 @@ sessions, configuration, or compatibility directories.
|
|
|
27
27
|
- macOS or Linux
|
|
28
28
|
- Node.js 24 or newer
|
|
29
29
|
- [`ripgrep`](https://github.com/BurntSushi/ripgrep) (`rg`) for the Grep tool
|
|
30
|
-
- an API key and model ID for an Anthropic or OpenAI-compatible provider
|
|
30
|
+
- an API key and model ID for an Anthropic or OpenAI-compatible provider (the
|
|
31
|
+
stable setup), or the explicitly enabled experimental ChatGPT-backed Codex
|
|
32
|
+
subscription integration
|
|
31
33
|
|
|
32
34
|
Praxis does not use Claude subscription authentication. Claude-shaped message,
|
|
33
35
|
tool, and CLI protocol forms remain supported where they are part of the
|
|
@@ -61,6 +63,15 @@ cd /path/to/project
|
|
|
61
63
|
praxis
|
|
62
64
|
```
|
|
63
65
|
|
|
66
|
+
Praxis also has an experimental `openai-codex` provider for ChatGPT-backed
|
|
67
|
+
Codex subscriptions. It is separate from OpenAI API-key access, requires
|
|
68
|
+
`experimental.codexSubscription: true`, and stores OAuth credentials in the
|
|
69
|
+
native Vault. Start with `praxis auth login openai-codex`; see [Getting
|
|
70
|
+
Started](docs/GETTING_STARTED.md) for the browser/device flow and limitations.
|
|
71
|
+
This uses an undocumented third-party subscription/backend contract and may
|
|
72
|
+
change; it is not Claude subscription authentication. Subscription runs retain
|
|
73
|
+
token usage but do not provide API-dollar cost or enforce USD budgets.
|
|
74
|
+
|
|
64
75
|
For Anthropic Messages:
|
|
65
76
|
|
|
66
77
|
```sh
|
|
@@ -90,7 +101,8 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
90
101
|
## What Praxis provides
|
|
91
102
|
|
|
92
103
|
- **Local agent runtime** — C+ Quiet Operator responsive TUI with a linear
|
|
93
|
-
|
|
104
|
+
`❯` user / `⏺` assistant conversation, `✻` thinking activity, and `!` shell
|
|
105
|
+
composer grammar, compact stable tool rows, responsive density,
|
|
94
106
|
terminal-native background, and a minimal composer/status row. Interactive
|
|
95
107
|
surfaces share the same presentation across terminals, with English
|
|
96
108
|
permission/configuration choices and a taught `❯` / Up/Down / Enter / Esc
|
|
@@ -128,8 +140,9 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
128
140
|
provider-free `/terminal-setup` diagnostics and repeatable Shift+Enter setup
|
|
129
141
|
for supported local terminals,
|
|
130
142
|
`Ctrl+V` text/image clipboard paste, `Ctrl+Z` shell suspension and `fg`
|
|
131
|
-
recovery, permission-gated `!` shell turns
|
|
132
|
-
|
|
143
|
+
recovery, permission-gated provider-free `!` shell turns that persist shell
|
|
144
|
+
input/output for later ordinary prompts without creating an assistant turn,
|
|
145
|
+
navigable current/per-turn Git diff views, semantic plan/question decision panels with complete
|
|
133
146
|
screen-reader actions, semantic screen projection across selectable surfaces,
|
|
134
147
|
deterministic resize-aware URL/form elicitation rendering, and measured
|
|
135
148
|
context budgets; print mode,
|
|
@@ -154,11 +167,11 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
154
167
|
isolation, explicit ask/deny precedence, sandbox-only auto-allow,
|
|
155
168
|
write-allowlist/deny-within-allow enforcement, per-command overrides and
|
|
156
169
|
exclusions, violation reporting, and bare-repository control-file cleanup,
|
|
157
|
-
safe-property Skill auto-allow, interactive
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
safe-property Skill auto-allow, interactive workspace-directory add/remove
|
|
171
|
+
controls, path confinement, credential redaction, sanitized child processes,
|
|
172
|
+
and exact-fingerprint workspace trust that blocks automatically discovered
|
|
173
|
+
project/local provider selection, hooks, and MCP until the canonical
|
|
174
|
+
workspace configuration is accepted.
|
|
162
175
|
- **Durable local work** — resumable sessions, full-history forks, file
|
|
163
176
|
checkpoints, tasks, foreground/background subagents, top-level agents, and
|
|
164
177
|
Claude-compatible main-thread agent definitions with native prompt, model,
|
|
@@ -187,9 +200,10 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
187
200
|
plugins, and append-only `praxis.transcript` JSONL sessions under `~/.praxis`,
|
|
188
201
|
with bounded MCP connection, discovery, and tool operations plus safe
|
|
189
202
|
disconnect recovery that never replays an already-dispatched call.
|
|
190
|
-
- **Provider-neutral models** — native
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
- **Provider-neutral models** — native Provider Registry/Vault routing, API
|
|
204
|
+
adapters, an experimental Codex OAuth adapter, explicit capability checks,
|
|
205
|
+
per-attempt bounded deadlines, and token-only/no-API-dollar accounting for
|
|
206
|
+
subscription runs.
|
|
193
207
|
- **Transactional self-update** — `praxis update` verifies the package before
|
|
194
208
|
installing it, rejects concurrent updates, and can roll back after an
|
|
195
209
|
interruption or crash.
|
|
@@ -198,6 +212,22 @@ Detailed feature status and executable evidence live in the
|
|
|
198
212
|
[parity matrix](https://github.com/Forest-Isle/Praxis/blob/main/docs/PARITY_MATRIX.md),
|
|
199
213
|
not in this entry-point README.
|
|
200
214
|
|
|
215
|
+
## Native data plane
|
|
216
|
+
|
|
217
|
+
Praxis defaults to an independent local native data plane:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
Praxis ─── ~/.praxis (or PRAXIS_HOME)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
All sessions, memory, tasks, scheduled tasks, resources, and private state live
|
|
224
|
+
under `~/.praxis` (or `PRAXIS_HOME`). The authoritative transcript is
|
|
225
|
+
append-only `praxis.transcript` v1 JSONL; legacy Claude transcripts, indexes,
|
|
226
|
+
sidechains, and migration/recovery paths have been removed. `CLAUDE_CONFIG_DIR`
|
|
227
|
+
does not participate in native runs, and legacy directories are neither read
|
|
228
|
+
nor written. Claude-shaped messages and tool fields describe protocol shape
|
|
229
|
+
only; they do not change Praxis data ownership.
|
|
230
|
+
|
|
201
231
|
## Documentation
|
|
202
232
|
|
|
203
233
|
| Need | Document |
|
|
@@ -216,7 +246,7 @@ not in this entry-point README.
|
|
|
216
246
|
|
|
217
247
|
Praxis targets one local OS user working across multiple repositories and
|
|
218
248
|
sessions. It is CLI-only and provider-capability-aware. Organization, tenant,
|
|
219
|
-
RBAC,
|
|
249
|
+
RBAC, billing, enterprise gateway,
|
|
220
250
|
IDE/Desktop/mobile clients, Remote Control, Claude Desktop import, and hosted
|
|
221
251
|
review-product surfaces are permanent non-goals.
|
|
222
252
|
|
|
@@ -251,6 +281,8 @@ implemented profile checks, not qualification of the full native package.
|
|
|
251
281
|
injected regression protection, plus Quiet Operator input echo `<50 ms` and
|
|
252
282
|
normal/low-capability full-frame p95 budgets of `<16.7/<33 ms`.
|
|
253
283
|
`npm run check` also enforces the corresponding source dependency direction.
|
|
284
|
+
`npm run test:coverage` measures all production code under `src/**` with V8 and
|
|
285
|
+
enforces global floors of 79% statements, 70% branches, 85% functions, and 81% lines.
|
|
254
286
|
`npm run test:core-completion` runs the 56-story #402 audit and reports
|
|
255
287
|
implemented, qualified, blocked, deferred, and out-of-scope states separately;
|
|
256
288
|
it never treats missing live prerequisites as a pass.
|
|
@@ -2592,7 +2592,9 @@ export class ClaudeSessionService {
|
|
|
2592
2592
|
});
|
|
2593
2593
|
}
|
|
2594
2594
|
const initialPricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
|
|
2595
|
-
if (
|
|
2595
|
+
if (shellCommand === undefined &&
|
|
2596
|
+
this.options.maxBudgetUsd !== undefined &&
|
|
2597
|
+
!initialPricing) {
|
|
2596
2598
|
throw new Error(`Cannot enforce --max-budget-usd: no pricing is configured for model ${provider.model ?? 'praxis/provider'}`);
|
|
2597
2599
|
}
|
|
2598
2600
|
const shellInputUuid = shellCommand === undefined ? null : randomUUID();
|
|
@@ -3699,7 +3701,9 @@ export class ClaudeSessionService {
|
|
|
3699
3701
|
};
|
|
3700
3702
|
},
|
|
3701
3703
|
});
|
|
3702
|
-
|
|
3704
|
+
if (shellCommand === undefined) {
|
|
3705
|
+
await contextEngine.prepare(contextTransitionPort(pendingUserMessages), signal);
|
|
3706
|
+
}
|
|
3703
3707
|
for (const [index, message] of expandedMessages.entries()) {
|
|
3704
3708
|
if (shellCommand !== undefined)
|
|
3705
3709
|
break;
|
|
@@ -3783,6 +3787,9 @@ export class ClaudeSessionService {
|
|
|
3783
3787
|
}
|
|
3784
3788
|
let shellUsage = { inputTokens: 0, outputTokens: 0 };
|
|
3785
3789
|
let shellModelUsage;
|
|
3790
|
+
let shellDurationApiMs;
|
|
3791
|
+
let shellDurationApiWithoutRetriesMs;
|
|
3792
|
+
let shellToolDurationMs;
|
|
3786
3793
|
if (shellCommand !== undefined) {
|
|
3787
3794
|
const call = {
|
|
3788
3795
|
id: `shell_${randomUUID().replaceAll('-', '')}`,
|
|
@@ -3822,6 +3829,10 @@ export class ClaudeSessionService {
|
|
|
3822
3829
|
throw error;
|
|
3823
3830
|
}
|
|
3824
3831
|
shellUsage = shellResult.usage ?? shellUsage;
|
|
3832
|
+
shellDurationApiMs = shellResult.durationApiMs;
|
|
3833
|
+
shellDurationApiWithoutRetriesMs =
|
|
3834
|
+
shellResult.durationApiWithoutRetriesMs;
|
|
3835
|
+
shellToolDurationMs = shellResult.durationToolMs;
|
|
3825
3836
|
if (!shellResult.isError) {
|
|
3826
3837
|
shellModelUsage = shellResult.modelUsage;
|
|
3827
3838
|
foregroundLineChanges.add(shellResult);
|
|
@@ -3872,7 +3883,74 @@ export class ClaudeSessionService {
|
|
|
3872
3883
|
isError: shellResult.isError,
|
|
3873
3884
|
});
|
|
3874
3885
|
}
|
|
3875
|
-
if (
|
|
3886
|
+
if (shellCommand !== undefined) {
|
|
3887
|
+
const tracker = this.sessionCostTrackers.get(sessionId);
|
|
3888
|
+
if (!tracker) {
|
|
3889
|
+
throw new Error(`Session cost tracker is not active for session ${sessionId}`);
|
|
3890
|
+
}
|
|
3891
|
+
const totalUsage = mergeUsage(recoveryUsage, shellUsage);
|
|
3892
|
+
const turnModelUsage = mergeSessionRawModelUsage(recoveryModelUsage, shellModelUsage);
|
|
3893
|
+
let rawCostUsd;
|
|
3894
|
+
if (turnModelUsage) {
|
|
3895
|
+
for (const [model, usage] of Object.entries(turnModelUsage)) {
|
|
3896
|
+
const pricing = this.options.pricing?.resolve(model);
|
|
3897
|
+
const costUsd = pricing
|
|
3898
|
+
? usageCostUsd(usage, pricing)
|
|
3899
|
+
: undefined;
|
|
3900
|
+
if (costUsd !== undefined)
|
|
3901
|
+
rawCostUsd = (rawCostUsd ?? 0) + costUsd;
|
|
3902
|
+
tracker.recordTurn({
|
|
3903
|
+
model,
|
|
3904
|
+
usage,
|
|
3905
|
+
...(costUsd === undefined ? {} : { costUsd }),
|
|
3906
|
+
...(usage.webSearchRequests === undefined
|
|
3907
|
+
? {}
|
|
3908
|
+
: { webSearchRequests: usage.webSearchRequests }),
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
let combinedToolDurationMs = 0;
|
|
3913
|
+
for (const recoveryResult of recoveryResults) {
|
|
3914
|
+
combinedToolDurationMs = addToolDuration(recoveryResult.durationToolMs, combinedToolDurationMs);
|
|
3915
|
+
}
|
|
3916
|
+
combinedToolDurationMs = addToolDuration(shellToolDurationMs, combinedToolDurationMs);
|
|
3917
|
+
tracker.recordDurations({
|
|
3918
|
+
...(shellDurationApiMs === undefined
|
|
3919
|
+
? {}
|
|
3920
|
+
: { apiDurationMs: shellDurationApiMs }),
|
|
3921
|
+
...(shellDurationApiWithoutRetriesMs === undefined
|
|
3922
|
+
? {}
|
|
3923
|
+
: {
|
|
3924
|
+
apiDurationWithoutRetriesMs: shellDurationApiWithoutRetriesMs,
|
|
3925
|
+
}),
|
|
3926
|
+
...(combinedToolDurationMs === 0
|
|
3927
|
+
? {}
|
|
3928
|
+
: { toolDurationMs: combinedToolDurationMs }),
|
|
3929
|
+
});
|
|
3930
|
+
if (foregroundLineChanges.linesAdded !== 0 ||
|
|
3931
|
+
foregroundLineChanges.linesRemoved !== 0) {
|
|
3932
|
+
tracker.recordLineChanges({
|
|
3933
|
+
...(foregroundLineChanges.linesAdded === 0
|
|
3934
|
+
? {}
|
|
3935
|
+
: { linesAdded: foregroundLineChanges.linesAdded }),
|
|
3936
|
+
...(foregroundLineChanges.linesRemoved === 0
|
|
3937
|
+
? {}
|
|
3938
|
+
: { linesRemoved: foregroundLineChanges.linesRemoved }),
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
turnCompleted = true;
|
|
3942
|
+
return {
|
|
3943
|
+
sessionId,
|
|
3944
|
+
text: '',
|
|
3945
|
+
usage: totalUsage,
|
|
3946
|
+
...(rawCostUsd === undefined ? {} : { costUsd: rawCostUsd }),
|
|
3947
|
+
...(turnModelUsage ? { modelUsage: { ...turnModelUsage } } : {}),
|
|
3948
|
+
...(shellDurationApiMs === undefined
|
|
3949
|
+
? {}
|
|
3950
|
+
: { durationApiMs: shellDurationApiMs }),
|
|
3951
|
+
};
|
|
3952
|
+
}
|
|
3953
|
+
if (shellCommand === undefined && budget) {
|
|
3876
3954
|
await contextEngine.prepare(contextTransitionPort([], currentTurnUserMessages ?? []), signal);
|
|
3877
3955
|
budget.assertFits(budget.evaluate([
|
|
3878
3956
|
...contextMessages,
|
|
@@ -3911,7 +3989,9 @@ export class ClaudeSessionService {
|
|
|
3911
3989
|
];
|
|
3912
3990
|
}
|
|
3913
3991
|
await refreshRuntimeContext?.();
|
|
3914
|
-
|
|
3992
|
+
if (shellCommand === undefined) {
|
|
3993
|
+
await contextEngine.prepare(contextTransitionPort([], currentTurnUserMessages ?? []), signal);
|
|
3994
|
+
}
|
|
3915
3995
|
runtimeRequest.stableSystemMessageCount = stableSystemMessageCount;
|
|
3916
3996
|
return [
|
|
3917
3997
|
...contextMessages,
|
|
@@ -35,8 +35,15 @@ export interface TopLevelAgentManagerOptions {
|
|
|
35
35
|
cliPath: string;
|
|
36
36
|
executablePath?: string;
|
|
37
37
|
environment?: NodeJS.ProcessEnv;
|
|
38
|
+
resolveProviderEnvironment?: (request: {
|
|
39
|
+
cwd: string;
|
|
40
|
+
argv: readonly string[];
|
|
41
|
+
}) => Promise<ProviderEnvironmentOverride>;
|
|
38
42
|
version: string;
|
|
39
43
|
}
|
|
44
|
+
export interface ProviderEnvironmentOverride {
|
|
45
|
+
PRAXIS_API_KEY?: string;
|
|
46
|
+
}
|
|
40
47
|
export declare function topLevelAgentProcessRegistryRoot(configRoot: string, dataPlane?: DataPlane): string;
|
|
41
48
|
export declare class TopLevelAgentManager {
|
|
42
49
|
private readonly options;
|
|
@@ -24,8 +24,11 @@ const SOCKET_RETRY_INTERVAL_MS = 25;
|
|
|
24
24
|
// own provider from the same CLI/environment contract.
|
|
25
25
|
const WORKER_RUNTIME_ENVIRONMENT = [
|
|
26
26
|
'PRAXIS_API_KEY',
|
|
27
|
+
'CLAUDE_CODE_SIMPLE',
|
|
27
28
|
'PRAXIS_MODEL',
|
|
28
29
|
'PRAXIS_PROVIDER',
|
|
30
|
+
'PRAXIS_PROVIDER_PROFILE',
|
|
31
|
+
'PRAXIS_PROVIDER_DEADLINE_MS',
|
|
29
32
|
'PRAXIS_BASE_URL',
|
|
30
33
|
'PRAXIS_MAX_OUTPUT_TOKENS',
|
|
31
34
|
'PRAXIS_ANTHROPIC_VERSION',
|
|
@@ -38,10 +41,11 @@ const WORKER_RUNTIME_ENVIRONMENT = [
|
|
|
38
41
|
'PRAXIS_FILES_BASE_URL',
|
|
39
42
|
'PRAXIS_FILES_BEARER_TOKEN',
|
|
40
43
|
'PRAXIS_FILES_API_KEY',
|
|
44
|
+
'PRAXIS_PROVIDER_CREDENTIAL_STORE',
|
|
41
45
|
'PRAXIS_MCP_OAUTH_STORE',
|
|
42
46
|
'CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING',
|
|
43
47
|
];
|
|
44
|
-
function workerEnvironment(source, configRoot) {
|
|
48
|
+
function workerEnvironment(source, configRoot, resolved) {
|
|
45
49
|
const environment = sanitizeChildEnvironment({ PATH: source.PATH }, {});
|
|
46
50
|
for (const name of WORKER_RUNTIME_ENVIRONMENT) {
|
|
47
51
|
const value = source[name];
|
|
@@ -50,6 +54,8 @@ function workerEnvironment(source, configRoot) {
|
|
|
50
54
|
}
|
|
51
55
|
environment.PRAXIS_DATA_PLANE = 'native';
|
|
52
56
|
environment.PRAXIS_HOME = configRoot;
|
|
57
|
+
if (resolved?.PRAXIS_API_KEY !== undefined)
|
|
58
|
+
environment.PRAXIS_API_KEY = resolved.PRAXIS_API_KEY;
|
|
53
59
|
return environment;
|
|
54
60
|
}
|
|
55
61
|
function socketPath(configRoot, id) {
|
|
@@ -285,8 +291,15 @@ export class TopLevelAgentManager {
|
|
|
285
291
|
throw new Error('Could not allocate agent ID');
|
|
286
292
|
const allocatedExecution = execution;
|
|
287
293
|
let child;
|
|
294
|
+
let resolvedProviderEnvironment;
|
|
288
295
|
const failLaunch = async (error) => {
|
|
289
|
-
const
|
|
296
|
+
const sensitiveValues = [
|
|
297
|
+
...sensitiveEnvironmentValues(this.options.environment ?? process.env),
|
|
298
|
+
...(resolvedProviderEnvironment?.PRAXIS_API_KEY === undefined
|
|
299
|
+
? []
|
|
300
|
+
: [resolvedProviderEnvironment.PRAXIS_API_KEY]),
|
|
301
|
+
];
|
|
302
|
+
const message = redactSensitiveText(error instanceof Error ? error.message : String(error), sensitiveValues);
|
|
290
303
|
const secondary = [];
|
|
291
304
|
if (child?.pid !== undefined) {
|
|
292
305
|
try {
|
|
@@ -321,9 +334,14 @@ export class TopLevelAgentManager {
|
|
|
321
334
|
throw new AggregateError([error, ...secondary], 'Could not start background agent');
|
|
322
335
|
};
|
|
323
336
|
try {
|
|
337
|
+
resolvedProviderEnvironment =
|
|
338
|
+
await this.options.resolveProviderEnvironment?.({
|
|
339
|
+
cwd,
|
|
340
|
+
argv: options.argv,
|
|
341
|
+
});
|
|
324
342
|
child = spawn(this.options.executablePath ?? process.execPath, [this.options.cliPath, '__background-worker', identity.id], {
|
|
325
343
|
cwd,
|
|
326
|
-
env: workerEnvironment(this.options.environment ?? process.env, this.options.configRoot),
|
|
344
|
+
env: workerEnvironment(this.options.environment ?? process.env, this.options.configRoot, resolvedProviderEnvironment),
|
|
327
345
|
detached: true,
|
|
328
346
|
stdio: 'ignore',
|
|
329
347
|
});
|
package/dist/cli/controls.js
CHANGED
|
@@ -206,6 +206,10 @@ export async function resolveCliControls(controls, cwd) {
|
|
|
206
206
|
name: controls.name,
|
|
207
207
|
sessionPersistence: controls.sessionPersistence,
|
|
208
208
|
...(controls.model === undefined ? {} : { model: controls.model }),
|
|
209
|
+
...(controls.provider === undefined ? {} : { provider: controls.provider }),
|
|
210
|
+
...(controls.providerProfile === undefined
|
|
211
|
+
? {}
|
|
212
|
+
: { providerProfile: controls.providerProfile }),
|
|
209
213
|
...(controls.effort === undefined ? {} : { effort: controls.effort }),
|
|
210
214
|
...(controls.thinking === undefined ? {} : { thinking: controls.thinking }),
|
|
211
215
|
...(controls.maxThinkingTokens === undefined
|
package/dist/cli/interactive.js
CHANGED
|
@@ -3240,7 +3240,9 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
3240
3240
|
streamingFrameRef.current?.resetText();
|
|
3241
3241
|
streamingFrameRef.current?.resetThinking();
|
|
3242
3242
|
streamingFrameRef.current?.flush();
|
|
3243
|
-
|
|
3243
|
+
if (shellCommand === undefined) {
|
|
3244
|
+
append({ kind: 'assistant', text: result.text });
|
|
3245
|
+
}
|
|
3244
3246
|
if (turnMutatedFilesRef.current) {
|
|
3245
3247
|
try {
|
|
3246
3248
|
const snapshot = await loadDiffSnapshot();
|
package/dist/cli/protocol.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export interface CliControls {
|
|
|
52
52
|
rewindFiles?: string;
|
|
53
53
|
name: string | undefined;
|
|
54
54
|
sessionPersistence: boolean;
|
|
55
|
+
provider?: string;
|
|
56
|
+
providerProfile?: string;
|
|
55
57
|
model?: string;
|
|
56
58
|
effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
57
59
|
thinking?: CliThinkingMode;
|
|
@@ -114,6 +116,9 @@ export interface CliInvocation extends CliControls {
|
|
|
114
116
|
mcpClientSecret: boolean;
|
|
115
117
|
mcpNoBrowser: boolean;
|
|
116
118
|
mcpDebug: boolean;
|
|
119
|
+
/** Auth-command-only profile selector; distinct from providerProfile. */
|
|
120
|
+
authProfile?: string;
|
|
121
|
+
authDevice: boolean;
|
|
117
122
|
}
|
|
118
123
|
export interface StreamUserMessage {
|
|
119
124
|
message: {
|
package/dist/cli/protocol.js
CHANGED
|
@@ -387,6 +387,8 @@ export function parseCliInvocation(argv) {
|
|
|
387
387
|
let worktreeRequested = false;
|
|
388
388
|
let tmux;
|
|
389
389
|
let model;
|
|
390
|
+
let provider;
|
|
391
|
+
let providerProfile;
|
|
390
392
|
let effort;
|
|
391
393
|
let thinking;
|
|
392
394
|
let maxThinkingTokens;
|
|
@@ -404,6 +406,8 @@ export function parseCliInvocation(argv) {
|
|
|
404
406
|
let mcpClientSecret = false;
|
|
405
407
|
let mcpNoBrowser = false;
|
|
406
408
|
let mcpDebug = false;
|
|
409
|
+
let authProfile;
|
|
410
|
+
let authDevice = false;
|
|
407
411
|
for (let index = 0; index < argv.length; index += 1) {
|
|
408
412
|
const value = argv[index];
|
|
409
413
|
if (value === undefined)
|
|
@@ -444,6 +448,30 @@ export function parseCliInvocation(argv) {
|
|
|
444
448
|
index += selectedModel.consumed;
|
|
445
449
|
continue;
|
|
446
450
|
}
|
|
451
|
+
const selectedProvider = optionValue(argv, index, '--provider');
|
|
452
|
+
if (selectedProvider) {
|
|
453
|
+
if (provider !== undefined)
|
|
454
|
+
throw new Error('--provider may only be specified once');
|
|
455
|
+
provider = selectedProvider.value;
|
|
456
|
+
index += selectedProvider.consumed;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const selectedProviderProfile = optionValue(argv, index, '--provider-profile');
|
|
460
|
+
if (selectedProviderProfile) {
|
|
461
|
+
if (providerProfile !== undefined)
|
|
462
|
+
throw new Error('--provider-profile may only be specified once');
|
|
463
|
+
providerProfile = selectedProviderProfile.value;
|
|
464
|
+
index += selectedProviderProfile.consumed;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
const selectedAuthProfile = optionValue(argv, index, '--profile');
|
|
468
|
+
if (selectedAuthProfile) {
|
|
469
|
+
if (authProfile !== undefined)
|
|
470
|
+
throw new Error('--profile may only be specified once');
|
|
471
|
+
authProfile = selectedAuthProfile.value;
|
|
472
|
+
index += selectedAuthProfile.consumed;
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
447
475
|
const selectedAutocompact = optionValue(argv, index, '--autocompact');
|
|
448
476
|
if (selectedAutocompact) {
|
|
449
477
|
if (autocompact !== undefined)
|
|
@@ -1123,6 +1151,10 @@ export function parseCliInvocation(argv) {
|
|
|
1123
1151
|
mcpNoBrowser = true;
|
|
1124
1152
|
continue;
|
|
1125
1153
|
}
|
|
1154
|
+
if (value === '--device') {
|
|
1155
|
+
authDevice = true;
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1126
1158
|
if (value === '--json') {
|
|
1127
1159
|
legacyJson = true;
|
|
1128
1160
|
continue;
|
|
@@ -1174,6 +1206,14 @@ export function parseCliInvocation(argv) {
|
|
|
1174
1206
|
if (debug !== undefined && args[0] === 'mcp' && args[1] === 'serve') {
|
|
1175
1207
|
mcpDebug = true;
|
|
1176
1208
|
}
|
|
1209
|
+
if (authProfile !== undefined && args[0] !== 'auth')
|
|
1210
|
+
throw new Error('--profile is only valid with auth commands');
|
|
1211
|
+
if (authDevice && !(args[0] === 'auth' && args[1] === 'login'))
|
|
1212
|
+
throw new Error('--device is only valid with auth login');
|
|
1213
|
+
if (mcpNoBrowser &&
|
|
1214
|
+
!((args[0] === 'mcp' && args[1] === 'login') ||
|
|
1215
|
+
(args[0] === 'auth' && args[1] === 'login')))
|
|
1216
|
+
throw new Error('--no-browser is only valid with mcp login or auth login');
|
|
1177
1217
|
if (background && print) {
|
|
1178
1218
|
throw new Error("--bg and --print conflict: --print never starts the interactive session that `claude agents` attaches to, so the job would be unattachable. The prompt is the positional — drop --print: `claude --bg '<task>'`.");
|
|
1179
1219
|
}
|
|
@@ -1215,6 +1255,7 @@ export function parseCliInvocation(argv) {
|
|
|
1215
1255
|
'plugin',
|
|
1216
1256
|
'doctor',
|
|
1217
1257
|
'import',
|
|
1258
|
+
'auth',
|
|
1218
1259
|
].includes(args[0] ?? '');
|
|
1219
1260
|
if (promptSuggestions &&
|
|
1220
1261
|
!managementCommand &&
|
|
@@ -1385,6 +1426,8 @@ export function parseCliInvocation(argv) {
|
|
|
1385
1426
|
...(worktreeRequested ? { worktreeRequested: true } : {}),
|
|
1386
1427
|
...(tmux === undefined ? {} : { tmux }),
|
|
1387
1428
|
...(model === undefined ? {} : { model }),
|
|
1429
|
+
...(provider === undefined ? {} : { provider }),
|
|
1430
|
+
...(providerProfile === undefined ? {} : { providerProfile }),
|
|
1388
1431
|
...(effort === undefined ? {} : { effort }),
|
|
1389
1432
|
...(thinking === undefined ? {} : { thinking }),
|
|
1390
1433
|
...(maxThinkingTokens === undefined ? {} : { maxThinkingTokens }),
|
|
@@ -1402,6 +1445,8 @@ export function parseCliInvocation(argv) {
|
|
|
1402
1445
|
mcpClientSecret,
|
|
1403
1446
|
mcpNoBrowser,
|
|
1404
1447
|
mcpDebug,
|
|
1448
|
+
...(authProfile === undefined ? {} : { authProfile }),
|
|
1449
|
+
authDevice,
|
|
1405
1450
|
};
|
|
1406
1451
|
}
|
|
1407
1452
|
function parseUserMessage(value, lineNumber) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ProviderCredentialKey, type ProviderCredentialMetadata, type ProviderCredentialInput, type ProviderCredentialRecord } from '../persistence/provider-credential-vault.js';
|
|
2
|
+
import { deviceLoginWithCodexOAuth, loginWithCodexOAuth } from '../providers/codex-oauth.js';
|
|
3
|
+
export interface ProviderAuthCommandIO {
|
|
4
|
+
stdout(message: string): void;
|
|
5
|
+
stderr?(message: string): void;
|
|
6
|
+
readSecret?(prompt: string, signal?: AbortSignal): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
export interface ProviderAuthVault {
|
|
9
|
+
read(key: ProviderCredentialKey): Promise<ProviderCredentialRecord | undefined>;
|
|
10
|
+
list(): Promise<ProviderCredentialMetadata[]>;
|
|
11
|
+
modify(key: ProviderCredentialKey, callback: (current: ProviderCredentialRecord | undefined) => ProviderCredentialInput | undefined | Promise<ProviderCredentialInput | undefined>): Promise<ProviderCredentialRecord | undefined>;
|
|
12
|
+
delete(key: ProviderCredentialKey): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface ProviderAuthCommandOptions {
|
|
15
|
+
io: ProviderAuthCommandIO;
|
|
16
|
+
vault?: ProviderAuthVault;
|
|
17
|
+
configRoot?: string;
|
|
18
|
+
cwd?: string;
|
|
19
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
profile?: string;
|
|
22
|
+
providerProfile?: string;
|
|
23
|
+
noBrowser?: boolean;
|
|
24
|
+
json?: boolean;
|
|
25
|
+
device?: boolean;
|
|
26
|
+
loginWithCodexOAuth?: typeof loginWithCodexOAuth;
|
|
27
|
+
deviceLoginWithCodexOAuth?: typeof deviceLoginWithCodexOAuth;
|
|
28
|
+
assertCodexLoginEnabled?: (profileId: string) => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export declare function secretLine(value: string): string;
|
|
31
|
+
export declare function executeProviderAuthCommand(args: readonly string[], options: ProviderAuthCommandOptions): Promise<number>;
|
|
32
|
+
//# sourceMappingURL=provider-auth-command.d.ts.map
|