@controlvector/cv-agent 1.12.0 → 1.13.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/dist/bundle.cjs +69 -5
- package/dist/bundle.cjs.map +3 -3
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +86 -0
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/setup.d.ts +20 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +14 -3
- package/dist/commands/setup.js.map +1 -1
- package/package.json +2 -2
package/dist/bundle.cjs
CHANGED
|
@@ -3984,13 +3984,17 @@ var DEVICE_CLIENT_ID = "cv-agent-cli";
|
|
|
3984
3984
|
var DEVICE_SCOPES = "repo:read repo:write profile offline_access";
|
|
3985
3985
|
var POLL_INTERVAL_MS = 5e3;
|
|
3986
3986
|
var MAX_POLL_ATTEMPTS = 180;
|
|
3987
|
-
async function deviceAuthFlow(hubUrl, appUrl) {
|
|
3987
|
+
async function deviceAuthFlow(hubUrl, appUrl, opts = {}) {
|
|
3988
|
+
const requestScope = opts.scope ?? DEVICE_SCOPES;
|
|
3988
3989
|
const authRes = await fetch(`${hubUrl}/oauth/device/authorize`, {
|
|
3989
3990
|
method: "POST",
|
|
3990
3991
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
3991
3992
|
body: new URLSearchParams({
|
|
3992
3993
|
client_id: DEVICE_CLIENT_ID,
|
|
3993
|
-
scope:
|
|
3994
|
+
scope: requestScope,
|
|
3995
|
+
// The actor hint names this agent instance; cv-hub binds it as the token `act`
|
|
3996
|
+
// claim (it is never self-asserted at the token step). Omitted for a plain setup.
|
|
3997
|
+
...opts.actor ? { actor: opts.actor } : {}
|
|
3994
3998
|
})
|
|
3995
3999
|
});
|
|
3996
4000
|
if (!authRes.ok) {
|
|
@@ -4052,7 +4056,7 @@ async function deviceAuthFlow(hubUrl, appUrl) {
|
|
|
4052
4056
|
}
|
|
4053
4057
|
} catch {
|
|
4054
4058
|
}
|
|
4055
|
-
return { token: tokenData.access_token, username: uname };
|
|
4059
|
+
return { token: tokenData.access_token, username: uname, scope: tokenData.scope ?? requestScope };
|
|
4056
4060
|
}
|
|
4057
4061
|
if (tokenData.error === "slow_down") {
|
|
4058
4062
|
interval += 5e3;
|
|
@@ -23162,7 +23166,7 @@ async function runAgent(options) {
|
|
|
23162
23166
|
const creds = await readCredentials();
|
|
23163
23167
|
let loadedProfile;
|
|
23164
23168
|
if (options.profile) {
|
|
23165
|
-
const hostVersion = true ? "1.
|
|
23169
|
+
const hostVersion = true ? "1.13.0" : "0.0.0";
|
|
23166
23170
|
try {
|
|
23167
23171
|
loadedProfile = loadProfile(options.profile, { hostVersion });
|
|
23168
23172
|
} catch (err) {
|
|
@@ -23888,6 +23892,65 @@ function agentCommand() {
|
|
|
23888
23892
|
|
|
23889
23893
|
// src/commands/auth.ts
|
|
23890
23894
|
init_source();
|
|
23895
|
+
var import_node_os5 = require("node:os");
|
|
23896
|
+
var DEPLOY_TOKEN_FIELD = "CV_HUB_DEPLOY_TOKEN";
|
|
23897
|
+
var DEPLOY_APPROVE_SCOPE = "deploy:approve";
|
|
23898
|
+
function resolveDeviceScopes(requested, ceiling) {
|
|
23899
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23900
|
+
const req = requested.map((s) => s.trim()).filter((s) => s.length > 0 && !seen.has(s) && (seen.add(s), true));
|
|
23901
|
+
const droppedApprove = req.includes(DEPLOY_APPROVE_SCOPE);
|
|
23902
|
+
const withoutApprove = req.filter((s) => s !== DEPLOY_APPROVE_SCOPE);
|
|
23903
|
+
const kept = ceiling && ceiling.length > 0 ? capScopes(ceiling, withoutApprove) : withoutApprove;
|
|
23904
|
+
const keptSet = new Set(kept);
|
|
23905
|
+
const droppedByCeiling = withoutApprove.filter((s) => !keptSet.has(s));
|
|
23906
|
+
return { scopes: kept, droppedApprove, droppedByCeiling };
|
|
23907
|
+
}
|
|
23908
|
+
async function authDevice(opts) {
|
|
23909
|
+
const creds = await readCredentials();
|
|
23910
|
+
const hubUrl = (opts.hub || creds.CV_HUB_API || "https://api.hub.controlvector.io").replace(/\/$/, "");
|
|
23911
|
+
const actor = opts.actor || `cva@${(0, import_node_os5.hostname)().toLowerCase().replace(/[^a-z0-9.-]/g, "-")}`;
|
|
23912
|
+
const requested = (opts.scope || "deploy:request,deploy:status").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
|
|
23913
|
+
let ceiling;
|
|
23914
|
+
if (opts.profile) {
|
|
23915
|
+
const hostVersion = true ? "1.13.0" : "0.0.0";
|
|
23916
|
+
try {
|
|
23917
|
+
ceiling = loadProfile(opts.profile, { hostVersion }).manifest.credential_scopes;
|
|
23918
|
+
} catch (err) {
|
|
23919
|
+
console.log(source_default.red("Profile failed to load:") + " " + err.message);
|
|
23920
|
+
process.exit(1);
|
|
23921
|
+
}
|
|
23922
|
+
}
|
|
23923
|
+
const { scopes, droppedApprove, droppedByCeiling } = resolveDeviceScopes(requested, ceiling);
|
|
23924
|
+
if (droppedApprove) {
|
|
23925
|
+
console.log(source_default.yellow("!") + " deploy:approve is never granted to an agent (two-person rule); dropped.");
|
|
23926
|
+
}
|
|
23927
|
+
if (droppedByCeiling.length) {
|
|
23928
|
+
console.log(source_default.yellow("!") + ` dropped by the "${opts.profile}" credential_scopes ceiling: ${droppedByCeiling.join(", ")}`);
|
|
23929
|
+
}
|
|
23930
|
+
if (scopes.length === 0) {
|
|
23931
|
+
console.log(source_default.red("No scopes left to request after the deploy:approve / ceiling filter."));
|
|
23932
|
+
process.exit(1);
|
|
23933
|
+
}
|
|
23934
|
+
console.log(source_default.gray(`Requesting a delegated token from ${hubUrl}: scopes [${scopes.join(" ")}], actor ${source_default.bold(actor)}`));
|
|
23935
|
+
let result;
|
|
23936
|
+
try {
|
|
23937
|
+
result = await deviceAuthFlow(hubUrl, hubUrl, { scope: scopes.join(" "), actor });
|
|
23938
|
+
} catch (err) {
|
|
23939
|
+
console.log(source_default.red("Device authorization failed:") + ` ${err.message}`);
|
|
23940
|
+
process.exit(1);
|
|
23941
|
+
}
|
|
23942
|
+
const granted = result.scope.split(/\s+/).filter(Boolean);
|
|
23943
|
+
if (granted.includes(DEPLOY_APPROVE_SCOPE)) {
|
|
23944
|
+
console.log(source_default.red("Refusing to store a token carrying deploy:approve."));
|
|
23945
|
+
process.exit(1);
|
|
23946
|
+
}
|
|
23947
|
+
await writeCredentialField(DEPLOY_TOKEN_FIELD, result.token);
|
|
23948
|
+
await writeCredentialField("CV_HUB_API", hubUrl);
|
|
23949
|
+
const masked = result.token.slice(0, 8) + "..." + result.token.slice(-4);
|
|
23950
|
+
console.log(source_default.green("Delegated deploy token obtained") + ` as ${source_default.bold(result.username)}, acting as ${source_default.bold(actor)}`);
|
|
23951
|
+
console.log(source_default.gray(` scopes: ${granted.join(" ")}`));
|
|
23952
|
+
console.log(source_default.gray(` saved 0600 to the cv-hub credentials file as ${DEPLOY_TOKEN_FIELD} (${masked})`));
|
|
23953
|
+
}
|
|
23891
23954
|
async function authLogin(opts) {
|
|
23892
23955
|
const token = opts.token || await promptForToken();
|
|
23893
23956
|
const apiUrl = opts.apiUrl || "https://api.hub.controlvector.io";
|
|
@@ -23994,6 +24057,7 @@ function authCommand() {
|
|
|
23994
24057
|
const cmd = new Command("auth");
|
|
23995
24058
|
cmd.description("Manage CV-Hub authentication");
|
|
23996
24059
|
cmd.command("login").description("Authenticate with CV-Hub using a PAT token").option("--token <token>", "PAT token (or enter interactively)").option("--api-url <url>", "CV-Hub API URL", "https://api.hub.controlvector.io").action(authLogin);
|
|
24060
|
+
cmd.command("device").description("Obtain a delegated deploy token via the RFC 8628 device flow (sub = you, act = this agent)").option("--hub <url>", "CV-Hub API URL (default: saved CV_HUB_API, else production)").option("--scope <scopes>", "Comma/space-separated scopes (deploy:approve is always refused)", "deploy:request,deploy:status").option("--actor <name>", "Agent instance name surfaced as the act claim (default: cva@<hostname>)").option("--profile <spec>", "Apply a profile credential_scopes ceiling (P14)").action(authDevice);
|
|
23997
24061
|
cmd.command("status").description("Show current authentication status").action(authStatus);
|
|
23998
24062
|
cmd.command("set-api-key").description("Set Anthropic API key as fallback for Claude Code OAuth").argument("<key>", "Anthropic API key (sk-ant-...)").action(authSetApiKey);
|
|
23999
24063
|
cmd.command("remove-api-key").description("Remove stored Anthropic API key").action(authRemoveApiKey);
|
|
@@ -24307,7 +24371,7 @@ function gitCredentialCommand() {
|
|
|
24307
24371
|
|
|
24308
24372
|
// src/index.ts
|
|
24309
24373
|
var program2 = new Command();
|
|
24310
|
-
program2.name("cva").description('CV-Hub Agent \u2014 bridges Claude Code with CV-Hub task dispatch.\n\nRun "cva setup" to get started.').version(true ? "1.
|
|
24374
|
+
program2.name("cva").description('CV-Hub Agent \u2014 bridges Claude Code with CV-Hub task dispatch.\n\nRun "cva setup" to get started.').version(true ? "1.13.0" : "1.6.0");
|
|
24311
24375
|
program2.addCommand(setupCommand());
|
|
24312
24376
|
program2.addCommand(agentCommand());
|
|
24313
24377
|
program2.addCommand(authCommand());
|