skillvault-publisher 0.12.0 → 0.13.2
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/index.js +588 -245
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3891,11 +3891,11 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
3891
3891
|
}
|
|
3892
3892
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
3893
3893
|
function adopt(value) {
|
|
3894
|
-
return value instanceof P ? value : new P(function(
|
|
3895
|
-
|
|
3894
|
+
return value instanceof P ? value : new P(function(resolve12) {
|
|
3895
|
+
resolve12(value);
|
|
3896
3896
|
});
|
|
3897
3897
|
}
|
|
3898
|
-
return new (P || (P = Promise))(function(
|
|
3898
|
+
return new (P || (P = Promise))(function(resolve12, reject) {
|
|
3899
3899
|
function fulfilled(value) {
|
|
3900
3900
|
try {
|
|
3901
3901
|
step(generator.next(value));
|
|
@@ -3911,7 +3911,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
3911
3911
|
}
|
|
3912
3912
|
}
|
|
3913
3913
|
function step(result) {
|
|
3914
|
-
result.done ?
|
|
3914
|
+
result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3915
3915
|
}
|
|
3916
3916
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3917
3917
|
});
|
|
@@ -4102,14 +4102,14 @@ function __asyncValues(o) {
|
|
|
4102
4102
|
}, i);
|
|
4103
4103
|
function verb(n) {
|
|
4104
4104
|
i[n] = o[n] && function(v) {
|
|
4105
|
-
return new Promise(function(
|
|
4106
|
-
v = o[n](v), settle(
|
|
4105
|
+
return new Promise(function(resolve12, reject) {
|
|
4106
|
+
v = o[n](v), settle(resolve12, reject, v.done, v.value);
|
|
4107
4107
|
});
|
|
4108
4108
|
};
|
|
4109
4109
|
}
|
|
4110
|
-
function settle(
|
|
4110
|
+
function settle(resolve12, reject, d, v) {
|
|
4111
4111
|
Promise.resolve(v).then(function(v2) {
|
|
4112
|
-
|
|
4112
|
+
resolve12({ value: v2, done: d });
|
|
4113
4113
|
}, reject);
|
|
4114
4114
|
}
|
|
4115
4115
|
}
|
|
@@ -5054,9 +5054,9 @@ var require_clone = __commonJS({
|
|
|
5054
5054
|
} else if (_instanceof(parent2, nativeSet)) {
|
|
5055
5055
|
child = new nativeSet();
|
|
5056
5056
|
} else if (_instanceof(parent2, nativePromise)) {
|
|
5057
|
-
child = new nativePromise(function(
|
|
5057
|
+
child = new nativePromise(function(resolve12, reject) {
|
|
5058
5058
|
parent2.then(function(value) {
|
|
5059
|
-
|
|
5059
|
+
resolve12(_clone(value, depth2 - 1));
|
|
5060
5060
|
}, function(err) {
|
|
5061
5061
|
reject(_clone(err, depth2 - 1));
|
|
5062
5062
|
});
|
|
@@ -151595,7 +151595,7 @@ function confColor(c) {
|
|
|
151595
151595
|
return SV.sirenRed500;
|
|
151596
151596
|
}
|
|
151597
151597
|
async function generatePdfReport(data, outputPath) {
|
|
151598
|
-
return new Promise((
|
|
151598
|
+
return new Promise((resolve12, reject) => {
|
|
151599
151599
|
const doc = new import_pdfkit.default({
|
|
151600
151600
|
size: "A4",
|
|
151601
151601
|
margins: { top: 72, bottom: 0, left: 56, right: 56 },
|
|
@@ -151742,7 +151742,7 @@ async function generatePdfReport(data, outputPath) {
|
|
|
151742
151742
|
yPos += 72;
|
|
151743
151743
|
drawPageFooter(doc, leftMargin, contentWidth, pageWidth, pageNum);
|
|
151744
151744
|
doc.end();
|
|
151745
|
-
stream.on("finish",
|
|
151745
|
+
stream.on("finish", resolve12);
|
|
151746
151746
|
stream.on("error", reject);
|
|
151747
151747
|
});
|
|
151748
151748
|
}
|
|
@@ -151804,7 +151804,7 @@ var init_pdf_report = __esm({
|
|
|
151804
151804
|
});
|
|
151805
151805
|
|
|
151806
151806
|
// dist/index.js
|
|
151807
|
-
import { Command as
|
|
151807
|
+
import { Command as Command37 } from "commander";
|
|
151808
151808
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
151809
151809
|
import { fileURLToPath } from "node:url";
|
|
151810
151810
|
import { dirname as dirname5, join as join17 } from "node:path";
|
|
@@ -151926,6 +151926,41 @@ var loginCommand = new Command("login").description("Authenticate with the Skill
|
|
|
151926
151926
|
headers: { "Content-Type": "application/json" },
|
|
151927
151927
|
body: JSON.stringify(body2)
|
|
151928
151928
|
});
|
|
151929
|
+
if (loginRes.status === 403) {
|
|
151930
|
+
const err = await loginRes.json().catch(() => null);
|
|
151931
|
+
if (err?.error === "production_login_disabled") {
|
|
151932
|
+
console.log(chalk.dim("Production server: pivoting to magic-link verification..."));
|
|
151933
|
+
const mlRes = await fetch(`${serverUrl}/auth/magic-link`, {
|
|
151934
|
+
method: "POST",
|
|
151935
|
+
headers: { "Content-Type": "application/json" },
|
|
151936
|
+
body: JSON.stringify({ email: options.email })
|
|
151937
|
+
});
|
|
151938
|
+
if (mlRes.ok) {
|
|
151939
|
+
const mlData = await mlRes.json().catch(() => ({}));
|
|
151940
|
+
if (mlData.status === "sent") {
|
|
151941
|
+
console.log();
|
|
151942
|
+
console.log(chalk.green(" Verification email sent."));
|
|
151943
|
+
console.log();
|
|
151944
|
+
console.log(chalk.bold(" Next steps:"));
|
|
151945
|
+
console.log(` 1. Check ${chalk.cyan(options.email)} for an email from SkillVault`);
|
|
151946
|
+
console.log(" 2. Click the magic link to sign in to the dashboard");
|
|
151947
|
+
console.log(" 3. On the dashboard, go to Settings \u2192 Profile");
|
|
151948
|
+
console.log(" 4. Copy your CLI token and run:");
|
|
151949
|
+
console.log(chalk.cyan(` skillvault-publisher login --token <pasted_token>`));
|
|
151950
|
+
console.log();
|
|
151951
|
+
process.exit(0);
|
|
151952
|
+
}
|
|
151953
|
+
if (mlData.status === "not_found") {
|
|
151954
|
+
console.error(chalk.red(`No account found for ${options.email}.`));
|
|
151955
|
+
console.error(chalk.dim("Create one at https://app.getskillvault.com/login first."));
|
|
151956
|
+
process.exit(1);
|
|
151957
|
+
}
|
|
151958
|
+
}
|
|
151959
|
+
console.error(chalk.red("Failed to send verification email."));
|
|
151960
|
+
console.error(chalk.dim(err.message || "Unknown error"));
|
|
151961
|
+
process.exit(1);
|
|
151962
|
+
}
|
|
151963
|
+
}
|
|
151929
151964
|
if (!loginRes.ok) {
|
|
151930
151965
|
const err = await loginRes.json().catch(() => null);
|
|
151931
151966
|
const reason = err?.message || err?.error || loginRes.statusText || `HTTP ${loginRes.status}`;
|
|
@@ -152070,7 +152105,7 @@ var registerCommand = new Command2("register").description("Create a new publish
|
|
|
152070
152105
|
let verified = false;
|
|
152071
152106
|
const maxAttempts = 120;
|
|
152072
152107
|
for (let i = 0; i < maxAttempts; i++) {
|
|
152073
|
-
await new Promise((
|
|
152108
|
+
await new Promise((resolve12) => setTimeout(resolve12, 3e3));
|
|
152074
152109
|
try {
|
|
152075
152110
|
const statusRes = await fetch(`${serverUrl}/publishers/${publisher_id}/verification-status`);
|
|
152076
152111
|
if (statusRes.ok) {
|
|
@@ -153152,7 +153187,8 @@ The server will clean up automatically. If the problem persists, re-run with --f
|
|
|
153152
153187
|
}
|
|
153153
153188
|
const publishResult = await publishRes.json().catch(() => ({}));
|
|
153154
153189
|
const wasUnlinked = existingManifest === null;
|
|
153155
|
-
|
|
153190
|
+
const publishAccepted = publishResult.status !== "rejected";
|
|
153191
|
+
if (publishAccepted && !options.noLink && sessionPublisherId) {
|
|
153156
153192
|
const linkedAt = existingManifest?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
153157
153193
|
const newManifest = {
|
|
153158
153194
|
...existingManifest ?? {},
|
|
@@ -153186,6 +153222,26 @@ The server will clean up automatically. If the problem persists, re-run with --f
|
|
|
153186
153222
|
if (publishResult.status === "unchanged") {
|
|
153187
153223
|
console.log(chalk5.yellow(`Content unchanged for ${skillName} v${version}. No new version created.`));
|
|
153188
153224
|
console.log(chalk5.dim(` Use --force to publish anyway.`));
|
|
153225
|
+
} else if (publishResult.status === "rejected") {
|
|
153226
|
+
const reasonMessage = publishResult.public_reason?.message || "Skill rejected by the security review pipeline.";
|
|
153227
|
+
process.stderr.write(chalk5.red(`
|
|
153228
|
+
Publish rejected: ${reasonMessage}
|
|
153229
|
+
`));
|
|
153230
|
+
process.stderr.write(chalk5.dim(` Run \`skillvault-publisher skill-status ${skillName}\` for more details.
|
|
153231
|
+
`));
|
|
153232
|
+
process.stderr.write(chalk5.dim(` Download a rejection report with \`skillvault-publisher skill-status ${skillName} --review-report <file>\`.
|
|
153233
|
+
`));
|
|
153234
|
+
process.exit(1);
|
|
153235
|
+
} else if (publishResult.status === "under_review") {
|
|
153236
|
+
console.log(chalk5.yellow(`
|
|
153237
|
+
Skill queued for review: ${skillName} v${version}`));
|
|
153238
|
+
if (publishResult.review_id) {
|
|
153239
|
+
console.log(chalk5.dim(` Review ID: ${publishResult.review_id}`));
|
|
153240
|
+
}
|
|
153241
|
+
console.log(chalk5.dim(` Skill ID: ${publishResult.skill_id || "n/a"}`));
|
|
153242
|
+
console.log(chalk5.dim(` Capability: ${capabilityName}`));
|
|
153243
|
+
console.log(chalk5.dim(" Reviews usually complete within a few minutes."));
|
|
153244
|
+
console.log(chalk5.dim(` Check status with \`skillvault-publisher skill-status ${skillName}\` (or listen on your webhook).`));
|
|
153189
153245
|
} else {
|
|
153190
153246
|
console.log(chalk5.green(`Published ${skillName} v${version}`));
|
|
153191
153247
|
console.log(chalk5.dim(` Skill ID: ${publishResult.skill_id || "n/a"}`));
|
|
@@ -153674,8 +153730,17 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153674
153730
|
console.log(JSON.stringify({
|
|
153675
153731
|
host_id: data.host_id ?? config.host_id,
|
|
153676
153732
|
agent_id: data.agent_id ?? config.agent_id,
|
|
153677
|
-
...
|
|
153678
|
-
|
|
153733
|
+
...authMe ? {
|
|
153734
|
+
publisher_id: authMe.publisher_id,
|
|
153735
|
+
publisher_name: authMe.publisher_name,
|
|
153736
|
+
email: authMe.email,
|
|
153737
|
+
role: authMe.role,
|
|
153738
|
+
is_owner: authMe.is_owner,
|
|
153739
|
+
...authMe.skill_acls ? { skill_acls: authMe.skill_acls } : {}
|
|
153740
|
+
} : {
|
|
153741
|
+
...config.publisher_id ? { publisher_id: config.publisher_id } : {},
|
|
153742
|
+
...config.email ? { email: config.email } : {}
|
|
153743
|
+
},
|
|
153679
153744
|
device_fingerprint: fingerprint,
|
|
153680
153745
|
server_url: config.server_url,
|
|
153681
153746
|
status: data.status,
|
|
@@ -153683,6 +153748,18 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153683
153748
|
}, null, 2));
|
|
153684
153749
|
return;
|
|
153685
153750
|
}
|
|
153751
|
+
let skillsById = /* @__PURE__ */ new Map();
|
|
153752
|
+
if (authMe?.role === "member" && authMe.skill_acls && authMe.skill_acls.length > 0) {
|
|
153753
|
+
try {
|
|
153754
|
+
const skillsRes = await fetch(`${config.server_url}/skills`, { headers: ctx.headers });
|
|
153755
|
+
if (skillsRes.ok) {
|
|
153756
|
+
const sd = await skillsRes.json();
|
|
153757
|
+
for (const s of sd.skills)
|
|
153758
|
+
skillsById.set(s.id, s);
|
|
153759
|
+
}
|
|
153760
|
+
} catch {
|
|
153761
|
+
}
|
|
153762
|
+
}
|
|
153686
153763
|
console.log();
|
|
153687
153764
|
console.log(chalk10.bold(" Skill Vault Identity"));
|
|
153688
153765
|
console.log();
|
|
@@ -153695,6 +153772,20 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153695
153772
|
if (!authMe.is_owner) {
|
|
153696
153773
|
console.log(` ${chalk10.dim(" (you are a team member of this publisher)".padEnd(22))}`);
|
|
153697
153774
|
}
|
|
153775
|
+
if (authMe.role === "member" && authMe.skill_acls) {
|
|
153776
|
+
if (authMe.skill_acls.length === 0) {
|
|
153777
|
+
console.log(` ${chalk10.dim("Skill access:".padEnd(22))} ${chalk10.dim("(none yet \u2014 publish a new skill to auto-own it)")}`);
|
|
153778
|
+
} else {
|
|
153779
|
+
console.log(` ${"Skill access:".padEnd(22)}`);
|
|
153780
|
+
for (const a of authMe.skill_acls) {
|
|
153781
|
+
const sk = skillsById.get(a.skill_id);
|
|
153782
|
+
const label = sk?.name || a.skill_id;
|
|
153783
|
+
const roleColor2 = a.role === "owner" ? chalk10.green : a.role === "write" ? chalk10.cyan : chalk10.dim;
|
|
153784
|
+
const action = a.role === "owner" ? "publish + delete" : a.role === "write" ? "publish new versions" : "view only";
|
|
153785
|
+
console.log(` ${chalk10.cyan(label.padEnd(20))} ${roleColor2(a.role.padEnd(8))} ${chalk10.dim(action)}`);
|
|
153786
|
+
}
|
|
153787
|
+
}
|
|
153788
|
+
}
|
|
153698
153789
|
} else {
|
|
153699
153790
|
if (config.publisher_id) {
|
|
153700
153791
|
console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
|
|
@@ -153961,11 +154052,13 @@ var listCommand = new Command13("list").description("List your published skills"
|
|
|
153961
154052
|
const nameWidth = Math.max(20, ...skills.map((s) => s.name.length + 2));
|
|
153962
154053
|
const verWidth = 10;
|
|
153963
154054
|
const statusWidth = 10;
|
|
154055
|
+
const reviewWidth = 8;
|
|
153964
154056
|
const capWidth = Math.max(24, ...skills.map((s) => s.capability_name.length + 2));
|
|
153965
154057
|
const header = [
|
|
153966
154058
|
chalk14.dim("Name".padEnd(nameWidth)),
|
|
153967
154059
|
chalk14.dim("Version".padEnd(verWidth)),
|
|
153968
154060
|
chalk14.dim("Status".padEnd(statusWidth)),
|
|
154061
|
+
chalk14.dim("Review".padEnd(reviewWidth)),
|
|
153969
154062
|
chalk14.dim("Capability".padEnd(capWidth)),
|
|
153970
154063
|
chalk14.dim("Created")
|
|
153971
154064
|
].join(" ");
|
|
@@ -153977,10 +154070,29 @@ var listCommand = new Command13("list").description("List your published skills"
|
|
|
153977
154070
|
year: "numeric"
|
|
153978
154071
|
});
|
|
153979
154072
|
const statusColor = skill.status === "active" ? chalk14.green : chalk14.dim;
|
|
154073
|
+
let reviewCell;
|
|
154074
|
+
switch (skill.review_state) {
|
|
154075
|
+
case "approved":
|
|
154076
|
+
reviewCell = chalk14.green("ok".padEnd(reviewWidth));
|
|
154077
|
+
break;
|
|
154078
|
+
case "queued":
|
|
154079
|
+
case "running":
|
|
154080
|
+
reviewCell = chalk14.yellow("review".padEnd(reviewWidth));
|
|
154081
|
+
break;
|
|
154082
|
+
case "rejected":
|
|
154083
|
+
reviewCell = chalk14.red("reject".padEnd(reviewWidth));
|
|
154084
|
+
break;
|
|
154085
|
+
case "needs_human_review":
|
|
154086
|
+
reviewCell = chalk14.yellow("human".padEnd(reviewWidth));
|
|
154087
|
+
break;
|
|
154088
|
+
default:
|
|
154089
|
+
reviewCell = chalk14.dim("-".padEnd(reviewWidth));
|
|
154090
|
+
}
|
|
153980
154091
|
const row = [
|
|
153981
154092
|
chalk14.cyan(skill.name.padEnd(nameWidth)),
|
|
153982
154093
|
chalk14.green(("v" + skill.latest_version).padEnd(verWidth)),
|
|
153983
154094
|
statusColor(skill.status.padEnd(statusWidth)),
|
|
154095
|
+
reviewCell,
|
|
153984
154096
|
chalk14.dim(skill.capability_name.padEnd(capWidth)),
|
|
153985
154097
|
chalk14.dim(createdDate)
|
|
153986
154098
|
].join(" ");
|
|
@@ -155055,7 +155167,9 @@ var skillDeleteCommand = new Command20("skill-delete").description("Permanently
|
|
|
155055
155167
|
// dist/commands/skill-status.js
|
|
155056
155168
|
import { Command as Command21 } from "commander";
|
|
155057
155169
|
import chalk18 from "chalk";
|
|
155058
|
-
|
|
155170
|
+
import { writeFileSync as writeFileSync10 } from "node:fs";
|
|
155171
|
+
import { resolve as resolve9 } from "node:path";
|
|
155172
|
+
var skillStatusCommand = new Command21("skill-status").description("Show detailed status for a skill").argument("[skill-name]", "Name of the skill to inspect (defaults to workspace skill)").option("--json", "Output as JSON").option("--workspace <path>", "Use workspace at <path> to default skill-name").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').option("--review-report <file>", "Write a public review report (JSON) to <file>").action(async (skillNameArg, options) => {
|
|
155059
155173
|
try {
|
|
155060
155174
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155061
155175
|
const skillName = skillNameArg ?? ctx.defaultSkillName ?? void 0;
|
|
@@ -155077,17 +155191,56 @@ var skillStatusCommand = new Command21("skill-status").description("Show detaile
|
|
|
155077
155191
|
sessionFetch(ctx, "/grants")
|
|
155078
155192
|
]);
|
|
155079
155193
|
const activeGrants = grantsData.grants.filter((g) => g.capability === detail.capability_name && g.status === "active");
|
|
155194
|
+
if (options.reviewReport) {
|
|
155195
|
+
const report = {
|
|
155196
|
+
skill_id: detail.id,
|
|
155197
|
+
capability_name: detail.capability_name,
|
|
155198
|
+
version: detail.latest_version,
|
|
155199
|
+
review_state: detail.review_state ?? null,
|
|
155200
|
+
public_reason_code: detail.latest_review?.public_reason_code ?? null,
|
|
155201
|
+
public_reason_message: detail.latest_review?.public_reason_message ?? null,
|
|
155202
|
+
last_review_at: detail.latest_review?.last_review_at ?? null
|
|
155203
|
+
};
|
|
155204
|
+
const reportPath = resolve9(options.reviewReport);
|
|
155205
|
+
writeFileSync10(reportPath, JSON.stringify(report, null, 2) + "\n");
|
|
155206
|
+
process.stderr.write(chalk18.green(`Wrote review report to ${reportPath}
|
|
155207
|
+
`));
|
|
155208
|
+
}
|
|
155080
155209
|
if (options.json) {
|
|
155081
155210
|
console.log(JSON.stringify({ ...detail, active_grants: activeGrants.length }, null, 2));
|
|
155082
155211
|
return;
|
|
155083
155212
|
}
|
|
155084
155213
|
const statusColor = detail.status === "active" ? chalk18.green : detail.status === "archived" ? chalk18.yellow : chalk18.dim;
|
|
155085
155214
|
const createdDate = new Date(detail.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
155215
|
+
const reviewState = detail.review_state ?? "approved";
|
|
155216
|
+
let reviewLabel;
|
|
155217
|
+
switch (reviewState) {
|
|
155218
|
+
case "approved":
|
|
155219
|
+
reviewLabel = chalk18.green("Approved");
|
|
155220
|
+
break;
|
|
155221
|
+
case "queued":
|
|
155222
|
+
case "running":
|
|
155223
|
+
reviewLabel = chalk18.yellow("Under review");
|
|
155224
|
+
break;
|
|
155225
|
+
case "rejected":
|
|
155226
|
+
reviewLabel = chalk18.red("Rejected");
|
|
155227
|
+
break;
|
|
155228
|
+
case "needs_human_review":
|
|
155229
|
+
reviewLabel = chalk18.yellow("Awaiting review");
|
|
155230
|
+
break;
|
|
155231
|
+
default:
|
|
155232
|
+
reviewLabel = chalk18.dim(reviewState);
|
|
155233
|
+
}
|
|
155234
|
+
const lastReviewAt = detail.latest_review?.last_review_at ? new Date(detail.latest_review.last_review_at).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : null;
|
|
155086
155235
|
console.log();
|
|
155087
155236
|
console.log(chalk18.bold(` ${detail.name}`));
|
|
155088
155237
|
console.log();
|
|
155089
155238
|
console.log(` Capability: ${detail.capability_name}`);
|
|
155090
155239
|
console.log(` Status: ${statusColor(detail.status)}`);
|
|
155240
|
+
console.log(` Review: ${reviewLabel}${lastReviewAt ? chalk18.dim(` (${lastReviewAt})`) : ""}`);
|
|
155241
|
+
if (reviewState === "rejected" && detail.latest_review?.public_reason_message) {
|
|
155242
|
+
console.log(` Reason: ${chalk18.red(detail.latest_review.public_reason_message)}`);
|
|
155243
|
+
}
|
|
155091
155244
|
console.log(` Version: ${chalk18.green("v" + detail.latest_version)}`);
|
|
155092
155245
|
console.log(` Created: ${chalk18.dim(createdDate)}`);
|
|
155093
155246
|
console.log(` ID: ${chalk18.dim(detail.id)}`);
|
|
@@ -155144,10 +155297,199 @@ var skillUnarchiveCommand = new Command22("skill-unarchive").description("Restor
|
|
|
155144
155297
|
}
|
|
155145
155298
|
});
|
|
155146
155299
|
|
|
155147
|
-
// dist/commands/
|
|
155300
|
+
// dist/commands/skill-acl.js
|
|
155148
155301
|
import { Command as Command23 } from "commander";
|
|
155149
155302
|
import chalk20 from "chalk";
|
|
155150
|
-
var
|
|
155303
|
+
var VALID_ROLES = /* @__PURE__ */ new Set(["read", "write", "owner"]);
|
|
155304
|
+
async function resolveSkill(ctx, skillName) {
|
|
155305
|
+
const data = await sessionFetch(ctx, "/skills");
|
|
155306
|
+
const skill = data.skills.find((s) => s.name.toLowerCase() === skillName.toLowerCase() || s.capability_name.toLowerCase() === skillName.toLowerCase());
|
|
155307
|
+
if (!skill) {
|
|
155308
|
+
process.stderr.write(chalk20.red(`Skill not found: ${skillName}
|
|
155309
|
+
`));
|
|
155310
|
+
process.stderr.write(chalk20.dim("Run `skillvault-publisher list` to see your skills.\n"));
|
|
155311
|
+
process.exit(1);
|
|
155312
|
+
}
|
|
155313
|
+
return skill;
|
|
155314
|
+
}
|
|
155315
|
+
async function runList(ctx, skill, options) {
|
|
155316
|
+
const data = await sessionFetch(ctx, `/skills/${skill.id}/acls`);
|
|
155317
|
+
const acls = data.acls || [];
|
|
155318
|
+
if (options.json) {
|
|
155319
|
+
console.log(JSON.stringify({ skill: skill.name, skill_id: skill.id, acls }, null, 2));
|
|
155320
|
+
return;
|
|
155321
|
+
}
|
|
155322
|
+
console.log();
|
|
155323
|
+
console.log(chalk20.bold(` ACL grants on ${chalk20.cyan(skill.name)}`));
|
|
155324
|
+
console.log();
|
|
155325
|
+
if (acls.length === 0) {
|
|
155326
|
+
console.log(chalk20.dim(" No ACL grants. Account owners and admins always have full access."));
|
|
155327
|
+
console.log(chalk20.dim(` Add a member: skillvault-publisher skill-acl ${skill.name} add <email> --role read|write|owner`));
|
|
155328
|
+
console.log();
|
|
155329
|
+
return;
|
|
155330
|
+
}
|
|
155331
|
+
const emailWidth = Math.max(20, ...acls.map((a) => a.email.length + 2));
|
|
155332
|
+
const roleWidth = 8;
|
|
155333
|
+
const header = [
|
|
155334
|
+
chalk20.dim("Email".padEnd(emailWidth)),
|
|
155335
|
+
chalk20.dim("Role".padEnd(roleWidth)),
|
|
155336
|
+
chalk20.dim("Granted by")
|
|
155337
|
+
].join(" ");
|
|
155338
|
+
console.log(` ${header}`);
|
|
155339
|
+
console.log(` ${chalk20.dim("-".repeat(emailWidth + roleWidth + 24))}`);
|
|
155340
|
+
for (const a of acls) {
|
|
155341
|
+
const roleColor = a.role === "owner" ? chalk20.green : a.role === "write" ? chalk20.cyan : chalk20.dim;
|
|
155342
|
+
const row = [
|
|
155343
|
+
a.email.padEnd(emailWidth),
|
|
155344
|
+
roleColor(a.role.padEnd(roleWidth)),
|
|
155345
|
+
chalk20.dim(a.granted_by || "(self)")
|
|
155346
|
+
].join(" ");
|
|
155347
|
+
console.log(` ${row}`);
|
|
155348
|
+
}
|
|
155349
|
+
console.log();
|
|
155350
|
+
}
|
|
155351
|
+
async function runAdd(ctx, skill, email, options) {
|
|
155352
|
+
if (!options.role) {
|
|
155353
|
+
process.stderr.write(chalk20.red("Error: --role is required (read|write|owner)\n"));
|
|
155354
|
+
process.exit(1);
|
|
155355
|
+
}
|
|
155356
|
+
const role = options.role.toLowerCase();
|
|
155357
|
+
if (!VALID_ROLES.has(role)) {
|
|
155358
|
+
process.stderr.write(chalk20.red(`Invalid --role value: ${options.role}
|
|
155359
|
+
`));
|
|
155360
|
+
process.stderr.write(chalk20.dim(" Must be one of: read, write, owner\n"));
|
|
155361
|
+
process.exit(1);
|
|
155362
|
+
}
|
|
155363
|
+
const res = await fetch(`${ctx.serverUrl}/skills/${skill.id}/acls`, {
|
|
155364
|
+
method: "POST",
|
|
155365
|
+
headers: ctx.headers,
|
|
155366
|
+
body: JSON.stringify({ email, role })
|
|
155367
|
+
});
|
|
155368
|
+
const body = await res.json().catch(() => ({}));
|
|
155369
|
+
if (!res.ok) {
|
|
155370
|
+
if (body.error === "not_a_team_member") {
|
|
155371
|
+
process.stderr.write(chalk20.red(`${email} is not a member of this team.
|
|
155372
|
+
`));
|
|
155373
|
+
process.stderr.write(chalk20.dim(`Add them first: skillvault-publisher team add ${email} --role member
|
|
155374
|
+
`));
|
|
155375
|
+
process.exit(1);
|
|
155376
|
+
}
|
|
155377
|
+
process.stderr.write(chalk20.red(`Failed to grant: ${body.message || body.error || res.statusText}
|
|
155378
|
+
`));
|
|
155379
|
+
process.exit(1);
|
|
155380
|
+
}
|
|
155381
|
+
if (options.json) {
|
|
155382
|
+
console.log(JSON.stringify(body, null, 2));
|
|
155383
|
+
return;
|
|
155384
|
+
}
|
|
155385
|
+
if (body.note) {
|
|
155386
|
+
console.log(chalk20.yellow(` ${body.note}`));
|
|
155387
|
+
return;
|
|
155388
|
+
}
|
|
155389
|
+
const acl = body.acl;
|
|
155390
|
+
console.log(chalk20.green(`Granted ${acl.email} ${chalk20.bold(acl.role)} on ${skill.name}`));
|
|
155391
|
+
}
|
|
155392
|
+
async function runRemove(ctx, skill, target, options) {
|
|
155393
|
+
const data = await sessionFetch(ctx, `/skills/${skill.id}/acls`);
|
|
155394
|
+
const acls = data.acls || [];
|
|
155395
|
+
let acl;
|
|
155396
|
+
if (target.startsWith("acl_")) {
|
|
155397
|
+
acl = acls.find((a) => a.id === target);
|
|
155398
|
+
} else {
|
|
155399
|
+
acl = acls.find((a) => a.email.toLowerCase() === target.toLowerCase());
|
|
155400
|
+
}
|
|
155401
|
+
if (!acl) {
|
|
155402
|
+
process.stderr.write(chalk20.red(`No ACL row matches: ${target}
|
|
155403
|
+
`));
|
|
155404
|
+
process.exit(1);
|
|
155405
|
+
}
|
|
155406
|
+
if (!options.yes) {
|
|
155407
|
+
console.log();
|
|
155408
|
+
console.log(chalk20.yellow.bold(" Warning: ") + `This revokes ${acl.role} access on ${chalk20.cyan(skill.name)} for ${chalk20.cyan(acl.email)}.`);
|
|
155409
|
+
console.log(chalk20.dim(" Add --yes to confirm."));
|
|
155410
|
+
console.log();
|
|
155411
|
+
process.exit(0);
|
|
155412
|
+
}
|
|
155413
|
+
const res = await fetch(`${ctx.serverUrl}/skills/${skill.id}/acls/${acl.id}`, {
|
|
155414
|
+
method: "DELETE",
|
|
155415
|
+
headers: ctx.headers
|
|
155416
|
+
});
|
|
155417
|
+
const body = await res.json().catch(() => ({}));
|
|
155418
|
+
if (!res.ok) {
|
|
155419
|
+
if (body.error === "last_owner") {
|
|
155420
|
+
process.stderr.write(chalk20.red("Cannot remove the last owner ACL on this skill.\n"));
|
|
155421
|
+
process.stderr.write(chalk20.dim(" Grant another member owner access first, or have an account admin manage it.\n"));
|
|
155422
|
+
process.exit(1);
|
|
155423
|
+
}
|
|
155424
|
+
process.stderr.write(chalk20.red(`Failed to remove: ${body.message || body.error || res.statusText}
|
|
155425
|
+
`));
|
|
155426
|
+
process.exit(1);
|
|
155427
|
+
}
|
|
155428
|
+
if (options.json) {
|
|
155429
|
+
console.log(JSON.stringify({ removed: true, acl_id: acl.id, email: acl.email, role: acl.role }, null, 2));
|
|
155430
|
+
return;
|
|
155431
|
+
}
|
|
155432
|
+
console.log(chalk20.green(`Removed ${acl.email} (${acl.role}) from ${skill.name}`));
|
|
155433
|
+
}
|
|
155434
|
+
var skillAclCommand = new Command23("skill-acl").description("Manage per-skill ACL grants for team members").argument("<skill-name>", 'Skill to manage (or "list"/"add"/"remove" if using a workspace default)').argument("<action>", "Action: list | add | remove").argument("[target]", "Email (for add/remove) \u2014 not used by list").option("--role <role>", "Role for add: read | write | owner").option("--yes", "Skip confirmation on remove").option("--workspace <path>", "Use workspace at <path> to default skill-name").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').option("--json", "Output as JSON").action(async (skillNameArg, actionArg, targetArg, options) => {
|
|
155435
|
+
try {
|
|
155436
|
+
let skillName = skillNameArg;
|
|
155437
|
+
let action = actionArg;
|
|
155438
|
+
let target = targetArg;
|
|
155439
|
+
const isActionVerb = (s) => s === "list" || s === "add" || s === "remove";
|
|
155440
|
+
if (isActionVerb(skillNameArg) && !isActionVerb(actionArg)) {
|
|
155441
|
+
action = skillNameArg;
|
|
155442
|
+
target = actionArg;
|
|
155443
|
+
skillName = "";
|
|
155444
|
+
}
|
|
155445
|
+
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155446
|
+
if (!skillName) {
|
|
155447
|
+
if (!ctx.defaultSkillName) {
|
|
155448
|
+
process.stderr.write(chalk20.red("Error: No skill name provided and no workspace context.\n"));
|
|
155449
|
+
process.stderr.write(chalk20.dim(" Pass <skill-name> or run from a linked workspace directory.\n"));
|
|
155450
|
+
process.exit(1);
|
|
155451
|
+
}
|
|
155452
|
+
skillName = ctx.defaultSkillName;
|
|
155453
|
+
}
|
|
155454
|
+
if (!isActionVerb(action)) {
|
|
155455
|
+
process.stderr.write(chalk20.red(`Unknown action: ${action}
|
|
155456
|
+
`));
|
|
155457
|
+
process.stderr.write(chalk20.dim(" Must be one of: list, add, remove\n"));
|
|
155458
|
+
process.exit(1);
|
|
155459
|
+
}
|
|
155460
|
+
const skill = await resolveSkill(ctx, skillName);
|
|
155461
|
+
if (action === "list") {
|
|
155462
|
+
await runList(ctx, skill, options);
|
|
155463
|
+
return;
|
|
155464
|
+
}
|
|
155465
|
+
if (action === "add") {
|
|
155466
|
+
if (!target) {
|
|
155467
|
+
process.stderr.write(chalk20.red("Error: add requires <email>\n"));
|
|
155468
|
+
process.exit(1);
|
|
155469
|
+
}
|
|
155470
|
+
await runAdd(ctx, skill, target, options);
|
|
155471
|
+
return;
|
|
155472
|
+
}
|
|
155473
|
+
if (action === "remove") {
|
|
155474
|
+
if (!target) {
|
|
155475
|
+
process.stderr.write(chalk20.red("Error: remove requires <email-or-id>\n"));
|
|
155476
|
+
process.exit(1);
|
|
155477
|
+
}
|
|
155478
|
+
await runRemove(ctx, skill, target, options);
|
|
155479
|
+
return;
|
|
155480
|
+
}
|
|
155481
|
+
} catch (err) {
|
|
155482
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
155483
|
+
process.stderr.write(chalk20.red(`skill-acl failed: ${message}
|
|
155484
|
+
`));
|
|
155485
|
+
process.exit(1);
|
|
155486
|
+
}
|
|
155487
|
+
});
|
|
155488
|
+
|
|
155489
|
+
// dist/commands/grants.js
|
|
155490
|
+
import { Command as Command24 } from "commander";
|
|
155491
|
+
import chalk21 from "chalk";
|
|
155492
|
+
var grantsCommand = new Command24("grants").description("List capability grants issued to customers").option("--status <status>", "Filter by status: active, revoked, expired").option("--skill <name>", "Filter to grants for a specific skill (capability)").option("--json", "Output as JSON").option("--workspace <path>", "Use workspace at <path> to default --skill").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').option("--all", "Disable workspace --skill default; show grants for all skills").action(async (options) => {
|
|
155151
155493
|
try {
|
|
155152
155494
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155153
155495
|
const data = await sessionFetch(ctx, "/grants");
|
|
@@ -155165,18 +155507,18 @@ var grantsCommand = new Command23("grants").description("List capability grants
|
|
|
155165
155507
|
return;
|
|
155166
155508
|
}
|
|
155167
155509
|
if (grants.length === 0) {
|
|
155168
|
-
console.log(
|
|
155510
|
+
console.log(chalk21.dim("No grants found."));
|
|
155169
155511
|
return;
|
|
155170
155512
|
}
|
|
155171
155513
|
console.log();
|
|
155172
|
-
console.log(
|
|
155514
|
+
console.log(chalk21.bold(" Capability Grants"));
|
|
155173
155515
|
console.log();
|
|
155174
155516
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155175
155517
|
const header = `${pad4("Grant ID", 22)} ${pad4("Skill", 24)} ${pad4("Customer", 22)} ${pad4("Status", 10)} ${pad4("Granted", 12)} ${"Expires"}`;
|
|
155176
|
-
console.log(` ${
|
|
155177
|
-
console.log(` ${
|
|
155518
|
+
console.log(` ${chalk21.dim(header)}`);
|
|
155519
|
+
console.log(` ${chalk21.dim("\u2500".repeat(header.length))}`);
|
|
155178
155520
|
for (const grant of grants) {
|
|
155179
|
-
const statusColor = grant.status === "active" ?
|
|
155521
|
+
const statusColor = grant.status === "active" ? chalk21.green : grant.status === "revoked" ? chalk21.red : grant.status === "expired" ? chalk21.yellow : chalk21.white;
|
|
155180
155522
|
const row = [
|
|
155181
155523
|
pad4(grant.id, 22),
|
|
155182
155524
|
pad4(grant.capability, 24),
|
|
@@ -155188,20 +155530,20 @@ var grantsCommand = new Command23("grants").description("List capability grants
|
|
|
155188
155530
|
console.log(` ${row}`);
|
|
155189
155531
|
}
|
|
155190
155532
|
console.log();
|
|
155191
|
-
console.log(
|
|
155533
|
+
console.log(chalk21.dim(` ${grants.length} grant${grants.length !== 1 ? "s" : ""} total`));
|
|
155192
155534
|
console.log();
|
|
155193
155535
|
} catch (err) {
|
|
155194
155536
|
const message = err instanceof Error ? err.message : String(err);
|
|
155195
|
-
process.stderr.write(
|
|
155537
|
+
process.stderr.write(chalk21.red(`Error: ${message}
|
|
155196
155538
|
`));
|
|
155197
155539
|
process.exit(1);
|
|
155198
155540
|
}
|
|
155199
155541
|
});
|
|
155200
155542
|
|
|
155201
155543
|
// dist/commands/revoke-grant.js
|
|
155202
|
-
import { Command as
|
|
155203
|
-
import
|
|
155204
|
-
var revokeGrantCommand = new
|
|
155544
|
+
import { Command as Command25 } from "commander";
|
|
155545
|
+
import chalk22 from "chalk";
|
|
155546
|
+
var revokeGrantCommand = new Command25("revoke-grant").description("Revoke a capability grant by ID").argument("<grant-id>", "Grant ID to revoke (e.g., gnt_xxx)").option("--yes", "Skip confirmation and revoke immediately").option("--json", "Output as JSON").option("--workspace <path>", "Resolve workspace context (informational only \u2014 grant ID is authoritative)").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').action(async (grantId, options) => {
|
|
155205
155547
|
try {
|
|
155206
155548
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155207
155549
|
if (!options.yes) {
|
|
@@ -155212,7 +155554,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155212
155554
|
return;
|
|
155213
155555
|
}
|
|
155214
155556
|
console.log();
|
|
155215
|
-
console.log(
|
|
155557
|
+
console.log(chalk22.bold(" Grant details"));
|
|
155216
155558
|
console.log();
|
|
155217
155559
|
console.log(` ID: ${grant.id}`);
|
|
155218
155560
|
console.log(` Skill: ${grant.skill}`);
|
|
@@ -155221,7 +155563,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155221
155563
|
console.log(` Granted: ${new Date(grant.granted_at).toLocaleDateString()}`);
|
|
155222
155564
|
console.log(` Expires: ${grant.expires_at ? new Date(grant.expires_at).toLocaleDateString() : "never"}`);
|
|
155223
155565
|
console.log();
|
|
155224
|
-
console.log(
|
|
155566
|
+
console.log(chalk22.yellow(" Add --yes to confirm revocation."));
|
|
155225
155567
|
console.log();
|
|
155226
155568
|
return;
|
|
155227
155569
|
}
|
|
@@ -155230,19 +155572,19 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155230
155572
|
console.log(JSON.stringify(result.grant, null, 2));
|
|
155231
155573
|
return;
|
|
155232
155574
|
}
|
|
155233
|
-
console.log(
|
|
155575
|
+
console.log(chalk22.green(`Revoked grant ${result.grant.id} for ${result.grant.skill}`));
|
|
155234
155576
|
} catch (err) {
|
|
155235
155577
|
const message = err instanceof Error ? err.message : String(err);
|
|
155236
|
-
process.stderr.write(
|
|
155578
|
+
process.stderr.write(chalk22.red(`Error: ${message}
|
|
155237
155579
|
`));
|
|
155238
155580
|
process.exit(1);
|
|
155239
155581
|
}
|
|
155240
155582
|
});
|
|
155241
155583
|
|
|
155242
155584
|
// dist/commands/customers.js
|
|
155243
|
-
import { Command as
|
|
155244
|
-
import
|
|
155245
|
-
var customersCommand = new
|
|
155585
|
+
import { Command as Command26 } from "commander";
|
|
155586
|
+
import chalk23 from "chalk";
|
|
155587
|
+
var customersCommand = new Command26("customers").description("List your customers").option("--json", "Output as JSON").option("--workspace <path>", "Resolve workspace context (defaults from CWD)").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').action(async (options) => {
|
|
155246
155588
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155247
155589
|
try {
|
|
155248
155590
|
const data = await sessionFetch(ctx, "/customers");
|
|
@@ -155252,19 +155594,19 @@ var customersCommand = new Command25("customers").description("List your custome
|
|
|
155252
155594
|
return;
|
|
155253
155595
|
}
|
|
155254
155596
|
if (customers.length === 0) {
|
|
155255
|
-
console.log(
|
|
155597
|
+
console.log(chalk23.dim("No customers found."));
|
|
155256
155598
|
return;
|
|
155257
155599
|
}
|
|
155258
155600
|
console.log();
|
|
155259
|
-
console.log(
|
|
155601
|
+
console.log(chalk23.bold(" Customers"));
|
|
155260
155602
|
console.log();
|
|
155261
155603
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155262
155604
|
const header = `${pad4("Email", 32)} ${pad4("Skills", 8)} ${pad4("Loads", 8)} ${pad4("Status", 10)} Last Active`;
|
|
155263
|
-
console.log(` ${
|
|
155264
|
-
console.log(` ${
|
|
155605
|
+
console.log(` ${chalk23.dim(header)}`);
|
|
155606
|
+
console.log(` ${chalk23.dim("\u2500".repeat(header.length))}`);
|
|
155265
155607
|
for (const c of customers) {
|
|
155266
|
-
const statusColor = c.status === "active" ?
|
|
155267
|
-
const lastActive = c.last_active_at ? new Date(c.last_active_at).toLocaleDateString() :
|
|
155608
|
+
const statusColor = c.status === "active" ? chalk23.green : chalk23.dim;
|
|
155609
|
+
const lastActive = c.last_active_at ? new Date(c.last_active_at).toLocaleDateString() : chalk23.dim("never");
|
|
155268
155610
|
const row = [
|
|
155269
155611
|
pad4(c.email, 32),
|
|
155270
155612
|
pad4(String(c.skills_count), 8),
|
|
@@ -155275,25 +155617,25 @@ var customersCommand = new Command25("customers").description("List your custome
|
|
|
155275
155617
|
console.log(` ${row}`);
|
|
155276
155618
|
}
|
|
155277
155619
|
console.log();
|
|
155278
|
-
console.log(
|
|
155620
|
+
console.log(chalk23.dim(` ${customers.length} customer${customers.length !== 1 ? "s" : ""} total`));
|
|
155279
155621
|
console.log();
|
|
155280
155622
|
} catch (err) {
|
|
155281
155623
|
const message = err instanceof Error ? err.message : String(err);
|
|
155282
|
-
process.stderr.write(
|
|
155624
|
+
process.stderr.write(chalk23.red(`Error: ${message}
|
|
155283
155625
|
`));
|
|
155284
155626
|
process.exit(1);
|
|
155285
155627
|
}
|
|
155286
155628
|
});
|
|
155287
155629
|
|
|
155288
155630
|
// dist/commands/analytics.js
|
|
155289
|
-
import { Command as
|
|
155290
|
-
import
|
|
155291
|
-
var analyticsCommand = new
|
|
155631
|
+
import { Command as Command27 } from "commander";
|
|
155632
|
+
import chalk24 from "chalk";
|
|
155633
|
+
var analyticsCommand = new Command27("analytics").description("View publisher analytics").option("--days <n>", "Number of days to look back", "30").option("--skill <name>", "Filter top skills/stats to a specific skill").option("--json", "Output as JSON").option("--workspace <path>", "Use workspace at <path> to default --skill").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').option("--all", "Disable workspace --skill default; show analytics for all skills").action(async (options) => {
|
|
155292
155634
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155293
155635
|
try {
|
|
155294
155636
|
const days = parseInt(options.days, 10);
|
|
155295
155637
|
if (isNaN(days) || days < 1) {
|
|
155296
|
-
process.stderr.write(
|
|
155638
|
+
process.stderr.write(chalk24.red("--days must be a positive number.\n"));
|
|
155297
155639
|
process.exit(1);
|
|
155298
155640
|
}
|
|
155299
155641
|
const end = /* @__PURE__ */ new Date();
|
|
@@ -155306,11 +155648,11 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155306
155648
|
return;
|
|
155307
155649
|
}
|
|
155308
155650
|
console.log();
|
|
155309
|
-
console.log(
|
|
155651
|
+
console.log(chalk24.bold(" Publisher Analytics"));
|
|
155310
155652
|
console.log();
|
|
155311
|
-
console.log(` ${
|
|
155312
|
-
console.log(` ${
|
|
155313
|
-
console.log(` ${
|
|
155653
|
+
console.log(` ${chalk24.bold("Active Licenses:")} ${data.active_licenses}`);
|
|
155654
|
+
console.log(` ${chalk24.bold("Total Decryptions:")} ${data.total_decryptions}`);
|
|
155655
|
+
console.log(` ${chalk24.bold("Period:")} Last ${days} day${days !== 1 ? "s" : ""} (${start.toLocaleDateString()} \u2013 ${end.toLocaleDateString()})`);
|
|
155314
155656
|
const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
|
|
155315
155657
|
const filterSkill = (skillName) => !effectiveSkill || skillName.toLowerCase() === effectiveSkill.toLowerCase();
|
|
155316
155658
|
const statsMap = new Map((data.skill_stats || []).map((s) => [s.skill_name, s]));
|
|
@@ -155319,12 +155661,12 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155319
155661
|
}
|
|
155320
155662
|
if (data.top_skills && data.top_skills.length > 0) {
|
|
155321
155663
|
console.log();
|
|
155322
|
-
console.log(
|
|
155664
|
+
console.log(chalk24.bold(" Top Skills"));
|
|
155323
155665
|
console.log();
|
|
155324
155666
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155325
155667
|
const header = `${pad4("Skill", 28)} ${pad4("Decryptions", 14)} Active Licenses`;
|
|
155326
|
-
console.log(` ${
|
|
155327
|
-
console.log(` ${
|
|
155668
|
+
console.log(` ${chalk24.dim(header)}`);
|
|
155669
|
+
console.log(` ${chalk24.dim("\u2500".repeat(header.length))}`);
|
|
155328
155670
|
for (const skill of data.top_skills) {
|
|
155329
155671
|
const stats = statsMap.get(skill.name);
|
|
155330
155672
|
const row = [
|
|
@@ -155336,27 +155678,27 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155336
155678
|
}
|
|
155337
155679
|
} else {
|
|
155338
155680
|
console.log();
|
|
155339
|
-
console.log(
|
|
155681
|
+
console.log(chalk24.dim(" No skill activity in this period."));
|
|
155340
155682
|
}
|
|
155341
155683
|
console.log();
|
|
155342
155684
|
} catch (err) {
|
|
155343
155685
|
const message = err instanceof Error ? err.message : String(err);
|
|
155344
|
-
process.stderr.write(
|
|
155686
|
+
process.stderr.write(chalk24.red(`Error: ${message}
|
|
155345
155687
|
`));
|
|
155346
155688
|
process.exit(1);
|
|
155347
155689
|
}
|
|
155348
155690
|
});
|
|
155349
155691
|
|
|
155350
155692
|
// dist/commands/webhook.js
|
|
155351
|
-
import { Command as
|
|
155352
|
-
import
|
|
155353
|
-
var webhookCommand = new
|
|
155693
|
+
import { Command as Command28 } from "commander";
|
|
155694
|
+
import chalk25 from "chalk";
|
|
155695
|
+
var webhookCommand = new Command28("webhook").description("Manage publisher webhook (set, test, status)").argument("<action>", "Action: set, test, or status").option("--url <url>", "Webhook URL (required for set)").option("--json", "Output as JSON").action(async (action, options) => {
|
|
155354
155696
|
try {
|
|
155355
155697
|
const ctx = requireSession();
|
|
155356
155698
|
switch (action) {
|
|
155357
155699
|
case "set": {
|
|
155358
155700
|
if (!options.url) {
|
|
155359
|
-
process.stderr.write(
|
|
155701
|
+
process.stderr.write(chalk25.red("Missing --url option. Usage: skillvault-publisher webhook set --url <url>\n"));
|
|
155360
155702
|
process.exit(1);
|
|
155361
155703
|
}
|
|
155362
155704
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/webhook`, { method: "POST", body: { url: options.url } });
|
|
@@ -155365,12 +155707,12 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155365
155707
|
return;
|
|
155366
155708
|
}
|
|
155367
155709
|
console.log();
|
|
155368
|
-
console.log(
|
|
155710
|
+
console.log(chalk25.green(" Webhook configured"));
|
|
155369
155711
|
console.log();
|
|
155370
155712
|
console.log(` ${"URL:".padEnd(18)} ${data.webhook_url}`);
|
|
155371
|
-
console.log(` ${"Signing Secret:".padEnd(18)} ${
|
|
155713
|
+
console.log(` ${"Signing Secret:".padEnd(18)} ${chalk25.yellow(data.signing_secret)}`);
|
|
155372
155714
|
console.log();
|
|
155373
|
-
console.log(
|
|
155715
|
+
console.log(chalk25.dim(" Store the signing secret securely. It will not be shown again."));
|
|
155374
155716
|
console.log();
|
|
155375
155717
|
break;
|
|
155376
155718
|
}
|
|
@@ -155381,7 +155723,7 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155381
155723
|
return;
|
|
155382
155724
|
}
|
|
155383
155725
|
console.log();
|
|
155384
|
-
console.log(
|
|
155726
|
+
console.log(chalk25.green(" Test event sent to webhook URL"));
|
|
155385
155727
|
console.log();
|
|
155386
155728
|
break;
|
|
155387
155729
|
}
|
|
@@ -155393,36 +155735,36 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155393
155735
|
}
|
|
155394
155736
|
console.log();
|
|
155395
155737
|
if (data.webhook_url) {
|
|
155396
|
-
console.log(
|
|
155738
|
+
console.log(chalk25.bold(" Webhook Status"));
|
|
155397
155739
|
console.log();
|
|
155398
155740
|
console.log(` ${"URL:".padEnd(12)} ${data.webhook_url}`);
|
|
155399
|
-
console.log(` ${"Status:".padEnd(12)} ${
|
|
155741
|
+
console.log(` ${"Status:".padEnd(12)} ${chalk25.green("configured")}`);
|
|
155400
155742
|
} else {
|
|
155401
|
-
console.log(
|
|
155743
|
+
console.log(chalk25.dim(" No webhook configured."));
|
|
155402
155744
|
console.log();
|
|
155403
|
-
console.log(
|
|
155745
|
+
console.log(chalk25.dim(" Set one with: skillvault-publisher webhook set --url <url>"));
|
|
155404
155746
|
}
|
|
155405
155747
|
console.log();
|
|
155406
155748
|
break;
|
|
155407
155749
|
}
|
|
155408
155750
|
default:
|
|
155409
|
-
process.stderr.write(
|
|
155751
|
+
process.stderr.write(chalk25.red(`Unknown action: ${action}
|
|
155410
155752
|
`));
|
|
155411
|
-
process.stderr.write(
|
|
155753
|
+
process.stderr.write(chalk25.dim("Valid actions: set, test, status\n"));
|
|
155412
155754
|
process.exit(1);
|
|
155413
155755
|
}
|
|
155414
155756
|
} catch (err) {
|
|
155415
155757
|
const message = err instanceof Error ? err.message : String(err);
|
|
155416
|
-
process.stderr.write(
|
|
155758
|
+
process.stderr.write(chalk25.red(`Error: ${message}
|
|
155417
155759
|
`));
|
|
155418
155760
|
process.exit(1);
|
|
155419
155761
|
}
|
|
155420
155762
|
});
|
|
155421
155763
|
|
|
155422
155764
|
// dist/commands/audit.js
|
|
155423
|
-
import { Command as
|
|
155424
|
-
import
|
|
155425
|
-
var auditCommand = new
|
|
155765
|
+
import { Command as Command29 } from "commander";
|
|
155766
|
+
import chalk26 from "chalk";
|
|
155767
|
+
var auditCommand = new Command29("audit").description("View audit log events").option("--type <event_type>", "Filter by event type").option("--skill <name>", "Filter by capability/skill name").option("--since <date>", "Filter events since ISO date").option("--limit <n>", "Number of events to return", "20").option("--export <format>", "Export as csv or json").option("--json", "Output as JSON").option("--workspace <path>", "Use workspace at <path> to default --skill").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').option("--all", "Disable workspace --skill default; show events for all skills").action(async (options) => {
|
|
155426
155768
|
try {
|
|
155427
155769
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155428
155770
|
const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
|
|
@@ -155437,7 +155779,7 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155437
155779
|
if (options.export) {
|
|
155438
155780
|
const format = options.export.toLowerCase();
|
|
155439
155781
|
if (format !== "csv" && format !== "json") {
|
|
155440
|
-
process.stderr.write(
|
|
155782
|
+
process.stderr.write(chalk26.red('Export format must be "csv" or "json".\n'));
|
|
155441
155783
|
process.exit(1);
|
|
155442
155784
|
}
|
|
155443
155785
|
params.set("format", format);
|
|
@@ -155456,16 +155798,16 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155456
155798
|
return;
|
|
155457
155799
|
}
|
|
155458
155800
|
if (events.length === 0) {
|
|
155459
|
-
console.log(
|
|
155801
|
+
console.log(chalk26.dim("No audit events found."));
|
|
155460
155802
|
return;
|
|
155461
155803
|
}
|
|
155462
155804
|
console.log();
|
|
155463
|
-
console.log(
|
|
155805
|
+
console.log(chalk26.bold(" Audit Log"));
|
|
155464
155806
|
console.log();
|
|
155465
155807
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155466
155808
|
const header = `${pad4("Event Type", 22)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} ${"Time"}`;
|
|
155467
|
-
console.log(` ${
|
|
155468
|
-
console.log(` ${
|
|
155809
|
+
console.log(` ${chalk26.dim(header)}`);
|
|
155810
|
+
console.log(` ${chalk26.dim("\u2500".repeat(header.length))}`);
|
|
155469
155811
|
for (const event of events) {
|
|
155470
155812
|
const skill = event.capability ? event.capability.replace(/^skill\//, "") : "-";
|
|
155471
155813
|
const agent = event.agent_id ? event.agent_id.slice(0, 18) : "-";
|
|
@@ -155479,45 +155821,45 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155479
155821
|
console.log(` ${row}`);
|
|
155480
155822
|
}
|
|
155481
155823
|
console.log();
|
|
155482
|
-
console.log(
|
|
155824
|
+
console.log(chalk26.dim(` Showing ${events.length} event${events.length !== 1 ? "s" : ""}`));
|
|
155483
155825
|
if (data.has_more) {
|
|
155484
|
-
console.log(
|
|
155826
|
+
console.log(chalk26.dim(` More results available`));
|
|
155485
155827
|
}
|
|
155486
155828
|
console.log();
|
|
155487
155829
|
} catch (err) {
|
|
155488
155830
|
const message = err instanceof Error ? err.message : String(err);
|
|
155489
|
-
process.stderr.write(
|
|
155831
|
+
process.stderr.write(chalk26.red(`Error: ${message}
|
|
155490
155832
|
`));
|
|
155491
155833
|
process.exit(1);
|
|
155492
155834
|
}
|
|
155493
155835
|
});
|
|
155494
155836
|
|
|
155495
155837
|
// dist/commands/investigate.js
|
|
155496
|
-
import { Command as
|
|
155497
|
-
import
|
|
155498
|
-
import { readFileSync as readFileSync15, mkdirSync as mkdirSync9, writeFileSync as
|
|
155838
|
+
import { Command as Command30 } from "commander";
|
|
155839
|
+
import chalk27 from "chalk";
|
|
155840
|
+
import { readFileSync as readFileSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
155499
155841
|
import { join as join14 } from "node:path";
|
|
155500
|
-
var orange =
|
|
155842
|
+
var orange = chalk27.hex("#f97316");
|
|
155501
155843
|
function riskColor2(level) {
|
|
155502
155844
|
switch (level.toLowerCase()) {
|
|
155503
155845
|
case "low":
|
|
155504
|
-
return
|
|
155846
|
+
return chalk27.green;
|
|
155505
155847
|
case "watch":
|
|
155506
|
-
return
|
|
155848
|
+
return chalk27.yellow;
|
|
155507
155849
|
case "alert":
|
|
155508
155850
|
return orange;
|
|
155509
155851
|
case "critical":
|
|
155510
|
-
return
|
|
155852
|
+
return chalk27.red;
|
|
155511
155853
|
default:
|
|
155512
|
-
return
|
|
155854
|
+
return chalk27.white;
|
|
155513
155855
|
}
|
|
155514
155856
|
}
|
|
155515
155857
|
function confidenceColor(c) {
|
|
155516
155858
|
if (c >= 0.9)
|
|
155517
|
-
return
|
|
155859
|
+
return chalk27.green;
|
|
155518
155860
|
if (c >= 0.5)
|
|
155519
|
-
return
|
|
155520
|
-
return
|
|
155861
|
+
return chalk27.yellow;
|
|
155862
|
+
return chalk27.red;
|
|
155521
155863
|
}
|
|
155522
155864
|
function pad(s, n) {
|
|
155523
155865
|
return s.padEnd(n).slice(0, n);
|
|
@@ -155533,30 +155875,30 @@ function toRawGitHubUrl(url) {
|
|
|
155533
155875
|
}
|
|
155534
155876
|
function displayResults(report) {
|
|
155535
155877
|
console.log();
|
|
155536
|
-
console.log(
|
|
155878
|
+
console.log(chalk27.bold(" Investigation Results"));
|
|
155537
155879
|
console.log();
|
|
155538
|
-
console.log(` ${
|
|
155539
|
-
console.log(` ${
|
|
155540
|
-
console.log(` ${
|
|
155541
|
-
console.log(` ${
|
|
155880
|
+
console.log(` ${chalk27.bold("Investigation ID:")} ${report.investigation_id}`);
|
|
155881
|
+
console.log(` ${chalk27.bold("Skill:")} ${report.skill_name}`);
|
|
155882
|
+
console.log(` ${chalk27.bold("Total Licensees:")} ${report.total_licensees}`);
|
|
155883
|
+
console.log(` ${chalk27.bold("Timestamp:")} ${new Date(report.created_at).toLocaleString()}`);
|
|
155542
155884
|
if (report.heartbeat_matches.length > 0) {
|
|
155543
155885
|
console.log();
|
|
155544
155886
|
const maxConf = Math.max(...report.heartbeat_matches.map((m) => m.confidence));
|
|
155545
155887
|
const confStr = (maxConf * 100).toFixed(0) + "%";
|
|
155546
155888
|
const confFn = confidenceColor(maxConf);
|
|
155547
|
-
console.log(` ${
|
|
155889
|
+
console.log(` ${chalk27.bold("Forensic Match:")} ${confFn(confStr + " confidence")} (${report.heartbeat_matches.length} match${report.heartbeat_matches.length !== 1 ? "es" : ""})`);
|
|
155548
155890
|
}
|
|
155549
155891
|
console.log();
|
|
155550
155892
|
if (report.suspects.length === 0) {
|
|
155551
|
-
console.log(
|
|
155893
|
+
console.log(chalk27.dim(" No suspects identified."));
|
|
155552
155894
|
console.log();
|
|
155553
155895
|
return;
|
|
155554
155896
|
}
|
|
155555
|
-
console.log(
|
|
155897
|
+
console.log(chalk27.bold(" Suspect Ranking"));
|
|
155556
155898
|
console.log();
|
|
155557
155899
|
const header = `${pad("Suspect", 24)} ${pad("Risk Level", 12)} ${pad("Confidence", 12)} ${pad("Anomalies", 10)} ${"Strikes"}`;
|
|
155558
|
-
console.log(` ${
|
|
155559
|
-
console.log(` ${
|
|
155900
|
+
console.log(` ${chalk27.dim(header)}`);
|
|
155901
|
+
console.log(` ${chalk27.dim("\u2500".repeat(header.length))}`);
|
|
155560
155902
|
for (const s of report.suspects) {
|
|
155561
155903
|
const colorFn = riskColor2(s.risk_level);
|
|
155562
155904
|
const label = s.customer_email || s.licensee_id.slice(0, 22);
|
|
@@ -155570,8 +155912,8 @@ function displayResults(report) {
|
|
|
155570
155912
|
console.log(` ${row}`);
|
|
155571
155913
|
}
|
|
155572
155914
|
console.log();
|
|
155573
|
-
console.log(
|
|
155574
|
-
console.log(
|
|
155915
|
+
console.log(chalk27.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
|
|
155916
|
+
console.log(chalk27.dim(" Contact investigations@getskillvault.com for the complete evidence package."));
|
|
155575
155917
|
console.log();
|
|
155576
155918
|
}
|
|
155577
155919
|
function buildHtmlReport(report, _auditEvents, metadata) {
|
|
@@ -155816,7 +156158,7 @@ ${report.suspects.length > 0 ? `<table>
|
|
|
155816
156158
|
</body>
|
|
155817
156159
|
</html>`;
|
|
155818
156160
|
}
|
|
155819
|
-
var investigateCommand = new
|
|
156161
|
+
var investigateCommand = new Command30("investigate").description("Investigate a suspected skill leak").argument("<skill-name>", "Name of the skill to investigate").option("--url <url>", "Fetch leaked content from a URL (GitHub raw, gist, etc.)").option("--file <path>", "Read leaked content from a local file").option("--report <dir>", "Generate full investigation report package to directory").option("--json", "Output as JSON").action(async (skillName, options) => {
|
|
155820
156162
|
try {
|
|
155821
156163
|
const ctx = requireSession();
|
|
155822
156164
|
let leakedContent;
|
|
@@ -155824,12 +156166,12 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155824
156166
|
if (options.url) {
|
|
155825
156167
|
const rawUrl = toRawGitHubUrl(options.url);
|
|
155826
156168
|
if (rawUrl !== options.url) {
|
|
155827
|
-
console.log(
|
|
156169
|
+
console.log(chalk27.dim(` Auto-converted GitHub blob URL to raw URL`));
|
|
155828
156170
|
}
|
|
155829
|
-
console.log(
|
|
156171
|
+
console.log(chalk27.dim(` Fetching leaked content from ${rawUrl}...`));
|
|
155830
156172
|
const resp = await fetch(rawUrl);
|
|
155831
156173
|
if (!resp.ok) {
|
|
155832
|
-
process.stderr.write(
|
|
156174
|
+
process.stderr.write(chalk27.red(`Failed to fetch URL: ${resp.status} ${resp.statusText}
|
|
155833
156175
|
`));
|
|
155834
156176
|
process.exit(1);
|
|
155835
156177
|
}
|
|
@@ -155840,24 +156182,24 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155840
156182
|
leakedContent = readFileSync15(options.file, "utf-8");
|
|
155841
156183
|
} catch (err) {
|
|
155842
156184
|
const msg = err instanceof Error ? err.message : String(err);
|
|
155843
|
-
process.stderr.write(
|
|
156185
|
+
process.stderr.write(chalk27.red(`Failed to read file: ${msg}
|
|
155844
156186
|
`));
|
|
155845
156187
|
process.exit(1);
|
|
155846
156188
|
}
|
|
155847
156189
|
sourceLabel = options.file;
|
|
155848
156190
|
} else {
|
|
155849
|
-
process.stderr.write(
|
|
156191
|
+
process.stderr.write(chalk27.red("Provide leaked content with --url <url> or --file <path>.\n"));
|
|
155850
156192
|
process.exit(1);
|
|
155851
156193
|
}
|
|
155852
|
-
console.log(
|
|
156194
|
+
console.log(chalk27.dim(` Loaded ${leakedContent.length.toLocaleString()} chars of leaked content`));
|
|
155853
156195
|
const skillsData = await sessionFetch(ctx, "/skills");
|
|
155854
156196
|
const skill = skillsData.skills.find((s) => s.name.toLowerCase() === skillName.toLowerCase());
|
|
155855
156197
|
if (!skill) {
|
|
155856
|
-
process.stderr.write(
|
|
156198
|
+
process.stderr.write(chalk27.red(`Skill "${skillName}" not found. Use \`skillvault-publisher list\` to see your skills.
|
|
155857
156199
|
`));
|
|
155858
156200
|
process.exit(1);
|
|
155859
156201
|
}
|
|
155860
|
-
console.log(
|
|
156202
|
+
console.log(chalk27.dim(` Running investigation on "${skill.name}"...`));
|
|
155861
156203
|
const report = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/investigate`, {
|
|
155862
156204
|
method: "POST",
|
|
155863
156205
|
body: { skill_id: skill.id, leaked_content: leakedContent }
|
|
@@ -155883,13 +156225,13 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155883
156225
|
source: sourceLabel,
|
|
155884
156226
|
notice: "This is an executive summary. Full evidence is retained server-side. Contact investigations@getskillvault.com for the complete evidence package."
|
|
155885
156227
|
};
|
|
155886
|
-
|
|
155887
|
-
|
|
156228
|
+
writeFileSync11(join14(dir, "metadata.json"), JSON.stringify(metadata, null, 2) + "\n");
|
|
156229
|
+
writeFileSync11(join14(dir, "summary.json"), JSON.stringify({
|
|
155888
156230
|
_generated_by: "SkillVault (https://getskillvault.com)",
|
|
155889
156231
|
...report
|
|
155890
156232
|
}, null, 2) + "\n");
|
|
155891
156233
|
const html = buildHtmlReport(report, [], metadata);
|
|
155892
|
-
|
|
156234
|
+
writeFileSync11(join14(dir, "report.html"), html);
|
|
155893
156235
|
const pdfPath = join14(dir, "report.pdf");
|
|
155894
156236
|
const { generatePdfReport: generatePdfReport2 } = await Promise.resolve().then(() => (init_pdf_report(), pdf_report_exports));
|
|
155895
156237
|
await generatePdfReport2({
|
|
@@ -155903,23 +156245,23 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155903
156245
|
heartbeat_matches: report.heartbeat_matches,
|
|
155904
156246
|
audit_events: []
|
|
155905
156247
|
}, pdfPath);
|
|
155906
|
-
console.log(
|
|
155907
|
-
console.log(
|
|
155908
|
-
console.log(
|
|
156248
|
+
console.log(chalk27.green(` Report saved to ${dir}/`) + chalk27.dim(" (4 files)"));
|
|
156249
|
+
console.log(chalk27.dim(` PDF: report.pdf`));
|
|
156250
|
+
console.log(chalk27.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
|
|
155909
156251
|
console.log();
|
|
155910
156252
|
}
|
|
155911
156253
|
} catch (err) {
|
|
155912
156254
|
const message = err instanceof Error ? err.message : String(err);
|
|
155913
|
-
process.stderr.write(
|
|
156255
|
+
process.stderr.write(chalk27.red(`Error: ${message}
|
|
155914
156256
|
`));
|
|
155915
156257
|
process.exit(1);
|
|
155916
156258
|
}
|
|
155917
156259
|
});
|
|
155918
156260
|
|
|
155919
156261
|
// dist/commands/watchtower.js
|
|
155920
|
-
import { Command as
|
|
155921
|
-
import
|
|
155922
|
-
var watchtowerCommand = new
|
|
156262
|
+
import { Command as Command31 } from "commander";
|
|
156263
|
+
import chalk28 from "chalk";
|
|
156264
|
+
var watchtowerCommand = new Command31("watchtower").description("Watchtower security dashboard").option("--json", "Output as JSON").option("--workspace <path>", "Resolve workspace context (defaults from CWD)").option("--quiet", 'Suppress the "(using workspace \u2026)" stderr note').action(async (options) => {
|
|
155923
156265
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155924
156266
|
try {
|
|
155925
156267
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/watchtower`);
|
|
@@ -155930,30 +156272,30 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155930
156272
|
const { summary } = data;
|
|
155931
156273
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155932
156274
|
console.log();
|
|
155933
|
-
console.log(
|
|
156275
|
+
console.log(chalk28.bold(" Watchtower \u2014 Security Overview"));
|
|
155934
156276
|
console.log();
|
|
155935
|
-
console.log(` ${
|
|
156277
|
+
console.log(` ${chalk28.bold("Skills")} ${summary.total_skills} ${chalk28.dim("|")} ${chalk28.bold("Licenses")} ${summary.total_licenses} ${chalk28.dim("|")} ${chalk28.bold("Alerts (7d)")} ${summary.active_alerts > 0 ? chalk28.yellow(String(summary.active_alerts)) : "0"} ${chalk28.dim("|")} ${chalk28.bold("Flagged")} ${summary.flagged_customers > 0 ? chalk28.red(String(summary.flagged_customers)) : "0"} ${chalk28.dim("|")} ${chalk28.bold("Suspended")} ${summary.suspended_grants > 0 ? chalk28.red(String(summary.suspended_grants)) : "0"}`);
|
|
155936
156278
|
if (data.flagged_customers && data.flagged_customers.length > 0) {
|
|
155937
156279
|
console.log();
|
|
155938
|
-
console.log(
|
|
156280
|
+
console.log(chalk28.bold(" Flagged Customers"));
|
|
155939
156281
|
console.log();
|
|
155940
156282
|
const header = `${pad4("Agent ID", 20)} ${pad4("Risk Score", 12)} ${pad4("Level", 10)} ${pad4("Strikes", 9)} ${pad4("Status", 12)} Skills`;
|
|
155941
|
-
console.log(` ${
|
|
155942
|
-
console.log(` ${
|
|
156283
|
+
console.log(` ${chalk28.dim(header)}`);
|
|
156284
|
+
console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
|
|
155943
156285
|
for (const c of data.flagged_customers) {
|
|
155944
156286
|
const agentShort = c.agent_id.length > 18 ? c.agent_id.slice(0, 18) + "\u2026" : c.agent_id;
|
|
155945
156287
|
let levelColored;
|
|
155946
156288
|
if (c.risk_level === "critical") {
|
|
155947
|
-
levelColored =
|
|
156289
|
+
levelColored = chalk28.red.bold(pad4(c.risk_level, 10));
|
|
155948
156290
|
} else if (c.risk_level === "high") {
|
|
155949
|
-
levelColored =
|
|
156291
|
+
levelColored = chalk28.red(pad4(c.risk_level, 10));
|
|
155950
156292
|
} else if (c.risk_level === "medium") {
|
|
155951
|
-
levelColored =
|
|
156293
|
+
levelColored = chalk28.yellow(pad4(c.risk_level, 10));
|
|
155952
156294
|
} else {
|
|
155953
|
-
levelColored =
|
|
156295
|
+
levelColored = chalk28.dim(pad4(c.risk_level, 10));
|
|
155954
156296
|
}
|
|
155955
|
-
const statusColored = c.status === "suspended" ?
|
|
155956
|
-
const skills = c.capabilities.length > 0 ? c.capabilities.join(", ") :
|
|
156297
|
+
const statusColored = c.status === "suspended" ? chalk28.red(pad4(c.status, 12)) : pad4(c.status, 12);
|
|
156298
|
+
const skills = c.capabilities.length > 0 ? c.capabilities.join(", ") : chalk28.dim("none");
|
|
155957
156299
|
const row = [
|
|
155958
156300
|
pad4(agentShort, 20),
|
|
155959
156301
|
pad4(String(c.risk_score), 12),
|
|
@@ -155967,15 +156309,15 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155967
156309
|
}
|
|
155968
156310
|
if (data.recent_events && data.recent_events.length > 0) {
|
|
155969
156311
|
console.log();
|
|
155970
|
-
console.log(
|
|
156312
|
+
console.log(chalk28.bold(" Recent Security Events"));
|
|
155971
156313
|
console.log();
|
|
155972
156314
|
const header = `${pad4("Event Type", 28)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} Time`;
|
|
155973
|
-
console.log(` ${
|
|
155974
|
-
console.log(` ${
|
|
156315
|
+
console.log(` ${chalk28.dim(header)}`);
|
|
156316
|
+
console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
|
|
155975
156317
|
const events = data.recent_events.slice(0, 10);
|
|
155976
156318
|
for (const e of events) {
|
|
155977
|
-
const skill = e.capability ? e.capability.replace(/^skill\//, "") :
|
|
155978
|
-
const agent = e.agent_id ? e.agent_id.slice(0, 18) :
|
|
156319
|
+
const skill = e.capability ? e.capability.replace(/^skill\//, "") : chalk28.dim("-");
|
|
156320
|
+
const agent = e.agent_id ? e.agent_id.slice(0, 18) : chalk28.dim("-");
|
|
155979
156321
|
const time = new Date(e.created_at).toLocaleString();
|
|
155980
156322
|
const row = [
|
|
155981
156323
|
pad4(e.event_type, 28),
|
|
@@ -155988,25 +156330,25 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155988
156330
|
}
|
|
155989
156331
|
if ((!data.flagged_customers || data.flagged_customers.length === 0) && (!data.recent_events || data.recent_events.length === 0)) {
|
|
155990
156332
|
console.log();
|
|
155991
|
-
console.log(
|
|
156333
|
+
console.log(chalk28.green(" All clear \u2014 no security alerts in the last 7 days."));
|
|
155992
156334
|
}
|
|
155993
156335
|
console.log();
|
|
155994
156336
|
} catch (err) {
|
|
155995
156337
|
const message = err instanceof Error ? err.message : String(err);
|
|
155996
|
-
process.stderr.write(
|
|
156338
|
+
process.stderr.write(chalk28.red(`Error: ${message}
|
|
155997
156339
|
`));
|
|
155998
156340
|
process.exit(1);
|
|
155999
156341
|
}
|
|
156000
156342
|
});
|
|
156001
156343
|
|
|
156002
156344
|
// dist/commands/watermark-decode.js
|
|
156003
|
-
import { Command as
|
|
156004
|
-
import
|
|
156345
|
+
import { Command as Command32 } from "commander";
|
|
156346
|
+
import chalk29 from "chalk";
|
|
156005
156347
|
import { readFileSync as readFileSync16 } from "node:fs";
|
|
156006
|
-
var watermarkDecodeCommand = new
|
|
156348
|
+
var watermarkDecodeCommand = new Command32("watermark-decode").description("Analyze leaked content for forensic watermarks (local-only)").option("--file <path>", "Path to file with leaked content").option("--json", "Output as JSON").action(async (options) => {
|
|
156007
156349
|
try {
|
|
156008
156350
|
if (!options.file) {
|
|
156009
|
-
process.stderr.write(
|
|
156351
|
+
process.stderr.write(chalk29.red("Provide --file <path> with the leaked content\n"));
|
|
156010
156352
|
process.exit(1);
|
|
156011
156353
|
}
|
|
156012
156354
|
let content;
|
|
@@ -156014,7 +156356,7 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
|
|
|
156014
156356
|
content = readFileSync16(options.file, "utf8");
|
|
156015
156357
|
} catch (err) {
|
|
156016
156358
|
const msg = err instanceof Error ? err.message : String(err);
|
|
156017
|
-
process.stderr.write(
|
|
156359
|
+
process.stderr.write(chalk29.red(`Cannot read file: ${msg}
|
|
156018
156360
|
`));
|
|
156019
156361
|
process.exit(1);
|
|
156020
156362
|
}
|
|
@@ -156044,56 +156386,56 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
|
|
|
156044
156386
|
return;
|
|
156045
156387
|
}
|
|
156046
156388
|
console.log();
|
|
156047
|
-
console.log(
|
|
156389
|
+
console.log(chalk29.bold(" Watermark Analysis"));
|
|
156048
156390
|
console.log();
|
|
156049
|
-
console.log(
|
|
156391
|
+
console.log(chalk29.bold(" Zero-Width Watermark"));
|
|
156050
156392
|
if (watermark.found) {
|
|
156051
|
-
console.log(` Licensee ID: ${
|
|
156393
|
+
console.log(` Licensee ID: ${chalk29.green.bold(watermark.licenseeId)}`);
|
|
156052
156394
|
} else {
|
|
156053
|
-
console.log(` ${
|
|
156395
|
+
console.log(` ${chalk29.dim("Not found")}`);
|
|
156054
156396
|
}
|
|
156055
156397
|
console.log();
|
|
156056
|
-
console.log(
|
|
156398
|
+
console.log(chalk29.bold(" Heartbeat Markers"));
|
|
156057
156399
|
if (heartbeats.hb1) {
|
|
156058
|
-
console.log(` HB1: ${
|
|
156400
|
+
console.log(` HB1: ${chalk29.green(heartbeats.hb1)}`);
|
|
156059
156401
|
} else {
|
|
156060
|
-
console.log(` HB1: ${
|
|
156402
|
+
console.log(` HB1: ${chalk29.dim("Not found")}`);
|
|
156061
156403
|
}
|
|
156062
156404
|
if (heartbeats.hb2) {
|
|
156063
|
-
console.log(` HB2: ${
|
|
156405
|
+
console.log(` HB2: ${chalk29.green(heartbeats.hb2)}`);
|
|
156064
156406
|
} else {
|
|
156065
|
-
console.log(` HB2: ${
|
|
156407
|
+
console.log(` HB2: ${chalk29.dim("Not found")}`);
|
|
156066
156408
|
}
|
|
156067
156409
|
if (candidates.length > 0) {
|
|
156068
|
-
console.log(` ${
|
|
156410
|
+
console.log(` ${chalk29.dim(`${candidates.length} potential heartbeat candidate${candidates.length !== 1 ? "s" : ""} found`)}`);
|
|
156069
156411
|
}
|
|
156070
156412
|
console.log();
|
|
156071
|
-
console.log(
|
|
156413
|
+
console.log(chalk29.bold(" Semantic Fingerprint"));
|
|
156072
156414
|
if (hasFingerprint) {
|
|
156073
156415
|
const binaryStr = fingerprint.map((v) => v === 1 ? "1" : v === -1 ? "X" : "0").join("");
|
|
156074
156416
|
const variationPoints = fingerprint.filter((v) => v !== 0).length;
|
|
156075
|
-
console.log(` Pattern: ${
|
|
156076
|
-
console.log(` ${
|
|
156417
|
+
console.log(` Pattern: ${chalk29.cyan(binaryStr)}`);
|
|
156418
|
+
console.log(` ${chalk29.dim(`${variationPoints} variation point${variationPoints !== 1 ? "s" : ""} detected`)}`);
|
|
156077
156419
|
} else {
|
|
156078
|
-
console.log(` ${
|
|
156420
|
+
console.log(` ${chalk29.dim("No variation points detected")}`);
|
|
156079
156421
|
}
|
|
156080
156422
|
console.log();
|
|
156081
|
-
const countColor = signalsDetected > 0 ?
|
|
156423
|
+
const countColor = signalsDetected > 0 ? chalk29.green.bold : chalk29.dim;
|
|
156082
156424
|
console.log(` ${countColor(`${signalsDetected} of 4`)} forensic signals detected`);
|
|
156083
156425
|
console.log();
|
|
156084
156426
|
} catch (err) {
|
|
156085
156427
|
const message = err instanceof Error ? err.message : String(err);
|
|
156086
|
-
process.stderr.write(
|
|
156428
|
+
process.stderr.write(chalk29.red(`Error: ${message}
|
|
156087
156429
|
`));
|
|
156088
156430
|
process.exit(1);
|
|
156089
156431
|
}
|
|
156090
156432
|
});
|
|
156091
156433
|
|
|
156092
156434
|
// dist/commands/link.js
|
|
156093
|
-
import { Command as
|
|
156094
|
-
import
|
|
156435
|
+
import { Command as Command33 } from "commander";
|
|
156436
|
+
import chalk30 from "chalk";
|
|
156095
156437
|
import { existsSync as existsSync14, readFileSync as readFileSync17, statSync as statSync6 } from "node:fs";
|
|
156096
|
-
import { resolve as
|
|
156438
|
+
import { resolve as resolve10, join as join15 } from "node:path";
|
|
156097
156439
|
function parseFrontmatter4(content) {
|
|
156098
156440
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
156099
156441
|
if (!match)
|
|
@@ -156112,12 +156454,12 @@ function parseFrontmatter4(content) {
|
|
|
156112
156454
|
}
|
|
156113
156455
|
return result;
|
|
156114
156456
|
}
|
|
156115
|
-
var linkCommand = new
|
|
156457
|
+
var linkCommand = new Command33("link").description("Link a skill source directory to your publisher account").argument("[directory]", "Skill directory to link (defaults to CWD)").option("--workspace <path>", "Explicit workspace directory (precedence over positional)").option("--force", "Overwrite an existing link to a different publisher_id").option("--name <name>", "Override skill name (defaults to SKILL.md frontmatter name)").option("--capability <cap>", "Override capability_name (advanced \u2014 usually matches skill name)").action(async (directory, options) => {
|
|
156116
156458
|
try {
|
|
156117
156459
|
const ctx = requireSession();
|
|
156118
|
-
const dirPath = options.workspace ?
|
|
156460
|
+
const dirPath = options.workspace ? resolve10(options.workspace) : directory ? resolve10(directory) : process.cwd();
|
|
156119
156461
|
if (!existsSync14(dirPath) || !statSync6(dirPath).isDirectory()) {
|
|
156120
|
-
process.stderr.write(
|
|
156462
|
+
process.stderr.write(chalk30.red(`Error: "${dirPath}" is not a valid directory
|
|
156121
156463
|
`));
|
|
156122
156464
|
process.exit(1);
|
|
156123
156465
|
}
|
|
@@ -156127,17 +156469,17 @@ var linkCommand = new Command32("link").description("Link a skill source directo
|
|
|
156127
156469
|
const existing = loadWorkspace(dirPath);
|
|
156128
156470
|
const skillName = options.name || existing?.skill_name || frontmatter.name;
|
|
156129
156471
|
if (!skillName) {
|
|
156130
|
-
process.stderr.write(
|
|
156131
|
-
process.stderr.write(
|
|
156472
|
+
process.stderr.write(chalk30.red("Error: Cannot determine skill name.\n"));
|
|
156473
|
+
process.stderr.write(chalk30.dim(" Pass --name <name> or set `name:` in SKILL.md frontmatter.\n"));
|
|
156132
156474
|
process.exit(1);
|
|
156133
156475
|
}
|
|
156134
156476
|
const capabilityName = options.capability || existing?.capability_name || `skill/${skillName.toLowerCase()}`;
|
|
156135
156477
|
if (existing && existing.publisher_id !== ctx.publisherId && !options.force) {
|
|
156136
|
-
process.stderr.write(
|
|
156478
|
+
process.stderr.write(chalk30.red(`Error: This directory is already linked to publisher ${existing.publisher_id}.
|
|
156137
156479
|
`));
|
|
156138
|
-
process.stderr.write(
|
|
156480
|
+
process.stderr.write(chalk30.dim(` You are logged in as ${ctx.publisherId}.
|
|
156139
156481
|
`));
|
|
156140
|
-
process.stderr.write(
|
|
156482
|
+
process.stderr.write(chalk30.cyan(" Use --force to re-link to your account.\n"));
|
|
156141
156483
|
process.exit(1);
|
|
156142
156484
|
}
|
|
156143
156485
|
const linkedAt = existing?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -156159,41 +156501,41 @@ var linkCommand = new Command32("link").description("Link a skill source directo
|
|
|
156159
156501
|
last_published_at: manifest.last_published_at
|
|
156160
156502
|
});
|
|
156161
156503
|
const action = existing ? "Re-linked" : "Linked";
|
|
156162
|
-
console.log(
|
|
156163
|
-
console.log(
|
|
156164
|
-
console.log(
|
|
156165
|
-
console.log(
|
|
156504
|
+
console.log(chalk30.green(`${action} "${skillName}" \u2192 ${capabilityName}`));
|
|
156505
|
+
console.log(chalk30.dim(` Directory: ${dirPath}`));
|
|
156506
|
+
console.log(chalk30.dim(` Publisher: ${ctx.publisherId}`));
|
|
156507
|
+
console.log(chalk30.dim(` Manifest: .skillvault-publisher/workspace.json`));
|
|
156166
156508
|
if (!existing) {
|
|
156167
156509
|
console.log();
|
|
156168
|
-
console.log(
|
|
156510
|
+
console.log(chalk30.cyan(" Tip: commit .skillvault-publisher/workspace.json so teammates and CI can find this skill."));
|
|
156169
156511
|
}
|
|
156170
156512
|
} catch (err) {
|
|
156171
156513
|
const message = err instanceof Error ? err.message : String(err);
|
|
156172
|
-
process.stderr.write(
|
|
156514
|
+
process.stderr.write(chalk30.red(`Link failed: ${message}
|
|
156173
156515
|
`));
|
|
156174
156516
|
process.exit(1);
|
|
156175
156517
|
}
|
|
156176
156518
|
});
|
|
156177
156519
|
|
|
156178
156520
|
// dist/commands/unlink.js
|
|
156179
|
-
import { Command as
|
|
156180
|
-
import
|
|
156521
|
+
import { Command as Command34 } from "commander";
|
|
156522
|
+
import chalk31 from "chalk";
|
|
156181
156523
|
import { existsSync as existsSync15, rmSync as rmSync2, statSync as statSync7 } from "node:fs";
|
|
156182
|
-
import { resolve as
|
|
156183
|
-
var unlinkCommand = new
|
|
156524
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
156525
|
+
var unlinkCommand = new Command34("unlink").description("Remove the workspace link from a skill source directory").argument("[directory]", "Skill directory to unlink (defaults to CWD)").option("--workspace <path>", "Explicit workspace directory (precedence over positional)").option("--keep-registry", "Remove the manifest file but leave the registry entry").action(async (directory, options) => {
|
|
156184
156526
|
try {
|
|
156185
|
-
const dirPath = options.workspace ?
|
|
156527
|
+
const dirPath = options.workspace ? resolve11(options.workspace) : directory ? resolve11(directory) : process.cwd();
|
|
156186
156528
|
if (!existsSync15(dirPath) || !statSync7(dirPath).isDirectory()) {
|
|
156187
|
-
process.stderr.write(
|
|
156529
|
+
process.stderr.write(chalk31.red(`Error: "${dirPath}" is not a valid directory
|
|
156188
156530
|
`));
|
|
156189
156531
|
process.exit(1);
|
|
156190
156532
|
}
|
|
156191
156533
|
const manifest = loadWorkspace(dirPath);
|
|
156192
156534
|
if (!manifest) {
|
|
156193
|
-
process.stderr.write(
|
|
156194
|
-
process.stderr.write(
|
|
156535
|
+
process.stderr.write(chalk31.red("Error: No workspace manifest found at this directory.\n"));
|
|
156536
|
+
process.stderr.write(chalk31.dim(` Looked for: ${join16(dirPath, ".skillvault-publisher", "workspace.json")}
|
|
156195
156537
|
`));
|
|
156196
|
-
process.stderr.write(
|
|
156538
|
+
process.stderr.write(chalk31.dim(" Run `skillvault-publisher link` first to create one.\n"));
|
|
156197
156539
|
process.exit(1);
|
|
156198
156540
|
}
|
|
156199
156541
|
const { manifestPath } = workspaceRootsFor(dirPath);
|
|
@@ -156201,7 +156543,7 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
|
|
|
156201
156543
|
rmSync2(manifestPath);
|
|
156202
156544
|
} catch (err) {
|
|
156203
156545
|
const message = err instanceof Error ? err.message : String(err);
|
|
156204
|
-
process.stderr.write(
|
|
156546
|
+
process.stderr.write(chalk31.red(`Failed to remove manifest: ${message}
|
|
156205
156547
|
`));
|
|
156206
156548
|
process.exit(1);
|
|
156207
156549
|
}
|
|
@@ -156213,25 +156555,25 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
|
|
|
156213
156555
|
if (!options.keepRegistry) {
|
|
156214
156556
|
unregisterWorkspace(dirPath);
|
|
156215
156557
|
}
|
|
156216
|
-
console.log(
|
|
156217
|
-
console.log(
|
|
156558
|
+
console.log(chalk31.green(`Unlinked "${manifest.skill_name}" (${manifest.capability_name})`));
|
|
156559
|
+
console.log(chalk31.dim(` Directory: ${dirPath}`));
|
|
156218
156560
|
if (options.keepRegistry) {
|
|
156219
|
-
console.log(
|
|
156561
|
+
console.log(chalk31.dim(" Registry entry kept (--keep-registry)"));
|
|
156220
156562
|
}
|
|
156221
156563
|
console.log();
|
|
156222
|
-
console.log(
|
|
156223
|
-
console.log(
|
|
156564
|
+
console.log(chalk31.dim(" Note: SKILL.md and source files are untouched."));
|
|
156565
|
+
console.log(chalk31.dim(" Note: The skill on the server is NOT deleted. Use `skill-delete` for that."));
|
|
156224
156566
|
} catch (err) {
|
|
156225
156567
|
const message = err instanceof Error ? err.message : String(err);
|
|
156226
|
-
process.stderr.write(
|
|
156568
|
+
process.stderr.write(chalk31.red(`Unlink failed: ${message}
|
|
156227
156569
|
`));
|
|
156228
156570
|
process.exit(1);
|
|
156229
156571
|
}
|
|
156230
156572
|
});
|
|
156231
156573
|
|
|
156232
156574
|
// dist/commands/workspaces.js
|
|
156233
|
-
import { Command as
|
|
156234
|
-
import
|
|
156575
|
+
import { Command as Command35 } from "commander";
|
|
156576
|
+
import chalk32 from "chalk";
|
|
156235
156577
|
function formatDate(iso) {
|
|
156236
156578
|
if (!iso)
|
|
156237
156579
|
return "-";
|
|
@@ -156266,8 +156608,8 @@ function listAction(options) {
|
|
|
156266
156608
|
return;
|
|
156267
156609
|
}
|
|
156268
156610
|
if (filtered.length === 0) {
|
|
156269
|
-
console.log(
|
|
156270
|
-
console.log(
|
|
156611
|
+
console.log(chalk32.dim("No workspaces linked."));
|
|
156612
|
+
console.log(chalk32.dim(" Run `skillvault-publisher link` from a skill source directory to create one."));
|
|
156271
156613
|
return;
|
|
156272
156614
|
}
|
|
156273
156615
|
const pathWidth = Math.min(Math.max(20, ...filtered.map((w) => w.path.length)), 50);
|
|
@@ -156275,27 +156617,27 @@ function listAction(options) {
|
|
|
156275
156617
|
const pubWidth = Math.max(10, ...filtered.map((w) => w.publisher_id.length));
|
|
156276
156618
|
console.log();
|
|
156277
156619
|
const header = `${pad2("PATH", pathWidth)} ${pad2("PUBLISHER", pubWidth)} ${pad2("SKILL", skillWidth)} ${pad2("VERSION", 10)} ${pad2("LAST PUBLISHED", 14)} SOURCE`;
|
|
156278
|
-
console.log(` ${
|
|
156279
|
-
console.log(` ${
|
|
156620
|
+
console.log(` ${chalk32.dim(header)}`);
|
|
156621
|
+
console.log(` ${chalk32.dim("\u2500".repeat(header.length))}`);
|
|
156280
156622
|
for (const w of filtered) {
|
|
156281
156623
|
const isOther = currentAccount !== null && w.publisher_id !== currentAccount;
|
|
156282
156624
|
const path = w.path.length > pathWidth ? "\u2026" + w.path.slice(-(pathWidth - 1)) : w.path;
|
|
156283
156625
|
const row = `${pad2(path, pathWidth)} ${pad2(w.publisher_id, pubWidth)} ${pad2(w.skill_name, skillWidth)} ${pad2(w.last_published_version ?? "-", 10)} ${pad2(formatDate(w.last_published_at), 14)} ${w.source}`;
|
|
156284
156626
|
if (isOther) {
|
|
156285
|
-
console.log(` ${
|
|
156627
|
+
console.log(` ${chalk32.dim(row + " [other account]")}`);
|
|
156286
156628
|
} else {
|
|
156287
156629
|
console.log(` ${row}`);
|
|
156288
156630
|
}
|
|
156289
156631
|
}
|
|
156290
156632
|
console.log();
|
|
156291
|
-
console.log(
|
|
156633
|
+
console.log(chalk32.dim(` ${filtered.length} workspace${filtered.length === 1 ? "" : "s"}` + (options.current ? " (filtered to current account)" : "")));
|
|
156292
156634
|
}
|
|
156293
|
-
var workspacesCommand = new
|
|
156635
|
+
var workspacesCommand = new Command35("workspaces").description("List linked skill source directories (workspaces)").option("--json", "Output as JSON").option("--current", "Only show workspaces matching the current logged-in publisher").action((options) => {
|
|
156294
156636
|
try {
|
|
156295
156637
|
listAction(options);
|
|
156296
156638
|
} catch (err) {
|
|
156297
156639
|
const message = err instanceof Error ? err.message : String(err);
|
|
156298
|
-
process.stderr.write(
|
|
156640
|
+
process.stderr.write(chalk32.red(`Error: ${message}
|
|
156299
156641
|
`));
|
|
156300
156642
|
process.exit(1);
|
|
156301
156643
|
}
|
|
@@ -156311,28 +156653,28 @@ workspacesCommand.command("find").description("Print the absolute path of a work
|
|
|
156311
156653
|
console.log(match.path);
|
|
156312
156654
|
} catch (err) {
|
|
156313
156655
|
const message = err instanceof Error ? err.message : String(err);
|
|
156314
|
-
process.stderr.write(
|
|
156656
|
+
process.stderr.write(chalk32.red(`Error: ${message}
|
|
156315
156657
|
`));
|
|
156316
156658
|
process.exit(1);
|
|
156317
156659
|
}
|
|
156318
156660
|
});
|
|
156319
156661
|
|
|
156320
156662
|
// dist/commands/team.js
|
|
156321
|
-
import { Command as
|
|
156322
|
-
import
|
|
156663
|
+
import { Command as Command36 } from "commander";
|
|
156664
|
+
import chalk33 from "chalk";
|
|
156323
156665
|
function formatRole(role) {
|
|
156324
156666
|
if (role === "owner")
|
|
156325
|
-
return
|
|
156667
|
+
return chalk33.green("owner");
|
|
156326
156668
|
if (role === "admin")
|
|
156327
|
-
return
|
|
156328
|
-
return
|
|
156669
|
+
return chalk33.cyan("admin");
|
|
156670
|
+
return chalk33.dim("member");
|
|
156329
156671
|
}
|
|
156330
156672
|
function formatStatus(status) {
|
|
156331
156673
|
if (status === "active")
|
|
156332
|
-
return
|
|
156674
|
+
return chalk33.green("active");
|
|
156333
156675
|
if (status === "pending")
|
|
156334
|
-
return
|
|
156335
|
-
return
|
|
156676
|
+
return chalk33.yellow("pending");
|
|
156677
|
+
return chalk33.dim(status);
|
|
156336
156678
|
}
|
|
156337
156679
|
function pad3(s, n) {
|
|
156338
156680
|
const visible = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -156340,7 +156682,7 @@ function pad3(s, n) {
|
|
|
156340
156682
|
return s;
|
|
156341
156683
|
return s + " ".repeat(n - visible.length);
|
|
156342
156684
|
}
|
|
156343
|
-
var teamCommand = new
|
|
156685
|
+
var teamCommand = new Command36("team").description("Manage your publisher team members").option("--json", "Output as JSON").action(async (options) => {
|
|
156344
156686
|
try {
|
|
156345
156687
|
const ctx = requireSession();
|
|
156346
156688
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team`);
|
|
@@ -156351,27 +156693,27 @@ var teamCommand = new Command35("team").description("Manage your publisher team
|
|
|
156351
156693
|
}
|
|
156352
156694
|
if (members.length === 0) {
|
|
156353
156695
|
console.log();
|
|
156354
|
-
console.log(
|
|
156355
|
-
console.log(
|
|
156696
|
+
console.log(chalk33.dim(" No team members yet. Invite someone:"));
|
|
156697
|
+
console.log(chalk33.cyan(" skillvault-publisher team add <email> [--role member|admin]"));
|
|
156356
156698
|
console.log();
|
|
156357
156699
|
return;
|
|
156358
156700
|
}
|
|
156359
156701
|
console.log();
|
|
156360
|
-
console.log(
|
|
156702
|
+
console.log(chalk33.bold(` Team members (${members.length})`));
|
|
156361
156703
|
console.log();
|
|
156362
|
-
const header = `${pad3(
|
|
156704
|
+
const header = `${pad3(chalk33.dim("Email"), 36)} ${pad3(chalk33.dim("Role"), 14)} ${pad3(chalk33.dim("Status"), 14)} ${chalk33.dim("Member ID")}`;
|
|
156363
156705
|
console.log(` ${header}`);
|
|
156364
|
-
console.log(` ${
|
|
156706
|
+
console.log(` ${chalk33.dim("\u2500".repeat(80))}`);
|
|
156365
156707
|
for (const m of members) {
|
|
156366
|
-
const row = `${pad3(m.email, 36)} ${pad3(formatRole(m.role), 14)} ${pad3(formatStatus(m.status), 14)} ${
|
|
156708
|
+
const row = `${pad3(m.email, 36)} ${pad3(formatRole(m.role), 14)} ${pad3(formatStatus(m.status), 14)} ${chalk33.dim(m.id)}`;
|
|
156367
156709
|
console.log(` ${row}`);
|
|
156368
156710
|
}
|
|
156369
156711
|
console.log();
|
|
156370
|
-
console.log(
|
|
156712
|
+
console.log(chalk33.dim(` Logged in as publisher ${ctx.publisherId}`));
|
|
156371
156713
|
console.log();
|
|
156372
156714
|
} catch (err) {
|
|
156373
156715
|
const message = err instanceof Error ? err.message : String(err);
|
|
156374
|
-
process.stderr.write(
|
|
156716
|
+
process.stderr.write(chalk33.red(`team list failed: ${message}
|
|
156375
156717
|
`));
|
|
156376
156718
|
process.exit(1);
|
|
156377
156719
|
}
|
|
@@ -156379,7 +156721,7 @@ var teamCommand = new Command35("team").description("Manage your publisher team
|
|
|
156379
156721
|
teamCommand.command("add").description("Invite someone to your publisher team. Sends a magic-link email.").argument("<email>", "The email address to invite").option("--role <role>", "Role: member (default) or admin", "member").option("--name <name>", "Display name for the invitee (optional)").option("--json", "Output as JSON").action(async (email, options) => {
|
|
156380
156722
|
try {
|
|
156381
156723
|
if (!["member", "admin"].includes(options.role)) {
|
|
156382
|
-
process.stderr.write(
|
|
156724
|
+
process.stderr.write(chalk33.red(`Invalid role "${options.role}". Use --role member or --role admin.
|
|
156383
156725
|
`));
|
|
156384
156726
|
process.exit(1);
|
|
156385
156727
|
}
|
|
@@ -156393,17 +156735,17 @@ teamCommand.command("add").description("Invite someone to your publisher team. S
|
|
|
156393
156735
|
return;
|
|
156394
156736
|
}
|
|
156395
156737
|
console.log();
|
|
156396
|
-
console.log(
|
|
156397
|
-
console.log(
|
|
156398
|
-
console.log(
|
|
156738
|
+
console.log(chalk33.green(` \u2713 Invited ${email} as ${formatRole(options.role)}`));
|
|
156739
|
+
console.log(chalk33.dim(` Member ID: ${member.id}`));
|
|
156740
|
+
console.log(chalk33.dim(` Status: ${formatStatus(member.status)}`));
|
|
156399
156741
|
console.log();
|
|
156400
|
-
console.log(
|
|
156401
|
-
console.log(
|
|
156402
|
-
console.log(
|
|
156742
|
+
console.log(chalk33.dim(" A magic-link invitation email has been sent. The new member can"));
|
|
156743
|
+
console.log(chalk33.dim(" click the link to activate, then run:"));
|
|
156744
|
+
console.log(chalk33.cyan(` skillvault-publisher login --email ${email}`));
|
|
156403
156745
|
console.log();
|
|
156404
156746
|
} catch (err) {
|
|
156405
156747
|
const message = err instanceof Error ? err.message : String(err);
|
|
156406
|
-
process.stderr.write(
|
|
156748
|
+
process.stderr.write(chalk33.red(`team add failed: ${message}
|
|
156407
156749
|
`));
|
|
156408
156750
|
process.exit(1);
|
|
156409
156751
|
}
|
|
@@ -156415,30 +156757,30 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156415
156757
|
const members = listData.members || [];
|
|
156416
156758
|
const member = members.find((m) => m.id === target || m.email === target);
|
|
156417
156759
|
if (!member) {
|
|
156418
|
-
process.stderr.write(
|
|
156760
|
+
process.stderr.write(chalk33.red(`No team member found matching "${target}".
|
|
156419
156761
|
`));
|
|
156420
|
-
process.stderr.write(
|
|
156762
|
+
process.stderr.write(chalk33.dim("Run `skillvault-publisher team` to see the current list.\n"));
|
|
156421
156763
|
process.exit(1);
|
|
156422
156764
|
}
|
|
156423
156765
|
if (member.role === "owner") {
|
|
156424
|
-
process.stderr.write(
|
|
156766
|
+
process.stderr.write(chalk33.red("Cannot remove the owner of a publisher account.\n"));
|
|
156425
156767
|
process.exit(1);
|
|
156426
156768
|
}
|
|
156427
156769
|
if (member.status === "removed") {
|
|
156428
|
-
process.stderr.write(
|
|
156770
|
+
process.stderr.write(chalk33.yellow(`${member.email} is already removed.
|
|
156429
156771
|
`));
|
|
156430
156772
|
process.exit(0);
|
|
156431
156773
|
}
|
|
156432
156774
|
if (!options.yes) {
|
|
156433
156775
|
console.log();
|
|
156434
|
-
console.log(
|
|
156776
|
+
console.log(chalk33.yellow.bold(" Warning: ") + "This will revoke " + chalk33.bold(member.email) + `'s access to publisher ${ctx.publisherId}.`);
|
|
156435
156777
|
console.log();
|
|
156436
|
-
console.log(` Email: ${
|
|
156778
|
+
console.log(` Email: ${chalk33.cyan(member.email)}`);
|
|
156437
156779
|
console.log(` Role: ${formatRole(member.role)}`);
|
|
156438
156780
|
console.log(` Status: ${formatStatus(member.status)}`);
|
|
156439
|
-
console.log(` Added: ${
|
|
156781
|
+
console.log(` Added: ${chalk33.dim(new Date(member.created_at).toLocaleDateString())}`);
|
|
156440
156782
|
console.log();
|
|
156441
|
-
console.log(
|
|
156783
|
+
console.log(chalk33.dim(" Add --yes to confirm."));
|
|
156442
156784
|
console.log();
|
|
156443
156785
|
process.exit(0);
|
|
156444
156786
|
}
|
|
@@ -156447,10 +156789,10 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156447
156789
|
console.log(JSON.stringify({ removed: true, member_id: member.id, email: member.email }, null, 2));
|
|
156448
156790
|
return;
|
|
156449
156791
|
}
|
|
156450
|
-
console.log(
|
|
156792
|
+
console.log(chalk33.green(` \u2713 Removed ${member.email} from the team`));
|
|
156451
156793
|
} catch (err) {
|
|
156452
156794
|
const message = err instanceof Error ? err.message : String(err);
|
|
156453
|
-
process.stderr.write(
|
|
156795
|
+
process.stderr.write(chalk33.red(`team remove failed: ${message}
|
|
156454
156796
|
`));
|
|
156455
156797
|
process.exit(1);
|
|
156456
156798
|
}
|
|
@@ -156459,7 +156801,7 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156459
156801
|
// dist/index.js
|
|
156460
156802
|
var __dirname2 = dirname5(fileURLToPath(import.meta.url));
|
|
156461
156803
|
var pkg = JSON.parse(readFileSync18(join17(__dirname2, "..", "package.json"), "utf8"));
|
|
156462
|
-
var program = new
|
|
156804
|
+
var program = new Command37();
|
|
156463
156805
|
program.name("skillvault-publisher").description("SkillVault publisher CLI \u2014 publish, manage, and distribute encrypted skills").version(pkg.version).addHelpText("after", `
|
|
156464
156806
|
|
|
156465
156807
|
Getting Started:
|
|
@@ -156492,6 +156834,7 @@ program.addCommand(sessionCleanupCommand);
|
|
|
156492
156834
|
program.addCommand(skillDeleteCommand);
|
|
156493
156835
|
program.addCommand(skillStatusCommand);
|
|
156494
156836
|
program.addCommand(skillUnarchiveCommand);
|
|
156837
|
+
program.addCommand(skillAclCommand);
|
|
156495
156838
|
program.addCommand(grantsCommand);
|
|
156496
156839
|
program.addCommand(revokeGrantCommand);
|
|
156497
156840
|
program.addCommand(customersCommand);
|