skillvault-publisher 0.11.2 → 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.
Files changed (47) hide show
  1. package/dist/index.js +905 -300
  2. package/package.json +6 -2
  3. package/dist/commands/analytics.js +0 -75
  4. package/dist/commands/audit.js +0 -96
  5. package/dist/commands/changelog.js +0 -78
  6. package/dist/commands/check-session.js +0 -117
  7. package/dist/commands/customers.js +0 -53
  8. package/dist/commands/grants.js +0 -69
  9. package/dist/commands/info.js +0 -30
  10. package/dist/commands/init.js +0 -83
  11. package/dist/commands/investigate.js +0 -455
  12. package/dist/commands/invite.js +0 -198
  13. package/dist/commands/licenses.js +0 -65
  14. package/dist/commands/link.js +0 -112
  15. package/dist/commands/list.js +0 -80
  16. package/dist/commands/login.js +0 -137
  17. package/dist/commands/logout.js +0 -11
  18. package/dist/commands/publish-all.js +0 -336
  19. package/dist/commands/publish.js +0 -341
  20. package/dist/commands/register.js +0 -118
  21. package/dist/commands/report.js +0 -45
  22. package/dist/commands/revoke-grant.js +0 -49
  23. package/dist/commands/scan-output.js +0 -201
  24. package/dist/commands/search.js +0 -89
  25. package/dist/commands/session-cleanup.js +0 -108
  26. package/dist/commands/session-common.js +0 -180
  27. package/dist/commands/session-keepalive.js +0 -215
  28. package/dist/commands/skill-delete.js +0 -58
  29. package/dist/commands/skill-status.js +0 -63
  30. package/dist/commands/skill-unarchive.js +0 -51
  31. package/dist/commands/unlink.js +0 -67
  32. package/dist/commands/update.js +0 -221
  33. package/dist/commands/watchtower.js +0 -109
  34. package/dist/commands/watermark-decode.js +0 -105
  35. package/dist/commands/webhook.js +0 -77
  36. package/dist/commands/whoami.js +0 -118
  37. package/dist/commands/workspaces.js +0 -108
  38. package/dist/credentials.js +0 -185
  39. package/dist/fingerprint.js +0 -51
  40. package/dist/grant-cache.js +0 -112
  41. package/dist/hooks-manager.js +0 -202
  42. package/dist/pdf-report.js +0 -265
  43. package/dist/projects-registry.js +0 -192
  44. package/dist/publisher-workspace.js +0 -165
  45. package/dist/publisher-workspaces-registry.js +0 -133
  46. package/dist/scope.js +0 -100
  47. package/dist/session.js +0 -103
