@agentproto/driver-agent-cli 2.3.0 → 2.4.1
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/dist/{chunk-774L5IO5.mjs → chunk-E4MSI6PV.mjs} +117 -13
- package/dist/chunk-E4MSI6PV.mjs.map +1 -0
- package/dist/index.d.ts +35 -3
- 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-BjnfZku5.d.ts → schema-BKnQX5Sj.d.ts} +62 -5
- package/package.json +4 -4
- package/dist/chunk-774L5IO5.mjs.map +0 -1
|
@@ -4,7 +4,7 @@ import { createAcpClient } from '@agentproto/acp/client';
|
|
|
4
4
|
import { spawn } from 'child_process';
|
|
5
5
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync, mkdtempSync } from 'fs';
|
|
6
6
|
import { createInterface } from 'readline';
|
|
7
|
-
import { join } from 'path';
|
|
7
|
+
import { join, dirname, delimiter } from 'path';
|
|
8
8
|
import { tmpdir, homedir } from 'os';
|
|
9
9
|
import { loadAdapterSpawnSandboxConfig, resolveCommandSandbox } from '@agentproto/command-sandbox';
|
|
10
10
|
import { randomUUID } from 'crypto';
|
|
@@ -151,11 +151,14 @@ var authSchema = z.object({
|
|
|
151
151
|
grace_s: z.number().int().nonnegative().optional()
|
|
152
152
|
}).strict().optional()
|
|
153
153
|
}).strict();
|
|
154
|
-
var
|
|
154
|
+
var authSubscriptionEntrySchema = z.object({
|
|
155
155
|
setEnv: z.string().min(1).optional(),
|
|
156
156
|
external: z.boolean().optional(),
|
|
157
157
|
conflictEnv: z.array(z.string()).optional(),
|
|
158
|
-
unsetEnvAdd: z.array(z.string()).optional()
|
|
158
|
+
unsetEnvAdd: z.array(z.string()).optional(),
|
|
159
|
+
// Provider scope for a multi-provider adapter's bearer surface (pi's
|
|
160
|
+
// ANTHROPIC_OAUTH_TOKEN is anthropic-only) — see AgentCliAuthSubscription.
|
|
161
|
+
provider: z.string().min(1).optional()
|
|
159
162
|
}).strict().superRefine((v, ctx) => {
|
|
160
163
|
if (v.external) {
|
|
161
164
|
if (v.setEnv !== void 0) {
|
|
@@ -173,6 +176,20 @@ var authSubscriptionSchema = z.object({
|
|
|
173
176
|
});
|
|
174
177
|
}
|
|
175
178
|
});
|
|
179
|
+
var authSubscriptionSchema = z.union([authSubscriptionEntrySchema, z.array(authSubscriptionEntrySchema).min(1)]).superRefine((v, ctx) => {
|
|
180
|
+
if (!Array.isArray(v)) return;
|
|
181
|
+
const seen = /* @__PURE__ */ new Set();
|
|
182
|
+
for (const entry of v) {
|
|
183
|
+
const key = entry.provider ?? "\0unscoped";
|
|
184
|
+
if (seen.has(key)) {
|
|
185
|
+
ctx.addIssue({
|
|
186
|
+
code: z.ZodIssueCode.custom,
|
|
187
|
+
message: entry.provider ? `authSubscription: duplicate provider scope "${entry.provider}" \u2014 two entries claim the same provider, which is ambiguous at spawn time.` : "authSubscription: more than one unscoped entry (no `provider`) \u2014 ambiguous which one applies at spawn time."
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
seen.add(key);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
176
193
|
var sessionSchema = z.object({
|
|
177
194
|
mode: z.enum(["ephemeral", "persistent", "resumable"]).default("ephemeral"),
|
|
178
195
|
idle_timeout_ms: z.number().int().min(1e3).default(6e5),
|
|
@@ -493,6 +510,9 @@ function createAcpProtocolArm(options) {
|
|
|
493
510
|
get availableConfigOptions() {
|
|
494
511
|
return session?.availableConfigOptions ?? [];
|
|
495
512
|
},
|
|
513
|
+
get modelApplyRejection() {
|
|
514
|
+
return session?.modelApplyRejection;
|
|
515
|
+
},
|
|
496
516
|
get availableModes() {
|
|
497
517
|
return session?.availableModes ?? [];
|
|
498
518
|
},
|
|
@@ -646,6 +666,14 @@ async function wrapAgentCliSpawn(bin, args, opts) {
|
|
|
646
666
|
}
|
|
647
667
|
|
|
648
668
|
// src/protocol/print-arm.ts
|
|
669
|
+
function printModelMismatch(requested, reported) {
|
|
670
|
+
const basename = (id) => {
|
|
671
|
+
const noSuffix = id.split("@")[0] ?? id;
|
|
672
|
+
const segs = noSuffix.split("/");
|
|
673
|
+
return (segs[segs.length - 1] ?? noSuffix).trim().toLowerCase();
|
|
674
|
+
};
|
|
675
|
+
return basename(requested) !== basename(reported);
|
|
676
|
+
}
|
|
649
677
|
var DEFAULT_OUTPUT = ["--output-format", "stream-json"];
|
|
650
678
|
var DEFAULT_PRE_PROMPT = ["--no-interactive"];
|
|
651
679
|
var DEFAULT_RESUME = { flag: "--resume", kind: "value" };
|
|
@@ -683,6 +711,7 @@ function createPrintSession(opts) {
|
|
|
683
711
|
mode: opts.commandSandbox,
|
|
684
712
|
cwd: opts.cwd,
|
|
685
713
|
...opts.extraWritePaths ? { extraWritePaths: opts.extraWritePaths } : {},
|
|
714
|
+
...opts.extraReadPaths ? { extraReadPaths: opts.extraReadPaths } : {},
|
|
686
715
|
label: "print-arm"
|
|
687
716
|
});
|
|
688
717
|
const child = spawn(execBin, execArgs, {
|
|
@@ -725,14 +754,29 @@ function createPrintSession(opts) {
|
|
|
725
754
|
const jcodeState = eventSchema === "jcode-ndjson" ? createJcodeMapperState() : void 0;
|
|
726
755
|
const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
727
756
|
const queue = new EventQueue();
|
|
757
|
+
let modelMismatchAborted = false;
|
|
728
758
|
rl.on("line", (line) => {
|
|
729
759
|
if (!line.trim()) return;
|
|
760
|
+
if (modelMismatchAborted) return;
|
|
730
761
|
let evt;
|
|
731
762
|
try {
|
|
732
763
|
evt = JSON.parse(line);
|
|
733
764
|
} catch {
|
|
734
765
|
return;
|
|
735
766
|
}
|
|
767
|
+
if (opts.expectedModel && eventSchema === "jcode-ndjson" && evt.type === "start" && typeof evt.model === "string" && printModelMismatch(opts.expectedModel, evt.model)) {
|
|
768
|
+
modelMismatchAborted = true;
|
|
769
|
+
const provider = typeof evt.provider === "string" ? ` (provider ${evt.provider})` : "";
|
|
770
|
+
queue.push({
|
|
771
|
+
kind: "error",
|
|
772
|
+
error: {
|
|
773
|
+
message: `model mismatch: requested "${opts.expectedModel}" but the agent started on "${evt.model}"${provider} \u2014 its CLI silently fell back to a default it resolved itself. This adapter routes AND bills by the model id, so the turn was aborted instead of silently running (and billing) a model you didn't ask for. Check the id against the adapter's model menu.`
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
queue.end();
|
|
777
|
+
child.kill("SIGTERM");
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
736
780
|
const csid = captureSessionId(evt, eventSchema);
|
|
737
781
|
if (csid) capturedSessionId = csid;
|
|
738
782
|
const sid = capturedSessionId || sessionId || "";
|
|
@@ -1626,6 +1670,13 @@ function createArmSessionControls(arm, definition) {
|
|
|
1626
1670
|
}
|
|
1627
1671
|
};
|
|
1628
1672
|
}
|
|
1673
|
+
var MODEL_SWITCH_ACK_RE = /switch|model\s+set|now using/i;
|
|
1674
|
+
function isModelSwitchAcknowledgement(evt) {
|
|
1675
|
+
return MODEL_SWITCH_ACK_RE.test(JSON.stringify(evt));
|
|
1676
|
+
}
|
|
1677
|
+
function parseModelSwitchCommand(text) {
|
|
1678
|
+
return /^\s*\/model\s+(\S+)/i.exec(text)?.[1];
|
|
1679
|
+
}
|
|
1629
1680
|
async function applyModelCommand(arm, modelId) {
|
|
1630
1681
|
const turnId = randomUUID();
|
|
1631
1682
|
let acked = false;
|
|
@@ -1634,7 +1685,7 @@ async function applyModelCommand(arm, modelId) {
|
|
|
1634
1685
|
type: "text",
|
|
1635
1686
|
text: `/model ${modelId}`
|
|
1636
1687
|
})) {
|
|
1637
|
-
if (
|
|
1688
|
+
if (isModelSwitchAcknowledgement(evt)) acked = true;
|
|
1638
1689
|
}
|
|
1639
1690
|
} catch (err) {
|
|
1640
1691
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -1709,8 +1760,24 @@ var defineAgentCli = createDoctype(
|
|
|
1709
1760
|
}
|
|
1710
1761
|
}
|
|
1711
1762
|
);
|
|
1712
|
-
function resolveSpawnBin(bin) {
|
|
1713
|
-
|
|
1763
|
+
function resolveSpawnBin(bin, deps) {
|
|
1764
|
+
const execPath = process.execPath;
|
|
1765
|
+
if (bin === "node") return execPath;
|
|
1766
|
+
if (bin === "npx" || bin === "npm") {
|
|
1767
|
+
const exists = existsSync;
|
|
1768
|
+
const sibling = join(
|
|
1769
|
+
dirname(execPath),
|
|
1770
|
+
process.platform === "win32" ? `${bin}.cmd` : bin
|
|
1771
|
+
);
|
|
1772
|
+
if (exists(sibling)) return sibling;
|
|
1773
|
+
}
|
|
1774
|
+
return bin;
|
|
1775
|
+
}
|
|
1776
|
+
function ensureExecDirOnPath(env, execPath = process.execPath) {
|
|
1777
|
+
const execDir = dirname(execPath);
|
|
1778
|
+
const parts = (env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
1779
|
+
if (parts.includes(execDir)) return;
|
|
1780
|
+
env.PATH = [...parts, execDir].join(delimiter);
|
|
1714
1781
|
}
|
|
1715
1782
|
function createAgentCliRuntime(definition) {
|
|
1716
1783
|
return {
|
|
@@ -1751,6 +1818,10 @@ function createAgentCliRuntime(definition) {
|
|
|
1751
1818
|
}
|
|
1752
1819
|
}
|
|
1753
1820
|
Object.assign(env, opts?.env ?? {});
|
|
1821
|
+
ensureExecDirOnPath(env);
|
|
1822
|
+
if (opts?.additionalReadPaths?.length) {
|
|
1823
|
+
env.AGENTPROTO_ADDITIONAL_READ_PATHS = JSON.stringify(opts.additionalReadPaths);
|
|
1824
|
+
}
|
|
1754
1825
|
const permissionMode = resolveClaudeCodePermissionMode(
|
|
1755
1826
|
definition,
|
|
1756
1827
|
opts?.posture,
|
|
@@ -1793,6 +1864,7 @@ function createAgentCliRuntime(definition) {
|
|
|
1793
1864
|
env.CLAUDE_CONFIG_DIR = claudeConfigDir;
|
|
1794
1865
|
}
|
|
1795
1866
|
if (definition.protocol === "print") {
|
|
1867
|
+
const printModel = config?.options?.model;
|
|
1796
1868
|
return createPrintSession({
|
|
1797
1869
|
bin: resolvedBin,
|
|
1798
1870
|
baseArgs: composed.binArgs,
|
|
@@ -1802,7 +1874,10 @@ function createAgentCliRuntime(definition) {
|
|
|
1802
1874
|
...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
|
|
1803
1875
|
printConfig: definition.print,
|
|
1804
1876
|
commandSandbox: opts?.commandSandbox,
|
|
1805
|
-
...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {}
|
|
1877
|
+
...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
|
|
1878
|
+
// Exact-file read grant — see the ACP arm's wrapAgentCliSpawn call.
|
|
1879
|
+
...opts?.additionalReadPaths?.length ? { extraReadPaths: opts.additionalReadPaths } : {},
|
|
1880
|
+
...definition.routeSelection === "derived-from-model" && printModel ? { expectedModel: String(printModel) } : {}
|
|
1806
1881
|
});
|
|
1807
1882
|
}
|
|
1808
1883
|
let child;
|
|
@@ -1815,6 +1890,9 @@ function createAgentCliRuntime(definition) {
|
|
|
1815
1890
|
mode: opts?.commandSandbox,
|
|
1816
1891
|
cwd,
|
|
1817
1892
|
...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
|
|
1893
|
+
// Exact-file read grant (see additionalReadPaths above):
|
|
1894
|
+
// READ-only exceptions to the confinement boundary, never writes.
|
|
1895
|
+
...opts?.additionalReadPaths?.length ? { extraReadPaths: opts.additionalReadPaths } : {},
|
|
1818
1896
|
label: definition.id
|
|
1819
1897
|
}
|
|
1820
1898
|
);
|
|
@@ -1835,8 +1913,10 @@ function createAgentCliRuntime(definition) {
|
|
|
1835
1913
|
});
|
|
1836
1914
|
if (spawnFailure) {
|
|
1837
1915
|
const isEnoent = spawnFailure.code === "ENOENT";
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1916
|
+
const cwdMissing = isEnoent && !existsSync(cwd);
|
|
1917
|
+
const enoentHint = !isEnoent ? "" : cwdMissing ? `
|
|
1918
|
+
cwd '${cwd}' does not exist \u2014 Node reports a missing working directory with this same ENOENT. Recreate the directory, or pass a valid cwd/workspace (is the workspace path stale, or its worktree removed?).` : `
|
|
1919
|
+
'${execBin}' was not found on the daemon's PATH. If it works in your own terminal, the daemon's environment may be stale \u2014 restart the daemon from a shell where \`which ${definition.bin}\` resolves (\`agentproto daemon restart\`).`;
|
|
1840
1920
|
throw new Error(
|
|
1841
1921
|
`agent-cli '${definition.id}': failed to spawn '${execBin} ${execArgs.join(" ")}': ${spawnFailure.message}${enoentHint}`
|
|
1842
1922
|
);
|
|
@@ -1889,8 +1969,25 @@ function createAgentCliRuntime(definition) {
|
|
|
1889
1969
|
...turnIdleTimeoutMs !== void 0 ? { turnIdleTimeoutMs } : {},
|
|
1890
1970
|
...opts?.permissionHold ? { permissionHold: true } : {}
|
|
1891
1971
|
});
|
|
1972
|
+
if (configModel && definition.routeSelection === "derived-from-model" && arm.modelApplyRejection) {
|
|
1973
|
+
const { requested, reason } = arm.modelApplyRejection;
|
|
1974
|
+
await arm.close().catch(() => {
|
|
1975
|
+
});
|
|
1976
|
+
if (child && !child.killed) child.kill("SIGTERM");
|
|
1977
|
+
throw derivedModelRefusalError(definition, requested, reason);
|
|
1978
|
+
}
|
|
1892
1979
|
if (optModel && modelApply === "command") {
|
|
1893
|
-
await applyModelCommand(arm, String(optModel));
|
|
1980
|
+
const commandResult = await applyModelCommand(arm, String(optModel));
|
|
1981
|
+
if (!commandResult.applied && definition.routeSelection === "derived-from-model") {
|
|
1982
|
+
await arm.close().catch(() => {
|
|
1983
|
+
});
|
|
1984
|
+
if (child && !child.killed) child.kill("SIGTERM");
|
|
1985
|
+
throw derivedModelRefusalError(
|
|
1986
|
+
definition,
|
|
1987
|
+
String(optModel),
|
|
1988
|
+
commandResult.reason ?? "model switch not acknowledged"
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1894
1991
|
}
|
|
1895
1992
|
const sessionId = arm.sessionId ?? randomUUID();
|
|
1896
1993
|
let currentTurnId;
|
|
@@ -1999,7 +2096,14 @@ function filterStringEnv(env) {
|
|
|
1999
2096
|
}
|
|
2000
2097
|
return out;
|
|
2001
2098
|
}
|
|
2099
|
+
function derivedModelRefusalError(definition, requested, reason) {
|
|
2100
|
+
const first = definition.models?.allowed?.[0];
|
|
2101
|
+
const example = (typeof first === "string" ? first : first?.id) ?? "openrouter/anthropic/claude-sonnet-4-6";
|
|
2102
|
+
return new Error(
|
|
2103
|
+
`${definition.bin}: refusing to start on the default model \u2014 the requested model "${requested}" was not applied (${reason}). This adapter routes AND bills by the model id's own provider prefix, so continuing would silently run (and bill) a model you didn't ask for. Use the adapter's "<provider>/<model>" form (e.g. "${example}"), or pick an id from its model menu.`
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2002
2106
|
|
|
2003
|
-
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createJcodeMapperState, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, mapJcodeEvent, mapMastraEvent, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
2004
|
-
//# sourceMappingURL=chunk-
|
|
2005
|
-
//# sourceMappingURL=chunk-
|
|
2107
|
+
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createJcodeMapperState, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, isModelSwitchAcknowledgement, mapJcodeEvent, mapMastraEvent, parseModelSwitchCommand, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
2108
|
+
//# sourceMappingURL=chunk-E4MSI6PV.mjs.map
|
|
2109
|
+
//# sourceMappingURL=chunk-E4MSI6PV.mjs.map
|