skillvault-publisher 0.12.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +553 -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";
|
|
@@ -152070,7 +152070,7 @@ var registerCommand = new Command2("register").description("Create a new publish
|
|
|
152070
152070
|
let verified = false;
|
|
152071
152071
|
const maxAttempts = 120;
|
|
152072
152072
|
for (let i = 0; i < maxAttempts; i++) {
|
|
152073
|
-
await new Promise((
|
|
152073
|
+
await new Promise((resolve12) => setTimeout(resolve12, 3e3));
|
|
152074
152074
|
try {
|
|
152075
152075
|
const statusRes = await fetch(`${serverUrl}/publishers/${publisher_id}/verification-status`);
|
|
152076
152076
|
if (statusRes.ok) {
|
|
@@ -153152,7 +153152,8 @@ The server will clean up automatically. If the problem persists, re-run with --f
|
|
|
153152
153152
|
}
|
|
153153
153153
|
const publishResult = await publishRes.json().catch(() => ({}));
|
|
153154
153154
|
const wasUnlinked = existingManifest === null;
|
|
153155
|
-
|
|
153155
|
+
const publishAccepted = publishResult.status !== "rejected";
|
|
153156
|
+
if (publishAccepted && !options.noLink && sessionPublisherId) {
|
|
153156
153157
|
const linkedAt = existingManifest?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
153157
153158
|
const newManifest = {
|
|
153158
153159
|
...existingManifest ?? {},
|
|
@@ -153186,6 +153187,26 @@ The server will clean up automatically. If the problem persists, re-run with --f
|
|
|
153186
153187
|
if (publishResult.status === "unchanged") {
|
|
153187
153188
|
console.log(chalk5.yellow(`Content unchanged for ${skillName} v${version}. No new version created.`));
|
|
153188
153189
|
console.log(chalk5.dim(` Use --force to publish anyway.`));
|
|
153190
|
+
} else if (publishResult.status === "rejected") {
|
|
153191
|
+
const reasonMessage = publishResult.public_reason?.message || "Skill rejected by the security review pipeline.";
|
|
153192
|
+
process.stderr.write(chalk5.red(`
|
|
153193
|
+
Publish rejected: ${reasonMessage}
|
|
153194
|
+
`));
|
|
153195
|
+
process.stderr.write(chalk5.dim(` Run \`skillvault-publisher skill-status ${skillName}\` for more details.
|
|
153196
|
+
`));
|
|
153197
|
+
process.stderr.write(chalk5.dim(` Download a rejection report with \`skillvault-publisher skill-status ${skillName} --review-report <file>\`.
|
|
153198
|
+
`));
|
|
153199
|
+
process.exit(1);
|
|
153200
|
+
} else if (publishResult.status === "under_review") {
|
|
153201
|
+
console.log(chalk5.yellow(`
|
|
153202
|
+
Skill queued for review: ${skillName} v${version}`));
|
|
153203
|
+
if (publishResult.review_id) {
|
|
153204
|
+
console.log(chalk5.dim(` Review ID: ${publishResult.review_id}`));
|
|
153205
|
+
}
|
|
153206
|
+
console.log(chalk5.dim(` Skill ID: ${publishResult.skill_id || "n/a"}`));
|
|
153207
|
+
console.log(chalk5.dim(` Capability: ${capabilityName}`));
|
|
153208
|
+
console.log(chalk5.dim(" Reviews usually complete within a few minutes."));
|
|
153209
|
+
console.log(chalk5.dim(` Check status with \`skillvault-publisher skill-status ${skillName}\` (or listen on your webhook).`));
|
|
153189
153210
|
} else {
|
|
153190
153211
|
console.log(chalk5.green(`Published ${skillName} v${version}`));
|
|
153191
153212
|
console.log(chalk5.dim(` Skill ID: ${publishResult.skill_id || "n/a"}`));
|
|
@@ -153674,8 +153695,17 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153674
153695
|
console.log(JSON.stringify({
|
|
153675
153696
|
host_id: data.host_id ?? config.host_id,
|
|
153676
153697
|
agent_id: data.agent_id ?? config.agent_id,
|
|
153677
|
-
...
|
|
153678
|
-
|
|
153698
|
+
...authMe ? {
|
|
153699
|
+
publisher_id: authMe.publisher_id,
|
|
153700
|
+
publisher_name: authMe.publisher_name,
|
|
153701
|
+
email: authMe.email,
|
|
153702
|
+
role: authMe.role,
|
|
153703
|
+
is_owner: authMe.is_owner,
|
|
153704
|
+
...authMe.skill_acls ? { skill_acls: authMe.skill_acls } : {}
|
|
153705
|
+
} : {
|
|
153706
|
+
...config.publisher_id ? { publisher_id: config.publisher_id } : {},
|
|
153707
|
+
...config.email ? { email: config.email } : {}
|
|
153708
|
+
},
|
|
153679
153709
|
device_fingerprint: fingerprint,
|
|
153680
153710
|
server_url: config.server_url,
|
|
153681
153711
|
status: data.status,
|
|
@@ -153683,6 +153713,18 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153683
153713
|
}, null, 2));
|
|
153684
153714
|
return;
|
|
153685
153715
|
}
|
|
153716
|
+
let skillsById = /* @__PURE__ */ new Map();
|
|
153717
|
+
if (authMe?.role === "member" && authMe.skill_acls && authMe.skill_acls.length > 0) {
|
|
153718
|
+
try {
|
|
153719
|
+
const skillsRes = await fetch(`${config.server_url}/skills`, { headers: ctx.headers });
|
|
153720
|
+
if (skillsRes.ok) {
|
|
153721
|
+
const sd = await skillsRes.json();
|
|
153722
|
+
for (const s of sd.skills)
|
|
153723
|
+
skillsById.set(s.id, s);
|
|
153724
|
+
}
|
|
153725
|
+
} catch {
|
|
153726
|
+
}
|
|
153727
|
+
}
|
|
153686
153728
|
console.log();
|
|
153687
153729
|
console.log(chalk10.bold(" Skill Vault Identity"));
|
|
153688
153730
|
console.log();
|
|
@@ -153695,6 +153737,20 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
|
|
|
153695
153737
|
if (!authMe.is_owner) {
|
|
153696
153738
|
console.log(` ${chalk10.dim(" (you are a team member of this publisher)".padEnd(22))}`);
|
|
153697
153739
|
}
|
|
153740
|
+
if (authMe.role === "member" && authMe.skill_acls) {
|
|
153741
|
+
if (authMe.skill_acls.length === 0) {
|
|
153742
|
+
console.log(` ${chalk10.dim("Skill access:".padEnd(22))} ${chalk10.dim("(none yet \u2014 publish a new skill to auto-own it)")}`);
|
|
153743
|
+
} else {
|
|
153744
|
+
console.log(` ${"Skill access:".padEnd(22)}`);
|
|
153745
|
+
for (const a of authMe.skill_acls) {
|
|
153746
|
+
const sk = skillsById.get(a.skill_id);
|
|
153747
|
+
const label = sk?.name || a.skill_id;
|
|
153748
|
+
const roleColor2 = a.role === "owner" ? chalk10.green : a.role === "write" ? chalk10.cyan : chalk10.dim;
|
|
153749
|
+
const action = a.role === "owner" ? "publish + delete" : a.role === "write" ? "publish new versions" : "view only";
|
|
153750
|
+
console.log(` ${chalk10.cyan(label.padEnd(20))} ${roleColor2(a.role.padEnd(8))} ${chalk10.dim(action)}`);
|
|
153751
|
+
}
|
|
153752
|
+
}
|
|
153753
|
+
}
|
|
153698
153754
|
} else {
|
|
153699
153755
|
if (config.publisher_id) {
|
|
153700
153756
|
console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
|
|
@@ -153961,11 +154017,13 @@ var listCommand = new Command13("list").description("List your published skills"
|
|
|
153961
154017
|
const nameWidth = Math.max(20, ...skills.map((s) => s.name.length + 2));
|
|
153962
154018
|
const verWidth = 10;
|
|
153963
154019
|
const statusWidth = 10;
|
|
154020
|
+
const reviewWidth = 8;
|
|
153964
154021
|
const capWidth = Math.max(24, ...skills.map((s) => s.capability_name.length + 2));
|
|
153965
154022
|
const header = [
|
|
153966
154023
|
chalk14.dim("Name".padEnd(nameWidth)),
|
|
153967
154024
|
chalk14.dim("Version".padEnd(verWidth)),
|
|
153968
154025
|
chalk14.dim("Status".padEnd(statusWidth)),
|
|
154026
|
+
chalk14.dim("Review".padEnd(reviewWidth)),
|
|
153969
154027
|
chalk14.dim("Capability".padEnd(capWidth)),
|
|
153970
154028
|
chalk14.dim("Created")
|
|
153971
154029
|
].join(" ");
|
|
@@ -153977,10 +154035,29 @@ var listCommand = new Command13("list").description("List your published skills"
|
|
|
153977
154035
|
year: "numeric"
|
|
153978
154036
|
});
|
|
153979
154037
|
const statusColor = skill.status === "active" ? chalk14.green : chalk14.dim;
|
|
154038
|
+
let reviewCell;
|
|
154039
|
+
switch (skill.review_state) {
|
|
154040
|
+
case "approved":
|
|
154041
|
+
reviewCell = chalk14.green("ok".padEnd(reviewWidth));
|
|
154042
|
+
break;
|
|
154043
|
+
case "queued":
|
|
154044
|
+
case "running":
|
|
154045
|
+
reviewCell = chalk14.yellow("review".padEnd(reviewWidth));
|
|
154046
|
+
break;
|
|
154047
|
+
case "rejected":
|
|
154048
|
+
reviewCell = chalk14.red("reject".padEnd(reviewWidth));
|
|
154049
|
+
break;
|
|
154050
|
+
case "needs_human_review":
|
|
154051
|
+
reviewCell = chalk14.yellow("human".padEnd(reviewWidth));
|
|
154052
|
+
break;
|
|
154053
|
+
default:
|
|
154054
|
+
reviewCell = chalk14.dim("-".padEnd(reviewWidth));
|
|
154055
|
+
}
|
|
153980
154056
|
const row = [
|
|
153981
154057
|
chalk14.cyan(skill.name.padEnd(nameWidth)),
|
|
153982
154058
|
chalk14.green(("v" + skill.latest_version).padEnd(verWidth)),
|
|
153983
154059
|
statusColor(skill.status.padEnd(statusWidth)),
|
|
154060
|
+
reviewCell,
|
|
153984
154061
|
chalk14.dim(skill.capability_name.padEnd(capWidth)),
|
|
153985
154062
|
chalk14.dim(createdDate)
|
|
153986
154063
|
].join(" ");
|
|
@@ -155055,7 +155132,9 @@ var skillDeleteCommand = new Command20("skill-delete").description("Permanently
|
|
|
155055
155132
|
// dist/commands/skill-status.js
|
|
155056
155133
|
import { Command as Command21 } from "commander";
|
|
155057
155134
|
import chalk18 from "chalk";
|
|
155058
|
-
|
|
155135
|
+
import { writeFileSync as writeFileSync10 } from "node:fs";
|
|
155136
|
+
import { resolve as resolve9 } from "node:path";
|
|
155137
|
+
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
155138
|
try {
|
|
155060
155139
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155061
155140
|
const skillName = skillNameArg ?? ctx.defaultSkillName ?? void 0;
|
|
@@ -155077,17 +155156,56 @@ var skillStatusCommand = new Command21("skill-status").description("Show detaile
|
|
|
155077
155156
|
sessionFetch(ctx, "/grants")
|
|
155078
155157
|
]);
|
|
155079
155158
|
const activeGrants = grantsData.grants.filter((g) => g.capability === detail.capability_name && g.status === "active");
|
|
155159
|
+
if (options.reviewReport) {
|
|
155160
|
+
const report = {
|
|
155161
|
+
skill_id: detail.id,
|
|
155162
|
+
capability_name: detail.capability_name,
|
|
155163
|
+
version: detail.latest_version,
|
|
155164
|
+
review_state: detail.review_state ?? null,
|
|
155165
|
+
public_reason_code: detail.latest_review?.public_reason_code ?? null,
|
|
155166
|
+
public_reason_message: detail.latest_review?.public_reason_message ?? null,
|
|
155167
|
+
last_review_at: detail.latest_review?.last_review_at ?? null
|
|
155168
|
+
};
|
|
155169
|
+
const reportPath = resolve9(options.reviewReport);
|
|
155170
|
+
writeFileSync10(reportPath, JSON.stringify(report, null, 2) + "\n");
|
|
155171
|
+
process.stderr.write(chalk18.green(`Wrote review report to ${reportPath}
|
|
155172
|
+
`));
|
|
155173
|
+
}
|
|
155080
155174
|
if (options.json) {
|
|
155081
155175
|
console.log(JSON.stringify({ ...detail, active_grants: activeGrants.length }, null, 2));
|
|
155082
155176
|
return;
|
|
155083
155177
|
}
|
|
155084
155178
|
const statusColor = detail.status === "active" ? chalk18.green : detail.status === "archived" ? chalk18.yellow : chalk18.dim;
|
|
155085
155179
|
const createdDate = new Date(detail.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
155180
|
+
const reviewState = detail.review_state ?? "approved";
|
|
155181
|
+
let reviewLabel;
|
|
155182
|
+
switch (reviewState) {
|
|
155183
|
+
case "approved":
|
|
155184
|
+
reviewLabel = chalk18.green("Approved");
|
|
155185
|
+
break;
|
|
155186
|
+
case "queued":
|
|
155187
|
+
case "running":
|
|
155188
|
+
reviewLabel = chalk18.yellow("Under review");
|
|
155189
|
+
break;
|
|
155190
|
+
case "rejected":
|
|
155191
|
+
reviewLabel = chalk18.red("Rejected");
|
|
155192
|
+
break;
|
|
155193
|
+
case "needs_human_review":
|
|
155194
|
+
reviewLabel = chalk18.yellow("Awaiting review");
|
|
155195
|
+
break;
|
|
155196
|
+
default:
|
|
155197
|
+
reviewLabel = chalk18.dim(reviewState);
|
|
155198
|
+
}
|
|
155199
|
+
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
155200
|
console.log();
|
|
155087
155201
|
console.log(chalk18.bold(` ${detail.name}`));
|
|
155088
155202
|
console.log();
|
|
155089
155203
|
console.log(` Capability: ${detail.capability_name}`);
|
|
155090
155204
|
console.log(` Status: ${statusColor(detail.status)}`);
|
|
155205
|
+
console.log(` Review: ${reviewLabel}${lastReviewAt ? chalk18.dim(` (${lastReviewAt})`) : ""}`);
|
|
155206
|
+
if (reviewState === "rejected" && detail.latest_review?.public_reason_message) {
|
|
155207
|
+
console.log(` Reason: ${chalk18.red(detail.latest_review.public_reason_message)}`);
|
|
155208
|
+
}
|
|
155091
155209
|
console.log(` Version: ${chalk18.green("v" + detail.latest_version)}`);
|
|
155092
155210
|
console.log(` Created: ${chalk18.dim(createdDate)}`);
|
|
155093
155211
|
console.log(` ID: ${chalk18.dim(detail.id)}`);
|
|
@@ -155144,10 +155262,199 @@ var skillUnarchiveCommand = new Command22("skill-unarchive").description("Restor
|
|
|
155144
155262
|
}
|
|
155145
155263
|
});
|
|
155146
155264
|
|
|
155147
|
-
// dist/commands/
|
|
155265
|
+
// dist/commands/skill-acl.js
|
|
155148
155266
|
import { Command as Command23 } from "commander";
|
|
155149
155267
|
import chalk20 from "chalk";
|
|
155150
|
-
var
|
|
155268
|
+
var VALID_ROLES = /* @__PURE__ */ new Set(["read", "write", "owner"]);
|
|
155269
|
+
async function resolveSkill(ctx, skillName) {
|
|
155270
|
+
const data = await sessionFetch(ctx, "/skills");
|
|
155271
|
+
const skill = data.skills.find((s) => s.name.toLowerCase() === skillName.toLowerCase() || s.capability_name.toLowerCase() === skillName.toLowerCase());
|
|
155272
|
+
if (!skill) {
|
|
155273
|
+
process.stderr.write(chalk20.red(`Skill not found: ${skillName}
|
|
155274
|
+
`));
|
|
155275
|
+
process.stderr.write(chalk20.dim("Run `skillvault-publisher list` to see your skills.\n"));
|
|
155276
|
+
process.exit(1);
|
|
155277
|
+
}
|
|
155278
|
+
return skill;
|
|
155279
|
+
}
|
|
155280
|
+
async function runList(ctx, skill, options) {
|
|
155281
|
+
const data = await sessionFetch(ctx, `/skills/${skill.id}/acls`);
|
|
155282
|
+
const acls = data.acls || [];
|
|
155283
|
+
if (options.json) {
|
|
155284
|
+
console.log(JSON.stringify({ skill: skill.name, skill_id: skill.id, acls }, null, 2));
|
|
155285
|
+
return;
|
|
155286
|
+
}
|
|
155287
|
+
console.log();
|
|
155288
|
+
console.log(chalk20.bold(` ACL grants on ${chalk20.cyan(skill.name)}`));
|
|
155289
|
+
console.log();
|
|
155290
|
+
if (acls.length === 0) {
|
|
155291
|
+
console.log(chalk20.dim(" No ACL grants. Account owners and admins always have full access."));
|
|
155292
|
+
console.log(chalk20.dim(` Add a member: skillvault-publisher skill-acl ${skill.name} add <email> --role read|write|owner`));
|
|
155293
|
+
console.log();
|
|
155294
|
+
return;
|
|
155295
|
+
}
|
|
155296
|
+
const emailWidth = Math.max(20, ...acls.map((a) => a.email.length + 2));
|
|
155297
|
+
const roleWidth = 8;
|
|
155298
|
+
const header = [
|
|
155299
|
+
chalk20.dim("Email".padEnd(emailWidth)),
|
|
155300
|
+
chalk20.dim("Role".padEnd(roleWidth)),
|
|
155301
|
+
chalk20.dim("Granted by")
|
|
155302
|
+
].join(" ");
|
|
155303
|
+
console.log(` ${header}`);
|
|
155304
|
+
console.log(` ${chalk20.dim("-".repeat(emailWidth + roleWidth + 24))}`);
|
|
155305
|
+
for (const a of acls) {
|
|
155306
|
+
const roleColor = a.role === "owner" ? chalk20.green : a.role === "write" ? chalk20.cyan : chalk20.dim;
|
|
155307
|
+
const row = [
|
|
155308
|
+
a.email.padEnd(emailWidth),
|
|
155309
|
+
roleColor(a.role.padEnd(roleWidth)),
|
|
155310
|
+
chalk20.dim(a.granted_by || "(self)")
|
|
155311
|
+
].join(" ");
|
|
155312
|
+
console.log(` ${row}`);
|
|
155313
|
+
}
|
|
155314
|
+
console.log();
|
|
155315
|
+
}
|
|
155316
|
+
async function runAdd(ctx, skill, email, options) {
|
|
155317
|
+
if (!options.role) {
|
|
155318
|
+
process.stderr.write(chalk20.red("Error: --role is required (read|write|owner)\n"));
|
|
155319
|
+
process.exit(1);
|
|
155320
|
+
}
|
|
155321
|
+
const role = options.role.toLowerCase();
|
|
155322
|
+
if (!VALID_ROLES.has(role)) {
|
|
155323
|
+
process.stderr.write(chalk20.red(`Invalid --role value: ${options.role}
|
|
155324
|
+
`));
|
|
155325
|
+
process.stderr.write(chalk20.dim(" Must be one of: read, write, owner\n"));
|
|
155326
|
+
process.exit(1);
|
|
155327
|
+
}
|
|
155328
|
+
const res = await fetch(`${ctx.serverUrl}/skills/${skill.id}/acls`, {
|
|
155329
|
+
method: "POST",
|
|
155330
|
+
headers: ctx.headers,
|
|
155331
|
+
body: JSON.stringify({ email, role })
|
|
155332
|
+
});
|
|
155333
|
+
const body = await res.json().catch(() => ({}));
|
|
155334
|
+
if (!res.ok) {
|
|
155335
|
+
if (body.error === "not_a_team_member") {
|
|
155336
|
+
process.stderr.write(chalk20.red(`${email} is not a member of this team.
|
|
155337
|
+
`));
|
|
155338
|
+
process.stderr.write(chalk20.dim(`Add them first: skillvault-publisher team add ${email} --role member
|
|
155339
|
+
`));
|
|
155340
|
+
process.exit(1);
|
|
155341
|
+
}
|
|
155342
|
+
process.stderr.write(chalk20.red(`Failed to grant: ${body.message || body.error || res.statusText}
|
|
155343
|
+
`));
|
|
155344
|
+
process.exit(1);
|
|
155345
|
+
}
|
|
155346
|
+
if (options.json) {
|
|
155347
|
+
console.log(JSON.stringify(body, null, 2));
|
|
155348
|
+
return;
|
|
155349
|
+
}
|
|
155350
|
+
if (body.note) {
|
|
155351
|
+
console.log(chalk20.yellow(` ${body.note}`));
|
|
155352
|
+
return;
|
|
155353
|
+
}
|
|
155354
|
+
const acl = body.acl;
|
|
155355
|
+
console.log(chalk20.green(`Granted ${acl.email} ${chalk20.bold(acl.role)} on ${skill.name}`));
|
|
155356
|
+
}
|
|
155357
|
+
async function runRemove(ctx, skill, target, options) {
|
|
155358
|
+
const data = await sessionFetch(ctx, `/skills/${skill.id}/acls`);
|
|
155359
|
+
const acls = data.acls || [];
|
|
155360
|
+
let acl;
|
|
155361
|
+
if (target.startsWith("acl_")) {
|
|
155362
|
+
acl = acls.find((a) => a.id === target);
|
|
155363
|
+
} else {
|
|
155364
|
+
acl = acls.find((a) => a.email.toLowerCase() === target.toLowerCase());
|
|
155365
|
+
}
|
|
155366
|
+
if (!acl) {
|
|
155367
|
+
process.stderr.write(chalk20.red(`No ACL row matches: ${target}
|
|
155368
|
+
`));
|
|
155369
|
+
process.exit(1);
|
|
155370
|
+
}
|
|
155371
|
+
if (!options.yes) {
|
|
155372
|
+
console.log();
|
|
155373
|
+
console.log(chalk20.yellow.bold(" Warning: ") + `This revokes ${acl.role} access on ${chalk20.cyan(skill.name)} for ${chalk20.cyan(acl.email)}.`);
|
|
155374
|
+
console.log(chalk20.dim(" Add --yes to confirm."));
|
|
155375
|
+
console.log();
|
|
155376
|
+
process.exit(0);
|
|
155377
|
+
}
|
|
155378
|
+
const res = await fetch(`${ctx.serverUrl}/skills/${skill.id}/acls/${acl.id}`, {
|
|
155379
|
+
method: "DELETE",
|
|
155380
|
+
headers: ctx.headers
|
|
155381
|
+
});
|
|
155382
|
+
const body = await res.json().catch(() => ({}));
|
|
155383
|
+
if (!res.ok) {
|
|
155384
|
+
if (body.error === "last_owner") {
|
|
155385
|
+
process.stderr.write(chalk20.red("Cannot remove the last owner ACL on this skill.\n"));
|
|
155386
|
+
process.stderr.write(chalk20.dim(" Grant another member owner access first, or have an account admin manage it.\n"));
|
|
155387
|
+
process.exit(1);
|
|
155388
|
+
}
|
|
155389
|
+
process.stderr.write(chalk20.red(`Failed to remove: ${body.message || body.error || res.statusText}
|
|
155390
|
+
`));
|
|
155391
|
+
process.exit(1);
|
|
155392
|
+
}
|
|
155393
|
+
if (options.json) {
|
|
155394
|
+
console.log(JSON.stringify({ removed: true, acl_id: acl.id, email: acl.email, role: acl.role }, null, 2));
|
|
155395
|
+
return;
|
|
155396
|
+
}
|
|
155397
|
+
console.log(chalk20.green(`Removed ${acl.email} (${acl.role}) from ${skill.name}`));
|
|
155398
|
+
}
|
|
155399
|
+
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) => {
|
|
155400
|
+
try {
|
|
155401
|
+
let skillName = skillNameArg;
|
|
155402
|
+
let action = actionArg;
|
|
155403
|
+
let target = targetArg;
|
|
155404
|
+
const isActionVerb = (s) => s === "list" || s === "add" || s === "remove";
|
|
155405
|
+
if (isActionVerb(skillNameArg) && !isActionVerb(actionArg)) {
|
|
155406
|
+
action = skillNameArg;
|
|
155407
|
+
target = actionArg;
|
|
155408
|
+
skillName = "";
|
|
155409
|
+
}
|
|
155410
|
+
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155411
|
+
if (!skillName) {
|
|
155412
|
+
if (!ctx.defaultSkillName) {
|
|
155413
|
+
process.stderr.write(chalk20.red("Error: No skill name provided and no workspace context.\n"));
|
|
155414
|
+
process.stderr.write(chalk20.dim(" Pass <skill-name> or run from a linked workspace directory.\n"));
|
|
155415
|
+
process.exit(1);
|
|
155416
|
+
}
|
|
155417
|
+
skillName = ctx.defaultSkillName;
|
|
155418
|
+
}
|
|
155419
|
+
if (!isActionVerb(action)) {
|
|
155420
|
+
process.stderr.write(chalk20.red(`Unknown action: ${action}
|
|
155421
|
+
`));
|
|
155422
|
+
process.stderr.write(chalk20.dim(" Must be one of: list, add, remove\n"));
|
|
155423
|
+
process.exit(1);
|
|
155424
|
+
}
|
|
155425
|
+
const skill = await resolveSkill(ctx, skillName);
|
|
155426
|
+
if (action === "list") {
|
|
155427
|
+
await runList(ctx, skill, options);
|
|
155428
|
+
return;
|
|
155429
|
+
}
|
|
155430
|
+
if (action === "add") {
|
|
155431
|
+
if (!target) {
|
|
155432
|
+
process.stderr.write(chalk20.red("Error: add requires <email>\n"));
|
|
155433
|
+
process.exit(1);
|
|
155434
|
+
}
|
|
155435
|
+
await runAdd(ctx, skill, target, options);
|
|
155436
|
+
return;
|
|
155437
|
+
}
|
|
155438
|
+
if (action === "remove") {
|
|
155439
|
+
if (!target) {
|
|
155440
|
+
process.stderr.write(chalk20.red("Error: remove requires <email-or-id>\n"));
|
|
155441
|
+
process.exit(1);
|
|
155442
|
+
}
|
|
155443
|
+
await runRemove(ctx, skill, target, options);
|
|
155444
|
+
return;
|
|
155445
|
+
}
|
|
155446
|
+
} catch (err) {
|
|
155447
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
155448
|
+
process.stderr.write(chalk20.red(`skill-acl failed: ${message}
|
|
155449
|
+
`));
|
|
155450
|
+
process.exit(1);
|
|
155451
|
+
}
|
|
155452
|
+
});
|
|
155453
|
+
|
|
155454
|
+
// dist/commands/grants.js
|
|
155455
|
+
import { Command as Command24 } from "commander";
|
|
155456
|
+
import chalk21 from "chalk";
|
|
155457
|
+
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
155458
|
try {
|
|
155152
155459
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155153
155460
|
const data = await sessionFetch(ctx, "/grants");
|
|
@@ -155165,18 +155472,18 @@ var grantsCommand = new Command23("grants").description("List capability grants
|
|
|
155165
155472
|
return;
|
|
155166
155473
|
}
|
|
155167
155474
|
if (grants.length === 0) {
|
|
155168
|
-
console.log(
|
|
155475
|
+
console.log(chalk21.dim("No grants found."));
|
|
155169
155476
|
return;
|
|
155170
155477
|
}
|
|
155171
155478
|
console.log();
|
|
155172
|
-
console.log(
|
|
155479
|
+
console.log(chalk21.bold(" Capability Grants"));
|
|
155173
155480
|
console.log();
|
|
155174
155481
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155175
155482
|
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(` ${
|
|
155483
|
+
console.log(` ${chalk21.dim(header)}`);
|
|
155484
|
+
console.log(` ${chalk21.dim("\u2500".repeat(header.length))}`);
|
|
155178
155485
|
for (const grant of grants) {
|
|
155179
|
-
const statusColor = grant.status === "active" ?
|
|
155486
|
+
const statusColor = grant.status === "active" ? chalk21.green : grant.status === "revoked" ? chalk21.red : grant.status === "expired" ? chalk21.yellow : chalk21.white;
|
|
155180
155487
|
const row = [
|
|
155181
155488
|
pad4(grant.id, 22),
|
|
155182
155489
|
pad4(grant.capability, 24),
|
|
@@ -155188,20 +155495,20 @@ var grantsCommand = new Command23("grants").description("List capability grants
|
|
|
155188
155495
|
console.log(` ${row}`);
|
|
155189
155496
|
}
|
|
155190
155497
|
console.log();
|
|
155191
|
-
console.log(
|
|
155498
|
+
console.log(chalk21.dim(` ${grants.length} grant${grants.length !== 1 ? "s" : ""} total`));
|
|
155192
155499
|
console.log();
|
|
155193
155500
|
} catch (err) {
|
|
155194
155501
|
const message = err instanceof Error ? err.message : String(err);
|
|
155195
|
-
process.stderr.write(
|
|
155502
|
+
process.stderr.write(chalk21.red(`Error: ${message}
|
|
155196
155503
|
`));
|
|
155197
155504
|
process.exit(1);
|
|
155198
155505
|
}
|
|
155199
155506
|
});
|
|
155200
155507
|
|
|
155201
155508
|
// dist/commands/revoke-grant.js
|
|
155202
|
-
import { Command as
|
|
155203
|
-
import
|
|
155204
|
-
var revokeGrantCommand = new
|
|
155509
|
+
import { Command as Command25 } from "commander";
|
|
155510
|
+
import chalk22 from "chalk";
|
|
155511
|
+
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
155512
|
try {
|
|
155206
155513
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155207
155514
|
if (!options.yes) {
|
|
@@ -155212,7 +155519,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155212
155519
|
return;
|
|
155213
155520
|
}
|
|
155214
155521
|
console.log();
|
|
155215
|
-
console.log(
|
|
155522
|
+
console.log(chalk22.bold(" Grant details"));
|
|
155216
155523
|
console.log();
|
|
155217
155524
|
console.log(` ID: ${grant.id}`);
|
|
155218
155525
|
console.log(` Skill: ${grant.skill}`);
|
|
@@ -155221,7 +155528,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155221
155528
|
console.log(` Granted: ${new Date(grant.granted_at).toLocaleDateString()}`);
|
|
155222
155529
|
console.log(` Expires: ${grant.expires_at ? new Date(grant.expires_at).toLocaleDateString() : "never"}`);
|
|
155223
155530
|
console.log();
|
|
155224
|
-
console.log(
|
|
155531
|
+
console.log(chalk22.yellow(" Add --yes to confirm revocation."));
|
|
155225
155532
|
console.log();
|
|
155226
155533
|
return;
|
|
155227
155534
|
}
|
|
@@ -155230,19 +155537,19 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
|
|
|
155230
155537
|
console.log(JSON.stringify(result.grant, null, 2));
|
|
155231
155538
|
return;
|
|
155232
155539
|
}
|
|
155233
|
-
console.log(
|
|
155540
|
+
console.log(chalk22.green(`Revoked grant ${result.grant.id} for ${result.grant.skill}`));
|
|
155234
155541
|
} catch (err) {
|
|
155235
155542
|
const message = err instanceof Error ? err.message : String(err);
|
|
155236
|
-
process.stderr.write(
|
|
155543
|
+
process.stderr.write(chalk22.red(`Error: ${message}
|
|
155237
155544
|
`));
|
|
155238
155545
|
process.exit(1);
|
|
155239
155546
|
}
|
|
155240
155547
|
});
|
|
155241
155548
|
|
|
155242
155549
|
// dist/commands/customers.js
|
|
155243
|
-
import { Command as
|
|
155244
|
-
import
|
|
155245
|
-
var customersCommand = new
|
|
155550
|
+
import { Command as Command26 } from "commander";
|
|
155551
|
+
import chalk23 from "chalk";
|
|
155552
|
+
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
155553
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155247
155554
|
try {
|
|
155248
155555
|
const data = await sessionFetch(ctx, "/customers");
|
|
@@ -155252,19 +155559,19 @@ var customersCommand = new Command25("customers").description("List your custome
|
|
|
155252
155559
|
return;
|
|
155253
155560
|
}
|
|
155254
155561
|
if (customers.length === 0) {
|
|
155255
|
-
console.log(
|
|
155562
|
+
console.log(chalk23.dim("No customers found."));
|
|
155256
155563
|
return;
|
|
155257
155564
|
}
|
|
155258
155565
|
console.log();
|
|
155259
|
-
console.log(
|
|
155566
|
+
console.log(chalk23.bold(" Customers"));
|
|
155260
155567
|
console.log();
|
|
155261
155568
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155262
155569
|
const header = `${pad4("Email", 32)} ${pad4("Skills", 8)} ${pad4("Loads", 8)} ${pad4("Status", 10)} Last Active`;
|
|
155263
|
-
console.log(` ${
|
|
155264
|
-
console.log(` ${
|
|
155570
|
+
console.log(` ${chalk23.dim(header)}`);
|
|
155571
|
+
console.log(` ${chalk23.dim("\u2500".repeat(header.length))}`);
|
|
155265
155572
|
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() :
|
|
155573
|
+
const statusColor = c.status === "active" ? chalk23.green : chalk23.dim;
|
|
155574
|
+
const lastActive = c.last_active_at ? new Date(c.last_active_at).toLocaleDateString() : chalk23.dim("never");
|
|
155268
155575
|
const row = [
|
|
155269
155576
|
pad4(c.email, 32),
|
|
155270
155577
|
pad4(String(c.skills_count), 8),
|
|
@@ -155275,25 +155582,25 @@ var customersCommand = new Command25("customers").description("List your custome
|
|
|
155275
155582
|
console.log(` ${row}`);
|
|
155276
155583
|
}
|
|
155277
155584
|
console.log();
|
|
155278
|
-
console.log(
|
|
155585
|
+
console.log(chalk23.dim(` ${customers.length} customer${customers.length !== 1 ? "s" : ""} total`));
|
|
155279
155586
|
console.log();
|
|
155280
155587
|
} catch (err) {
|
|
155281
155588
|
const message = err instanceof Error ? err.message : String(err);
|
|
155282
|
-
process.stderr.write(
|
|
155589
|
+
process.stderr.write(chalk23.red(`Error: ${message}
|
|
155283
155590
|
`));
|
|
155284
155591
|
process.exit(1);
|
|
155285
155592
|
}
|
|
155286
155593
|
});
|
|
155287
155594
|
|
|
155288
155595
|
// dist/commands/analytics.js
|
|
155289
|
-
import { Command as
|
|
155290
|
-
import
|
|
155291
|
-
var analyticsCommand = new
|
|
155596
|
+
import { Command as Command27 } from "commander";
|
|
155597
|
+
import chalk24 from "chalk";
|
|
155598
|
+
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
155599
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155293
155600
|
try {
|
|
155294
155601
|
const days = parseInt(options.days, 10);
|
|
155295
155602
|
if (isNaN(days) || days < 1) {
|
|
155296
|
-
process.stderr.write(
|
|
155603
|
+
process.stderr.write(chalk24.red("--days must be a positive number.\n"));
|
|
155297
155604
|
process.exit(1);
|
|
155298
155605
|
}
|
|
155299
155606
|
const end = /* @__PURE__ */ new Date();
|
|
@@ -155306,11 +155613,11 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155306
155613
|
return;
|
|
155307
155614
|
}
|
|
155308
155615
|
console.log();
|
|
155309
|
-
console.log(
|
|
155616
|
+
console.log(chalk24.bold(" Publisher Analytics"));
|
|
155310
155617
|
console.log();
|
|
155311
|
-
console.log(` ${
|
|
155312
|
-
console.log(` ${
|
|
155313
|
-
console.log(` ${
|
|
155618
|
+
console.log(` ${chalk24.bold("Active Licenses:")} ${data.active_licenses}`);
|
|
155619
|
+
console.log(` ${chalk24.bold("Total Decryptions:")} ${data.total_decryptions}`);
|
|
155620
|
+
console.log(` ${chalk24.bold("Period:")} Last ${days} day${days !== 1 ? "s" : ""} (${start.toLocaleDateString()} \u2013 ${end.toLocaleDateString()})`);
|
|
155314
155621
|
const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
|
|
155315
155622
|
const filterSkill = (skillName) => !effectiveSkill || skillName.toLowerCase() === effectiveSkill.toLowerCase();
|
|
155316
155623
|
const statsMap = new Map((data.skill_stats || []).map((s) => [s.skill_name, s]));
|
|
@@ -155319,12 +155626,12 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155319
155626
|
}
|
|
155320
155627
|
if (data.top_skills && data.top_skills.length > 0) {
|
|
155321
155628
|
console.log();
|
|
155322
|
-
console.log(
|
|
155629
|
+
console.log(chalk24.bold(" Top Skills"));
|
|
155323
155630
|
console.log();
|
|
155324
155631
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155325
155632
|
const header = `${pad4("Skill", 28)} ${pad4("Decryptions", 14)} Active Licenses`;
|
|
155326
|
-
console.log(` ${
|
|
155327
|
-
console.log(` ${
|
|
155633
|
+
console.log(` ${chalk24.dim(header)}`);
|
|
155634
|
+
console.log(` ${chalk24.dim("\u2500".repeat(header.length))}`);
|
|
155328
155635
|
for (const skill of data.top_skills) {
|
|
155329
155636
|
const stats = statsMap.get(skill.name);
|
|
155330
155637
|
const row = [
|
|
@@ -155336,27 +155643,27 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
|
|
|
155336
155643
|
}
|
|
155337
155644
|
} else {
|
|
155338
155645
|
console.log();
|
|
155339
|
-
console.log(
|
|
155646
|
+
console.log(chalk24.dim(" No skill activity in this period."));
|
|
155340
155647
|
}
|
|
155341
155648
|
console.log();
|
|
155342
155649
|
} catch (err) {
|
|
155343
155650
|
const message = err instanceof Error ? err.message : String(err);
|
|
155344
|
-
process.stderr.write(
|
|
155651
|
+
process.stderr.write(chalk24.red(`Error: ${message}
|
|
155345
155652
|
`));
|
|
155346
155653
|
process.exit(1);
|
|
155347
155654
|
}
|
|
155348
155655
|
});
|
|
155349
155656
|
|
|
155350
155657
|
// dist/commands/webhook.js
|
|
155351
|
-
import { Command as
|
|
155352
|
-
import
|
|
155353
|
-
var webhookCommand = new
|
|
155658
|
+
import { Command as Command28 } from "commander";
|
|
155659
|
+
import chalk25 from "chalk";
|
|
155660
|
+
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
155661
|
try {
|
|
155355
155662
|
const ctx = requireSession();
|
|
155356
155663
|
switch (action) {
|
|
155357
155664
|
case "set": {
|
|
155358
155665
|
if (!options.url) {
|
|
155359
|
-
process.stderr.write(
|
|
155666
|
+
process.stderr.write(chalk25.red("Missing --url option. Usage: skillvault-publisher webhook set --url <url>\n"));
|
|
155360
155667
|
process.exit(1);
|
|
155361
155668
|
}
|
|
155362
155669
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/webhook`, { method: "POST", body: { url: options.url } });
|
|
@@ -155365,12 +155672,12 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155365
155672
|
return;
|
|
155366
155673
|
}
|
|
155367
155674
|
console.log();
|
|
155368
|
-
console.log(
|
|
155675
|
+
console.log(chalk25.green(" Webhook configured"));
|
|
155369
155676
|
console.log();
|
|
155370
155677
|
console.log(` ${"URL:".padEnd(18)} ${data.webhook_url}`);
|
|
155371
|
-
console.log(` ${"Signing Secret:".padEnd(18)} ${
|
|
155678
|
+
console.log(` ${"Signing Secret:".padEnd(18)} ${chalk25.yellow(data.signing_secret)}`);
|
|
155372
155679
|
console.log();
|
|
155373
|
-
console.log(
|
|
155680
|
+
console.log(chalk25.dim(" Store the signing secret securely. It will not be shown again."));
|
|
155374
155681
|
console.log();
|
|
155375
155682
|
break;
|
|
155376
155683
|
}
|
|
@@ -155381,7 +155688,7 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155381
155688
|
return;
|
|
155382
155689
|
}
|
|
155383
155690
|
console.log();
|
|
155384
|
-
console.log(
|
|
155691
|
+
console.log(chalk25.green(" Test event sent to webhook URL"));
|
|
155385
155692
|
console.log();
|
|
155386
155693
|
break;
|
|
155387
155694
|
}
|
|
@@ -155393,36 +155700,36 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
|
|
|
155393
155700
|
}
|
|
155394
155701
|
console.log();
|
|
155395
155702
|
if (data.webhook_url) {
|
|
155396
|
-
console.log(
|
|
155703
|
+
console.log(chalk25.bold(" Webhook Status"));
|
|
155397
155704
|
console.log();
|
|
155398
155705
|
console.log(` ${"URL:".padEnd(12)} ${data.webhook_url}`);
|
|
155399
|
-
console.log(` ${"Status:".padEnd(12)} ${
|
|
155706
|
+
console.log(` ${"Status:".padEnd(12)} ${chalk25.green("configured")}`);
|
|
155400
155707
|
} else {
|
|
155401
|
-
console.log(
|
|
155708
|
+
console.log(chalk25.dim(" No webhook configured."));
|
|
155402
155709
|
console.log();
|
|
155403
|
-
console.log(
|
|
155710
|
+
console.log(chalk25.dim(" Set one with: skillvault-publisher webhook set --url <url>"));
|
|
155404
155711
|
}
|
|
155405
155712
|
console.log();
|
|
155406
155713
|
break;
|
|
155407
155714
|
}
|
|
155408
155715
|
default:
|
|
155409
|
-
process.stderr.write(
|
|
155716
|
+
process.stderr.write(chalk25.red(`Unknown action: ${action}
|
|
155410
155717
|
`));
|
|
155411
|
-
process.stderr.write(
|
|
155718
|
+
process.stderr.write(chalk25.dim("Valid actions: set, test, status\n"));
|
|
155412
155719
|
process.exit(1);
|
|
155413
155720
|
}
|
|
155414
155721
|
} catch (err) {
|
|
155415
155722
|
const message = err instanceof Error ? err.message : String(err);
|
|
155416
|
-
process.stderr.write(
|
|
155723
|
+
process.stderr.write(chalk25.red(`Error: ${message}
|
|
155417
155724
|
`));
|
|
155418
155725
|
process.exit(1);
|
|
155419
155726
|
}
|
|
155420
155727
|
});
|
|
155421
155728
|
|
|
155422
155729
|
// dist/commands/audit.js
|
|
155423
|
-
import { Command as
|
|
155424
|
-
import
|
|
155425
|
-
var auditCommand = new
|
|
155730
|
+
import { Command as Command29 } from "commander";
|
|
155731
|
+
import chalk26 from "chalk";
|
|
155732
|
+
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
155733
|
try {
|
|
155427
155734
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155428
155735
|
const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
|
|
@@ -155437,7 +155744,7 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155437
155744
|
if (options.export) {
|
|
155438
155745
|
const format = options.export.toLowerCase();
|
|
155439
155746
|
if (format !== "csv" && format !== "json") {
|
|
155440
|
-
process.stderr.write(
|
|
155747
|
+
process.stderr.write(chalk26.red('Export format must be "csv" or "json".\n'));
|
|
155441
155748
|
process.exit(1);
|
|
155442
155749
|
}
|
|
155443
155750
|
params.set("format", format);
|
|
@@ -155456,16 +155763,16 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155456
155763
|
return;
|
|
155457
155764
|
}
|
|
155458
155765
|
if (events.length === 0) {
|
|
155459
|
-
console.log(
|
|
155766
|
+
console.log(chalk26.dim("No audit events found."));
|
|
155460
155767
|
return;
|
|
155461
155768
|
}
|
|
155462
155769
|
console.log();
|
|
155463
|
-
console.log(
|
|
155770
|
+
console.log(chalk26.bold(" Audit Log"));
|
|
155464
155771
|
console.log();
|
|
155465
155772
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155466
155773
|
const header = `${pad4("Event Type", 22)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} ${"Time"}`;
|
|
155467
|
-
console.log(` ${
|
|
155468
|
-
console.log(` ${
|
|
155774
|
+
console.log(` ${chalk26.dim(header)}`);
|
|
155775
|
+
console.log(` ${chalk26.dim("\u2500".repeat(header.length))}`);
|
|
155469
155776
|
for (const event of events) {
|
|
155470
155777
|
const skill = event.capability ? event.capability.replace(/^skill\//, "") : "-";
|
|
155471
155778
|
const agent = event.agent_id ? event.agent_id.slice(0, 18) : "-";
|
|
@@ -155479,45 +155786,45 @@ var auditCommand = new Command28("audit").description("View audit log events").o
|
|
|
155479
155786
|
console.log(` ${row}`);
|
|
155480
155787
|
}
|
|
155481
155788
|
console.log();
|
|
155482
|
-
console.log(
|
|
155789
|
+
console.log(chalk26.dim(` Showing ${events.length} event${events.length !== 1 ? "s" : ""}`));
|
|
155483
155790
|
if (data.has_more) {
|
|
155484
|
-
console.log(
|
|
155791
|
+
console.log(chalk26.dim(` More results available`));
|
|
155485
155792
|
}
|
|
155486
155793
|
console.log();
|
|
155487
155794
|
} catch (err) {
|
|
155488
155795
|
const message = err instanceof Error ? err.message : String(err);
|
|
155489
|
-
process.stderr.write(
|
|
155796
|
+
process.stderr.write(chalk26.red(`Error: ${message}
|
|
155490
155797
|
`));
|
|
155491
155798
|
process.exit(1);
|
|
155492
155799
|
}
|
|
155493
155800
|
});
|
|
155494
155801
|
|
|
155495
155802
|
// dist/commands/investigate.js
|
|
155496
|
-
import { Command as
|
|
155497
|
-
import
|
|
155498
|
-
import { readFileSync as readFileSync15, mkdirSync as mkdirSync9, writeFileSync as
|
|
155803
|
+
import { Command as Command30 } from "commander";
|
|
155804
|
+
import chalk27 from "chalk";
|
|
155805
|
+
import { readFileSync as readFileSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
155499
155806
|
import { join as join14 } from "node:path";
|
|
155500
|
-
var orange =
|
|
155807
|
+
var orange = chalk27.hex("#f97316");
|
|
155501
155808
|
function riskColor2(level) {
|
|
155502
155809
|
switch (level.toLowerCase()) {
|
|
155503
155810
|
case "low":
|
|
155504
|
-
return
|
|
155811
|
+
return chalk27.green;
|
|
155505
155812
|
case "watch":
|
|
155506
|
-
return
|
|
155813
|
+
return chalk27.yellow;
|
|
155507
155814
|
case "alert":
|
|
155508
155815
|
return orange;
|
|
155509
155816
|
case "critical":
|
|
155510
|
-
return
|
|
155817
|
+
return chalk27.red;
|
|
155511
155818
|
default:
|
|
155512
|
-
return
|
|
155819
|
+
return chalk27.white;
|
|
155513
155820
|
}
|
|
155514
155821
|
}
|
|
155515
155822
|
function confidenceColor(c) {
|
|
155516
155823
|
if (c >= 0.9)
|
|
155517
|
-
return
|
|
155824
|
+
return chalk27.green;
|
|
155518
155825
|
if (c >= 0.5)
|
|
155519
|
-
return
|
|
155520
|
-
return
|
|
155826
|
+
return chalk27.yellow;
|
|
155827
|
+
return chalk27.red;
|
|
155521
155828
|
}
|
|
155522
155829
|
function pad(s, n) {
|
|
155523
155830
|
return s.padEnd(n).slice(0, n);
|
|
@@ -155533,30 +155840,30 @@ function toRawGitHubUrl(url) {
|
|
|
155533
155840
|
}
|
|
155534
155841
|
function displayResults(report) {
|
|
155535
155842
|
console.log();
|
|
155536
|
-
console.log(
|
|
155843
|
+
console.log(chalk27.bold(" Investigation Results"));
|
|
155537
155844
|
console.log();
|
|
155538
|
-
console.log(` ${
|
|
155539
|
-
console.log(` ${
|
|
155540
|
-
console.log(` ${
|
|
155541
|
-
console.log(` ${
|
|
155845
|
+
console.log(` ${chalk27.bold("Investigation ID:")} ${report.investigation_id}`);
|
|
155846
|
+
console.log(` ${chalk27.bold("Skill:")} ${report.skill_name}`);
|
|
155847
|
+
console.log(` ${chalk27.bold("Total Licensees:")} ${report.total_licensees}`);
|
|
155848
|
+
console.log(` ${chalk27.bold("Timestamp:")} ${new Date(report.created_at).toLocaleString()}`);
|
|
155542
155849
|
if (report.heartbeat_matches.length > 0) {
|
|
155543
155850
|
console.log();
|
|
155544
155851
|
const maxConf = Math.max(...report.heartbeat_matches.map((m) => m.confidence));
|
|
155545
155852
|
const confStr = (maxConf * 100).toFixed(0) + "%";
|
|
155546
155853
|
const confFn = confidenceColor(maxConf);
|
|
155547
|
-
console.log(` ${
|
|
155854
|
+
console.log(` ${chalk27.bold("Forensic Match:")} ${confFn(confStr + " confidence")} (${report.heartbeat_matches.length} match${report.heartbeat_matches.length !== 1 ? "es" : ""})`);
|
|
155548
155855
|
}
|
|
155549
155856
|
console.log();
|
|
155550
155857
|
if (report.suspects.length === 0) {
|
|
155551
|
-
console.log(
|
|
155858
|
+
console.log(chalk27.dim(" No suspects identified."));
|
|
155552
155859
|
console.log();
|
|
155553
155860
|
return;
|
|
155554
155861
|
}
|
|
155555
|
-
console.log(
|
|
155862
|
+
console.log(chalk27.bold(" Suspect Ranking"));
|
|
155556
155863
|
console.log();
|
|
155557
155864
|
const header = `${pad("Suspect", 24)} ${pad("Risk Level", 12)} ${pad("Confidence", 12)} ${pad("Anomalies", 10)} ${"Strikes"}`;
|
|
155558
|
-
console.log(` ${
|
|
155559
|
-
console.log(` ${
|
|
155865
|
+
console.log(` ${chalk27.dim(header)}`);
|
|
155866
|
+
console.log(` ${chalk27.dim("\u2500".repeat(header.length))}`);
|
|
155560
155867
|
for (const s of report.suspects) {
|
|
155561
155868
|
const colorFn = riskColor2(s.risk_level);
|
|
155562
155869
|
const label = s.customer_email || s.licensee_id.slice(0, 22);
|
|
@@ -155570,8 +155877,8 @@ function displayResults(report) {
|
|
|
155570
155877
|
console.log(` ${row}`);
|
|
155571
155878
|
}
|
|
155572
155879
|
console.log();
|
|
155573
|
-
console.log(
|
|
155574
|
-
console.log(
|
|
155880
|
+
console.log(chalk27.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
|
|
155881
|
+
console.log(chalk27.dim(" Contact investigations@getskillvault.com for the complete evidence package."));
|
|
155575
155882
|
console.log();
|
|
155576
155883
|
}
|
|
155577
155884
|
function buildHtmlReport(report, _auditEvents, metadata) {
|
|
@@ -155816,7 +156123,7 @@ ${report.suspects.length > 0 ? `<table>
|
|
|
155816
156123
|
</body>
|
|
155817
156124
|
</html>`;
|
|
155818
156125
|
}
|
|
155819
|
-
var investigateCommand = new
|
|
156126
|
+
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
156127
|
try {
|
|
155821
156128
|
const ctx = requireSession();
|
|
155822
156129
|
let leakedContent;
|
|
@@ -155824,12 +156131,12 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155824
156131
|
if (options.url) {
|
|
155825
156132
|
const rawUrl = toRawGitHubUrl(options.url);
|
|
155826
156133
|
if (rawUrl !== options.url) {
|
|
155827
|
-
console.log(
|
|
156134
|
+
console.log(chalk27.dim(` Auto-converted GitHub blob URL to raw URL`));
|
|
155828
156135
|
}
|
|
155829
|
-
console.log(
|
|
156136
|
+
console.log(chalk27.dim(` Fetching leaked content from ${rawUrl}...`));
|
|
155830
156137
|
const resp = await fetch(rawUrl);
|
|
155831
156138
|
if (!resp.ok) {
|
|
155832
|
-
process.stderr.write(
|
|
156139
|
+
process.stderr.write(chalk27.red(`Failed to fetch URL: ${resp.status} ${resp.statusText}
|
|
155833
156140
|
`));
|
|
155834
156141
|
process.exit(1);
|
|
155835
156142
|
}
|
|
@@ -155840,24 +156147,24 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155840
156147
|
leakedContent = readFileSync15(options.file, "utf-8");
|
|
155841
156148
|
} catch (err) {
|
|
155842
156149
|
const msg = err instanceof Error ? err.message : String(err);
|
|
155843
|
-
process.stderr.write(
|
|
156150
|
+
process.stderr.write(chalk27.red(`Failed to read file: ${msg}
|
|
155844
156151
|
`));
|
|
155845
156152
|
process.exit(1);
|
|
155846
156153
|
}
|
|
155847
156154
|
sourceLabel = options.file;
|
|
155848
156155
|
} else {
|
|
155849
|
-
process.stderr.write(
|
|
156156
|
+
process.stderr.write(chalk27.red("Provide leaked content with --url <url> or --file <path>.\n"));
|
|
155850
156157
|
process.exit(1);
|
|
155851
156158
|
}
|
|
155852
|
-
console.log(
|
|
156159
|
+
console.log(chalk27.dim(` Loaded ${leakedContent.length.toLocaleString()} chars of leaked content`));
|
|
155853
156160
|
const skillsData = await sessionFetch(ctx, "/skills");
|
|
155854
156161
|
const skill = skillsData.skills.find((s) => s.name.toLowerCase() === skillName.toLowerCase());
|
|
155855
156162
|
if (!skill) {
|
|
155856
|
-
process.stderr.write(
|
|
156163
|
+
process.stderr.write(chalk27.red(`Skill "${skillName}" not found. Use \`skillvault-publisher list\` to see your skills.
|
|
155857
156164
|
`));
|
|
155858
156165
|
process.exit(1);
|
|
155859
156166
|
}
|
|
155860
|
-
console.log(
|
|
156167
|
+
console.log(chalk27.dim(` Running investigation on "${skill.name}"...`));
|
|
155861
156168
|
const report = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/investigate`, {
|
|
155862
156169
|
method: "POST",
|
|
155863
156170
|
body: { skill_id: skill.id, leaked_content: leakedContent }
|
|
@@ -155883,13 +156190,13 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155883
156190
|
source: sourceLabel,
|
|
155884
156191
|
notice: "This is an executive summary. Full evidence is retained server-side. Contact investigations@getskillvault.com for the complete evidence package."
|
|
155885
156192
|
};
|
|
155886
|
-
|
|
155887
|
-
|
|
156193
|
+
writeFileSync11(join14(dir, "metadata.json"), JSON.stringify(metadata, null, 2) + "\n");
|
|
156194
|
+
writeFileSync11(join14(dir, "summary.json"), JSON.stringify({
|
|
155888
156195
|
_generated_by: "SkillVault (https://getskillvault.com)",
|
|
155889
156196
|
...report
|
|
155890
156197
|
}, null, 2) + "\n");
|
|
155891
156198
|
const html = buildHtmlReport(report, [], metadata);
|
|
155892
|
-
|
|
156199
|
+
writeFileSync11(join14(dir, "report.html"), html);
|
|
155893
156200
|
const pdfPath = join14(dir, "report.pdf");
|
|
155894
156201
|
const { generatePdfReport: generatePdfReport2 } = await Promise.resolve().then(() => (init_pdf_report(), pdf_report_exports));
|
|
155895
156202
|
await generatePdfReport2({
|
|
@@ -155903,23 +156210,23 @@ var investigateCommand = new Command29("investigate").description("Investigate a
|
|
|
155903
156210
|
heartbeat_matches: report.heartbeat_matches,
|
|
155904
156211
|
audit_events: []
|
|
155905
156212
|
}, pdfPath);
|
|
155906
|
-
console.log(
|
|
155907
|
-
console.log(
|
|
155908
|
-
console.log(
|
|
156213
|
+
console.log(chalk27.green(` Report saved to ${dir}/`) + chalk27.dim(" (4 files)"));
|
|
156214
|
+
console.log(chalk27.dim(` PDF: report.pdf`));
|
|
156215
|
+
console.log(chalk27.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
|
|
155909
156216
|
console.log();
|
|
155910
156217
|
}
|
|
155911
156218
|
} catch (err) {
|
|
155912
156219
|
const message = err instanceof Error ? err.message : String(err);
|
|
155913
|
-
process.stderr.write(
|
|
156220
|
+
process.stderr.write(chalk27.red(`Error: ${message}
|
|
155914
156221
|
`));
|
|
155915
156222
|
process.exit(1);
|
|
155916
156223
|
}
|
|
155917
156224
|
});
|
|
155918
156225
|
|
|
155919
156226
|
// dist/commands/watchtower.js
|
|
155920
|
-
import { Command as
|
|
155921
|
-
import
|
|
155922
|
-
var watchtowerCommand = new
|
|
156227
|
+
import { Command as Command31 } from "commander";
|
|
156228
|
+
import chalk28 from "chalk";
|
|
156229
|
+
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
156230
|
const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
|
|
155924
156231
|
try {
|
|
155925
156232
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/watchtower`);
|
|
@@ -155930,30 +156237,30 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155930
156237
|
const { summary } = data;
|
|
155931
156238
|
const pad4 = (s, n) => s.padEnd(n).slice(0, n);
|
|
155932
156239
|
console.log();
|
|
155933
|
-
console.log(
|
|
156240
|
+
console.log(chalk28.bold(" Watchtower \u2014 Security Overview"));
|
|
155934
156241
|
console.log();
|
|
155935
|
-
console.log(` ${
|
|
156242
|
+
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
156243
|
if (data.flagged_customers && data.flagged_customers.length > 0) {
|
|
155937
156244
|
console.log();
|
|
155938
|
-
console.log(
|
|
156245
|
+
console.log(chalk28.bold(" Flagged Customers"));
|
|
155939
156246
|
console.log();
|
|
155940
156247
|
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(` ${
|
|
156248
|
+
console.log(` ${chalk28.dim(header)}`);
|
|
156249
|
+
console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
|
|
155943
156250
|
for (const c of data.flagged_customers) {
|
|
155944
156251
|
const agentShort = c.agent_id.length > 18 ? c.agent_id.slice(0, 18) + "\u2026" : c.agent_id;
|
|
155945
156252
|
let levelColored;
|
|
155946
156253
|
if (c.risk_level === "critical") {
|
|
155947
|
-
levelColored =
|
|
156254
|
+
levelColored = chalk28.red.bold(pad4(c.risk_level, 10));
|
|
155948
156255
|
} else if (c.risk_level === "high") {
|
|
155949
|
-
levelColored =
|
|
156256
|
+
levelColored = chalk28.red(pad4(c.risk_level, 10));
|
|
155950
156257
|
} else if (c.risk_level === "medium") {
|
|
155951
|
-
levelColored =
|
|
156258
|
+
levelColored = chalk28.yellow(pad4(c.risk_level, 10));
|
|
155952
156259
|
} else {
|
|
155953
|
-
levelColored =
|
|
156260
|
+
levelColored = chalk28.dim(pad4(c.risk_level, 10));
|
|
155954
156261
|
}
|
|
155955
|
-
const statusColored = c.status === "suspended" ?
|
|
155956
|
-
const skills = c.capabilities.length > 0 ? c.capabilities.join(", ") :
|
|
156262
|
+
const statusColored = c.status === "suspended" ? chalk28.red(pad4(c.status, 12)) : pad4(c.status, 12);
|
|
156263
|
+
const skills = c.capabilities.length > 0 ? c.capabilities.join(", ") : chalk28.dim("none");
|
|
155957
156264
|
const row = [
|
|
155958
156265
|
pad4(agentShort, 20),
|
|
155959
156266
|
pad4(String(c.risk_score), 12),
|
|
@@ -155967,15 +156274,15 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155967
156274
|
}
|
|
155968
156275
|
if (data.recent_events && data.recent_events.length > 0) {
|
|
155969
156276
|
console.log();
|
|
155970
|
-
console.log(
|
|
156277
|
+
console.log(chalk28.bold(" Recent Security Events"));
|
|
155971
156278
|
console.log();
|
|
155972
156279
|
const header = `${pad4("Event Type", 28)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} Time`;
|
|
155973
|
-
console.log(` ${
|
|
155974
|
-
console.log(` ${
|
|
156280
|
+
console.log(` ${chalk28.dim(header)}`);
|
|
156281
|
+
console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
|
|
155975
156282
|
const events = data.recent_events.slice(0, 10);
|
|
155976
156283
|
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) :
|
|
156284
|
+
const skill = e.capability ? e.capability.replace(/^skill\//, "") : chalk28.dim("-");
|
|
156285
|
+
const agent = e.agent_id ? e.agent_id.slice(0, 18) : chalk28.dim("-");
|
|
155979
156286
|
const time = new Date(e.created_at).toLocaleString();
|
|
155980
156287
|
const row = [
|
|
155981
156288
|
pad4(e.event_type, 28),
|
|
@@ -155988,25 +156295,25 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
|
|
|
155988
156295
|
}
|
|
155989
156296
|
if ((!data.flagged_customers || data.flagged_customers.length === 0) && (!data.recent_events || data.recent_events.length === 0)) {
|
|
155990
156297
|
console.log();
|
|
155991
|
-
console.log(
|
|
156298
|
+
console.log(chalk28.green(" All clear \u2014 no security alerts in the last 7 days."));
|
|
155992
156299
|
}
|
|
155993
156300
|
console.log();
|
|
155994
156301
|
} catch (err) {
|
|
155995
156302
|
const message = err instanceof Error ? err.message : String(err);
|
|
155996
|
-
process.stderr.write(
|
|
156303
|
+
process.stderr.write(chalk28.red(`Error: ${message}
|
|
155997
156304
|
`));
|
|
155998
156305
|
process.exit(1);
|
|
155999
156306
|
}
|
|
156000
156307
|
});
|
|
156001
156308
|
|
|
156002
156309
|
// dist/commands/watermark-decode.js
|
|
156003
|
-
import { Command as
|
|
156004
|
-
import
|
|
156310
|
+
import { Command as Command32 } from "commander";
|
|
156311
|
+
import chalk29 from "chalk";
|
|
156005
156312
|
import { readFileSync as readFileSync16 } from "node:fs";
|
|
156006
|
-
var watermarkDecodeCommand = new
|
|
156313
|
+
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
156314
|
try {
|
|
156008
156315
|
if (!options.file) {
|
|
156009
|
-
process.stderr.write(
|
|
156316
|
+
process.stderr.write(chalk29.red("Provide --file <path> with the leaked content\n"));
|
|
156010
156317
|
process.exit(1);
|
|
156011
156318
|
}
|
|
156012
156319
|
let content;
|
|
@@ -156014,7 +156321,7 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
|
|
|
156014
156321
|
content = readFileSync16(options.file, "utf8");
|
|
156015
156322
|
} catch (err) {
|
|
156016
156323
|
const msg = err instanceof Error ? err.message : String(err);
|
|
156017
|
-
process.stderr.write(
|
|
156324
|
+
process.stderr.write(chalk29.red(`Cannot read file: ${msg}
|
|
156018
156325
|
`));
|
|
156019
156326
|
process.exit(1);
|
|
156020
156327
|
}
|
|
@@ -156044,56 +156351,56 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
|
|
|
156044
156351
|
return;
|
|
156045
156352
|
}
|
|
156046
156353
|
console.log();
|
|
156047
|
-
console.log(
|
|
156354
|
+
console.log(chalk29.bold(" Watermark Analysis"));
|
|
156048
156355
|
console.log();
|
|
156049
|
-
console.log(
|
|
156356
|
+
console.log(chalk29.bold(" Zero-Width Watermark"));
|
|
156050
156357
|
if (watermark.found) {
|
|
156051
|
-
console.log(` Licensee ID: ${
|
|
156358
|
+
console.log(` Licensee ID: ${chalk29.green.bold(watermark.licenseeId)}`);
|
|
156052
156359
|
} else {
|
|
156053
|
-
console.log(` ${
|
|
156360
|
+
console.log(` ${chalk29.dim("Not found")}`);
|
|
156054
156361
|
}
|
|
156055
156362
|
console.log();
|
|
156056
|
-
console.log(
|
|
156363
|
+
console.log(chalk29.bold(" Heartbeat Markers"));
|
|
156057
156364
|
if (heartbeats.hb1) {
|
|
156058
|
-
console.log(` HB1: ${
|
|
156365
|
+
console.log(` HB1: ${chalk29.green(heartbeats.hb1)}`);
|
|
156059
156366
|
} else {
|
|
156060
|
-
console.log(` HB1: ${
|
|
156367
|
+
console.log(` HB1: ${chalk29.dim("Not found")}`);
|
|
156061
156368
|
}
|
|
156062
156369
|
if (heartbeats.hb2) {
|
|
156063
|
-
console.log(` HB2: ${
|
|
156370
|
+
console.log(` HB2: ${chalk29.green(heartbeats.hb2)}`);
|
|
156064
156371
|
} else {
|
|
156065
|
-
console.log(` HB2: ${
|
|
156372
|
+
console.log(` HB2: ${chalk29.dim("Not found")}`);
|
|
156066
156373
|
}
|
|
156067
156374
|
if (candidates.length > 0) {
|
|
156068
|
-
console.log(` ${
|
|
156375
|
+
console.log(` ${chalk29.dim(`${candidates.length} potential heartbeat candidate${candidates.length !== 1 ? "s" : ""} found`)}`);
|
|
156069
156376
|
}
|
|
156070
156377
|
console.log();
|
|
156071
|
-
console.log(
|
|
156378
|
+
console.log(chalk29.bold(" Semantic Fingerprint"));
|
|
156072
156379
|
if (hasFingerprint) {
|
|
156073
156380
|
const binaryStr = fingerprint.map((v) => v === 1 ? "1" : v === -1 ? "X" : "0").join("");
|
|
156074
156381
|
const variationPoints = fingerprint.filter((v) => v !== 0).length;
|
|
156075
|
-
console.log(` Pattern: ${
|
|
156076
|
-
console.log(` ${
|
|
156382
|
+
console.log(` Pattern: ${chalk29.cyan(binaryStr)}`);
|
|
156383
|
+
console.log(` ${chalk29.dim(`${variationPoints} variation point${variationPoints !== 1 ? "s" : ""} detected`)}`);
|
|
156077
156384
|
} else {
|
|
156078
|
-
console.log(` ${
|
|
156385
|
+
console.log(` ${chalk29.dim("No variation points detected")}`);
|
|
156079
156386
|
}
|
|
156080
156387
|
console.log();
|
|
156081
|
-
const countColor = signalsDetected > 0 ?
|
|
156388
|
+
const countColor = signalsDetected > 0 ? chalk29.green.bold : chalk29.dim;
|
|
156082
156389
|
console.log(` ${countColor(`${signalsDetected} of 4`)} forensic signals detected`);
|
|
156083
156390
|
console.log();
|
|
156084
156391
|
} catch (err) {
|
|
156085
156392
|
const message = err instanceof Error ? err.message : String(err);
|
|
156086
|
-
process.stderr.write(
|
|
156393
|
+
process.stderr.write(chalk29.red(`Error: ${message}
|
|
156087
156394
|
`));
|
|
156088
156395
|
process.exit(1);
|
|
156089
156396
|
}
|
|
156090
156397
|
});
|
|
156091
156398
|
|
|
156092
156399
|
// dist/commands/link.js
|
|
156093
|
-
import { Command as
|
|
156094
|
-
import
|
|
156400
|
+
import { Command as Command33 } from "commander";
|
|
156401
|
+
import chalk30 from "chalk";
|
|
156095
156402
|
import { existsSync as existsSync14, readFileSync as readFileSync17, statSync as statSync6 } from "node:fs";
|
|
156096
|
-
import { resolve as
|
|
156403
|
+
import { resolve as resolve10, join as join15 } from "node:path";
|
|
156097
156404
|
function parseFrontmatter4(content) {
|
|
156098
156405
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
156099
156406
|
if (!match)
|
|
@@ -156112,12 +156419,12 @@ function parseFrontmatter4(content) {
|
|
|
156112
156419
|
}
|
|
156113
156420
|
return result;
|
|
156114
156421
|
}
|
|
156115
|
-
var linkCommand = new
|
|
156422
|
+
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
156423
|
try {
|
|
156117
156424
|
const ctx = requireSession();
|
|
156118
|
-
const dirPath = options.workspace ?
|
|
156425
|
+
const dirPath = options.workspace ? resolve10(options.workspace) : directory ? resolve10(directory) : process.cwd();
|
|
156119
156426
|
if (!existsSync14(dirPath) || !statSync6(dirPath).isDirectory()) {
|
|
156120
|
-
process.stderr.write(
|
|
156427
|
+
process.stderr.write(chalk30.red(`Error: "${dirPath}" is not a valid directory
|
|
156121
156428
|
`));
|
|
156122
156429
|
process.exit(1);
|
|
156123
156430
|
}
|
|
@@ -156127,17 +156434,17 @@ var linkCommand = new Command32("link").description("Link a skill source directo
|
|
|
156127
156434
|
const existing = loadWorkspace(dirPath);
|
|
156128
156435
|
const skillName = options.name || existing?.skill_name || frontmatter.name;
|
|
156129
156436
|
if (!skillName) {
|
|
156130
|
-
process.stderr.write(
|
|
156131
|
-
process.stderr.write(
|
|
156437
|
+
process.stderr.write(chalk30.red("Error: Cannot determine skill name.\n"));
|
|
156438
|
+
process.stderr.write(chalk30.dim(" Pass --name <name> or set `name:` in SKILL.md frontmatter.\n"));
|
|
156132
156439
|
process.exit(1);
|
|
156133
156440
|
}
|
|
156134
156441
|
const capabilityName = options.capability || existing?.capability_name || `skill/${skillName.toLowerCase()}`;
|
|
156135
156442
|
if (existing && existing.publisher_id !== ctx.publisherId && !options.force) {
|
|
156136
|
-
process.stderr.write(
|
|
156443
|
+
process.stderr.write(chalk30.red(`Error: This directory is already linked to publisher ${existing.publisher_id}.
|
|
156137
156444
|
`));
|
|
156138
|
-
process.stderr.write(
|
|
156445
|
+
process.stderr.write(chalk30.dim(` You are logged in as ${ctx.publisherId}.
|
|
156139
156446
|
`));
|
|
156140
|
-
process.stderr.write(
|
|
156447
|
+
process.stderr.write(chalk30.cyan(" Use --force to re-link to your account.\n"));
|
|
156141
156448
|
process.exit(1);
|
|
156142
156449
|
}
|
|
156143
156450
|
const linkedAt = existing?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -156159,41 +156466,41 @@ var linkCommand = new Command32("link").description("Link a skill source directo
|
|
|
156159
156466
|
last_published_at: manifest.last_published_at
|
|
156160
156467
|
});
|
|
156161
156468
|
const action = existing ? "Re-linked" : "Linked";
|
|
156162
|
-
console.log(
|
|
156163
|
-
console.log(
|
|
156164
|
-
console.log(
|
|
156165
|
-
console.log(
|
|
156469
|
+
console.log(chalk30.green(`${action} "${skillName}" \u2192 ${capabilityName}`));
|
|
156470
|
+
console.log(chalk30.dim(` Directory: ${dirPath}`));
|
|
156471
|
+
console.log(chalk30.dim(` Publisher: ${ctx.publisherId}`));
|
|
156472
|
+
console.log(chalk30.dim(` Manifest: .skillvault-publisher/workspace.json`));
|
|
156166
156473
|
if (!existing) {
|
|
156167
156474
|
console.log();
|
|
156168
|
-
console.log(
|
|
156475
|
+
console.log(chalk30.cyan(" Tip: commit .skillvault-publisher/workspace.json so teammates and CI can find this skill."));
|
|
156169
156476
|
}
|
|
156170
156477
|
} catch (err) {
|
|
156171
156478
|
const message = err instanceof Error ? err.message : String(err);
|
|
156172
|
-
process.stderr.write(
|
|
156479
|
+
process.stderr.write(chalk30.red(`Link failed: ${message}
|
|
156173
156480
|
`));
|
|
156174
156481
|
process.exit(1);
|
|
156175
156482
|
}
|
|
156176
156483
|
});
|
|
156177
156484
|
|
|
156178
156485
|
// dist/commands/unlink.js
|
|
156179
|
-
import { Command as
|
|
156180
|
-
import
|
|
156486
|
+
import { Command as Command34 } from "commander";
|
|
156487
|
+
import chalk31 from "chalk";
|
|
156181
156488
|
import { existsSync as existsSync15, rmSync as rmSync2, statSync as statSync7 } from "node:fs";
|
|
156182
|
-
import { resolve as
|
|
156183
|
-
var unlinkCommand = new
|
|
156489
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
156490
|
+
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
156491
|
try {
|
|
156185
|
-
const dirPath = options.workspace ?
|
|
156492
|
+
const dirPath = options.workspace ? resolve11(options.workspace) : directory ? resolve11(directory) : process.cwd();
|
|
156186
156493
|
if (!existsSync15(dirPath) || !statSync7(dirPath).isDirectory()) {
|
|
156187
|
-
process.stderr.write(
|
|
156494
|
+
process.stderr.write(chalk31.red(`Error: "${dirPath}" is not a valid directory
|
|
156188
156495
|
`));
|
|
156189
156496
|
process.exit(1);
|
|
156190
156497
|
}
|
|
156191
156498
|
const manifest = loadWorkspace(dirPath);
|
|
156192
156499
|
if (!manifest) {
|
|
156193
|
-
process.stderr.write(
|
|
156194
|
-
process.stderr.write(
|
|
156500
|
+
process.stderr.write(chalk31.red("Error: No workspace manifest found at this directory.\n"));
|
|
156501
|
+
process.stderr.write(chalk31.dim(` Looked for: ${join16(dirPath, ".skillvault-publisher", "workspace.json")}
|
|
156195
156502
|
`));
|
|
156196
|
-
process.stderr.write(
|
|
156503
|
+
process.stderr.write(chalk31.dim(" Run `skillvault-publisher link` first to create one.\n"));
|
|
156197
156504
|
process.exit(1);
|
|
156198
156505
|
}
|
|
156199
156506
|
const { manifestPath } = workspaceRootsFor(dirPath);
|
|
@@ -156201,7 +156508,7 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
|
|
|
156201
156508
|
rmSync2(manifestPath);
|
|
156202
156509
|
} catch (err) {
|
|
156203
156510
|
const message = err instanceof Error ? err.message : String(err);
|
|
156204
|
-
process.stderr.write(
|
|
156511
|
+
process.stderr.write(chalk31.red(`Failed to remove manifest: ${message}
|
|
156205
156512
|
`));
|
|
156206
156513
|
process.exit(1);
|
|
156207
156514
|
}
|
|
@@ -156213,25 +156520,25 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
|
|
|
156213
156520
|
if (!options.keepRegistry) {
|
|
156214
156521
|
unregisterWorkspace(dirPath);
|
|
156215
156522
|
}
|
|
156216
|
-
console.log(
|
|
156217
|
-
console.log(
|
|
156523
|
+
console.log(chalk31.green(`Unlinked "${manifest.skill_name}" (${manifest.capability_name})`));
|
|
156524
|
+
console.log(chalk31.dim(` Directory: ${dirPath}`));
|
|
156218
156525
|
if (options.keepRegistry) {
|
|
156219
|
-
console.log(
|
|
156526
|
+
console.log(chalk31.dim(" Registry entry kept (--keep-registry)"));
|
|
156220
156527
|
}
|
|
156221
156528
|
console.log();
|
|
156222
|
-
console.log(
|
|
156223
|
-
console.log(
|
|
156529
|
+
console.log(chalk31.dim(" Note: SKILL.md and source files are untouched."));
|
|
156530
|
+
console.log(chalk31.dim(" Note: The skill on the server is NOT deleted. Use `skill-delete` for that."));
|
|
156224
156531
|
} catch (err) {
|
|
156225
156532
|
const message = err instanceof Error ? err.message : String(err);
|
|
156226
|
-
process.stderr.write(
|
|
156533
|
+
process.stderr.write(chalk31.red(`Unlink failed: ${message}
|
|
156227
156534
|
`));
|
|
156228
156535
|
process.exit(1);
|
|
156229
156536
|
}
|
|
156230
156537
|
});
|
|
156231
156538
|
|
|
156232
156539
|
// dist/commands/workspaces.js
|
|
156233
|
-
import { Command as
|
|
156234
|
-
import
|
|
156540
|
+
import { Command as Command35 } from "commander";
|
|
156541
|
+
import chalk32 from "chalk";
|
|
156235
156542
|
function formatDate(iso) {
|
|
156236
156543
|
if (!iso)
|
|
156237
156544
|
return "-";
|
|
@@ -156266,8 +156573,8 @@ function listAction(options) {
|
|
|
156266
156573
|
return;
|
|
156267
156574
|
}
|
|
156268
156575
|
if (filtered.length === 0) {
|
|
156269
|
-
console.log(
|
|
156270
|
-
console.log(
|
|
156576
|
+
console.log(chalk32.dim("No workspaces linked."));
|
|
156577
|
+
console.log(chalk32.dim(" Run `skillvault-publisher link` from a skill source directory to create one."));
|
|
156271
156578
|
return;
|
|
156272
156579
|
}
|
|
156273
156580
|
const pathWidth = Math.min(Math.max(20, ...filtered.map((w) => w.path.length)), 50);
|
|
@@ -156275,27 +156582,27 @@ function listAction(options) {
|
|
|
156275
156582
|
const pubWidth = Math.max(10, ...filtered.map((w) => w.publisher_id.length));
|
|
156276
156583
|
console.log();
|
|
156277
156584
|
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(` ${
|
|
156585
|
+
console.log(` ${chalk32.dim(header)}`);
|
|
156586
|
+
console.log(` ${chalk32.dim("\u2500".repeat(header.length))}`);
|
|
156280
156587
|
for (const w of filtered) {
|
|
156281
156588
|
const isOther = currentAccount !== null && w.publisher_id !== currentAccount;
|
|
156282
156589
|
const path = w.path.length > pathWidth ? "\u2026" + w.path.slice(-(pathWidth - 1)) : w.path;
|
|
156283
156590
|
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
156591
|
if (isOther) {
|
|
156285
|
-
console.log(` ${
|
|
156592
|
+
console.log(` ${chalk32.dim(row + " [other account]")}`);
|
|
156286
156593
|
} else {
|
|
156287
156594
|
console.log(` ${row}`);
|
|
156288
156595
|
}
|
|
156289
156596
|
}
|
|
156290
156597
|
console.log();
|
|
156291
|
-
console.log(
|
|
156598
|
+
console.log(chalk32.dim(` ${filtered.length} workspace${filtered.length === 1 ? "" : "s"}` + (options.current ? " (filtered to current account)" : "")));
|
|
156292
156599
|
}
|
|
156293
|
-
var workspacesCommand = new
|
|
156600
|
+
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
156601
|
try {
|
|
156295
156602
|
listAction(options);
|
|
156296
156603
|
} catch (err) {
|
|
156297
156604
|
const message = err instanceof Error ? err.message : String(err);
|
|
156298
|
-
process.stderr.write(
|
|
156605
|
+
process.stderr.write(chalk32.red(`Error: ${message}
|
|
156299
156606
|
`));
|
|
156300
156607
|
process.exit(1);
|
|
156301
156608
|
}
|
|
@@ -156311,28 +156618,28 @@ workspacesCommand.command("find").description("Print the absolute path of a work
|
|
|
156311
156618
|
console.log(match.path);
|
|
156312
156619
|
} catch (err) {
|
|
156313
156620
|
const message = err instanceof Error ? err.message : String(err);
|
|
156314
|
-
process.stderr.write(
|
|
156621
|
+
process.stderr.write(chalk32.red(`Error: ${message}
|
|
156315
156622
|
`));
|
|
156316
156623
|
process.exit(1);
|
|
156317
156624
|
}
|
|
156318
156625
|
});
|
|
156319
156626
|
|
|
156320
156627
|
// dist/commands/team.js
|
|
156321
|
-
import { Command as
|
|
156322
|
-
import
|
|
156628
|
+
import { Command as Command36 } from "commander";
|
|
156629
|
+
import chalk33 from "chalk";
|
|
156323
156630
|
function formatRole(role) {
|
|
156324
156631
|
if (role === "owner")
|
|
156325
|
-
return
|
|
156632
|
+
return chalk33.green("owner");
|
|
156326
156633
|
if (role === "admin")
|
|
156327
|
-
return
|
|
156328
|
-
return
|
|
156634
|
+
return chalk33.cyan("admin");
|
|
156635
|
+
return chalk33.dim("member");
|
|
156329
156636
|
}
|
|
156330
156637
|
function formatStatus(status) {
|
|
156331
156638
|
if (status === "active")
|
|
156332
|
-
return
|
|
156639
|
+
return chalk33.green("active");
|
|
156333
156640
|
if (status === "pending")
|
|
156334
|
-
return
|
|
156335
|
-
return
|
|
156641
|
+
return chalk33.yellow("pending");
|
|
156642
|
+
return chalk33.dim(status);
|
|
156336
156643
|
}
|
|
156337
156644
|
function pad3(s, n) {
|
|
156338
156645
|
const visible = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -156340,7 +156647,7 @@ function pad3(s, n) {
|
|
|
156340
156647
|
return s;
|
|
156341
156648
|
return s + " ".repeat(n - visible.length);
|
|
156342
156649
|
}
|
|
156343
|
-
var teamCommand = new
|
|
156650
|
+
var teamCommand = new Command36("team").description("Manage your publisher team members").option("--json", "Output as JSON").action(async (options) => {
|
|
156344
156651
|
try {
|
|
156345
156652
|
const ctx = requireSession();
|
|
156346
156653
|
const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team`);
|
|
@@ -156351,27 +156658,27 @@ var teamCommand = new Command35("team").description("Manage your publisher team
|
|
|
156351
156658
|
}
|
|
156352
156659
|
if (members.length === 0) {
|
|
156353
156660
|
console.log();
|
|
156354
|
-
console.log(
|
|
156355
|
-
console.log(
|
|
156661
|
+
console.log(chalk33.dim(" No team members yet. Invite someone:"));
|
|
156662
|
+
console.log(chalk33.cyan(" skillvault-publisher team add <email> [--role member|admin]"));
|
|
156356
156663
|
console.log();
|
|
156357
156664
|
return;
|
|
156358
156665
|
}
|
|
156359
156666
|
console.log();
|
|
156360
|
-
console.log(
|
|
156667
|
+
console.log(chalk33.bold(` Team members (${members.length})`));
|
|
156361
156668
|
console.log();
|
|
156362
|
-
const header = `${pad3(
|
|
156669
|
+
const header = `${pad3(chalk33.dim("Email"), 36)} ${pad3(chalk33.dim("Role"), 14)} ${pad3(chalk33.dim("Status"), 14)} ${chalk33.dim("Member ID")}`;
|
|
156363
156670
|
console.log(` ${header}`);
|
|
156364
|
-
console.log(` ${
|
|
156671
|
+
console.log(` ${chalk33.dim("\u2500".repeat(80))}`);
|
|
156365
156672
|
for (const m of members) {
|
|
156366
|
-
const row = `${pad3(m.email, 36)} ${pad3(formatRole(m.role), 14)} ${pad3(formatStatus(m.status), 14)} ${
|
|
156673
|
+
const row = `${pad3(m.email, 36)} ${pad3(formatRole(m.role), 14)} ${pad3(formatStatus(m.status), 14)} ${chalk33.dim(m.id)}`;
|
|
156367
156674
|
console.log(` ${row}`);
|
|
156368
156675
|
}
|
|
156369
156676
|
console.log();
|
|
156370
|
-
console.log(
|
|
156677
|
+
console.log(chalk33.dim(` Logged in as publisher ${ctx.publisherId}`));
|
|
156371
156678
|
console.log();
|
|
156372
156679
|
} catch (err) {
|
|
156373
156680
|
const message = err instanceof Error ? err.message : String(err);
|
|
156374
|
-
process.stderr.write(
|
|
156681
|
+
process.stderr.write(chalk33.red(`team list failed: ${message}
|
|
156375
156682
|
`));
|
|
156376
156683
|
process.exit(1);
|
|
156377
156684
|
}
|
|
@@ -156379,7 +156686,7 @@ var teamCommand = new Command35("team").description("Manage your publisher team
|
|
|
156379
156686
|
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
156687
|
try {
|
|
156381
156688
|
if (!["member", "admin"].includes(options.role)) {
|
|
156382
|
-
process.stderr.write(
|
|
156689
|
+
process.stderr.write(chalk33.red(`Invalid role "${options.role}". Use --role member or --role admin.
|
|
156383
156690
|
`));
|
|
156384
156691
|
process.exit(1);
|
|
156385
156692
|
}
|
|
@@ -156393,17 +156700,17 @@ teamCommand.command("add").description("Invite someone to your publisher team. S
|
|
|
156393
156700
|
return;
|
|
156394
156701
|
}
|
|
156395
156702
|
console.log();
|
|
156396
|
-
console.log(
|
|
156397
|
-
console.log(
|
|
156398
|
-
console.log(
|
|
156703
|
+
console.log(chalk33.green(` \u2713 Invited ${email} as ${formatRole(options.role)}`));
|
|
156704
|
+
console.log(chalk33.dim(` Member ID: ${member.id}`));
|
|
156705
|
+
console.log(chalk33.dim(` Status: ${formatStatus(member.status)}`));
|
|
156399
156706
|
console.log();
|
|
156400
|
-
console.log(
|
|
156401
|
-
console.log(
|
|
156402
|
-
console.log(
|
|
156707
|
+
console.log(chalk33.dim(" A magic-link invitation email has been sent. The new member can"));
|
|
156708
|
+
console.log(chalk33.dim(" click the link to activate, then run:"));
|
|
156709
|
+
console.log(chalk33.cyan(` skillvault-publisher login --email ${email}`));
|
|
156403
156710
|
console.log();
|
|
156404
156711
|
} catch (err) {
|
|
156405
156712
|
const message = err instanceof Error ? err.message : String(err);
|
|
156406
|
-
process.stderr.write(
|
|
156713
|
+
process.stderr.write(chalk33.red(`team add failed: ${message}
|
|
156407
156714
|
`));
|
|
156408
156715
|
process.exit(1);
|
|
156409
156716
|
}
|
|
@@ -156415,30 +156722,30 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156415
156722
|
const members = listData.members || [];
|
|
156416
156723
|
const member = members.find((m) => m.id === target || m.email === target);
|
|
156417
156724
|
if (!member) {
|
|
156418
|
-
process.stderr.write(
|
|
156725
|
+
process.stderr.write(chalk33.red(`No team member found matching "${target}".
|
|
156419
156726
|
`));
|
|
156420
|
-
process.stderr.write(
|
|
156727
|
+
process.stderr.write(chalk33.dim("Run `skillvault-publisher team` to see the current list.\n"));
|
|
156421
156728
|
process.exit(1);
|
|
156422
156729
|
}
|
|
156423
156730
|
if (member.role === "owner") {
|
|
156424
|
-
process.stderr.write(
|
|
156731
|
+
process.stderr.write(chalk33.red("Cannot remove the owner of a publisher account.\n"));
|
|
156425
156732
|
process.exit(1);
|
|
156426
156733
|
}
|
|
156427
156734
|
if (member.status === "removed") {
|
|
156428
|
-
process.stderr.write(
|
|
156735
|
+
process.stderr.write(chalk33.yellow(`${member.email} is already removed.
|
|
156429
156736
|
`));
|
|
156430
156737
|
process.exit(0);
|
|
156431
156738
|
}
|
|
156432
156739
|
if (!options.yes) {
|
|
156433
156740
|
console.log();
|
|
156434
|
-
console.log(
|
|
156741
|
+
console.log(chalk33.yellow.bold(" Warning: ") + "This will revoke " + chalk33.bold(member.email) + `'s access to publisher ${ctx.publisherId}.`);
|
|
156435
156742
|
console.log();
|
|
156436
|
-
console.log(` Email: ${
|
|
156743
|
+
console.log(` Email: ${chalk33.cyan(member.email)}`);
|
|
156437
156744
|
console.log(` Role: ${formatRole(member.role)}`);
|
|
156438
156745
|
console.log(` Status: ${formatStatus(member.status)}`);
|
|
156439
|
-
console.log(` Added: ${
|
|
156746
|
+
console.log(` Added: ${chalk33.dim(new Date(member.created_at).toLocaleDateString())}`);
|
|
156440
156747
|
console.log();
|
|
156441
|
-
console.log(
|
|
156748
|
+
console.log(chalk33.dim(" Add --yes to confirm."));
|
|
156442
156749
|
console.log();
|
|
156443
156750
|
process.exit(0);
|
|
156444
156751
|
}
|
|
@@ -156447,10 +156754,10 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156447
156754
|
console.log(JSON.stringify({ removed: true, member_id: member.id, email: member.email }, null, 2));
|
|
156448
156755
|
return;
|
|
156449
156756
|
}
|
|
156450
|
-
console.log(
|
|
156757
|
+
console.log(chalk33.green(` \u2713 Removed ${member.email} from the team`));
|
|
156451
156758
|
} catch (err) {
|
|
156452
156759
|
const message = err instanceof Error ? err.message : String(err);
|
|
156453
|
-
process.stderr.write(
|
|
156760
|
+
process.stderr.write(chalk33.red(`team remove failed: ${message}
|
|
156454
156761
|
`));
|
|
156455
156762
|
process.exit(1);
|
|
156456
156763
|
}
|
|
@@ -156459,7 +156766,7 @@ teamCommand.command("remove").description("Remove a team member by email or memb
|
|
|
156459
156766
|
// dist/index.js
|
|
156460
156767
|
var __dirname2 = dirname5(fileURLToPath(import.meta.url));
|
|
156461
156768
|
var pkg = JSON.parse(readFileSync18(join17(__dirname2, "..", "package.json"), "utf8"));
|
|
156462
|
-
var program = new
|
|
156769
|
+
var program = new Command37();
|
|
156463
156770
|
program.name("skillvault-publisher").description("SkillVault publisher CLI \u2014 publish, manage, and distribute encrypted skills").version(pkg.version).addHelpText("after", `
|
|
156464
156771
|
|
|
156465
156772
|
Getting Started:
|
|
@@ -156492,6 +156799,7 @@ program.addCommand(sessionCleanupCommand);
|
|
|
156492
156799
|
program.addCommand(skillDeleteCommand);
|
|
156493
156800
|
program.addCommand(skillStatusCommand);
|
|
156494
156801
|
program.addCommand(skillUnarchiveCommand);
|
|
156802
|
+
program.addCommand(skillAclCommand);
|
|
156495
156803
|
program.addCommand(grantsCommand);
|
|
156496
156804
|
program.addCommand(revokeGrantCommand);
|
|
156497
156805
|
program.addCommand(customersCommand);
|