package/dist/index.js CHANGED
@@ -237,10 +237,10 @@ var require_utils = __commonJS({
237
237
  sum += a.length;
238
238
  }
239
239
  const res = new Uint8Array(sum);
240
- for (let i = 0, pad3 = 0; i < arrays.length; i++) {
240
+ for (let i = 0, pad4 = 0; i < arrays.length; i++) {
241
241
  const a = arrays[i];
242
- res.set(a, pad3);
243
- pad3 += a.length;
242
+ res.set(a, pad4);
243
+ pad4 += a.length;
244
244
  }
245
245
  return res;
246
246
  }
@@ -1769,10 +1769,10 @@ var require_utils2 = __commonJS({
1769
1769
  sum += a.length;
1770
1770
  }
1771
1771
  const res = new Uint8Array(sum);
1772
- for (let i = 0, pad3 = 0; i < arrays.length; i++) {
1772
+ for (let i = 0, pad4 = 0; i < arrays.length; i++) {
1773
1773
  const a = arrays[i];
1774
- res.set(a, pad3);
1775
- pad3 += a.length;
1774
+ res.set(a, pad4);
1775
+ pad4 += a.length;
1776
1776
  }
1777
1777
  return res;
1778
1778
  }
@@ -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(resolve10) {
3895
- resolve10(value);
3894
+ return value instanceof P ? value : new P(function(resolve12) {
3895
+ resolve12(value);
3896
3896
  });
3897
3897
  }
3898
- return new (P || (P = Promise))(function(resolve10, reject) {
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 ? resolve10(result.value) : adopt(result.value).then(fulfilled, rejected);
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(resolve10, reject) {
4106
- v = o[n](v), settle(resolve10, reject, v.done, v.value);
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(resolve10, reject, d, v) {
4110
+ function settle(resolve12, reject, d, v) {
4111
4111
  Promise.resolve(v).then(function(v2) {
4112
- resolve10({ value: v2, done: d });
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(resolve10, reject) {
5057
+ child = new nativePromise(function(resolve12, reject) {
5058
5058
  parent2.then(function(value) {
5059
- resolve10(_clone(value, depth2 - 1));
5059
+ resolve12(_clone(value, depth2 - 1));
5060
5060
  }, function(err) {
5061
5061
  reject(_clone(err, depth2 - 1));
5062
5062
  });
@@ -145431,7 +145431,7 @@ var require_pdfkit = __commonJS({
145431
145431
  return `${this.ref.id} 0 R`;
145432
145432
  }
145433
145433
  };
145434
- var pad3 = (str, length) => (Array(length + 1).join("0") + str).slice(-length);
145434
+ var pad4 = (str, length) => (Array(length + 1).join("0") + str).slice(-length);
145435
145435
  var escapableRe = /[\n\r\t\b\f()\\]/g;
145436
145436
  var escapable = {
145437
145437
  "\n": "\\n",
@@ -145487,7 +145487,7 @@ var require_pdfkit = __commonJS({
145487
145487
  } else if (object instanceof PDFAbstractReference || object instanceof PDFTree || object instanceof SpotColor) {
145488
145488
  return object.toString();
145489
145489
  } else if (object instanceof Date) {
145490
- let string = `D:${pad3(object.getUTCFullYear(), 4)}` + pad3(object.getUTCMonth() + 1, 2) + pad3(object.getUTCDate(), 2) + pad3(object.getUTCHours(), 2) + pad3(object.getUTCMinutes(), 2) + pad3(object.getUTCSeconds(), 2) + "Z";
145490
+ let string = `D:${pad4(object.getUTCFullYear(), 4)}` + pad4(object.getUTCMonth() + 1, 2) + pad4(object.getUTCDate(), 2) + pad4(object.getUTCHours(), 2) + pad4(object.getUTCMinutes(), 2) + pad4(object.getUTCSeconds(), 2) + "Z";
145491
145491
  if (encryptFn) {
145492
145492
  string = encryptFn(Buffer.from(string, "ascii")).toString("binary");
145493
145493
  string = string.replace(escapableRe, (c) => escapable[c]);
@@ -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((resolve10, reject) => {
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", resolve10);
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 Command35 } from "commander";
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";
@@ -151813,6 +151813,7 @@ import { dirname as dirname5, join as join17 } from "node:path";
151813
151813
  import { Command } from "commander";
151814
151814
  import chalk from "chalk";
151815
151815
  import { randomBytes } from "node:crypto";
151816
+ import { createInterface } from "node:readline/promises";
151816
151817
 
151817
151818
  // dist/credentials.js
151818
151819
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, rmSync, existsSync as existsSync2, openSync as openSync2, closeSync as closeSync2, unlinkSync as unlinkSync2 } from "node:fs";
@@ -151861,7 +151862,43 @@ function removeKeypair() {
151861
151862
  }
151862
151863
 
151863
151864
  // dist/commands/login.js
151864
- var loginCommand = new Command("login").description("Authenticate with the Skill Vault server").option("--email <email>", "Your publisher account email").option("--token <token>", "Authenticate with a publisher session JWT (Bearer token from dashboard)").option("--license-key <key>", "Authenticate with a license key (customer)").option("--code <code>", "Redeem an invite code after login").option("--server <url>", "Server URL", "https://api.getskillvault.com").action(async (options) => {
151865
+ async function chooseFromMultiple(available, publisherFlag) {
151866
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
151867
+ if (publisherFlag) {
151868
+ const match = available.find((p) => p.publisher_id === publisherFlag);
151869
+ if (match)
151870
+ return match;
151871
+ console.error(chalk.red(`Publisher ${publisherFlag} not in your accessible list.`));
151872
+ }
151873
+ console.error(chalk.red("Multiple publishers available for this email. Pass --publisher <id> to choose:"));
151874
+ for (const p of available) {
151875
+ console.error(chalk.dim(` --publisher ${p.publisher_id} (${p.publisher_name || "unnamed"}, role: ${p.role})`));
151876
+ }
151877
+ process.exit(1);
151878
+ }
151879
+ console.log();
151880
+ console.log(chalk.bold(" This email has access to multiple publishers:"));
151881
+ console.log();
151882
+ available.forEach((p, idx) => {
151883
+ const roleColor = p.role === "owner" ? chalk.green : p.role === "admin" ? chalk.cyan : chalk.dim;
151884
+ console.log(` ${chalk.bold(`[${idx + 1}]`)} ${p.publisher_name || p.publisher_id} ${chalk.dim(`(${p.publisher_id})`)} ${roleColor(p.role)}`);
151885
+ });
151886
+ console.log();
151887
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
151888
+ try {
151889
+ while (true) {
151890
+ const answer = (await rl.question(` Pick a publisher [1-${available.length}]: `)).trim();
151891
+ const idx = parseInt(answer, 10);
151892
+ if (Number.isInteger(idx) && idx >= 1 && idx <= available.length) {
151893
+ return available[idx - 1];
151894
+ }
151895
+ console.log(chalk.red(` Invalid choice \u2014 enter a number between 1 and ${available.length}`));
151896
+ }
151897
+ } finally {
151898
+ rl.close();
151899
+ }
151900
+ }
151901
+ var loginCommand = new Command("login").description("Authenticate with the Skill Vault server").option("--email <email>", "Your publisher account email").option("--token <token>", "Authenticate with a publisher session JWT (Bearer token from dashboard)").option("--license-key <key>", "Authenticate with a license key (customer)").option("--code <code>", "Redeem an invite code after login").option("--publisher <id>", "Disambiguate when your email has access to multiple publisher accounts").option("--server <url>", "Server URL", "https://api.getskillvault.com").action(async (options) => {
151865
151902
  try {
151866
151903
  const serverUrl = options.server;
151867
151904
  const publisherToken = options.token || process.env.SKILLVAULT_TOKEN || null;
@@ -151881,22 +151918,52 @@ var loginCommand = new Command("login").description("Authenticate with the Skill
151881
151918
  publisherIdentity = { publisher_id: me.publisher_id, email: me.email, name: me.name };
151882
151919
  } else if (options.email) {
151883
151920
  console.log(chalk.dim(`Authenticating as ${options.email}...`));
151921
+ const body2 = { email: options.email };
151922
+ if (options.publisher)
151923
+ body2.publisher_id = options.publisher;
151884
151924
  const loginRes = await fetch(`${serverUrl}/auth/login`, {
151885
151925
  method: "POST",
151886
151926
  headers: { "Content-Type": "application/json" },
151887
- body: JSON.stringify({ email: options.email })
151927
+ body: JSON.stringify(body2)
151888
151928
  });
151889
151929
  if (!loginRes.ok) {
151890
- const err = await loginRes.json().catch(() => ({ message: loginRes.statusText }));
151891
- console.error(chalk.red(`Login failed: ${err.message}`));
151930
+ const err = await loginRes.json().catch(() => null);
151931
+ const reason = err?.message || err?.error || loginRes.statusText || `HTTP ${loginRes.status}`;
151932
+ console.error(chalk.red(`Login failed: ${reason}`));
151892
151933
  if (loginRes.status === 404) {
151893
151934
  console.error(chalk.dim("No account found. Create one at https://app.getskillvault.com/login"));
151935
+ console.error(chalk.dim("Or ask a team owner to add your email via `skillvault-publisher team add`."));
151894
151936
  }
151895
151937
  process.exit(1);
151896
151938
  }
151897
151939
  const loginData = await loginRes.json();
151898
- sessionToken = loginData.session_token;
151899
- publisherIdentity = { publisher_id: loginData.publisher_id, email: loginData.email, name: loginData.name };
151940
+ if ("multiple_choice" in loginData && loginData.multiple_choice) {
151941
+ const chosen = await chooseFromMultiple(loginData.available_publishers, options.publisher);
151942
+ const retryRes = await fetch(`${serverUrl}/auth/login`, {
151943
+ method: "POST",
151944
+ headers: { "Content-Type": "application/json" },
151945
+ body: JSON.stringify({ email: options.email, publisher_id: chosen.publisher_id })
151946
+ });
151947
+ if (!retryRes.ok) {
151948
+ const err = await retryRes.json().catch(() => null);
151949
+ const reason = err?.message || err?.error || retryRes.statusText;
151950
+ console.error(chalk.red(`Login retry failed: ${reason}`));
151951
+ process.exit(1);
151952
+ }
151953
+ const retryData = await retryRes.json();
151954
+ sessionToken = retryData.session_token;
151955
+ publisherIdentity = { publisher_id: retryData.publisher_id, email: retryData.email, name: retryData.name };
151956
+ if (retryData.role && retryData.role !== "owner") {
151957
+ console.log(chalk.dim(` Logged in as ${chalk.bold(retryData.role)} of ${chosen.publisher_name || retryData.publisher_id}`));
151958
+ }
151959
+ } else {
151960
+ const single = loginData;
151961
+ sessionToken = single.session_token;
151962
+ publisherIdentity = { publisher_id: single.publisher_id, email: single.email, name: single.name };
151963
+ if (single.role && single.role !== "owner") {
151964
+ console.log(chalk.dim(` Logged in as ${chalk.bold(single.role)} of ${single.publisher_id}`));
151965
+ }
151966
+ }
151900
151967
  } else if (!options.licenseKey) {
151901
151968
  console.error(chalk.red("Publisher identity required."));
151902
151969
  console.error("");
@@ -152003,7 +152070,7 @@ var registerCommand = new Command2("register").description("Create a new publish
152003
152070
  let verified = false;
152004
152071
  const maxAttempts = 120;
152005
152072
  for (let i = 0; i < maxAttempts; i++) {
152006
- await new Promise((resolve10) => setTimeout(resolve10, 3e3));
152073
+ await new Promise((resolve12) => setTimeout(resolve12, 3e3));
152007
152074
  try {
152008
152075
  const statusRes = await fetch(`${serverUrl}/publishers/${publisher_id}/verification-status`);
152009
152076
  if (statusRes.ok) {
@@ -152094,7 +152161,7 @@ var logoutCommand = new Command3("logout").description("Remove stored credential
152094
152161
  import { Command as Command4 } from "commander";
152095
152162
  import chalk5 from "chalk";
152096
152163
  import { readFileSync as readFileSync6, existsSync as existsSync6, statSync as statSync3 } from "node:fs";
152097
- import { resolve as resolve4, join as join6 } from "node:path";
152164
+ import { resolve as resolve5, join as join6 } from "node:path";
152098
152165
  import { createHash as createHash3 } from "node:crypto";
152099
152166
 
152100
152167
  // ../shared/dist/crypto.js
@@ -152212,7 +152279,7 @@ function readVaultMetadata(data) {
152212
152279
  // ../shared/dist/packer.js
152213
152280
  import { readFileSync as readFileSync3, readdirSync, existsSync as existsSync3 } from "node:fs";
152214
152281
  import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
152215
- import { join as join3, relative } from "node:path";
152282
+ import { join as join3, relative, resolve as resolve2, isAbsolute, sep } from "node:path";
152216
152283
  import { createHash as createHash2 } from "node:crypto";
152217
152284
  var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
152218
152285
  "node_modules",
@@ -152245,10 +152312,12 @@ function collectFiles(dir, base, ignoreSet) {
152245
152312
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
152246
152313
  if (ignoreSet.has(entry.name))
152247
152314
  continue;
152315
+ if (entry.isSymbolicLink())
152316
+ continue;
152248
152317
  const fullPath = join3(dir, entry.name);
152249
152318
  if (entry.isDirectory()) {
152250
152319
  entries.push(...collectFiles(fullPath, base, ignoreSet));
152251
- } else {
152320
+ } else if (entry.isFile()) {
152252
152321
  entries.push({
152253
152322
  path: relative(base, fullPath),
152254
152323
  content: readFileSync3(fullPath)
@@ -152529,17 +152598,57 @@ function extractPotentialHeartbeats(content) {
152529
152598
  return values;
152530
152599
  }
152531
152600
 
152601
+ // ../shared/dist/skill-name.js
152602
+ var MAX_SKILL_NAME_LENGTH = 64;
152603
+ var ALLOWED_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
152604
+ var InvalidSkillNameError = class extends Error {
152605
+ reason;
152606
+ name;
152607
+ constructor(reason, name) {
152608
+ super(`invalid skill name: ${reason}`);
152609
+ this.reason = reason;
152610
+ this.name = name;
152611
+ this.name = "InvalidSkillNameError";
152612
+ }
152613
+ };
152614
+ function validateSkillName(name) {
152615
+ if (typeof name !== "string") {
152616
+ throw new InvalidSkillNameError("must be a string", String(name));
152617
+ }
152618
+ if (name.length === 0) {
152619
+ throw new InvalidSkillNameError("must not be empty", name);
152620
+ }
152621
+ if (name.length > MAX_SKILL_NAME_LENGTH) {
152622
+ throw new InvalidSkillNameError(`exceeds ${MAX_SKILL_NAME_LENGTH} characters`, name);
152623
+ }
152624
+ for (let i = 0; i < name.length; i++) {
152625
+ const code = name.charCodeAt(i);
152626
+ if (code < 32 || code === 127) {
152627
+ throw new InvalidSkillNameError(`contains control character (0x${code.toString(16).padStart(2, "0")})`, name);
152628
+ }
152629
+ }
152630
+ if (name.includes("..")) {
152631
+ throw new InvalidSkillNameError('contains parent-directory segment "..", which is not allowed in path components', name);
152632
+ }
152633
+ if (name.includes("/") || name.includes("\\")) {
152634
+ throw new InvalidSkillNameError("contains a path separator, which is not allowed in skill names", name);
152635
+ }
152636
+ if (!ALLOWED_PATTERN.test(name)) {
152637
+ throw new InvalidSkillNameError(`must match ${ALLOWED_PATTERN.source} (ASCII letters, digits, dashes, underscores; must start with a letter or digit)`, name);
152638
+ }
152639
+ }
152640
+
152532
152641
  // dist/session.js
152533
152642
  import chalk4 from "chalk";
152534
152643
 
152535
152644
  // dist/publisher-workspace.js
152536
152645
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync4 } from "node:fs";
152537
- import { join as join4, dirname as dirname3, resolve as resolve2 } from "node:path";
152646
+ import { join as join4, dirname as dirname3, resolve as resolve3 } from "node:path";
152538
152647
  import { homedir as homedir3 } from "node:os";
152539
152648
  var MANIFEST_DIRNAME = ".skillvault-publisher";
152540
152649
  var MANIFEST_FILENAME = "workspace.json";
152541
152650
  function workspaceRootsFor(dir) {
152542
- const abs = resolve2(dir);
152651
+ const abs = resolve3(dir);
152543
152652
  const manifestPath = join4(abs, MANIFEST_DIRNAME, MANIFEST_FILENAME);
152544
152653
  return {
152545
152654
  dir: abs,
@@ -152586,7 +152695,7 @@ function saveWorkspace(dir, manifest) {
152586
152695
  writeFileSync4(manifestPath, JSON.stringify(manifest, null, 2), { mode: 420 });
152587
152696
  }
152588
152697
  function findWorkspace(cwd) {
152589
- const start = resolve2(cwd ?? process.cwd());
152698
+ const start = resolve3(cwd ?? process.cwd());
152590
152699
  const home = homedir3();
152591
152700
  let dir = start;
152592
152701
  while (true) {
@@ -152658,8 +152767,9 @@ async function sessionFetch(ctx, path, options) {
152658
152767
  process.exit(1);
152659
152768
  }
152660
152769
  if (!res.ok) {
152661
- const err = await res.json().catch(() => ({ message: res.statusText }));
152662
- process.stderr.write(chalk4.red(`Error: ${err.message}
152770
+ const err = await res.json().catch(() => null);
152771
+ const reason = err?.message || err?.error || res.statusText || `HTTP ${res.status}`;
152772
+ process.stderr.write(chalk4.red(`Error: ${reason}
152663
152773
  `));
152664
152774
  process.exit(1);
152665
152775
  }
@@ -152696,7 +152806,7 @@ function requireCommandContext(opts = {}) {
152696
152806
 
152697
152807
  // dist/publisher-workspaces-registry.js
152698
152808
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync5, statSync as statSync2 } from "node:fs";
152699
- import { dirname as dirname4, join as join5, resolve as resolve3 } from "node:path";
152809
+ import { dirname as dirname4, join as join5, resolve as resolve4 } from "node:path";
152700
152810
  import { homedir as homedir4 } from "node:os";
152701
152811
  var REGISTRY_VERSION = 1;
152702
152812
  var MANIFEST_DIRNAME2 = ".skillvault-publisher";
@@ -152730,7 +152840,7 @@ function listWorkspaces() {
152730
152840
  const live = [];
152731
152841
  let pruned = false;
152732
152842
  for (const entry of reg.workspaces) {
152733
- const path = resolve3(entry.path);
152843
+ const path = resolve4(entry.path);
152734
152844
  let stillThere = false;
152735
152845
  try {
152736
152846
  const st = statSync2(path);
@@ -152755,8 +152865,8 @@ function listWorkspaces() {
152755
152865
  }
152756
152866
  function registerWorkspace(entry) {
152757
152867
  const reg = readRegistry();
152758
- const normalized = { ...entry, path: resolve3(entry.path) };
152759
- const idx = reg.workspaces.findIndex((w) => resolve3(w.path) === normalized.path);
152868
+ const normalized = { ...entry, path: resolve4(entry.path) };
152869
+ const idx = reg.workspaces.findIndex((w) => resolve4(w.path) === normalized.path);
152760
152870
  if (idx >= 0) {
152761
152871
  reg.workspaces[idx] = normalized;
152762
152872
  } else {
@@ -152766,9 +152876,9 @@ function registerWorkspace(entry) {
152766
152876
  }
152767
152877
  function unregisterWorkspace(path) {
152768
152878
  const reg = readRegistry();
152769
- const target = resolve3(path);
152879
+ const target = resolve4(path);
152770
152880
  const before = reg.workspaces.length;
152771
- reg.workspaces = reg.workspaces.filter((w) => resolve3(w.path) !== target);
152881
+ reg.workspaces = reg.workspaces.filter((w) => resolve4(w.path) !== target);
152772
152882
  if (reg.workspaces.length !== before)
152773
152883
  writeRegistry(reg);
152774
152884
  }
@@ -152798,9 +152908,9 @@ var publishCommand = new Command4("publish").description("Encrypt and publish a
152798
152908
  const config = ctx.config;
152799
152909
  const workspaceCtx = resolveWorkspaceContext({
152800
152910
  workspaceFlag: options.workspace,
152801
- cwd: directory ? resolve4(directory) : process.cwd()
152911
+ cwd: directory ? resolve5(directory) : process.cwd()
152802
152912
  });
152803
- const dirPath = options.workspace ? resolve4(options.workspace) : directory ? resolve4(directory) : workspaceCtx?.dir ?? process.cwd();
152913
+ const dirPath = options.workspace ? resolve5(options.workspace) : directory ? resolve5(directory) : workspaceCtx?.dir ?? process.cwd();
152804
152914
  if (!existsSync6(dirPath) || !statSync3(dirPath).isDirectory()) {
152805
152915
  process.stderr.write(chalk5.red(`Error: "${dirPath}" is not a valid directory
152806
152916
  `));
@@ -152821,6 +152931,17 @@ var publishCommand = new Command4("publish").description("Encrypt and publish a
152821
152931
  process.stderr.write(chalk5.red("Error: Skill name required \u2014 set in SKILL.md frontmatter or use --name\n"));
152822
152932
  process.exit(1);
152823
152933
  }
152934
+ try {
152935
+ validateSkillName(skillName);
152936
+ } catch (err) {
152937
+ if (err instanceof InvalidSkillNameError) {
152938
+ process.stderr.write(chalk5.red(`Error: ${err.message}
152939
+ `));
152940
+ process.stderr.write(chalk5.dim("Skill names must be ASCII letters, digits, dashes, or underscores (1-64 chars).\n"));
152941
+ process.exit(1);
152942
+ }
152943
+ throw err;
152944
+ }
152824
152945
  if (!description) {
152825
152946
  process.stderr.write(chalk5.red("Error: Description required \u2014 set in SKILL.md frontmatter or use --description\n"));
152826
152947
  process.exit(1);
@@ -153031,7 +153152,8 @@ The server will clean up automatically. If the problem persists, re-run with --f
153031
153152
  }
153032
153153
  const publishResult = await publishRes.json().catch(() => ({}));
153033
153154
  const wasUnlinked = existingManifest === null;
153034
- if (!options.noLink && sessionPublisherId) {
153155
+ const publishAccepted = publishResult.status !== "rejected";
153156
+ if (publishAccepted && !options.noLink && sessionPublisherId) {
153035
153157
  const linkedAt = existingManifest?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
153036
153158
  const newManifest = {
153037
153159
  ...existingManifest ?? {},
@@ -153065,6 +153187,26 @@ The server will clean up automatically. If the problem persists, re-run with --f
153065
153187
  if (publishResult.status === "unchanged") {
153066
153188
  console.log(chalk5.yellow(`Content unchanged for ${skillName} v${version}. No new version created.`));
153067
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).`));
153068
153210
  } else {
153069
153211
  console.log(chalk5.green(`Published ${skillName} v${version}`));
153070
153212
  console.log(chalk5.dim(` Skill ID: ${publishResult.skill_id || "n/a"}`));
@@ -153092,7 +153234,7 @@ import chalk6 from "chalk";
153092
153234
  var searchCommand = new Command5("search").description("Search for skills in the registry").argument("<query>", "Search query").option("--type <type>", "Filter by capability type").option("--publisher <publisher>", "Filter by publisher name or ID").option("--mine", "Show only your own published skills").option("--json", "Output results as JSON").action(async (query, options) => {
153093
153235
  try {
153094
153236
  const config = getConfig();
153095
- const serverUrl = config?.server_url ?? "http://localhost:3001";
153237
+ const serverUrl = config?.server_url ?? "https://api.getskillvault.com";
153096
153238
  let publisherFilter = options.publisher;
153097
153239
  if (options.mine) {
153098
153240
  if (!config) {
@@ -153253,7 +153395,7 @@ var licensesCommand = new Command7("licenses").description("List your active ski
153253
153395
  import { Command as Command8 } from "commander";
153254
153396
  import chalk9 from "chalk";
153255
153397
  import { readFileSync as readFileSync8, existsSync as existsSync7, statSync as statSync4 } from "node:fs";
153256
- import { resolve as resolve5, join as join7 } from "node:path";
153398
+ import { resolve as resolve6, join as join7 } from "node:path";
153257
153399
  import { createHash as createHash4 } from "node:crypto";
153258
153400
  function parseFrontmatter2(content) {
153259
153401
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
@@ -153304,7 +153446,7 @@ var updateCommand = new Command8("update").description("Push a new version of an
153304
153446
  try {
153305
153447
  const ctx = requireSession();
153306
153448
  const config = ctx.config;
153307
- const dirPath = resolve5(directory);
153449
+ const dirPath = resolve6(directory);
153308
153450
  if (!existsSync7(dirPath) || !statSync4(dirPath).isDirectory()) {
153309
153451
  process.stderr.write(chalk9.red(`Error: "${dirPath}" is not a valid directory
153310
153452
  `));
@@ -153487,6 +153629,14 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
153487
153629
  const ctx = requireSession();
153488
153630
  const config = ctx.config;
153489
153631
  const fingerprint = getDeviceFingerprint();
153632
+ let authMe = null;
153633
+ try {
153634
+ const meRes = await fetch(`${config.server_url}/auth/me`, { headers: ctx.headers });
153635
+ if (meRes.ok) {
153636
+ authMe = await meRes.json();
153637
+ }
153638
+ } catch {
153639
+ }
153490
153640
  const response = await fetch(`${config.server_url}/agent/status?agent_id=${encodeURIComponent(config.agent_id)}`, {
153491
153641
  headers: ctx.headers
153492
153642
  });
@@ -153495,29 +153645,48 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
153495
153645
  console.log(JSON.stringify({
153496
153646
  host_id: config.host_id,
153497
153647
  agent_id: config.agent_id,
153498
- ...config.publisher_id ? { publisher_id: config.publisher_id } : {},
153499
- ...config.email ? { email: config.email } : {},
153648
+ ...authMe ? {
153649
+ publisher_id: authMe.publisher_id,
153650
+ publisher_name: authMe.publisher_name,
153651
+ email: authMe.email,
153652
+ role: authMe.role,
153653
+ is_owner: authMe.is_owner
153654
+ } : {
153655
+ ...config.publisher_id ? { publisher_id: config.publisher_id } : {},
153656
+ ...config.email ? { email: config.email } : {}
153657
+ },
153500
153658
  device_fingerprint: fingerprint,
153501
153659
  server_url: config.server_url,
153502
- server_status: "unreachable"
153660
+ server_status: "agent_status_unreachable"
153503
153661
  }, null, 2));
153504
153662
  return;
153505
153663
  }
153506
153664
  console.log();
153507
153665
  console.log(chalk10.bold(" Skill Vault Identity"));
153508
153666
  console.log();
153509
- if (config.publisher_id) {
153510
- console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
153511
- }
153512
- if (config.email) {
153513
- console.log(` ${"Email:".padEnd(22)} ${config.email}`);
153667
+ if (authMe) {
153668
+ const roleColor = authMe.role === "owner" ? chalk10.green : authMe.role === "admin" ? chalk10.cyan : chalk10.dim;
153669
+ const roleLabel = authMe.role || (authMe.is_owner ? "owner" : "member");
153670
+ console.log(` ${"You:".padEnd(22)} ${authMe.email} ${roleColor(`(${roleLabel})`)}`);
153671
+ const publisherDisplay = authMe.publisher_name ? `${authMe.publisher_name} ${chalk10.dim(`(${authMe.publisher_id})`)}` : authMe.publisher_id;
153672
+ console.log(` ${"Publisher:".padEnd(22)} ${publisherDisplay}`);
153673
+ if (!authMe.is_owner) {
153674
+ console.log(` ${chalk10.dim(" (you are a team member of this publisher)".padEnd(22))}`);
153675
+ }
153676
+ } else {
153677
+ if (config.publisher_id) {
153678
+ console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
153679
+ }
153680
+ if (config.email) {
153681
+ console.log(` ${"Email:".padEnd(22)} ${config.email}`);
153682
+ }
153514
153683
  }
153515
153684
  console.log(` ${"Host ID:".padEnd(22)} ${config.host_id}`);
153516
153685
  console.log(` ${"Agent ID:".padEnd(22)} ${config.agent_id}`);
153517
153686
  console.log(` ${"Device Fingerprint:".padEnd(22)} ${fingerprint}`);
153518
153687
  console.log(` ${"Server:".padEnd(22)} ${config.server_url}`);
153519
153688
  console.log();
153520
- console.log(chalk10.yellow(` Server unreachable (${response.status}). Showing local config only.`));
153689
+ console.log(chalk10.yellow(` Status endpoint unreachable (${response.status}); skipped grants list.`));
153521
153690
  console.log();
153522
153691
  return;
153523
153692
  }
@@ -153526,8 +153695,17 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
153526
153695
  console.log(JSON.stringify({
153527
153696
  host_id: data.host_id ?? config.host_id,
153528
153697
  agent_id: data.agent_id ?? config.agent_id,
153529
- ...config.publisher_id ? { publisher_id: config.publisher_id } : {},
153530
- ...config.email ? { email: config.email } : {},
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
+ },
153531
153709
  device_fingerprint: fingerprint,
153532
153710
  server_url: config.server_url,
153533
153711
  status: data.status,
@@ -153535,14 +153713,51 @@ var whoamiCommand = new Command9("whoami").description("Show current user, activ
153535
153713
  }, null, 2));
153536
153714
  return;
153537
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
+ }
153538
153728
  console.log();
153539
153729
  console.log(chalk10.bold(" Skill Vault Identity"));
153540
153730
  console.log();
153541
- if (config.publisher_id) {
153542
- console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
153543
- }
153544
- if (config.email) {
153545
- console.log(` ${"Email:".padEnd(22)} ${config.email}`);
153731
+ if (authMe) {
153732
+ const roleColor = authMe.role === "owner" ? chalk10.green : authMe.role === "admin" ? chalk10.cyan : chalk10.dim;
153733
+ const roleLabel = authMe.role || (authMe.is_owner ? "owner" : "member");
153734
+ console.log(` ${"You:".padEnd(22)} ${authMe.email} ${roleColor(`(${roleLabel})`)}`);
153735
+ const publisherDisplay = authMe.publisher_name ? `${authMe.publisher_name} ${chalk10.dim(`(${authMe.publisher_id})`)}` : authMe.publisher_id;
153736
+ console.log(` ${"Publisher:".padEnd(22)} ${publisherDisplay}`);
153737
+ if (!authMe.is_owner) {
153738
+ console.log(` ${chalk10.dim(" (you are a team member of this publisher)".padEnd(22))}`);
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
+ }
153754
+ } else {
153755
+ if (config.publisher_id) {
153756
+ console.log(` ${"Publisher ID:".padEnd(22)} ${config.publisher_id}`);
153757
+ }
153758
+ if (config.email) {
153759
+ console.log(` ${"Email:".padEnd(22)} ${config.email}`);
153760
+ }
153546
153761
  }
153547
153762
  console.log(` ${"Host ID:".padEnd(22)} ${data.host_id ?? config.host_id}`);
153548
153763
  console.log(` ${"Agent ID:".padEnd(22)} ${data.agent_id ?? config.agent_id}`);
@@ -153627,7 +153842,7 @@ var reportCommand = new Command10("report").description("Report a telemetry even
153627
153842
  import { Command as Command11 } from "commander";
153628
153843
  import chalk12 from "chalk";
153629
153844
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
153630
- import { resolve as resolve6, join as join8 } from "node:path";
153845
+ import { resolve as resolve7, join as join8 } from "node:path";
153631
153846
  function toTitleCase(name) {
153632
153847
  return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
153633
153848
  }
@@ -153664,7 +153879,7 @@ var initCommand = new Command11("init").description("Scaffold a new skill direct
153664
153879
  process.stderr.write(chalk12.dim(" skillvault-publisher init my-awesome-skill\n"));
153665
153880
  process.exit(1);
153666
153881
  }
153667
- const dirPath = resolve6(name);
153882
+ const dirPath = resolve7(name);
153668
153883
  if (existsSync8(dirPath)) {
153669
153884
  process.stderr.write(chalk12.red(`Error: Directory "${name}" already exists.
153670
153885
  `));
@@ -153779,11 +153994,9 @@ var listCommand = new Command13("list").description("List your published skills"
153779
153994
  headers: ctx.headers
153780
153995
  });
153781
153996
  if (!response.ok) {
153782
- const err = await response.json().catch(() => ({
153783
- error: "unknown",
153784
- message: response.statusText
153785
- }));
153786
- process.stderr.write(chalk14.red(`Failed to list skills: ${err.message}
153997
+ const err = await response.json().catch(() => null);
153998
+ const reason = err?.message || err?.error || response.statusText || `HTTP ${response.status}`;
153999
+ process.stderr.write(chalk14.red(`Failed to list skills: ${reason}
153787
154000
  `));
153788
154001
  process.exit(1);
153789
154002
  }
@@ -153804,11 +154017,13 @@ var listCommand = new Command13("list").description("List your published skills"
153804
154017
  const nameWidth = Math.max(20, ...skills.map((s) => s.name.length + 2));
153805
154018
  const verWidth = 10;
153806
154019
  const statusWidth = 10;
154020
+ const reviewWidth = 8;
153807
154021
  const capWidth = Math.max(24, ...skills.map((s) => s.capability_name.length + 2));
153808
154022
  const header = [
153809
154023
  chalk14.dim("Name".padEnd(nameWidth)),
153810
154024
  chalk14.dim("Version".padEnd(verWidth)),
153811
154025
  chalk14.dim("Status".padEnd(statusWidth)),
154026
+ chalk14.dim("Review".padEnd(reviewWidth)),
153812
154027
  chalk14.dim("Capability".padEnd(capWidth)),
153813
154028
  chalk14.dim("Created")
153814
154029
  ].join(" ");
@@ -153820,10 +154035,29 @@ var listCommand = new Command13("list").description("List your published skills"
153820
154035
  year: "numeric"
153821
154036
  });
153822
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
+ }
153823
154056
  const row = [
153824
154057
  chalk14.cyan(skill.name.padEnd(nameWidth)),
153825
154058
  chalk14.green(("v" + skill.latest_version).padEnd(verWidth)),
153826
154059
  statusColor(skill.status.padEnd(statusWidth)),
154060
+ reviewCell,
153827
154061
  chalk14.dim(skill.capability_name.padEnd(capWidth)),
153828
154062
  chalk14.dim(createdDate)
153829
154063
  ].join(" ");
@@ -153842,7 +154076,7 @@ var listCommand = new Command13("list").description("List your published skills"
153842
154076
  import { Command as Command14 } from "commander";
153843
154077
  import chalk15 from "chalk";
153844
154078
  import { readFileSync as readFileSync9, existsSync as existsSync9, statSync as statSync5, readdirSync as readdirSync2 } from "node:fs";
153845
- import { resolve as resolve7, join as join9, basename } from "node:path";
154079
+ import { resolve as resolve8, join as join9, basename } from "node:path";
153846
154080
  import { createHash as createHash6 } from "node:crypto";
153847
154081
  function parseFrontmatter3(content) {
153848
154082
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
@@ -153990,7 +154224,7 @@ var publishAllCommand = new Command14("publish-all").description("Discover and p
153990
154224
  skillDirs = entries.map((e) => e.path);
153991
154225
  console.log(chalk15.dim(`Iterating ${skillDirs.length} registered workspace${skillDirs.length === 1 ? "" : "s"}` + (options.current ? " (current account only)" : "") + "..."));
153992
154226
  } else {
153993
- const rootDir = resolve7(directory);
154227
+ const rootDir = resolve8(directory);
153994
154228
  if (!existsSync9(rootDir) || !statSync5(rootDir).isDirectory()) {
153995
154229
  process.stderr.write(chalk15.red(`Error: "${rootDir}" is not a valid directory
153996
154230
  `));
@@ -154270,12 +154504,12 @@ var inviteListCommand = new Command15("list").description("List all invites").op
154270
154504
  }
154271
154505
  console.log(`Invites (${invites.length}):
154272
154506
  `);
154273
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
154274
- console.log(chalk16.dim(`${pad3("Code", 14)} ${pad3("Email", 30)} ${pad3("Status", 10)} ${pad3("Skills", 25)} ${pad3("Created", 12)}`));
154507
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
154508
+ console.log(chalk16.dim(`${pad4("Code", 14)} ${pad4("Email", 30)} ${pad4("Status", 10)} ${pad4("Skills", 25)} ${pad4("Created", 12)}`));
154275
154509
  console.log(chalk16.dim("\u2500".repeat(95)));
154276
154510
  for (const inv of invites) {
154277
154511
  const statusColor = inv.status === "redeemed" ? chalk16.green : inv.status === "expired" ? chalk16.dim : chalk16.yellow;
154278
- console.log(`${pad3(inv.code, 14)} ${pad3(inv.customer_email || "(open)", 30)} ${statusColor(pad3(inv.status, 10))} ${pad3(inv.capabilities.join(", ") || "(none)", 25)} ${pad3(new Date(inv.created_at).toLocaleDateString(), 12)}`);
154512
+ console.log(`${pad4(inv.code, 14)} ${pad4(inv.customer_email || "(open)", 30)} ${statusColor(pad4(inv.status, 10))} ${pad4(inv.capabilities.join(", ") || "(none)", 25)} ${pad4(new Date(inv.created_at).toLocaleDateString(), 12)}`);
154279
154513
  }
154280
154514
  } catch (err) {
154281
154515
  process.stderr.write(chalk16.red(`Error: ${err instanceof Error ? err.message : String(err)}
@@ -154898,7 +155132,9 @@ var skillDeleteCommand = new Command20("skill-delete").description("Permanently
154898
155132
  // dist/commands/skill-status.js
154899
155133
  import { Command as Command21 } from "commander";
154900
155134
  import chalk18 from "chalk";
154901
- 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').action(async (skillNameArg, options) => {
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) => {
154902
155138
  try {
154903
155139
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
154904
155140
  const skillName = skillNameArg ?? ctx.defaultSkillName ?? void 0;
@@ -154920,17 +155156,56 @@ var skillStatusCommand = new Command21("skill-status").description("Show detaile
154920
155156
  sessionFetch(ctx, "/grants")
154921
155157
  ]);
154922
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
+ }
154923
155174
  if (options.json) {
154924
155175
  console.log(JSON.stringify({ ...detail, active_grants: activeGrants.length }, null, 2));
154925
155176
  return;
154926
155177
  }
154927
155178
  const statusColor = detail.status === "active" ? chalk18.green : detail.status === "archived" ? chalk18.yellow : chalk18.dim;
154928
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;
154929
155200
  console.log();
154930
155201
  console.log(chalk18.bold(` ${detail.name}`));
154931
155202
  console.log();
154932
155203
  console.log(` Capability: ${detail.capability_name}`);
154933
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
+ }
154934
155209
  console.log(` Version: ${chalk18.green("v" + detail.latest_version)}`);
154935
155210
  console.log(` Created: ${chalk18.dim(createdDate)}`);
154936
155211
  console.log(` ID: ${chalk18.dim(detail.id)}`);
@@ -154987,10 +155262,199 @@ var skillUnarchiveCommand = new Command22("skill-unarchive").description("Restor
154987
155262
  }
154988
155263
  });
154989
155264
 
154990
- // dist/commands/grants.js
155265
+ // dist/commands/skill-acl.js
154991
155266
  import { Command as Command23 } from "commander";
154992
155267
  import chalk20 from "chalk";
154993
- var grantsCommand = new Command23("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) => {
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) => {
154994
155458
  try {
154995
155459
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
154996
155460
  const data = await sessionFetch(ctx, "/grants");
@@ -155008,43 +155472,43 @@ var grantsCommand = new Command23("grants").description("List capability grants
155008
155472
  return;
155009
155473
  }
155010
155474
  if (grants.length === 0) {
155011
- console.log(chalk20.dim("No grants found."));
155475
+ console.log(chalk21.dim("No grants found."));
155012
155476
  return;
155013
155477
  }
155014
155478
  console.log();
155015
- console.log(chalk20.bold(" Capability Grants"));
155479
+ console.log(chalk21.bold(" Capability Grants"));
155016
155480
  console.log();
155017
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
155018
- const header = `${pad3("Grant ID", 22)} ${pad3("Skill", 24)} ${pad3("Customer", 22)} ${pad3("Status", 10)} ${pad3("Granted", 12)} ${"Expires"}`;
155019
- console.log(` ${chalk20.dim(header)}`);
155020
- console.log(` ${chalk20.dim("\u2500".repeat(header.length))}`);
155481
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
155482
+ const header = `${pad4("Grant ID", 22)} ${pad4("Skill", 24)} ${pad4("Customer", 22)} ${pad4("Status", 10)} ${pad4("Granted", 12)} ${"Expires"}`;
155483
+ console.log(` ${chalk21.dim(header)}`);
155484
+ console.log(` ${chalk21.dim("\u2500".repeat(header.length))}`);
155021
155485
  for (const grant of grants) {
155022
- const statusColor = grant.status === "active" ? chalk20.green : grant.status === "revoked" ? chalk20.red : grant.status === "expired" ? chalk20.yellow : chalk20.white;
155486
+ const statusColor = grant.status === "active" ? chalk21.green : grant.status === "revoked" ? chalk21.red : grant.status === "expired" ? chalk21.yellow : chalk21.white;
155023
155487
  const row = [
155024
- pad3(grant.id, 22),
155025
- pad3(grant.capability, 24),
155026
- pad3(grant.customer_id || "-", 22),
155027
- statusColor(pad3(grant.status, 10)),
155028
- pad3(new Date(grant.created_at).toLocaleDateString(), 12),
155488
+ pad4(grant.id, 22),
155489
+ pad4(grant.capability, 24),
155490
+ pad4(grant.customer_id || "-", 22),
155491
+ statusColor(pad4(grant.status, 10)),
155492
+ pad4(new Date(grant.created_at).toLocaleDateString(), 12),
155029
155493
  grant.expires_at ? new Date(grant.expires_at).toLocaleDateString() : "never"
155030
155494
  ].join(" ");
155031
155495
  console.log(` ${row}`);
155032
155496
  }
155033
155497
  console.log();
155034
- console.log(chalk20.dim(` ${grants.length} grant${grants.length !== 1 ? "s" : ""} total`));
155498
+ console.log(chalk21.dim(` ${grants.length} grant${grants.length !== 1 ? "s" : ""} total`));
155035
155499
  console.log();
155036
155500
  } catch (err) {
155037
155501
  const message = err instanceof Error ? err.message : String(err);
155038
- process.stderr.write(chalk20.red(`Error: ${message}
155502
+ process.stderr.write(chalk21.red(`Error: ${message}
155039
155503
  `));
155040
155504
  process.exit(1);
155041
155505
  }
155042
155506
  });
155043
155507
 
155044
155508
  // dist/commands/revoke-grant.js
155045
- import { Command as Command24 } from "commander";
155046
- import chalk21 from "chalk";
155047
- var revokeGrantCommand = new Command24("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) => {
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) => {
155048
155512
  try {
155049
155513
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
155050
155514
  if (!options.yes) {
@@ -155055,7 +155519,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
155055
155519
  return;
155056
155520
  }
155057
155521
  console.log();
155058
- console.log(chalk21.bold(" Grant details"));
155522
+ console.log(chalk22.bold(" Grant details"));
155059
155523
  console.log();
155060
155524
  console.log(` ID: ${grant.id}`);
155061
155525
  console.log(` Skill: ${grant.skill}`);
@@ -155064,7 +155528,7 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
155064
155528
  console.log(` Granted: ${new Date(grant.granted_at).toLocaleDateString()}`);
155065
155529
  console.log(` Expires: ${grant.expires_at ? new Date(grant.expires_at).toLocaleDateString() : "never"}`);
155066
155530
  console.log();
155067
- console.log(chalk21.yellow(" Add --yes to confirm revocation."));
155531
+ console.log(chalk22.yellow(" Add --yes to confirm revocation."));
155068
155532
  console.log();
155069
155533
  return;
155070
155534
  }
@@ -155073,19 +155537,19 @@ var revokeGrantCommand = new Command24("revoke-grant").description("Revoke a cap
155073
155537
  console.log(JSON.stringify(result.grant, null, 2));
155074
155538
  return;
155075
155539
  }
155076
- console.log(chalk21.green(`Revoked grant ${result.grant.id} for ${result.grant.skill}`));
155540
+ console.log(chalk22.green(`Revoked grant ${result.grant.id} for ${result.grant.skill}`));
155077
155541
  } catch (err) {
155078
155542
  const message = err instanceof Error ? err.message : String(err);
155079
- process.stderr.write(chalk21.red(`Error: ${message}
155543
+ process.stderr.write(chalk22.red(`Error: ${message}
155080
155544
  `));
155081
155545
  process.exit(1);
155082
155546
  }
155083
155547
  });
155084
155548
 
155085
155549
  // dist/commands/customers.js
155086
- import { Command as Command25 } from "commander";
155087
- import chalk22 from "chalk";
155088
- var customersCommand = new Command25("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) => {
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) => {
155089
155553
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
155090
155554
  try {
155091
155555
  const data = await sessionFetch(ctx, "/customers");
@@ -155095,48 +155559,48 @@ var customersCommand = new Command25("customers").description("List your custome
155095
155559
  return;
155096
155560
  }
155097
155561
  if (customers.length === 0) {
155098
- console.log(chalk22.dim("No customers found."));
155562
+ console.log(chalk23.dim("No customers found."));
155099
155563
  return;
155100
155564
  }
155101
155565
  console.log();
155102
- console.log(chalk22.bold(" Customers"));
155566
+ console.log(chalk23.bold(" Customers"));
155103
155567
  console.log();
155104
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
155105
- const header = `${pad3("Email", 32)} ${pad3("Skills", 8)} ${pad3("Loads", 8)} ${pad3("Status", 10)} Last Active`;
155106
- console.log(` ${chalk22.dim(header)}`);
155107
- console.log(` ${chalk22.dim("\u2500".repeat(header.length))}`);
155568
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
155569
+ const header = `${pad4("Email", 32)} ${pad4("Skills", 8)} ${pad4("Loads", 8)} ${pad4("Status", 10)} Last Active`;
155570
+ console.log(` ${chalk23.dim(header)}`);
155571
+ console.log(` ${chalk23.dim("\u2500".repeat(header.length))}`);
155108
155572
  for (const c of customers) {
155109
- const statusColor = c.status === "active" ? chalk22.green : chalk22.dim;
155110
- const lastActive = c.last_active_at ? new Date(c.last_active_at).toLocaleDateString() : chalk22.dim("never");
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");
155111
155575
  const row = [
155112
- pad3(c.email, 32),
155113
- pad3(String(c.skills_count), 8),
155114
- pad3(String(c.total_loads), 8),
155115
- statusColor(pad3(c.status, 10)),
155576
+ pad4(c.email, 32),
155577
+ pad4(String(c.skills_count), 8),
155578
+ pad4(String(c.total_loads), 8),
155579
+ statusColor(pad4(c.status, 10)),
155116
155580
  lastActive
155117
155581
  ].join(" ");
155118
155582
  console.log(` ${row}`);
155119
155583
  }
155120
155584
  console.log();
155121
- console.log(chalk22.dim(` ${customers.length} customer${customers.length !== 1 ? "s" : ""} total`));
155585
+ console.log(chalk23.dim(` ${customers.length} customer${customers.length !== 1 ? "s" : ""} total`));
155122
155586
  console.log();
155123
155587
  } catch (err) {
155124
155588
  const message = err instanceof Error ? err.message : String(err);
155125
- process.stderr.write(chalk22.red(`Error: ${message}
155589
+ process.stderr.write(chalk23.red(`Error: ${message}
155126
155590
  `));
155127
155591
  process.exit(1);
155128
155592
  }
155129
155593
  });
155130
155594
 
155131
155595
  // dist/commands/analytics.js
155132
- import { Command as Command26 } from "commander";
155133
- import chalk23 from "chalk";
155134
- var analyticsCommand = new Command26("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) => {
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) => {
155135
155599
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
155136
155600
  try {
155137
155601
  const days = parseInt(options.days, 10);
155138
155602
  if (isNaN(days) || days < 1) {
155139
- process.stderr.write(chalk23.red("--days must be a positive number.\n"));
155603
+ process.stderr.write(chalk24.red("--days must be a positive number.\n"));
155140
155604
  process.exit(1);
155141
155605
  }
155142
155606
  const end = /* @__PURE__ */ new Date();
@@ -155149,11 +155613,11 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
155149
155613
  return;
155150
155614
  }
155151
155615
  console.log();
155152
- console.log(chalk23.bold(" Publisher Analytics"));
155616
+ console.log(chalk24.bold(" Publisher Analytics"));
155153
155617
  console.log();
155154
- console.log(` ${chalk23.bold("Active Licenses:")} ${data.active_licenses}`);
155155
- console.log(` ${chalk23.bold("Total Decryptions:")} ${data.total_decryptions}`);
155156
- console.log(` ${chalk23.bold("Period:")} Last ${days} day${days !== 1 ? "s" : ""} (${start.toLocaleDateString()} \u2013 ${end.toLocaleDateString()})`);
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()})`);
155157
155621
  const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
155158
155622
  const filterSkill = (skillName) => !effectiveSkill || skillName.toLowerCase() === effectiveSkill.toLowerCase();
155159
155623
  const statsMap = new Map((data.skill_stats || []).map((s) => [s.skill_name, s]));
@@ -155162,44 +155626,44 @@ var analyticsCommand = new Command26("analytics").description("View publisher an
155162
155626
  }
155163
155627
  if (data.top_skills && data.top_skills.length > 0) {
155164
155628
  console.log();
155165
- console.log(chalk23.bold(" Top Skills"));
155629
+ console.log(chalk24.bold(" Top Skills"));
155166
155630
  console.log();
155167
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
155168
- const header = `${pad3("Skill", 28)} ${pad3("Decryptions", 14)} Active Licenses`;
155169
- console.log(` ${chalk23.dim(header)}`);
155170
- console.log(` ${chalk23.dim("\u2500".repeat(header.length))}`);
155631
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
155632
+ const header = `${pad4("Skill", 28)} ${pad4("Decryptions", 14)} Active Licenses`;
155633
+ console.log(` ${chalk24.dim(header)}`);
155634
+ console.log(` ${chalk24.dim("\u2500".repeat(header.length))}`);
155171
155635
  for (const skill of data.top_skills) {
155172
155636
  const stats = statsMap.get(skill.name);
155173
155637
  const row = [
155174
- pad3(skill.name, 28),
155175
- pad3(String(skill.decryptions), 14),
155638
+ pad4(skill.name, 28),
155639
+ pad4(String(skill.decryptions), 14),
155176
155640
  String(stats?.active_licenses ?? "-")
155177
155641
  ].join(" ");
155178
155642
  console.log(` ${row}`);
155179
155643
  }
155180
155644
  } else {
155181
155645
  console.log();
155182
- console.log(chalk23.dim(" No skill activity in this period."));
155646
+ console.log(chalk24.dim(" No skill activity in this period."));
155183
155647
  }
155184
155648
  console.log();
155185
155649
  } catch (err) {
155186
155650
  const message = err instanceof Error ? err.message : String(err);
155187
- process.stderr.write(chalk23.red(`Error: ${message}
155651
+ process.stderr.write(chalk24.red(`Error: ${message}
155188
155652
  `));
155189
155653
  process.exit(1);
155190
155654
  }
155191
155655
  });
155192
155656
 
155193
155657
  // dist/commands/webhook.js
155194
- import { Command as Command27 } from "commander";
155195
- import chalk24 from "chalk";
155196
- var webhookCommand = new Command27("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) => {
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) => {
155197
155661
  try {
155198
155662
  const ctx = requireSession();
155199
155663
  switch (action) {
155200
155664
  case "set": {
155201
155665
  if (!options.url) {
155202
- process.stderr.write(chalk24.red("Missing --url option. Usage: skillvault-publisher webhook set --url <url>\n"));
155666
+ process.stderr.write(chalk25.red("Missing --url option. Usage: skillvault-publisher webhook set --url <url>\n"));
155203
155667
  process.exit(1);
155204
155668
  }
155205
155669
  const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/webhook`, { method: "POST", body: { url: options.url } });
@@ -155208,12 +155672,12 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
155208
155672
  return;
155209
155673
  }
155210
155674
  console.log();
155211
- console.log(chalk24.green(" Webhook configured"));
155675
+ console.log(chalk25.green(" Webhook configured"));
155212
155676
  console.log();
155213
155677
  console.log(` ${"URL:".padEnd(18)} ${data.webhook_url}`);
155214
- console.log(` ${"Signing Secret:".padEnd(18)} ${chalk24.yellow(data.signing_secret)}`);
155678
+ console.log(` ${"Signing Secret:".padEnd(18)} ${chalk25.yellow(data.signing_secret)}`);
155215
155679
  console.log();
155216
- console.log(chalk24.dim(" Store the signing secret securely. It will not be shown again."));
155680
+ console.log(chalk25.dim(" Store the signing secret securely. It will not be shown again."));
155217
155681
  console.log();
155218
155682
  break;
155219
155683
  }
@@ -155224,7 +155688,7 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
155224
155688
  return;
155225
155689
  }
155226
155690
  console.log();
155227
- console.log(chalk24.green(" Test event sent to webhook URL"));
155691
+ console.log(chalk25.green(" Test event sent to webhook URL"));
155228
155692
  console.log();
155229
155693
  break;
155230
155694
  }
@@ -155236,36 +155700,36 @@ var webhookCommand = new Command27("webhook").description("Manage publisher webh
155236
155700
  }
155237
155701
  console.log();
155238
155702
  if (data.webhook_url) {
155239
- console.log(chalk24.bold(" Webhook Status"));
155703
+ console.log(chalk25.bold(" Webhook Status"));
155240
155704
  console.log();
155241
155705
  console.log(` ${"URL:".padEnd(12)} ${data.webhook_url}`);
155242
- console.log(` ${"Status:".padEnd(12)} ${chalk24.green("configured")}`);
155706
+ console.log(` ${"Status:".padEnd(12)} ${chalk25.green("configured")}`);
155243
155707
  } else {
155244
- console.log(chalk24.dim(" No webhook configured."));
155708
+ console.log(chalk25.dim(" No webhook configured."));
155245
155709
  console.log();
155246
- console.log(chalk24.dim(" Set one with: skillvault-publisher webhook set --url <url>"));
155710
+ console.log(chalk25.dim(" Set one with: skillvault-publisher webhook set --url <url>"));
155247
155711
  }
155248
155712
  console.log();
155249
155713
  break;
155250
155714
  }
155251
155715
  default:
155252
- process.stderr.write(chalk24.red(`Unknown action: ${action}
155716
+ process.stderr.write(chalk25.red(`Unknown action: ${action}
155253
155717
  `));
155254
- process.stderr.write(chalk24.dim("Valid actions: set, test, status\n"));
155718
+ process.stderr.write(chalk25.dim("Valid actions: set, test, status\n"));
155255
155719
  process.exit(1);
155256
155720
  }
155257
155721
  } catch (err) {
155258
155722
  const message = err instanceof Error ? err.message : String(err);
155259
- process.stderr.write(chalk24.red(`Error: ${message}
155723
+ process.stderr.write(chalk25.red(`Error: ${message}
155260
155724
  `));
155261
155725
  process.exit(1);
155262
155726
  }
155263
155727
  });
155264
155728
 
155265
155729
  // dist/commands/audit.js
155266
- import { Command as Command28 } from "commander";
155267
- import chalk25 from "chalk";
155268
- var auditCommand = new Command28("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) => {
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) => {
155269
155733
  try {
155270
155734
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
155271
155735
  const effectiveSkill = options.skill ?? (options.all ? void 0 : ctx.defaultSkillName ?? void 0);
@@ -155280,7 +155744,7 @@ var auditCommand = new Command28("audit").description("View audit log events").o
155280
155744
  if (options.export) {
155281
155745
  const format = options.export.toLowerCase();
155282
155746
  if (format !== "csv" && format !== "json") {
155283
- process.stderr.write(chalk25.red('Export format must be "csv" or "json".\n'));
155747
+ process.stderr.write(chalk26.red('Export format must be "csv" or "json".\n'));
155284
155748
  process.exit(1);
155285
155749
  }
155286
155750
  params.set("format", format);
@@ -155299,68 +155763,68 @@ var auditCommand = new Command28("audit").description("View audit log events").o
155299
155763
  return;
155300
155764
  }
155301
155765
  if (events.length === 0) {
155302
- console.log(chalk25.dim("No audit events found."));
155766
+ console.log(chalk26.dim("No audit events found."));
155303
155767
  return;
155304
155768
  }
155305
155769
  console.log();
155306
- console.log(chalk25.bold(" Audit Log"));
155770
+ console.log(chalk26.bold(" Audit Log"));
155307
155771
  console.log();
155308
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
155309
- const header = `${pad3("Event Type", 22)} ${pad3("Skill", 24)} ${pad3("Agent", 20)} ${"Time"}`;
155310
- console.log(` ${chalk25.dim(header)}`);
155311
- console.log(` ${chalk25.dim("\u2500".repeat(header.length))}`);
155772
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
155773
+ const header = `${pad4("Event Type", 22)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} ${"Time"}`;
155774
+ console.log(` ${chalk26.dim(header)}`);
155775
+ console.log(` ${chalk26.dim("\u2500".repeat(header.length))}`);
155312
155776
  for (const event of events) {
155313
155777
  const skill = event.capability ? event.capability.replace(/^skill\//, "") : "-";
155314
155778
  const agent = event.agent_id ? event.agent_id.slice(0, 18) : "-";
155315
155779
  const time = new Date(event.created_at).toLocaleString();
155316
155780
  const row = [
155317
- pad3(event.event_type, 22),
155318
- pad3(skill, 24),
155319
- pad3(agent, 20),
155781
+ pad4(event.event_type, 22),
155782
+ pad4(skill, 24),
155783
+ pad4(agent, 20),
155320
155784
  time
155321
155785
  ].join(" ");
155322
155786
  console.log(` ${row}`);
155323
155787
  }
155324
155788
  console.log();
155325
- console.log(chalk25.dim(` Showing ${events.length} event${events.length !== 1 ? "s" : ""}`));
155789
+ console.log(chalk26.dim(` Showing ${events.length} event${events.length !== 1 ? "s" : ""}`));
155326
155790
  if (data.has_more) {
155327
- console.log(chalk25.dim(` More results available`));
155791
+ console.log(chalk26.dim(` More results available`));
155328
155792
  }
155329
155793
  console.log();
155330
155794
  } catch (err) {
155331
155795
  const message = err instanceof Error ? err.message : String(err);
155332
- process.stderr.write(chalk25.red(`Error: ${message}
155796
+ process.stderr.write(chalk26.red(`Error: ${message}
155333
155797
  `));
155334
155798
  process.exit(1);
155335
155799
  }
155336
155800
  });
155337
155801
 
155338
155802
  // dist/commands/investigate.js
155339
- import { Command as Command29 } from "commander";
155340
- import chalk26 from "chalk";
155341
- import { readFileSync as readFileSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
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";
155342
155806
  import { join as join14 } from "node:path";
155343
- var orange = chalk26.hex("#f97316");
155807
+ var orange = chalk27.hex("#f97316");
155344
155808
  function riskColor2(level) {
155345
155809
  switch (level.toLowerCase()) {
155346
155810
  case "low":
155347
- return chalk26.green;
155811
+ return chalk27.green;
155348
155812
  case "watch":
155349
- return chalk26.yellow;
155813
+ return chalk27.yellow;
155350
155814
  case "alert":
155351
155815
  return orange;
155352
155816
  case "critical":
155353
- return chalk26.red;
155817
+ return chalk27.red;
155354
155818
  default:
155355
- return chalk26.white;
155819
+ return chalk27.white;
155356
155820
  }
155357
155821
  }
155358
155822
  function confidenceColor(c) {
155359
155823
  if (c >= 0.9)
155360
- return chalk26.green;
155824
+ return chalk27.green;
155361
155825
  if (c >= 0.5)
155362
- return chalk26.yellow;
155363
- return chalk26.red;
155826
+ return chalk27.yellow;
155827
+ return chalk27.red;
155364
155828
  }
155365
155829
  function pad(s, n) {
155366
155830
  return s.padEnd(n).slice(0, n);
@@ -155376,30 +155840,30 @@ function toRawGitHubUrl(url) {
155376
155840
  }
155377
155841
  function displayResults(report) {
155378
155842
  console.log();
155379
- console.log(chalk26.bold(" Investigation Results"));
155843
+ console.log(chalk27.bold(" Investigation Results"));
155380
155844
  console.log();
155381
- console.log(` ${chalk26.bold("Investigation ID:")} ${report.investigation_id}`);
155382
- console.log(` ${chalk26.bold("Skill:")} ${report.skill_name}`);
155383
- console.log(` ${chalk26.bold("Total Licensees:")} ${report.total_licensees}`);
155384
- console.log(` ${chalk26.bold("Timestamp:")} ${new Date(report.created_at).toLocaleString()}`);
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()}`);
155385
155849
  if (report.heartbeat_matches.length > 0) {
155386
155850
  console.log();
155387
155851
  const maxConf = Math.max(...report.heartbeat_matches.map((m) => m.confidence));
155388
155852
  const confStr = (maxConf * 100).toFixed(0) + "%";
155389
155853
  const confFn = confidenceColor(maxConf);
155390
- console.log(` ${chalk26.bold("Forensic Match:")} ${confFn(confStr + " confidence")} (${report.heartbeat_matches.length} match${report.heartbeat_matches.length !== 1 ? "es" : ""})`);
155854
+ console.log(` ${chalk27.bold("Forensic Match:")} ${confFn(confStr + " confidence")} (${report.heartbeat_matches.length} match${report.heartbeat_matches.length !== 1 ? "es" : ""})`);
155391
155855
  }
155392
155856
  console.log();
155393
155857
  if (report.suspects.length === 0) {
155394
- console.log(chalk26.dim(" No suspects identified."));
155858
+ console.log(chalk27.dim(" No suspects identified."));
155395
155859
  console.log();
155396
155860
  return;
155397
155861
  }
155398
- console.log(chalk26.bold(" Suspect Ranking"));
155862
+ console.log(chalk27.bold(" Suspect Ranking"));
155399
155863
  console.log();
155400
155864
  const header = `${pad("Suspect", 24)} ${pad("Risk Level", 12)} ${pad("Confidence", 12)} ${pad("Anomalies", 10)} ${"Strikes"}`;
155401
- console.log(` ${chalk26.dim(header)}`);
155402
- console.log(` ${chalk26.dim("\u2500".repeat(header.length))}`);
155865
+ console.log(` ${chalk27.dim(header)}`);
155866
+ console.log(` ${chalk27.dim("\u2500".repeat(header.length))}`);
155403
155867
  for (const s of report.suspects) {
155404
155868
  const colorFn = riskColor2(s.risk_level);
155405
155869
  const label = s.customer_email || s.licensee_id.slice(0, 22);
@@ -155413,8 +155877,8 @@ function displayResults(report) {
155413
155877
  console.log(` ${row}`);
155414
155878
  }
155415
155879
  console.log();
155416
- console.log(chalk26.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
155417
- console.log(chalk26.dim(" Contact investigations@getskillvault.com for the complete evidence package."));
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."));
155418
155882
  console.log();
155419
155883
  }
155420
155884
  function buildHtmlReport(report, _auditEvents, metadata) {
@@ -155659,7 +156123,7 @@ ${report.suspects.length > 0 ? `<table>
155659
156123
  </body>
155660
156124
  </html>`;
155661
156125
  }
155662
- var investigateCommand = new Command29("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) => {
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) => {
155663
156127
  try {
155664
156128
  const ctx = requireSession();
155665
156129
  let leakedContent;
@@ -155667,12 +156131,12 @@ var investigateCommand = new Command29("investigate").description("Investigate a
155667
156131
  if (options.url) {
155668
156132
  const rawUrl = toRawGitHubUrl(options.url);
155669
156133
  if (rawUrl !== options.url) {
155670
- console.log(chalk26.dim(` Auto-converted GitHub blob URL to raw URL`));
156134
+ console.log(chalk27.dim(` Auto-converted GitHub blob URL to raw URL`));
155671
156135
  }
155672
- console.log(chalk26.dim(` Fetching leaked content from ${rawUrl}...`));
156136
+ console.log(chalk27.dim(` Fetching leaked content from ${rawUrl}...`));
155673
156137
  const resp = await fetch(rawUrl);
155674
156138
  if (!resp.ok) {
155675
- process.stderr.write(chalk26.red(`Failed to fetch URL: ${resp.status} ${resp.statusText}
156139
+ process.stderr.write(chalk27.red(`Failed to fetch URL: ${resp.status} ${resp.statusText}
155676
156140
  `));
155677
156141
  process.exit(1);
155678
156142
  }
@@ -155683,24 +156147,24 @@ var investigateCommand = new Command29("investigate").description("Investigate a
155683
156147
  leakedContent = readFileSync15(options.file, "utf-8");
155684
156148
  } catch (err) {
155685
156149
  const msg = err instanceof Error ? err.message : String(err);
155686
- process.stderr.write(chalk26.red(`Failed to read file: ${msg}
156150
+ process.stderr.write(chalk27.red(`Failed to read file: ${msg}
155687
156151
  `));
155688
156152
  process.exit(1);
155689
156153
  }
155690
156154
  sourceLabel = options.file;
155691
156155
  } else {
155692
- process.stderr.write(chalk26.red("Provide leaked content with --url <url> or --file <path>.\n"));
156156
+ process.stderr.write(chalk27.red("Provide leaked content with --url <url> or --file <path>.\n"));
155693
156157
  process.exit(1);
155694
156158
  }
155695
- console.log(chalk26.dim(` Loaded ${leakedContent.length.toLocaleString()} chars of leaked content`));
156159
+ console.log(chalk27.dim(` Loaded ${leakedContent.length.toLocaleString()} chars of leaked content`));
155696
156160
  const skillsData = await sessionFetch(ctx, "/skills");
155697
156161
  const skill = skillsData.skills.find((s) => s.name.toLowerCase() === skillName.toLowerCase());
155698
156162
  if (!skill) {
155699
- process.stderr.write(chalk26.red(`Skill "${skillName}" not found. Use \`skillvault-publisher list\` to see your skills.
156163
+ process.stderr.write(chalk27.red(`Skill "${skillName}" not found. Use \`skillvault-publisher list\` to see your skills.
155700
156164
  `));
155701
156165
  process.exit(1);
155702
156166
  }
155703
- console.log(chalk26.dim(` Running investigation on "${skill.name}"...`));
156167
+ console.log(chalk27.dim(` Running investigation on "${skill.name}"...`));
155704
156168
  const report = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/investigate`, {
155705
156169
  method: "POST",
155706
156170
  body: { skill_id: skill.id, leaked_content: leakedContent }
@@ -155726,13 +156190,13 @@ var investigateCommand = new Command29("investigate").description("Investigate a
155726
156190
  source: sourceLabel,
155727
156191
  notice: "This is an executive summary. Full evidence is retained server-side. Contact investigations@getskillvault.com for the complete evidence package."
155728
156192
  };
155729
- writeFileSync10(join14(dir, "metadata.json"), JSON.stringify(metadata, null, 2) + "\n");
155730
- writeFileSync10(join14(dir, "summary.json"), JSON.stringify({
156193
+ writeFileSync11(join14(dir, "metadata.json"), JSON.stringify(metadata, null, 2) + "\n");
156194
+ writeFileSync11(join14(dir, "summary.json"), JSON.stringify({
155731
156195
  _generated_by: "SkillVault (https://getskillvault.com)",
155732
156196
  ...report
155733
156197
  }, null, 2) + "\n");
155734
156198
  const html = buildHtmlReport(report, [], metadata);
155735
- writeFileSync10(join14(dir, "report.html"), html);
156199
+ writeFileSync11(join14(dir, "report.html"), html);
155736
156200
  const pdfPath = join14(dir, "report.pdf");
155737
156201
  const { generatePdfReport: generatePdfReport2 } = await Promise.resolve().then(() => (init_pdf_report(), pdf_report_exports));
155738
156202
  await generatePdfReport2({
@@ -155746,23 +156210,23 @@ var investigateCommand = new Command29("investigate").description("Investigate a
155746
156210
  heartbeat_matches: report.heartbeat_matches,
155747
156211
  audit_events: []
155748
156212
  }, pdfPath);
155749
- console.log(chalk26.green(` Report saved to ${dir}/`) + chalk26.dim(" (4 files)"));
155750
- console.log(chalk26.dim(` PDF: report.pdf`));
155751
- console.log(chalk26.dim(` Full evidence retained server-side (ID: ${report.investigation_id})`));
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})`));
155752
156216
  console.log();
155753
156217
  }
155754
156218
  } catch (err) {
155755
156219
  const message = err instanceof Error ? err.message : String(err);
155756
- process.stderr.write(chalk26.red(`Error: ${message}
156220
+ process.stderr.write(chalk27.red(`Error: ${message}
155757
156221
  `));
155758
156222
  process.exit(1);
155759
156223
  }
155760
156224
  });
155761
156225
 
155762
156226
  // dist/commands/watchtower.js
155763
- import { Command as Command30 } from "commander";
155764
- import chalk27 from "chalk";
155765
- var watchtowerCommand = new Command30("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) => {
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) => {
155766
156230
  const ctx = requireCommandContext({ workspaceFlag: options.workspace, quiet: options.quiet });
155767
156231
  try {
155768
156232
  const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/watchtower`);
@@ -155771,37 +156235,37 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
155771
156235
  return;
155772
156236
  }
155773
156237
  const { summary } = data;
155774
- const pad3 = (s, n) => s.padEnd(n).slice(0, n);
156238
+ const pad4 = (s, n) => s.padEnd(n).slice(0, n);
155775
156239
  console.log();
155776
- console.log(chalk27.bold(" Watchtower \u2014 Security Overview"));
156240
+ console.log(chalk28.bold(" Watchtower \u2014 Security Overview"));
155777
156241
  console.log();
155778
- console.log(` ${chalk27.bold("Skills")} ${summary.total_skills} ${chalk27.dim("|")} ${chalk27.bold("Licenses")} ${summary.total_licenses} ${chalk27.dim("|")} ${chalk27.bold("Alerts (7d)")} ${summary.active_alerts > 0 ? chalk27.yellow(String(summary.active_alerts)) : "0"} ${chalk27.dim("|")} ${chalk27.bold("Flagged")} ${summary.flagged_customers > 0 ? chalk27.red(String(summary.flagged_customers)) : "0"} ${chalk27.dim("|")} ${chalk27.bold("Suspended")} ${summary.suspended_grants > 0 ? chalk27.red(String(summary.suspended_grants)) : "0"}`);
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"}`);
155779
156243
  if (data.flagged_customers && data.flagged_customers.length > 0) {
155780
156244
  console.log();
155781
- console.log(chalk27.bold(" Flagged Customers"));
156245
+ console.log(chalk28.bold(" Flagged Customers"));
155782
156246
  console.log();
155783
- const header = `${pad3("Agent ID", 20)} ${pad3("Risk Score", 12)} ${pad3("Level", 10)} ${pad3("Strikes", 9)} ${pad3("Status", 12)} Skills`;
155784
- console.log(` ${chalk27.dim(header)}`);
155785
- console.log(` ${chalk27.dim("\u2500".repeat(header.length))}`);
156247
+ const header = `${pad4("Agent ID", 20)} ${pad4("Risk Score", 12)} ${pad4("Level", 10)} ${pad4("Strikes", 9)} ${pad4("Status", 12)} Skills`;
156248
+ console.log(` ${chalk28.dim(header)}`);
156249
+ console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
155786
156250
  for (const c of data.flagged_customers) {
155787
156251
  const agentShort = c.agent_id.length > 18 ? c.agent_id.slice(0, 18) + "\u2026" : c.agent_id;
155788
156252
  let levelColored;
155789
156253
  if (c.risk_level === "critical") {
155790
- levelColored = chalk27.red.bold(pad3(c.risk_level, 10));
156254
+ levelColored = chalk28.red.bold(pad4(c.risk_level, 10));
155791
156255
  } else if (c.risk_level === "high") {
155792
- levelColored = chalk27.red(pad3(c.risk_level, 10));
156256
+ levelColored = chalk28.red(pad4(c.risk_level, 10));
155793
156257
  } else if (c.risk_level === "medium") {
155794
- levelColored = chalk27.yellow(pad3(c.risk_level, 10));
156258
+ levelColored = chalk28.yellow(pad4(c.risk_level, 10));
155795
156259
  } else {
155796
- levelColored = chalk27.dim(pad3(c.risk_level, 10));
156260
+ levelColored = chalk28.dim(pad4(c.risk_level, 10));
155797
156261
  }
155798
- const statusColored = c.status === "suspended" ? chalk27.red(pad3(c.status, 12)) : pad3(c.status, 12);
155799
- const skills = c.capabilities.length > 0 ? c.capabilities.join(", ") : chalk27.dim("none");
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");
155800
156264
  const row = [
155801
- pad3(agentShort, 20),
155802
- pad3(String(c.risk_score), 12),
156265
+ pad4(agentShort, 20),
156266
+ pad4(String(c.risk_score), 12),
155803
156267
  levelColored,
155804
- pad3(String(c.strike_count), 9),
156268
+ pad4(String(c.strike_count), 9),
155805
156269
  statusColored,
155806
156270
  skills
155807
156271
  ].join(" ");
@@ -155810,20 +156274,20 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
155810
156274
  }
155811
156275
  if (data.recent_events && data.recent_events.length > 0) {
155812
156276
  console.log();
155813
- console.log(chalk27.bold(" Recent Security Events"));
156277
+ console.log(chalk28.bold(" Recent Security Events"));
155814
156278
  console.log();
155815
- const header = `${pad3("Event Type", 28)} ${pad3("Skill", 24)} ${pad3("Agent", 20)} Time`;
155816
- console.log(` ${chalk27.dim(header)}`);
155817
- console.log(` ${chalk27.dim("\u2500".repeat(header.length))}`);
156279
+ const header = `${pad4("Event Type", 28)} ${pad4("Skill", 24)} ${pad4("Agent", 20)} Time`;
156280
+ console.log(` ${chalk28.dim(header)}`);
156281
+ console.log(` ${chalk28.dim("\u2500".repeat(header.length))}`);
155818
156282
  const events = data.recent_events.slice(0, 10);
155819
156283
  for (const e of events) {
155820
- const skill = e.capability ? e.capability.replace(/^skill\//, "") : chalk27.dim("-");
155821
- const agent = e.agent_id ? e.agent_id.slice(0, 18) : chalk27.dim("-");
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("-");
155822
156286
  const time = new Date(e.created_at).toLocaleString();
155823
156287
  const row = [
155824
- pad3(e.event_type, 28),
155825
- pad3(skill, 24),
155826
- pad3(agent, 20),
156288
+ pad4(e.event_type, 28),
156289
+ pad4(skill, 24),
156290
+ pad4(agent, 20),
155827
156291
  time
155828
156292
  ].join(" ");
155829
156293
  console.log(` ${row}`);
@@ -155831,25 +156295,25 @@ var watchtowerCommand = new Command30("watchtower").description("Watchtower secu
155831
156295
  }
155832
156296
  if ((!data.flagged_customers || data.flagged_customers.length === 0) && (!data.recent_events || data.recent_events.length === 0)) {
155833
156297
  console.log();
155834
- console.log(chalk27.green(" All clear \u2014 no security alerts in the last 7 days."));
156298
+ console.log(chalk28.green(" All clear \u2014 no security alerts in the last 7 days."));
155835
156299
  }
155836
156300
  console.log();
155837
156301
  } catch (err) {
155838
156302
  const message = err instanceof Error ? err.message : String(err);
155839
- process.stderr.write(chalk27.red(`Error: ${message}
156303
+ process.stderr.write(chalk28.red(`Error: ${message}
155840
156304
  `));
155841
156305
  process.exit(1);
155842
156306
  }
155843
156307
  });
155844
156308
 
155845
156309
  // dist/commands/watermark-decode.js
155846
- import { Command as Command31 } from "commander";
155847
- import chalk28 from "chalk";
156310
+ import { Command as Command32 } from "commander";
156311
+ import chalk29 from "chalk";
155848
156312
  import { readFileSync as readFileSync16 } from "node:fs";
155849
- var watermarkDecodeCommand = new Command31("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) => {
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) => {
155850
156314
  try {
155851
156315
  if (!options.file) {
155852
- process.stderr.write(chalk28.red("Provide --file <path> with the leaked content\n"));
156316
+ process.stderr.write(chalk29.red("Provide --file <path> with the leaked content\n"));
155853
156317
  process.exit(1);
155854
156318
  }
155855
156319
  let content;
@@ -155857,7 +156321,7 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
155857
156321
  content = readFileSync16(options.file, "utf8");
155858
156322
  } catch (err) {
155859
156323
  const msg = err instanceof Error ? err.message : String(err);
155860
- process.stderr.write(chalk28.red(`Cannot read file: ${msg}
156324
+ process.stderr.write(chalk29.red(`Cannot read file: ${msg}
155861
156325
  `));
155862
156326
  process.exit(1);
155863
156327
  }
@@ -155887,56 +156351,56 @@ var watermarkDecodeCommand = new Command31("watermark-decode").description("Anal
155887
156351
  return;
155888
156352
  }
155889
156353
  console.log();
155890
- console.log(chalk28.bold(" Watermark Analysis"));
156354
+ console.log(chalk29.bold(" Watermark Analysis"));
155891
156355
  console.log();
155892
- console.log(chalk28.bold(" Zero-Width Watermark"));
156356
+ console.log(chalk29.bold(" Zero-Width Watermark"));
155893
156357
  if (watermark.found) {
155894
- console.log(` Licensee ID: ${chalk28.green.bold(watermark.licenseeId)}`);
156358
+ console.log(` Licensee ID: ${chalk29.green.bold(watermark.licenseeId)}`);
155895
156359
  } else {
155896
- console.log(` ${chalk28.dim("Not found")}`);
156360
+ console.log(` ${chalk29.dim("Not found")}`);
155897
156361
  }
155898
156362
  console.log();
155899
- console.log(chalk28.bold(" Heartbeat Markers"));
156363
+ console.log(chalk29.bold(" Heartbeat Markers"));
155900
156364
  if (heartbeats.hb1) {
155901
- console.log(` HB1: ${chalk28.green(heartbeats.hb1)}`);
156365
+ console.log(` HB1: ${chalk29.green(heartbeats.hb1)}`);
155902
156366
  } else {
155903
- console.log(` HB1: ${chalk28.dim("Not found")}`);
156367
+ console.log(` HB1: ${chalk29.dim("Not found")}`);
155904
156368
  }
155905
156369
  if (heartbeats.hb2) {
155906
- console.log(` HB2: ${chalk28.green(heartbeats.hb2)}`);
156370
+ console.log(` HB2: ${chalk29.green(heartbeats.hb2)}`);
155907
156371
  } else {
155908
- console.log(` HB2: ${chalk28.dim("Not found")}`);
156372
+ console.log(` HB2: ${chalk29.dim("Not found")}`);
155909
156373
  }
155910
156374
  if (candidates.length > 0) {
155911
- console.log(` ${chalk28.dim(`${candidates.length} potential heartbeat candidate${candidates.length !== 1 ? "s" : ""} found`)}`);
156375
+ console.log(` ${chalk29.dim(`${candidates.length} potential heartbeat candidate${candidates.length !== 1 ? "s" : ""} found`)}`);
155912
156376
  }
155913
156377
  console.log();
155914
- console.log(chalk28.bold(" Semantic Fingerprint"));
156378
+ console.log(chalk29.bold(" Semantic Fingerprint"));
155915
156379
  if (hasFingerprint) {
155916
156380
  const binaryStr = fingerprint.map((v) => v === 1 ? "1" : v === -1 ? "X" : "0").join("");
155917
156381
  const variationPoints = fingerprint.filter((v) => v !== 0).length;
155918
- console.log(` Pattern: ${chalk28.cyan(binaryStr)}`);
155919
- console.log(` ${chalk28.dim(`${variationPoints} variation point${variationPoints !== 1 ? "s" : ""} detected`)}`);
156382
+ console.log(` Pattern: ${chalk29.cyan(binaryStr)}`);
156383
+ console.log(` ${chalk29.dim(`${variationPoints} variation point${variationPoints !== 1 ? "s" : ""} detected`)}`);
155920
156384
  } else {
155921
- console.log(` ${chalk28.dim("No variation points detected")}`);
156385
+ console.log(` ${chalk29.dim("No variation points detected")}`);
155922
156386
  }
155923
156387
  console.log();
155924
- const countColor = signalsDetected > 0 ? chalk28.green.bold : chalk28.dim;
156388
+ const countColor = signalsDetected > 0 ? chalk29.green.bold : chalk29.dim;
155925
156389
  console.log(` ${countColor(`${signalsDetected} of 4`)} forensic signals detected`);
155926
156390
  console.log();
155927
156391
  } catch (err) {
155928
156392
  const message = err instanceof Error ? err.message : String(err);
155929
- process.stderr.write(chalk28.red(`Error: ${message}
156393
+ process.stderr.write(chalk29.red(`Error: ${message}
155930
156394
  `));
155931
156395
  process.exit(1);
155932
156396
  }
155933
156397
  });
155934
156398
 
155935
156399
  // dist/commands/link.js
155936
- import { Command as Command32 } from "commander";
155937
- import chalk29 from "chalk";
156400
+ import { Command as Command33 } from "commander";
156401
+ import chalk30 from "chalk";
155938
156402
  import { existsSync as existsSync14, readFileSync as readFileSync17, statSync as statSync6 } from "node:fs";
155939
- import { resolve as resolve8, join as join15 } from "node:path";
156403
+ import { resolve as resolve10, join as join15 } from "node:path";
155940
156404
  function parseFrontmatter4(content) {
155941
156405
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
155942
156406
  if (!match)
@@ -155955,12 +156419,12 @@ function parseFrontmatter4(content) {
155955
156419
  }
155956
156420
  return result;
155957
156421
  }
155958
- var linkCommand = new Command32("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) => {
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) => {
155959
156423
  try {
155960
156424
  const ctx = requireSession();
155961
- const dirPath = options.workspace ? resolve8(options.workspace) : directory ? resolve8(directory) : process.cwd();
156425
+ const dirPath = options.workspace ? resolve10(options.workspace) : directory ? resolve10(directory) : process.cwd();
155962
156426
  if (!existsSync14(dirPath) || !statSync6(dirPath).isDirectory()) {
155963
- process.stderr.write(chalk29.red(`Error: "${dirPath}" is not a valid directory
156427
+ process.stderr.write(chalk30.red(`Error: "${dirPath}" is not a valid directory
155964
156428
  `));
155965
156429
  process.exit(1);
155966
156430
  }
@@ -155970,17 +156434,17 @@ var linkCommand = new Command32("link").description("Link a skill source directo
155970
156434
  const existing = loadWorkspace(dirPath);
155971
156435
  const skillName = options.name || existing?.skill_name || frontmatter.name;
155972
156436
  if (!skillName) {
155973
- process.stderr.write(chalk29.red("Error: Cannot determine skill name.\n"));
155974
- process.stderr.write(chalk29.dim(" Pass --name <name> or set `name:` in SKILL.md frontmatter.\n"));
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"));
155975
156439
  process.exit(1);
155976
156440
  }
155977
156441
  const capabilityName = options.capability || existing?.capability_name || `skill/${skillName.toLowerCase()}`;
155978
156442
  if (existing && existing.publisher_id !== ctx.publisherId && !options.force) {
155979
- process.stderr.write(chalk29.red(`Error: This directory is already linked to publisher ${existing.publisher_id}.
156443
+ process.stderr.write(chalk30.red(`Error: This directory is already linked to publisher ${existing.publisher_id}.
155980
156444
  `));
155981
- process.stderr.write(chalk29.dim(` You are logged in as ${ctx.publisherId}.
156445
+ process.stderr.write(chalk30.dim(` You are logged in as ${ctx.publisherId}.
155982
156446
  `));
155983
- process.stderr.write(chalk29.cyan(" Use --force to re-link to your account.\n"));
156447
+ process.stderr.write(chalk30.cyan(" Use --force to re-link to your account.\n"));
155984
156448
  process.exit(1);
155985
156449
  }
155986
156450
  const linkedAt = existing?.linked_at ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -156002,41 +156466,41 @@ var linkCommand = new Command32("link").description("Link a skill source directo
156002
156466
  last_published_at: manifest.last_published_at
156003
156467
  });
156004
156468
  const action = existing ? "Re-linked" : "Linked";
156005
- console.log(chalk29.green(`${action} "${skillName}" \u2192 ${capabilityName}`));
156006
- console.log(chalk29.dim(` Directory: ${dirPath}`));
156007
- console.log(chalk29.dim(` Publisher: ${ctx.publisherId}`));
156008
- console.log(chalk29.dim(` Manifest: .skillvault-publisher/workspace.json`));
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`));
156009
156473
  if (!existing) {
156010
156474
  console.log();
156011
- console.log(chalk29.cyan(" Tip: commit .skillvault-publisher/workspace.json so teammates and CI can find this skill."));
156475
+ console.log(chalk30.cyan(" Tip: commit .skillvault-publisher/workspace.json so teammates and CI can find this skill."));
156012
156476
  }
156013
156477
  } catch (err) {
156014
156478
  const message = err instanceof Error ? err.message : String(err);
156015
- process.stderr.write(chalk29.red(`Link failed: ${message}
156479
+ process.stderr.write(chalk30.red(`Link failed: ${message}
156016
156480
  `));
156017
156481
  process.exit(1);
156018
156482
  }
156019
156483
  });
156020
156484
 
156021
156485
  // dist/commands/unlink.js
156022
- import { Command as Command33 } from "commander";
156023
- import chalk30 from "chalk";
156486
+ import { Command as Command34 } from "commander";
156487
+ import chalk31 from "chalk";
156024
156488
  import { existsSync as existsSync15, rmSync as rmSync2, statSync as statSync7 } from "node:fs";
156025
- import { resolve as resolve9, join as join16 } from "node:path";
156026
- var unlinkCommand = new Command33("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) => {
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) => {
156027
156491
  try {
156028
- const dirPath = options.workspace ? resolve9(options.workspace) : directory ? resolve9(directory) : process.cwd();
156492
+ const dirPath = options.workspace ? resolve11(options.workspace) : directory ? resolve11(directory) : process.cwd();
156029
156493
  if (!existsSync15(dirPath) || !statSync7(dirPath).isDirectory()) {
156030
- process.stderr.write(chalk30.red(`Error: "${dirPath}" is not a valid directory
156494
+ process.stderr.write(chalk31.red(`Error: "${dirPath}" is not a valid directory
156031
156495
  `));
156032
156496
  process.exit(1);
156033
156497
  }
156034
156498
  const manifest = loadWorkspace(dirPath);
156035
156499
  if (!manifest) {
156036
- process.stderr.write(chalk30.red("Error: No workspace manifest found at this directory.\n"));
156037
- process.stderr.write(chalk30.dim(` Looked for: ${join16(dirPath, ".skillvault-publisher", "workspace.json")}
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")}
156038
156502
  `));
156039
- process.stderr.write(chalk30.dim(" Run `skillvault-publisher link` first to create one.\n"));
156503
+ process.stderr.write(chalk31.dim(" Run `skillvault-publisher link` first to create one.\n"));
156040
156504
  process.exit(1);
156041
156505
  }
156042
156506
  const { manifestPath } = workspaceRootsFor(dirPath);
@@ -156044,7 +156508,7 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
156044
156508
  rmSync2(manifestPath);
156045
156509
  } catch (err) {
156046
156510
  const message = err instanceof Error ? err.message : String(err);
156047
- process.stderr.write(chalk30.red(`Failed to remove manifest: ${message}
156511
+ process.stderr.write(chalk31.red(`Failed to remove manifest: ${message}
156048
156512
  `));
156049
156513
  process.exit(1);
156050
156514
  }
@@ -156056,25 +156520,25 @@ var unlinkCommand = new Command33("unlink").description("Remove the workspace li
156056
156520
  if (!options.keepRegistry) {
156057
156521
  unregisterWorkspace(dirPath);
156058
156522
  }
156059
- console.log(chalk30.green(`Unlinked "${manifest.skill_name}" (${manifest.capability_name})`));
156060
- console.log(chalk30.dim(` Directory: ${dirPath}`));
156523
+ console.log(chalk31.green(`Unlinked "${manifest.skill_name}" (${manifest.capability_name})`));
156524
+ console.log(chalk31.dim(` Directory: ${dirPath}`));
156061
156525
  if (options.keepRegistry) {
156062
- console.log(chalk30.dim(" Registry entry kept (--keep-registry)"));
156526
+ console.log(chalk31.dim(" Registry entry kept (--keep-registry)"));
156063
156527
  }
156064
156528
  console.log();
156065
- console.log(chalk30.dim(" Note: SKILL.md and source files are untouched."));
156066
- console.log(chalk30.dim(" Note: The skill on the server is NOT deleted. Use `skill-delete` for that."));
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."));
156067
156531
  } catch (err) {
156068
156532
  const message = err instanceof Error ? err.message : String(err);
156069
- process.stderr.write(chalk30.red(`Unlink failed: ${message}
156533
+ process.stderr.write(chalk31.red(`Unlink failed: ${message}
156070
156534
  `));
156071
156535
  process.exit(1);
156072
156536
  }
156073
156537
  });
156074
156538
 
156075
156539
  // dist/commands/workspaces.js
156076
- import { Command as Command34 } from "commander";
156077
- import chalk31 from "chalk";
156540
+ import { Command as Command35 } from "commander";
156541
+ import chalk32 from "chalk";
156078
156542
  function formatDate(iso) {
156079
156543
  if (!iso)
156080
156544
  return "-";
@@ -156109,8 +156573,8 @@ function listAction(options) {
156109
156573
  return;
156110
156574
  }
156111
156575
  if (filtered.length === 0) {
156112
- console.log(chalk31.dim("No workspaces linked."));
156113
- console.log(chalk31.dim(" Run `skillvault-publisher link` from a skill source directory to create one."));
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."));
156114
156578
  return;
156115
156579
  }
156116
156580
  const pathWidth = Math.min(Math.max(20, ...filtered.map((w) => w.path.length)), 50);
@@ -156118,27 +156582,27 @@ function listAction(options) {
156118
156582
  const pubWidth = Math.max(10, ...filtered.map((w) => w.publisher_id.length));
156119
156583
  console.log();
156120
156584
  const header = `${pad2("PATH", pathWidth)} ${pad2("PUBLISHER", pubWidth)} ${pad2("SKILL", skillWidth)} ${pad2("VERSION", 10)} ${pad2("LAST PUBLISHED", 14)} SOURCE`;
156121
- console.log(` ${chalk31.dim(header)}`);
156122
- console.log(` ${chalk31.dim("\u2500".repeat(header.length))}`);
156585
+ console.log(` ${chalk32.dim(header)}`);
156586
+ console.log(` ${chalk32.dim("\u2500".repeat(header.length))}`);
156123
156587
  for (const w of filtered) {
156124
156588
  const isOther = currentAccount !== null && w.publisher_id !== currentAccount;
156125
156589
  const path = w.path.length > pathWidth ? "\u2026" + w.path.slice(-(pathWidth - 1)) : w.path;
156126
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}`;
156127
156591
  if (isOther) {
156128
- console.log(` ${chalk31.dim(row + " [other account]")}`);
156592
+ console.log(` ${chalk32.dim(row + " [other account]")}`);
156129
156593
  } else {
156130
156594
  console.log(` ${row}`);
156131
156595
  }
156132
156596
  }
156133
156597
  console.log();
156134
- console.log(chalk31.dim(` ${filtered.length} workspace${filtered.length === 1 ? "" : "s"}` + (options.current ? " (filtered to current account)" : "")));
156598
+ console.log(chalk32.dim(` ${filtered.length} workspace${filtered.length === 1 ? "" : "s"}` + (options.current ? " (filtered to current account)" : "")));
156135
156599
  }
156136
- var workspacesCommand = new Command34("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) => {
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) => {
156137
156601
  try {
156138
156602
  listAction(options);
156139
156603
  } catch (err) {
156140
156604
  const message = err instanceof Error ? err.message : String(err);
156141
- process.stderr.write(chalk31.red(`Error: ${message}
156605
+ process.stderr.write(chalk32.red(`Error: ${message}
156142
156606
  `));
156143
156607
  process.exit(1);
156144
156608
  }
@@ -156154,7 +156618,146 @@ workspacesCommand.command("find").description("Print the absolute path of a work
156154
156618
  console.log(match.path);
156155
156619
  } catch (err) {
156156
156620
  const message = err instanceof Error ? err.message : String(err);
156157
- process.stderr.write(chalk31.red(`Error: ${message}
156621
+ process.stderr.write(chalk32.red(`Error: ${message}
156622
+ `));
156623
+ process.exit(1);
156624
+ }
156625
+ });
156626
+
156627
+ // dist/commands/team.js
156628
+ import { Command as Command36 } from "commander";
156629
+ import chalk33 from "chalk";
156630
+ function formatRole(role) {
156631
+ if (role === "owner")
156632
+ return chalk33.green("owner");
156633
+ if (role === "admin")
156634
+ return chalk33.cyan("admin");
156635
+ return chalk33.dim("member");
156636
+ }
156637
+ function formatStatus(status) {
156638
+ if (status === "active")
156639
+ return chalk33.green("active");
156640
+ if (status === "pending")
156641
+ return chalk33.yellow("pending");
156642
+ return chalk33.dim(status);
156643
+ }
156644
+ function pad3(s, n) {
156645
+ const visible = s.replace(/\x1b\[[0-9;]*m/g, "");
156646
+ if (visible.length >= n)
156647
+ return s;
156648
+ return s + " ".repeat(n - visible.length);
156649
+ }
156650
+ var teamCommand = new Command36("team").description("Manage your publisher team members").option("--json", "Output as JSON").action(async (options) => {
156651
+ try {
156652
+ const ctx = requireSession();
156653
+ const data = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team`);
156654
+ const members = data.members || [];
156655
+ if (options.json) {
156656
+ console.log(JSON.stringify(members, null, 2));
156657
+ return;
156658
+ }
156659
+ if (members.length === 0) {
156660
+ 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]"));
156663
+ console.log();
156664
+ return;
156665
+ }
156666
+ console.log();
156667
+ console.log(chalk33.bold(` Team members (${members.length})`));
156668
+ console.log();
156669
+ const header = `${pad3(chalk33.dim("Email"), 36)} ${pad3(chalk33.dim("Role"), 14)} ${pad3(chalk33.dim("Status"), 14)} ${chalk33.dim("Member ID")}`;
156670
+ console.log(` ${header}`);
156671
+ console.log(` ${chalk33.dim("\u2500".repeat(80))}`);
156672
+ for (const m of members) {
156673
+ const row = `${pad3(m.email, 36)} ${pad3(formatRole(m.role), 14)} ${pad3(formatStatus(m.status), 14)} ${chalk33.dim(m.id)}`;
156674
+ console.log(` ${row}`);
156675
+ }
156676
+ console.log();
156677
+ console.log(chalk33.dim(` Logged in as publisher ${ctx.publisherId}`));
156678
+ console.log();
156679
+ } catch (err) {
156680
+ const message = err instanceof Error ? err.message : String(err);
156681
+ process.stderr.write(chalk33.red(`team list failed: ${message}
156682
+ `));
156683
+ process.exit(1);
156684
+ }
156685
+ });
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) => {
156687
+ try {
156688
+ if (!["member", "admin"].includes(options.role)) {
156689
+ process.stderr.write(chalk33.red(`Invalid role "${options.role}". Use --role member or --role admin.
156690
+ `));
156691
+ process.exit(1);
156692
+ }
156693
+ const ctx = requireSession();
156694
+ const member = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team`, {
156695
+ method: "POST",
156696
+ body: { email, role: options.role, name: options.name || null }
156697
+ });
156698
+ if (options.json) {
156699
+ console.log(JSON.stringify(member, null, 2));
156700
+ return;
156701
+ }
156702
+ 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)}`));
156706
+ 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}`));
156710
+ console.log();
156711
+ } catch (err) {
156712
+ const message = err instanceof Error ? err.message : String(err);
156713
+ process.stderr.write(chalk33.red(`team add failed: ${message}
156714
+ `));
156715
+ process.exit(1);
156716
+ }
156717
+ });
156718
+ teamCommand.command("remove").description("Remove a team member by email or member ID").argument("<email-or-id>", "The member email address or member ID (tm_xxx)").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (target, options) => {
156719
+ try {
156720
+ const ctx = requireSession();
156721
+ const listData = await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team`);
156722
+ const members = listData.members || [];
156723
+ const member = members.find((m) => m.id === target || m.email === target);
156724
+ if (!member) {
156725
+ process.stderr.write(chalk33.red(`No team member found matching "${target}".
156726
+ `));
156727
+ process.stderr.write(chalk33.dim("Run `skillvault-publisher team` to see the current list.\n"));
156728
+ process.exit(1);
156729
+ }
156730
+ if (member.role === "owner") {
156731
+ process.stderr.write(chalk33.red("Cannot remove the owner of a publisher account.\n"));
156732
+ process.exit(1);
156733
+ }
156734
+ if (member.status === "removed") {
156735
+ process.stderr.write(chalk33.yellow(`${member.email} is already removed.
156736
+ `));
156737
+ process.exit(0);
156738
+ }
156739
+ if (!options.yes) {
156740
+ console.log();
156741
+ console.log(chalk33.yellow.bold(" Warning: ") + "This will revoke " + chalk33.bold(member.email) + `'s access to publisher ${ctx.publisherId}.`);
156742
+ console.log();
156743
+ console.log(` Email: ${chalk33.cyan(member.email)}`);
156744
+ console.log(` Role: ${formatRole(member.role)}`);
156745
+ console.log(` Status: ${formatStatus(member.status)}`);
156746
+ console.log(` Added: ${chalk33.dim(new Date(member.created_at).toLocaleDateString())}`);
156747
+ console.log();
156748
+ console.log(chalk33.dim(" Add --yes to confirm."));
156749
+ console.log();
156750
+ process.exit(0);
156751
+ }
156752
+ await sessionFetch(ctx, `/publishers/${ctx.publisherId}/team/${member.id}`, { method: "DELETE" });
156753
+ if (options.json) {
156754
+ console.log(JSON.stringify({ removed: true, member_id: member.id, email: member.email }, null, 2));
156755
+ return;
156756
+ }
156757
+ console.log(chalk33.green(` \u2713 Removed ${member.email} from the team`));
156758
+ } catch (err) {
156759
+ const message = err instanceof Error ? err.message : String(err);
156760
+ process.stderr.write(chalk33.red(`team remove failed: ${message}
156158
156761
  `));
156159
156762
  process.exit(1);
156160
156763
  }
@@ -156163,7 +156766,7 @@ workspacesCommand.command("find").description("Print the absolute path of a work
156163
156766
  // dist/index.js
156164
156767
  var __dirname2 = dirname5(fileURLToPath(import.meta.url));
156165
156768
  var pkg = JSON.parse(readFileSync18(join17(__dirname2, "..", "package.json"), "utf8"));
156166
- var program = new Command35();
156769
+ var program = new Command37();
156167
156770
  program.name("skillvault-publisher").description("SkillVault publisher CLI \u2014 publish, manage, and distribute encrypted skills").version(pkg.version).addHelpText("after", `
156168
156771
 
156169
156772
  Getting Started:
@@ -156196,6 +156799,7 @@ program.addCommand(sessionCleanupCommand);
156196
156799
  program.addCommand(skillDeleteCommand);
156197
156800
  program.addCommand(skillStatusCommand);
156198
156801
  program.addCommand(skillUnarchiveCommand);
156802
+ program.addCommand(skillAclCommand);
156199
156803
  program.addCommand(grantsCommand);
156200
156804
  program.addCommand(revokeGrantCommand);
156201
156805
  program.addCommand(customersCommand);
@@ -156208,6 +156812,7 @@ program.addCommand(watermarkDecodeCommand);
156208
156812
  program.addCommand(linkCommand);
156209
156813
  program.addCommand(unlinkCommand);
156210
156814
  program.addCommand(workspacesCommand);
156815
+ program.addCommand(teamCommand);
156211
156816
  program.parse();
156212
156817
  /*! Bundled license information:
156213
156818