@agentproto/driver-agent-cli 0.3.0 → 1.0.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/LICENSE +202 -21
- package/dist/{chunk-KHHRPQ2Q.mjs → chunk-XTZNZ7MA.mjs} +237 -28
- package/dist/chunk-XTZNZ7MA.mjs.map +1 -0
- package/dist/index.d.ts +22 -5
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/manifest/index.d.ts +2 -2
- package/dist/manifest/index.mjs +2 -2
- package/dist/{schema-Ds8jc9fL.d.ts → schema-D_7v0nav.d.ts} +342 -2
- package/package.json +4 -4
- package/dist/chunk-KHHRPQ2Q.mjs.map +0 -1
|
@@ -150,6 +150,11 @@ var authSchema = z.object({
|
|
|
150
150
|
grace_s: z.number().int().nonnegative().optional()
|
|
151
151
|
}).strict().optional()
|
|
152
152
|
}).strict();
|
|
153
|
+
var authSubscriptionSchema = z.object({
|
|
154
|
+
setEnv: z.string().min(1),
|
|
155
|
+
conflictEnv: z.array(z.string()).optional(),
|
|
156
|
+
unsetEnvAdd: z.array(z.string()).optional()
|
|
157
|
+
}).strict();
|
|
153
158
|
var sessionSchema = z.object({
|
|
154
159
|
mode: z.enum(["ephemeral", "persistent", "resumable"]).default("ephemeral"),
|
|
155
160
|
idle_timeout_ms: z.number().int().min(1e3).default(6e5),
|
|
@@ -164,6 +169,10 @@ var sessionSchema = z.object({
|
|
|
164
169
|
var modelsSchema = z.object({
|
|
165
170
|
default: z.string().optional(),
|
|
166
171
|
allowed: z.array(z.string()).optional(),
|
|
172
|
+
// Model-id patterns the adapter must never route to (case-insensitive,
|
|
173
|
+
// trailing `*` = prefix match). Enforced at compose time — see
|
|
174
|
+
// AgentCliModels.deny. Reserves premium providers for dedicated adapters.
|
|
175
|
+
deny: z.array(z.string()).optional(),
|
|
167
176
|
env: z.record(z.string(), z.string()).optional(),
|
|
168
177
|
// How a model is selected at session start: "config" (ACP
|
|
169
178
|
// set_config_option, default) | "command" (a `/model <id>` control turn,
|
|
@@ -190,8 +199,21 @@ var capabilitiesSchema = z.object({
|
|
|
190
199
|
var modeSchema = z.object({
|
|
191
200
|
id: z.string().regex(MODE_ID_PATTERN),
|
|
192
201
|
description: z.string().optional(),
|
|
202
|
+
bin_args_prepend: z.array(z.string()).optional(),
|
|
193
203
|
bin_args_append: z.array(z.string()).optional(),
|
|
194
|
-
env: z.record(z.string(), z.string()).optional()
|
|
204
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
205
|
+
// Env keys to DELETE from the spawn env (auth hygiene for gateway
|
|
206
|
+
// modes — see AgentCliMode.env_unset). Applied at the runtime merge
|
|
207
|
+
// point, not as a static set.
|
|
208
|
+
env_unset: z.array(z.string()).optional(),
|
|
209
|
+
// Honest support status surfaced to clients. Absent ⇒ "active".
|
|
210
|
+
status: z.enum(["active", "noop", "planned"]).optional(),
|
|
211
|
+
status_note: z.string().optional(),
|
|
212
|
+
// How the host activates this mode: "bin_args" (default, argv/env
|
|
213
|
+
// composed at spawn) | "config" (no CLI surface — forwarded to the ACP
|
|
214
|
+
// arm's connect({mode}) and applied via session/set_config_option
|
|
215
|
+
// configId:"mode", e.g. opencode).
|
|
216
|
+
apply: z.enum(["bin_args", "config"]).optional()
|
|
195
217
|
}).strict();
|
|
196
218
|
var optionSchema = z.object({
|
|
197
219
|
id: z.string().regex(OPTION_ID_PATTERN),
|
|
@@ -201,9 +223,14 @@ var optionSchema = z.object({
|
|
|
201
223
|
default: z.union([z.boolean(), z.number(), z.string()]).optional(),
|
|
202
224
|
min: z.number().int().optional(),
|
|
203
225
|
max: z.number().int().optional(),
|
|
226
|
+
bin_args_prepend: z.array(z.string()).optional(),
|
|
204
227
|
bin_args_template: z.array(z.string()).optional(),
|
|
205
228
|
bin_args_append_when_true: z.array(z.string()).optional(),
|
|
206
|
-
env: z.record(z.string(), z.string()).optional()
|
|
229
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
230
|
+
// Env keys to DELETE from the spawn env when this option is active
|
|
231
|
+
// (auth hygiene for value-bearing gateway options — see
|
|
232
|
+
// AgentCliOption.env_unset). Symmetric with modeSchema.env_unset.
|
|
233
|
+
env_unset: z.array(z.string()).optional()
|
|
207
234
|
}).strict().refine(
|
|
208
235
|
// type === "enum" REQUIRES an `enum` array. The JSON Schema enforces
|
|
209
236
|
// this via `if/then`; the zod side mirrors with a refine so both
|
|
@@ -211,6 +238,17 @@ var optionSchema = z.object({
|
|
|
211
238
|
(o) => o.type !== "enum" || Array.isArray(o.enum) && o.enum.length > 0,
|
|
212
239
|
{ message: "option.type === 'enum' requires a non-empty `enum` array" }
|
|
213
240
|
);
|
|
241
|
+
var presetSchema = z.object({
|
|
242
|
+
id: z.string().min(1),
|
|
243
|
+
label: z.string().min(1),
|
|
244
|
+
description: z.string().optional(),
|
|
245
|
+
schemaFlavor: z.enum(["anthropic", "openai"]),
|
|
246
|
+
baseUrl: z.string().min(1),
|
|
247
|
+
keyEnv: z.string().min(1),
|
|
248
|
+
scrubEnv: z.array(z.string()).optional(),
|
|
249
|
+
defaultModel: z.string().optional(),
|
|
250
|
+
homepage: z.string().optional()
|
|
251
|
+
}).strict();
|
|
214
252
|
var continuationStrategyIdSchema = z.enum(CONTINUATION_STRATEGY_IDS);
|
|
215
253
|
var continuationSchema = z.object({
|
|
216
254
|
default: continuationStrategyIdSchema,
|
|
@@ -250,10 +288,19 @@ var agentCliFrontmatterSchema = z.object({
|
|
|
250
288
|
version: z.string().regex(SEMVER_PATTERN),
|
|
251
289
|
bin: z.string().regex(BIN_PATTERN),
|
|
252
290
|
bin_args: z.array(z.string()).optional(),
|
|
291
|
+
// Always-on spawn env (merged before mode/option env, which can
|
|
292
|
+
// override). See AgentCliDefinition.env — used by generic ACP agents.
|
|
293
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
253
294
|
install: z.array(installMethodSchema).min(1),
|
|
254
295
|
version_check: versionCheckSchema,
|
|
255
296
|
setup: z.array(setupStepSchema).optional(),
|
|
256
297
|
auth: authSchema.optional(),
|
|
298
|
+
// Billing-auth resolver inputs (DECISION 3). `provider` is a CatalogProvider
|
|
299
|
+
// id (validated against the catalog by the runtime resolver, not here, to
|
|
300
|
+
// keep this generic doctype decoupled from @agentproto/model-catalog).
|
|
301
|
+
provider: z.string().min(1).optional(),
|
|
302
|
+
authSubscription: authSubscriptionSchema.optional(),
|
|
303
|
+
authEnforce: z.enum(["always", "when-configured"]).optional(),
|
|
257
304
|
sandbox: z.union([z.string(), z.record(z.string(), z.unknown())]),
|
|
258
305
|
runner: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
259
306
|
protocol: z.enum(["acp", "mcp", "proprietary", "print"]),
|
|
@@ -266,6 +313,9 @@ var agentCliFrontmatterSchema = z.object({
|
|
|
266
313
|
capabilities: capabilitiesSchema.optional(),
|
|
267
314
|
modes: z.array(modeSchema).optional(),
|
|
268
315
|
options: z.array(optionSchema).optional(),
|
|
316
|
+
// AIP-45 gateway presets this adapter can drive (merged into the
|
|
317
|
+
// provider-preset catalog; built-in wins on id collision).
|
|
318
|
+
presets: z.array(presetSchema).optional(),
|
|
269
319
|
continuation: continuationSchema.optional(),
|
|
270
320
|
requires: z.object({
|
|
271
321
|
os: z.array(z.enum(["darwin", "linux", "windows"])).optional(),
|
|
@@ -386,11 +436,17 @@ function createAcpProtocolArm(options) {
|
|
|
386
436
|
},
|
|
387
437
|
onActivity: opts.onActivity,
|
|
388
438
|
turnIdleTimeoutMs: opts.turnIdleTimeoutMs,
|
|
439
|
+
// Permission-hold mode: surface + park requests for the daemon inbox
|
|
440
|
+
// instead of auto-answering them in-arm (see AcpProtocolOptions).
|
|
441
|
+
...options.permissionHold ? { permissionHold: true } : {},
|
|
389
442
|
// Wire the permission handler so the agent's `session/request_permission`
|
|
390
443
|
// callbacks get a real answer instead of bubbling up as
|
|
391
444
|
// "AcpClient.requestPermission: no handler configured" → which
|
|
392
445
|
// surfaces in the chat as an opaque "Internal error" when the
|
|
393
446
|
// agent tries to Write / Bash anything gated.
|
|
447
|
+
// `params` is contextually typed as the SDK's `RequestPermissionRequest`
|
|
448
|
+
// (via `AcpClientOptions.handlers`), which is assignable to
|
|
449
|
+
// `AcpPermissionRequestParams` — so no cast is needed on either side.
|
|
394
450
|
handlers: {
|
|
395
451
|
requestPermission: async (params) => permissionHandler(params)
|
|
396
452
|
}
|
|
@@ -406,7 +462,8 @@ function createAcpProtocolArm(options) {
|
|
|
406
462
|
cwd,
|
|
407
463
|
mcpServers: opts.mcpServers,
|
|
408
464
|
...opts.model ? { model: opts.model } : {},
|
|
409
|
-
...opts.effort ? { effort: opts.effort } : {}
|
|
465
|
+
...opts.effort ? { effort: opts.effort } : {},
|
|
466
|
+
...opts.mode ? { mode: opts.mode } : {}
|
|
410
467
|
});
|
|
411
468
|
}
|
|
412
469
|
},
|
|
@@ -425,6 +482,9 @@ function createAcpProtocolArm(options) {
|
|
|
425
482
|
if (!session) return;
|
|
426
483
|
await session.cancel();
|
|
427
484
|
},
|
|
485
|
+
respondPermission(requestId, resolution) {
|
|
486
|
+
return client?.respondPermission(requestId, resolution) ?? false;
|
|
487
|
+
},
|
|
428
488
|
async close() {
|
|
429
489
|
if (session) await session.close();
|
|
430
490
|
if (client) await client.close();
|
|
@@ -493,22 +553,26 @@ function createPrintSession(opts) {
|
|
|
493
553
|
try {
|
|
494
554
|
if (!child.stdout)
|
|
495
555
|
throw new Error("print-arm: child has no stdout pipe");
|
|
496
|
-
const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
497
556
|
let capturedSessionId = "";
|
|
498
557
|
const mastraState = eventSchema === "mastra-jsonl" ? createMastraMapperState() : void 0;
|
|
499
|
-
|
|
500
|
-
|
|
558
|
+
const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
559
|
+
const queue = new EventQueue();
|
|
560
|
+
rl.on("line", (line) => {
|
|
561
|
+
if (!line.trim()) return;
|
|
501
562
|
let evt;
|
|
502
563
|
try {
|
|
503
564
|
evt = JSON.parse(line);
|
|
504
565
|
} catch {
|
|
505
|
-
|
|
566
|
+
return;
|
|
506
567
|
}
|
|
507
568
|
const csid = captureSessionId(evt, eventSchema);
|
|
508
569
|
if (csid) capturedSessionId = csid;
|
|
509
570
|
const sid = capturedSessionId || sessionId || "";
|
|
510
571
|
const mapped = mapEvent(evt, sid, stderrLines, eventSchema, mastraState);
|
|
511
|
-
if (
|
|
572
|
+
if (mapped) queue.push(mapped);
|
|
573
|
+
});
|
|
574
|
+
rl.once("close", () => queue.end());
|
|
575
|
+
for await (const mapped of queue) {
|
|
512
576
|
yield mapped;
|
|
513
577
|
}
|
|
514
578
|
const exitCode = await waitForExit(child);
|
|
@@ -774,6 +838,37 @@ function mapMastraEvent(evt, sessionId, stderrLines, state) {
|
|
|
774
838
|
}
|
|
775
839
|
};
|
|
776
840
|
}
|
|
841
|
+
// ── Token usage ─────────────────────────────────────────────
|
|
842
|
+
// Mastra Code DOES expose usage: its `AgentController` emits a native
|
|
843
|
+
// `usage_update` event ({ type: "usage_update", usage: TokenUsage })
|
|
844
|
+
// on every model step-finish — verified against @mastra/core 1.48.0's
|
|
845
|
+
// AgentControllerEvent union and its emit site
|
|
846
|
+
// (`this.#session.emit({ type: "usage_update", usage: stepUsage })`).
|
|
847
|
+
// `TokenUsage` carries `{ promptTokens, completionTokens, totalTokens }`.
|
|
848
|
+
// Map it to this repo's `usage_update` StreamEvent (the SAME shape
|
|
849
|
+
// claude-code emits over ACP) so mastracode sessions — both the print
|
|
850
|
+
// arm and the in-process arm, which share this mapper — carry token
|
|
851
|
+
// telemetry in the transcript. mastracode reports these cumulatively
|
|
852
|
+
// (its own headless `runMC` result-usage is last-write-wins over these
|
|
853
|
+
// events), and last-write-wins on the descriptor matches that. It
|
|
854
|
+
// carries no context-window size/used or per-turn cost here, so those
|
|
855
|
+
// stay 0 / absent (projectEvent guards on >0, never clobbering a real
|
|
856
|
+
// size).
|
|
857
|
+
case "usage_update": {
|
|
858
|
+
const usage = evt.usage;
|
|
859
|
+
const promptTokens = typeof usage?.promptTokens === "number" ? usage.promptTokens : void 0;
|
|
860
|
+
const completionTokens = typeof usage?.completionTokens === "number" ? usage.completionTokens : void 0;
|
|
861
|
+
if (promptTokens === void 0 && completionTokens === void 0)
|
|
862
|
+
return null;
|
|
863
|
+
return {
|
|
864
|
+
kind: "usage_update",
|
|
865
|
+
sessionId,
|
|
866
|
+
size: 0,
|
|
867
|
+
used: 0,
|
|
868
|
+
...promptTokens !== void 0 ? { tokensIn: promptTokens } : {},
|
|
869
|
+
...completionTokens !== void 0 ? { tokensOut: completionTokens } : {}
|
|
870
|
+
};
|
|
871
|
+
}
|
|
777
872
|
// ── Shell output (tool-like) ────────────────────────────────
|
|
778
873
|
case "shell_output":
|
|
779
874
|
return typeof evt.output === "string" ? {
|
|
@@ -794,6 +889,45 @@ function mapMastraEvent(evt, sessionId, stderrLines, state) {
|
|
|
794
889
|
return null;
|
|
795
890
|
}
|
|
796
891
|
}
|
|
892
|
+
var QUEUE_HIGH_WATER_MARK = 1e4;
|
|
893
|
+
var EventQueue = class {
|
|
894
|
+
buffer = [];
|
|
895
|
+
resolveNext = null;
|
|
896
|
+
ended = false;
|
|
897
|
+
highWaterWarned = false;
|
|
898
|
+
push(evt) {
|
|
899
|
+
this.buffer.push(evt);
|
|
900
|
+
if (this.buffer.length > QUEUE_HIGH_WATER_MARK && !this.highWaterWarned) {
|
|
901
|
+
this.highWaterWarned = true;
|
|
902
|
+
console.warn(
|
|
903
|
+
`print-arm: event backlog exceeded ${QUEUE_HIGH_WATER_MARK} buffered events \u2014 downstream consumer is not keeping up. The child's stdout is still being drained (no ENOBUFS), but memory will grow until the consumer catches up.`
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
const resolve = this.resolveNext;
|
|
907
|
+
this.resolveNext = null;
|
|
908
|
+
resolve?.();
|
|
909
|
+
}
|
|
910
|
+
/** Signal that no further events will be pushed. */
|
|
911
|
+
end() {
|
|
912
|
+
this.ended = true;
|
|
913
|
+
const resolve = this.resolveNext;
|
|
914
|
+
this.resolveNext = null;
|
|
915
|
+
resolve?.();
|
|
916
|
+
}
|
|
917
|
+
async *[Symbol.asyncIterator]() {
|
|
918
|
+
for (; ; ) {
|
|
919
|
+
const evt = this.buffer.shift();
|
|
920
|
+
if (evt !== void 0) {
|
|
921
|
+
yield evt;
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
if (this.ended) return;
|
|
925
|
+
await new Promise((resolve) => {
|
|
926
|
+
this.resolveNext = resolve;
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
};
|
|
797
931
|
function mapMastraFinishReason(raw) {
|
|
798
932
|
switch (raw) {
|
|
799
933
|
case "complete":
|
|
@@ -847,9 +981,16 @@ var RuntimeConfigError = class extends Error {
|
|
|
847
981
|
}
|
|
848
982
|
};
|
|
849
983
|
function composeSpawn(handle, config) {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
984
|
+
if (!config)
|
|
985
|
+
return {
|
|
986
|
+
binArgs: [...handle.bin_args ?? []],
|
|
987
|
+
env: { ...handle.env ?? {} },
|
|
988
|
+
envUnset: []
|
|
989
|
+
};
|
|
990
|
+
const prepend = [];
|
|
991
|
+
const append = [];
|
|
992
|
+
const env = { ...handle.env ?? {} };
|
|
993
|
+
const envUnset = [];
|
|
853
994
|
if (config.mode !== void 0) {
|
|
854
995
|
const mode = (handle.modes ?? []).find((m) => m.id === config.mode);
|
|
855
996
|
if (!mode) {
|
|
@@ -860,8 +1001,12 @@ function composeSpawn(handle, config) {
|
|
|
860
1001
|
`Mode '${config.mode}' is not declared by manifest '${handle.id}'. Known modes: ${known}`
|
|
861
1002
|
);
|
|
862
1003
|
}
|
|
863
|
-
if (mode.
|
|
864
|
-
|
|
1004
|
+
if ((mode.apply ?? "bin_args") === "bin_args") {
|
|
1005
|
+
if (mode.bin_args_prepend) prepend.push(...mode.bin_args_prepend);
|
|
1006
|
+
if (mode.bin_args_append) append.push(...mode.bin_args_append);
|
|
1007
|
+
if (mode.env) Object.assign(env, mode.env);
|
|
1008
|
+
if (mode.env_unset) envUnset.push(...mode.env_unset);
|
|
1009
|
+
}
|
|
865
1010
|
}
|
|
866
1011
|
if (config.options && Object.keys(config.options).length > 0) {
|
|
867
1012
|
const declared = handle.options ?? [];
|
|
@@ -881,8 +1026,23 @@ function composeSpawn(handle, config) {
|
|
|
881
1026
|
const value = config.options[option.id];
|
|
882
1027
|
validateOptionValue(option, value);
|
|
883
1028
|
const patch = renderOptionPatch(option, value);
|
|
884
|
-
|
|
1029
|
+
prepend.push(...patch.prepend);
|
|
1030
|
+
append.push(...patch.append);
|
|
885
1031
|
Object.assign(env, patch.env);
|
|
1032
|
+
if (patch.envUnset.length) envUnset.push(...patch.envUnset);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
const requestedModel = config.options?.model;
|
|
1036
|
+
if (typeof requestedModel === "string" && handle.models?.deny?.length) {
|
|
1037
|
+
const denyHit = handle.models.deny.find(
|
|
1038
|
+
(pattern) => matchesModelPattern(pattern, requestedModel)
|
|
1039
|
+
);
|
|
1040
|
+
if (denyHit) {
|
|
1041
|
+
throw new RuntimeConfigError(
|
|
1042
|
+
"model_denied",
|
|
1043
|
+
"config.options.model",
|
|
1044
|
+
`Model '${requestedModel}' is denied by manifest '${handle.id}' (matches deny pattern '${denyHit}'). This adapter deliberately does not route to that provider \u2014 use a permitted model or a different adapter.`
|
|
1045
|
+
);
|
|
886
1046
|
}
|
|
887
1047
|
}
|
|
888
1048
|
if (config.continuation !== void 0 && handle.continuation) {
|
|
@@ -894,12 +1054,21 @@ function composeSpawn(handle, config) {
|
|
|
894
1054
|
);
|
|
895
1055
|
}
|
|
896
1056
|
}
|
|
897
|
-
return {
|
|
1057
|
+
return {
|
|
1058
|
+
binArgs: [...prepend, ...handle.bin_args ?? [], ...append],
|
|
1059
|
+
env,
|
|
1060
|
+
envUnset
|
|
1061
|
+
};
|
|
898
1062
|
}
|
|
899
1063
|
function resolveContinuationStrategy(handle, config) {
|
|
900
1064
|
if (config?.continuation) return config.continuation;
|
|
901
1065
|
return handle.continuation?.default ?? "none";
|
|
902
1066
|
}
|
|
1067
|
+
function matchesModelPattern(pattern, modelId) {
|
|
1068
|
+
const p = pattern.toLowerCase();
|
|
1069
|
+
const m = modelId.toLowerCase();
|
|
1070
|
+
return p.endsWith("*") ? m.startsWith(p.slice(0, -1)) : m === p;
|
|
1071
|
+
}
|
|
903
1072
|
function validateOptionValue(option, value) {
|
|
904
1073
|
const path = `config.options.${option.id}`;
|
|
905
1074
|
switch (option.type) {
|
|
@@ -965,17 +1134,23 @@ function validateOptionValue(option, value) {
|
|
|
965
1134
|
function renderOptionPatch(option, value) {
|
|
966
1135
|
const stringValue = String(value);
|
|
967
1136
|
if (option.type === "boolean") {
|
|
968
|
-
if (value !== true) return {
|
|
1137
|
+
if (value !== true) return { prepend: [], append: [], env: {}, envUnset: [] };
|
|
969
1138
|
return {
|
|
970
|
-
|
|
971
|
-
|
|
1139
|
+
prepend: [],
|
|
1140
|
+
append: option.bin_args_append_when_true ? [...option.bin_args_append_when_true] : [],
|
|
1141
|
+
env: option.env ? interpolateEnv(option.env, stringValue) : {},
|
|
1142
|
+
envUnset: option.env_unset ? [...option.env_unset] : []
|
|
972
1143
|
};
|
|
973
1144
|
}
|
|
974
1145
|
return {
|
|
975
|
-
|
|
1146
|
+
prepend: option.bin_args_prepend ? option.bin_args_prepend.map(
|
|
1147
|
+
(token) => token.replace(/\{value\}/g, stringValue)
|
|
1148
|
+
) : [],
|
|
1149
|
+
append: option.bin_args_template ? option.bin_args_template.map(
|
|
976
1150
|
(token) => token.replace(/\{value\}/g, stringValue)
|
|
977
1151
|
) : [],
|
|
978
|
-
env: option.env ? interpolateEnv(option.env, stringValue) : {}
|
|
1152
|
+
env: option.env ? interpolateEnv(option.env, stringValue) : {},
|
|
1153
|
+
envUnset: option.env_unset ? [...option.env_unset] : []
|
|
979
1154
|
};
|
|
980
1155
|
}
|
|
981
1156
|
function interpolateEnv(env, value) {
|
|
@@ -1032,9 +1207,26 @@ function createAgentCliRuntime(definition) {
|
|
|
1032
1207
|
const composed = composeSpawn(definition, opts?.config);
|
|
1033
1208
|
const env = {
|
|
1034
1209
|
...filterStringEnv(process.env),
|
|
1035
|
-
...composed.env
|
|
1036
|
-
...opts?.env ?? {}
|
|
1210
|
+
...composed.env
|
|
1037
1211
|
};
|
|
1212
|
+
for (const k of composed.envUnset) delete env[k];
|
|
1213
|
+
const authSpec = opts?.auth;
|
|
1214
|
+
const hasGatewayAuthToken = "ANTHROPIC_AUTH_TOKEN" in composed.env;
|
|
1215
|
+
const engageAuth = !!authSpec && !hasGatewayAuthToken && (authSpec.enforce === "always" || authSpec.explicit === true);
|
|
1216
|
+
if (authSpec && engageAuth) {
|
|
1217
|
+
for (const key of authSpec.unsetEnv) {
|
|
1218
|
+
if (!(key in composed.env)) delete env[key];
|
|
1219
|
+
}
|
|
1220
|
+
if (!authSpec.credential) {
|
|
1221
|
+
throw new RuntimeConfigError(
|
|
1222
|
+
"missing_auth_credential",
|
|
1223
|
+
"opts.auth.credential",
|
|
1224
|
+
`agent-cli '${definition.id}': auth mode "${authSpec.mode}" requires an explicit credential (resolved from a named config/store ref), but none was provided.` + (authSpec.mode === "subscription" ? ` Mint one via \`claude setup-token\` (bills the Max/Pro subscription, not API credits) and configure it \u2014 never inherited from the shell.` : ` Configure an API key (\`agentproto auth provider set \u2026\` or per-spawn) \u2014 never inherited from the shell.`)
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
env[authSpec.setEnv] = authSpec.credential;
|
|
1228
|
+
}
|
|
1229
|
+
Object.assign(env, opts?.env ?? {});
|
|
1038
1230
|
const permissionMode = resolveClaudeCodePermissionMode(
|
|
1039
1231
|
definition,
|
|
1040
1232
|
opts?.config?.mode
|
|
@@ -1079,7 +1271,13 @@ function createAgentCliRuntime(definition) {
|
|
|
1079
1271
|
}
|
|
1080
1272
|
});
|
|
1081
1273
|
}
|
|
1082
|
-
const arm = await buildProtocolArm(
|
|
1274
|
+
const arm = await buildProtocolArm(
|
|
1275
|
+
definition,
|
|
1276
|
+
child,
|
|
1277
|
+
cwd,
|
|
1278
|
+
opts?.config?.mode,
|
|
1279
|
+
opts?.permissionHold ?? false
|
|
1280
|
+
);
|
|
1083
1281
|
arm._stderrTail = () => stderrBuf.join("\n");
|
|
1084
1282
|
const abortController = new AbortController();
|
|
1085
1283
|
if (opts?.signal) {
|
|
@@ -1091,6 +1289,9 @@ function createAgentCliRuntime(definition) {
|
|
|
1091
1289
|
const optEffort = opts?.config?.options?.effort;
|
|
1092
1290
|
const modelApply = definition.models?.apply ?? "config";
|
|
1093
1291
|
const configModel = optModel && modelApply === "config" ? String(optModel) : void 0;
|
|
1292
|
+
const requestedModeId = opts?.config?.mode;
|
|
1293
|
+
const requestedModeDecl = requestedModeId ? (definition.modes ?? []).find((m) => m.id === requestedModeId) : void 0;
|
|
1294
|
+
const configMode = requestedModeDecl?.apply === "config" ? requestedModeId : void 0;
|
|
1094
1295
|
const turnIdleTimeoutMs = opts?.turnIdleTimeoutMs ?? definition.session?.turn_idle_timeout_ms;
|
|
1095
1296
|
await arm.connect({
|
|
1096
1297
|
cwd,
|
|
@@ -1100,8 +1301,10 @@ function createAgentCliRuntime(definition) {
|
|
|
1100
1301
|
...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
|
|
1101
1302
|
...configModel ? { model: configModel } : {},
|
|
1102
1303
|
...optEffort ? { effort: String(optEffort) } : {},
|
|
1304
|
+
...configMode ? { mode: configMode } : {},
|
|
1103
1305
|
...opts?.onActivity ? { onActivity: opts.onActivity } : {},
|
|
1104
|
-
...turnIdleTimeoutMs !== void 0 ? { turnIdleTimeoutMs } : {}
|
|
1306
|
+
...turnIdleTimeoutMs !== void 0 ? { turnIdleTimeoutMs } : {},
|
|
1307
|
+
...opts?.permissionHold ? { permissionHold: true } : {}
|
|
1105
1308
|
});
|
|
1106
1309
|
if (optModel && modelApply === "command") {
|
|
1107
1310
|
await applyModelCommand(arm, String(optModel));
|
|
@@ -1117,6 +1320,11 @@ function createAgentCliRuntime(definition) {
|
|
|
1117
1320
|
async cancel() {
|
|
1118
1321
|
abortController.abort();
|
|
1119
1322
|
},
|
|
1323
|
+
...arm.respondPermission ? {
|
|
1324
|
+
respondPermission(requestId, resolution) {
|
|
1325
|
+
return arm.respondPermission(requestId, resolution);
|
|
1326
|
+
}
|
|
1327
|
+
} : {},
|
|
1120
1328
|
async close() {
|
|
1121
1329
|
await arm.close();
|
|
1122
1330
|
if (child && !child.killed) child.kill("SIGTERM");
|
|
@@ -1162,7 +1370,7 @@ async function* promptTurn(arm, turnId, message) {
|
|
|
1162
1370
|
yield evt;
|
|
1163
1371
|
}
|
|
1164
1372
|
}
|
|
1165
|
-
async function buildProtocolArm(def, child, cwd, requestedMode) {
|
|
1373
|
+
async function buildProtocolArm(def, child, cwd, requestedMode, permissionHold) {
|
|
1166
1374
|
switch (def.protocol) {
|
|
1167
1375
|
case "acp":
|
|
1168
1376
|
if (!child) {
|
|
@@ -1172,7 +1380,8 @@ async function buildProtocolArm(def, child, cwd, requestedMode) {
|
|
|
1172
1380
|
child,
|
|
1173
1381
|
cwd,
|
|
1174
1382
|
clientInfo: { name: def.id, version: def.version },
|
|
1175
|
-
requestedMode
|
|
1383
|
+
requestedMode,
|
|
1384
|
+
...permissionHold ? { permissionHold: true } : {}
|
|
1176
1385
|
});
|
|
1177
1386
|
case "mcp":
|
|
1178
1387
|
throw new Error("createAgentCliRuntime: mcp protocol arm not yet implemented");
|
|
@@ -1204,5 +1413,5 @@ function filterStringEnv(env) {
|
|
|
1204
1413
|
}
|
|
1205
1414
|
|
|
1206
1415
|
export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
1207
|
-
//# sourceMappingURL=chunk-
|
|
1208
|
-
//# sourceMappingURL=chunk-
|
|
1416
|
+
//# sourceMappingURL=chunk-XTZNZ7MA.mjs.map
|
|
1417
|
+
//# sourceMappingURL=chunk-XTZNZ7MA.mjs.map
|