@zgeoff/atc 3.5.0 → 3.6.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/package.json
CHANGED
|
@@ -58,7 +58,7 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
58
58
|
|
|
59
59
|
// A headless turn carries the same settings file the terminal spawn does,
|
|
60
60
|
// so it reaches this backend rather than the default one. A gateway whose
|
|
61
|
-
// credential comes through impd's broker runs no headless turn.
|
|
61
|
+
// credential comes through impd's broker alone runs no headless turn.
|
|
62
62
|
readonly headlessRunner: HeadlessRunner | null;
|
|
63
63
|
|
|
64
64
|
// The CLI's hooks are authoritative; no screen heuristics needed.
|
|
@@ -132,7 +132,7 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
132
132
|
);
|
|
133
133
|
|
|
134
134
|
this.headlessRunner =
|
|
135
|
-
headlessRun === null || gateway
|
|
135
|
+
headlessRun === null || isBrokerOnlyGateway(gateway)
|
|
136
136
|
? null
|
|
137
137
|
: makeClaudeHeadlessRunner(headlessRun, {
|
|
138
138
|
claudeBin: gateway.bin,
|
|
@@ -169,15 +169,16 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
169
169
|
return {
|
|
170
170
|
gateway: { id: this.gateway.id, baseURL: this.gateway.baseURL, auth },
|
|
171
171
|
profiles: this.config.authProfiles,
|
|
172
|
-
brokerRequired:
|
|
172
|
+
brokerRequired: isBrokerOnlyGateway(this.gateway),
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
// A gateway whose credential comes through impd's broker never
|
|
177
|
-
// the daemon's machine: started without the broker, the CLI
|
|
178
|
-
// whatever credential it holds to the gateway's host.
|
|
176
|
+
// A gateway whose credential comes through impd's broker alone never
|
|
177
|
+
// starts on the daemon's machine: started without the broker, the CLI
|
|
178
|
+
// would send whatever credential it holds to the gateway's host. One
|
|
179
|
+
// with a credential helper as well starts there under that helper.
|
|
179
180
|
planSpawn(opts: SpawnOptions): SpawnPlan {
|
|
180
|
-
if (this.gateway
|
|
181
|
+
if (isBrokerOnlyGateway(this.gateway)) {
|
|
181
182
|
throw this.buildBrokerRefusal('which only an imp target can give it');
|
|
182
183
|
}
|
|
183
184
|
|
|
@@ -186,7 +187,13 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
186
187
|
|
|
187
188
|
return {
|
|
188
189
|
bin: this.gateway.bin,
|
|
189
|
-
args: this.buildArgs(
|
|
190
|
+
args: this.buildArgs(
|
|
191
|
+
this.gateway.args,
|
|
192
|
+
opts,
|
|
193
|
+
modeArgs,
|
|
194
|
+
this.writeSettings(),
|
|
195
|
+
this.writeBridge(),
|
|
196
|
+
),
|
|
190
197
|
};
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -196,8 +203,9 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
196
203
|
// and placeholders in place of the credential, which the broker swaps
|
|
197
204
|
// for the real one on the host's side. A shell seeds the config folder
|
|
198
205
|
// before it runs the CLI, since a transferred file would replace the
|
|
199
|
-
// state an earlier run left.
|
|
200
|
-
//
|
|
206
|
+
// state an earlier run left. The launch takes the auth's own arguments
|
|
207
|
+
// when it sets them, and never the credential helper, which runs on the
|
|
208
|
+
// daemon's machine alone. A gateway without auth never runs remotely.
|
|
201
209
|
planGuestSpawn(opts: SpawnOptions, guest: GuestPaths): GuestSpawnPlan | null {
|
|
202
210
|
if (this.gateway.auth === undefined) {
|
|
203
211
|
return null;
|
|
@@ -244,11 +252,14 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
244
252
|
argv,
|
|
245
253
|
);
|
|
246
254
|
|
|
255
|
+
const args = this.gateway.auth.args ?? this.gateway.args;
|
|
256
|
+
|
|
247
257
|
const launch = buildClaudeGuestLaunch(guest.dir, [
|
|
248
258
|
this.gateway.bin,
|
|
249
259
|
...this.buildArgs(
|
|
260
|
+
args,
|
|
250
261
|
opts,
|
|
251
|
-
this.buildGuestModeArgs(),
|
|
262
|
+
this.buildGuestModeArgs(args),
|
|
252
263
|
`${guest.dir}/${settingsPath}`,
|
|
253
264
|
`${guest.dir}/atc-bridge`,
|
|
254
265
|
),
|
|
@@ -291,10 +302,10 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
291
302
|
// explicit flag, so that mode overrides the one the CLI would restore, and
|
|
292
303
|
// the generated settings file, because
|
|
293
304
|
// without it the CLI would resume the session against the default backend.
|
|
294
|
-
// A gateway whose credential comes through impd's broker has none,
|
|
295
|
-
// outside atc the broker never reaches it.
|
|
305
|
+
// A gateway whose credential comes through impd's broker alone has none,
|
|
306
|
+
// since outside atc the broker never reaches it.
|
|
296
307
|
buildResumeCommand(cwd: string, agentSessionID: AgentSessionID | undefined): string | null {
|
|
297
|
-
if (this.gateway
|
|
308
|
+
if (isBrokerOnlyGateway(this.gateway)) {
|
|
298
309
|
return null;
|
|
299
310
|
}
|
|
300
311
|
|
|
@@ -312,13 +323,14 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
312
323
|
}
|
|
313
324
|
|
|
314
325
|
private buildArgs(
|
|
326
|
+
args: readonly string[],
|
|
315
327
|
opts: SpawnOptions,
|
|
316
328
|
modeArgs: readonly string[],
|
|
317
329
|
settings: string,
|
|
318
330
|
pluginDir: string,
|
|
319
331
|
): string[] {
|
|
320
332
|
return [
|
|
321
|
-
...buildClaudeOverrideArgs(
|
|
333
|
+
...buildClaudeOverrideArgs(args, opts),
|
|
322
334
|
...modeArgs,
|
|
323
335
|
'--settings',
|
|
324
336
|
settings,
|
|
@@ -332,11 +344,11 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
332
344
|
|
|
333
345
|
// A brokered session's Claude config is fresh, so the CLI's own default
|
|
334
346
|
// mode would apply rather than the one the owner's settings set. Every
|
|
335
|
-
// start therefore names its mode: the one the
|
|
336
|
-
// settings set, else the CLI's manual mode, which asks before
|
|
337
|
-
// action.
|
|
338
|
-
private buildGuestModeArgs(): string[] {
|
|
339
|
-
if (findFlagValue(
|
|
347
|
+
// start therefore names its mode: the one the launch's arguments or the
|
|
348
|
+
// gateway's settings set, else the CLI's manual mode, which asks before
|
|
349
|
+
// each action.
|
|
350
|
+
private buildGuestModeArgs(args: readonly string[]): string[] {
|
|
351
|
+
if (findFlagValue(args, ['--permission-mode']) !== null) {
|
|
340
352
|
return [];
|
|
341
353
|
}
|
|
342
354
|
|
|
@@ -464,6 +476,12 @@ export class GatewayAdapter implements AgentAdapter {
|
|
|
464
476
|
}
|
|
465
477
|
}
|
|
466
478
|
|
|
479
|
+
// Whether a gateway takes its credential from impd's broker with no
|
|
480
|
+
// credential helper to fall back on, so it starts only behind the broker.
|
|
481
|
+
function isBrokerOnlyGateway(gateway: GatewayConfig): boolean {
|
|
482
|
+
return gateway.auth !== undefined && gateway.apiKeyHelper === undefined;
|
|
483
|
+
}
|
|
484
|
+
|
|
467
485
|
// The variable the Claude CLI sends as a bearer authorization header, and
|
|
468
486
|
// the value impd's broker replaces with the credential on the host's side.
|
|
469
487
|
const BEARER_VARIABLE = 'ANTHROPIC_AUTH_TOKEN';
|
|
@@ -142,6 +142,7 @@ function renderAgentEntry(entry: AgentEntry): Record<string, unknown> {
|
|
|
142
142
|
...(Object.keys(entry.auth.placeholderEnv).length > 0
|
|
143
143
|
? { placeholderEnv: entry.auth.placeholderEnv }
|
|
144
144
|
: {}),
|
|
145
|
+
...(entry.auth.args === undefined ? {} : { args: entry.auth.args }),
|
|
145
146
|
...(entry.mcpServers === undefined
|
|
146
147
|
? {}
|
|
147
148
|
: {
|
|
@@ -7,11 +7,14 @@ import { resolveAuthProfiles } from './resolve-auth-profiles';
|
|
|
7
7
|
/**
|
|
8
8
|
* The auth profiles a gateway's sessions are bound to through impd's
|
|
9
9
|
* broker, and the variables each session gets in place of a credential,
|
|
10
|
-
* every value the fixed placeholder.
|
|
10
|
+
* every value the fixed placeholder. `args`, when set, replaces the
|
|
11
|
+
* gateway's arguments on a launch behind the broker, whose host lays out
|
|
12
|
+
* its files apart from the daemon's.
|
|
11
13
|
*/
|
|
12
14
|
export interface GatewayAuth {
|
|
13
15
|
readonly profiles: readonly string[];
|
|
14
16
|
readonly placeholderEnv: Readonly<Record<string, string>>;
|
|
17
|
+
readonly args?: readonly string[];
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
/**
|
|
@@ -19,7 +22,6 @@ export interface GatewayAuth {
|
|
|
19
22
|
*/
|
|
20
23
|
interface GatewayAuthEntry {
|
|
21
24
|
readonly baseURL?: string | undefined;
|
|
22
|
-
readonly apiKeyHelper?: string | undefined;
|
|
23
25
|
readonly env: Readonly<Record<string, string>>;
|
|
24
26
|
readonly settings?: Readonly<Record<string, unknown>> | undefined;
|
|
25
27
|
}
|
|
@@ -40,15 +42,9 @@ export function checkGatewayAuth(
|
|
|
40
42
|
|
|
41
43
|
const problems: string[] = [];
|
|
42
44
|
|
|
43
|
-
if (entry.apiKeyHelper !== undefined) {
|
|
44
|
-
problems.push(
|
|
45
|
-
'apiKeyHelper cannot be set together with auth, which supplies the credential through the broker',
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
45
|
if (entry.settings?.['apiKeyHelper'] !== undefined) {
|
|
50
46
|
problems.push(
|
|
51
|
-
'settings.apiKeyHelper cannot be set together with auth
|
|
47
|
+
'settings.apiKeyHelper cannot be set together with auth; apiKeyHelper holds the credential helper of a launch without the broker',
|
|
52
48
|
);
|
|
53
49
|
}
|
|
54
50
|
|
|
@@ -128,7 +124,17 @@ function parseGatewayAuth(raw: unknown): GatewayAuth | string {
|
|
|
128
124
|
env[key] = value;
|
|
129
125
|
}
|
|
130
126
|
|
|
131
|
-
|
|
127
|
+
const args = raw['args'];
|
|
128
|
+
|
|
129
|
+
if (args === undefined) {
|
|
130
|
+
return { profiles: profiles.map(String), placeholderEnv: env };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!Array.isArray(args) || !args.every((arg) => typeof arg === 'string')) {
|
|
134
|
+
return 'auth.args must be an array of strings';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return { profiles: profiles.map(String), placeholderEnv: env, args: args.map(String) };
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
// A settings env's variable names; anything but an object sets none.
|
|
@@ -10,8 +10,10 @@ import { isRecord } from './report';
|
|
|
10
10
|
* A Claude-compatible backend the Claude CLI is pointed at: its own agent id,
|
|
11
11
|
* its own row in the spawn menu, and its own generated settings file. The
|
|
12
12
|
* credential is never held here: a helper command supplies it at run time,
|
|
13
|
-
*
|
|
14
|
-
* host's side, so it stays out of the file atc writes.
|
|
13
|
+
* and, with `auth`, impd's credential broker adds it to each request on the
|
|
14
|
+
* host's side, so it stays out of the file atc writes. A gateway with both
|
|
15
|
+
* runs the helper on the daemon's machine and takes the broker's
|
|
16
|
+
* credential on an imp.
|
|
15
17
|
*/
|
|
16
18
|
export interface GatewayConfig {
|
|
17
19
|
readonly id: AgentID;
|