Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@bonnard/agentops

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bonnard/agentops - npm Package Compare versions

Comparing version
0.7.7
to
0.7.8
+131
-9
dist/bin/agentops.mjs

@@ -7,2 +7,3 @@ #!/usr/bin/env node

import http from "node:http";
import readline from "node:readline/promises";
import open from "open";

@@ -155,2 +156,11 @@ import fs from "node:fs";

}
var ApiError = class extends Error {
status;
code;
constructor(message, status, code) {
super(message);
this.status = status;
this.code = code;
}
};
/**

@@ -161,3 +171,12 @@ * Download a skill bundle with metadata headers (version, etc.).

const res = await fetchWithRefresh(`${baseUrl}${apiPath}`, { headers: getHeaders() }, baseUrl);
if (!res.ok) throw new Error(`Download failed: ${res.status}`);
if (!res.ok) {
let code;
let message = `Download failed: ${res.status}`;
try {
const body = await res.json();
if (body.error?.message) message = body.error.message;
code = body.error?.code;
} catch {}
throw new ApiError(message, res.status, code);
}
const arrayBuf = await res.arrayBuffer();

@@ -213,6 +232,13 @@ const versionHeader = res.headers.get("x-skill-version");

}
const creds = validateCredentials(await callbackRes.json());
if (!creds) {
console.error(pc.red("Server returned an unexpected response format."));
process.exit(1);
const data = await callbackRes.json();
let creds;
if (data.needsOnboarding === true) {
creds = await onboardNewUser(data, baseUrl);
if (!creds) process.exit(1);
} else {
creds = validateCredentials(data);
if (!creds) {
console.error(pc.red("Server returned an unexpected response format."));
process.exit(1);
}
}

@@ -299,2 +325,57 @@ saveCredentials(creds);

}
/**
* First-time user path: the server returned needsOnboarding=true because
* the authenticated user has no WorkOS organization memberships. Prompt
* for an org name, call POST /api/auth/create-org with the pre-provisioned
* access token, and return the finalized credentials.
*/
async function onboardNewUser(pending, baseUrl) {
const accessToken = typeof pending.accessToken === "string" ? pending.accessToken : null;
const refreshToken = typeof pending.refreshToken === "string" ? pending.refreshToken : null;
const userFromCallback = pending.user;
const email = userFromCallback && typeof userFromCallback.email === "string" ? userFromCallback.email : null;
if (!accessToken || !email) {
console.error(pc.red("Server returned an unexpected onboarding response."));
return null;
}
console.log();
console.log(pc.bold(`Welcome, ${email}!`));
console.log(pc.dim("You don't belong to an organization yet. Name one to get started."));
console.log();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let orgName;
try {
orgName = (await rl.question("Organization name: ")).trim();
} finally {
rl.close();
}
if (!orgName) {
console.error(pc.red("Organization name is required."));
return null;
}
console.log(pc.dim(`Creating "${orgName}"...`));
const res = await fetch(`${baseUrl}/api/auth/create-org`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`
},
body: JSON.stringify({ name: orgName })
});
if (!res.ok) {
const body = await res.text();
console.error(pc.red(`Failed to create organization: ${body}`));
return null;
}
const result = await res.json();
return {
accessToken,
refreshToken,
user: result.user,
org: result.org
};
}
/** Static HTML page — never interpolate user/query data into this */

@@ -806,4 +887,7 @@ function resultPage(title, message) {

} catch (err) {
console.error(pc.red(`Download failed: ${err.message}`));
console.log(pc.dim(` The skill exists but has no published bundle yet.`));
if (err instanceof ApiError) {
console.error(pc.red(err.message));
if (err.code === "feature_gated") console.log(pc.dim(" agentops whoami — check your current plan"));
else if (err.code === "invalid_state") console.log(pc.dim(" The skill exists but has no published bundle yet."));
} else console.error(pc.red(`Download failed: ${err.message}`));
process.exit(1);

@@ -906,2 +990,3 @@ }

if (err.error?.code === "not_found") console.log(pc.dim(` Search the library: agentops skills search ${name}`));
else if (err.error?.code === "feature_gated") console.log(pc.dim(" agentops whoami — check your current plan"));
process.exit(1);

@@ -1161,3 +1246,3 @@ }

message: `Large file: ${relPath} (${(size / 1024 / 1024).toFixed(1)}MB)`,
hint: "Skill bundles are limited to 10MB total. Consider assets/ for large resources."
hint: "Consider assets/ for large resources. Check your plan's bundle limit with: agentops whoami"
});

@@ -1413,3 +1498,3 @@ }

const seatsLimit = limits.maxSeats ?? "∞";
const storageLimit = limits.storageQuotaBytes ? `${(limits.storageQuotaBytes / 1024 / 1024 / 1024).toFixed(0)} GB` : "∞";
const storageLimit = limits.storageQuotaBytes ? formatBytes(limits.storageQuotaBytes) : "∞";
const storageUsed = formatBytes(me.usage.storageBytes);

@@ -1468,2 +1553,38 @@ const bundleLimit = `${limits.maxBundleSizeBytes / 1024 / 1024} MB`;

//#endregion
//#region src/commands/rollback.ts
async function rollbackCommand(spec, opts) {
if (!loadCredentials()) {
console.log(pc.yellow("Not logged in. Run: agentops login"));
process.exit(1);
}
let parsed;
try {
parsed = parseSkillSpec(spec);
} catch (err) {
console.error(pc.red(err.message));
process.exit(1);
}
if (typeof parsed.version !== "number") {
console.error(pc.red("A specific version is required: agentops skills rollback <name>@v<N>"));
console.log(pc.dim(` e.g. agentops skills rollback ${parsed.name}@v1`));
process.exit(1);
}
const baseUrl = getBaseUrl(opts.url);
console.log(pc.dim(`Rolling back "${parsed.name}" to v${parsed.version}...`));
const res = await post(`/api/skills/${encodeURIComponent(parsed.name)}/rollback`, { version: parsed.version }, baseUrl);
if (!res.ok) {
const err = await res.json();
console.error(pc.red(err.error?.message ?? `Error: ${res.status}`));
if (err.error?.code === "feature_gated") {
console.log(pc.dim(` Version rollback requires the pro plan or higher.`));
console.log(pc.dim(` Manage your subscription at https://agentops.bonnard.ai`));
} else if (err.error?.code === "not_found") console.log(pc.dim(` Check available versions: agentops skills history ${parsed.name}`));
else if (err.error?.code === "forbidden") console.log(pc.dim(` Only the skill author or an admin can roll back.`));
process.exit(1);
}
const result = await res.json();
console.log(pc.green(`✓ "${parsed.name}" rolled back to v${result.rolledBackFrom} — now published as v${result.version}`));
console.log(pc.dim(` Install: agentops skills install ${parsed.name}`));
}
//#endregion
//#region src/commands/delete.ts

@@ -1521,2 +1642,3 @@ async function deleteCommand(name, opts) {

skills.command("history <name>").description("Show version history for a skill").option("--url <url>", "AgentOps server URL").action(historyCommand);
skills.command("rollback <spec>").description("Re-publish an older version as the new latest — use <name>@v<N> (pro+)").option("--url <url>", "AgentOps server URL").action(rollbackCommand);
skills.command("authored").description("Show skills you've authored (draft, submitted, published, rejected)").option("--url <url>", "AgentOps server URL").action(authoredCommand);

@@ -1523,0 +1645,0 @@ skills.command("publish <name>").description("Publish a submitted skill (admin only)").option("--url <url>", "AgentOps server URL").action(publishCommand);

+1
-1
{
"name": "@bonnard/agentops",
"version": "0.7.7",
"version": "0.7.8",
"type": "module",

@@ -5,0 +5,0 @@ "bin": {