@kb-labs/marketplace-registry-entry 2.109.0 → 2.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,6 @@ interface DeprecateFlags {
5
5
  message?: string;
6
6
  json?: boolean;
7
7
  }
8
- declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<DeprecateFlags>, {
9
- exitCode: number;
10
- }>;
8
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<DeprecateFlags>, unknown>;
11
9
 
12
10
  export { _default as default };
@@ -99,11 +99,11 @@ var deprecate_default = defineCommand({
99
99
  const t0 = Date.now();
100
100
  if (!pkg) {
101
101
  validationError(ctx, "Package spec is required", 'Usage: kb marketplace deprecate kb:handle/name [--message "reason"]', flags.json);
102
- return { exitCode: 1 };
102
+ return { ok: false, error: "Package spec is required" };
103
103
  }
104
104
  if (!pkg.startsWith("kb:")) {
105
105
  validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
106
- return { exitCode: 1 };
106
+ return { ok: false, error: "Package must be a kb: spec" };
107
107
  }
108
108
  const sliced = pkg.slice(3);
109
109
  const slashIdx = sliced.indexOf("/");
@@ -111,13 +111,13 @@ var deprecate_default = defineCommand({
111
111
  const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
112
112
  if (!handle || !name) {
113
113
  validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
114
- return { exitCode: 1 };
114
+ return { ok: false, error: "Invalid kb: spec" };
115
115
  }
116
116
  try {
117
117
  await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });
118
118
  if (flags.json) {
119
119
  ctx.ui?.json?.({ deprecated: true, pkg });
120
- return { exitCode: 0 };
120
+ return { ok: true };
121
121
  }
122
122
  const items = [
123
123
  "Hidden from the marketplace catalog",
@@ -132,10 +132,10 @@ var deprecate_default = defineCommand({
132
132
  hint: "To block a specific version only, use kb marketplace yank instead",
133
133
  timing: Date.now() - t0
134
134
  });
135
- return { exitCode: 0 };
135
+ return { ok: true };
136
136
  } catch (err) {
137
137
  handleError(ctx, err, flags.json);
138
- return { exitCode: 1 };
138
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
139
139
  }
140
140
  }
141
141
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/deprecate.ts"],"names":[],"mappings":";;;;;;AAuBA,IAAM,gBAAA,GAAmB,IAAA,CAAK,OAAA,EAAQ,EAAG,OAAO,kBAAkB,CAAA;AAClE,IAAM,uBAAA,GAA0B,kBAAA;AAChC,IAAM,gBAAA,GAAmB,GAAA;AACzB,IAAM,gBAAA,GAAmB,GAAA;AA6BzB,eAAe,WAAA,GAAqC;AAClD,EAAA,MAAM,QAAA,GAAa,OAAO,mBAAmB,CAAA;AAC7C,EAAA,MAAM,SAAA,GAAa,OAAO,iBAAiB,CAAA;AAC3C,EAAA,MAAM,UAAA,GAAa,OAAO,gBAAgB,CAAA;AAC1C,EAAA,MAAM,SAAA,GAAa,OAAO,2BAA2B,CAAA;AAGrD,EAAA,IAAI,YAAY,SAAA,EAAW;AACzB,IAAA,OAAO,EAAE,KAAA,EAAO,QAAA,EAAU,OAAA,EAAS,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,EAAG,MAAA,EAAQ,SAAA,IAAa,EAAA,EAAG;AAAA,EAC3F;AAGA,EAAA,IAAI,YAAY,UAAA,EAAY;AAC1B,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,QAAA;AAAA,MACP,OAAA,EAAS,GAAG,UAAA,CAAW,OAAA,CAAQ,OAAO,EAAE,CAAC,GAAG,uBAAuB,CAAA,CAAA;AAAA,MACnE,QAAQ,SAAA,IAAa;AAAA,KACvB;AAAA,EACF;AAGA,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,KAAK,KAAA,CAAM,MAAM,QAAA,CAAS,gBAAA,EAAkB,OAAO,CAAC,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,YAAY,gBAAA,EAAkB;AACpD,IAAA,MAAM,MAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,UAAU,CAAA,aAAA,CAAA,EAAiB;AAAA,MAC1D,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,YAAA,EAAc,KAAA,CAAM,cAAc;AAAA,KAC1D,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,MAAM,mGAAmG,CAAA;AAAA,IACrH;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,IAAA,EAAK;AACjC,IAAA,KAAA,GAAQ;AAAA,MACN,GAAG,KAAA;AAAA,MACH,aAAa,SAAA,CAAU,WAAA;AAAA,MACvB,cAAc,SAAA,CAAU,YAAA;AAAA,MACxB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,UAAU,SAAA,GAAY;AAAA,KAChD;AACA,IAAA,MAAM,SAAA,CAAU,kBAAkB,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,GAAG,OAAO,CAAA;AACzE,IAAA,MAAM,KAAA,CAAM,kBAAkB,GAAK,CAAA;AAAA,EACrC;AAEA,EAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACjB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAIA,EAAA,MAAM,OAAA,GAAU,SAAA,GACZ,SAAA,CAAU,OAAA,CAAQ,OAAO,EAAE,CAAA,GAC3B,CAAA,EAAG,KAAA,CAAM,WAAW,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,GAAG,uBAAuB,CAAA,CAAA;AAEpE,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,CAAM,aAAa,OAAA,EAAS,MAAA,EAAQ,MAAM,MAAA,EAAO;AACnE;AAWA,eAAsB,YAAA,CACpB,IAAA,EACA,IAAA,EACA,KAAA,EACY;AACZ,EAAA,MAAM,IAAA,GAEF,MAAM,WAAA,EAAY;AAEtB,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,OAAO,GAAG,IAAI,CAAA,CAAA;AAClC,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,gBAAgB,CAAA;AACnE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAC3B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,eAAe,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAA,EAAG;AAAA,MACrF,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAAA,MACzB,QAAQ,UAAA,CAAW;AAAA,KACpB,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,MAAM,IAAI,MAAM,CAAA,SAAA,EAAY,IAAI,YAAY,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,CAAA;AAAA,IACpE;AACA,IAAA,IAAI,GAAA,CAAI,WAAW,GAAA,EAAK;AAAE,MAAA,OAAO,KAAA,CAAA;AAAA,IAAgB;AACjD,IAAA,OAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EACxB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAAc,SAAS,YAAA,EAAc;AACxC,MAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,IACzE;AACA,IAAA,MAAM,GAAA;AAAA,EACR,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB;AACF;;;AC3JA,IAAO,oBAAQ,aAAA,CAAuE;AAAA,EACpF,EAAA,EAAI,uBAAA;AAAA,EACJ,WAAA,EAAa,mEAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAgE;AAClG,MAAA,MAAM,EAAE,KAAA,GAAQ,IAAI,IAAA,GAAO,IAAG,GAAI,KAAA;AAClC,MAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAClB,MAAA,MAAM,EAAA,GAAK,KAAK,GAAA,EAAI;AAEpB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,eAAA,CAAgB,GAAA,EAAK,0BAAA,EAA4B,qEAAA,EAAuE,KAAA,CAAM,IAAI,CAAA;AAClI,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,IAAI,CAAC,GAAA,CAAI,UAAA,CAAW,KAAK,CAAA,EAAG;AAC1B,QAAA,eAAA,CAAgB,GAAA,EAAK,4BAAA,EAA8B,8BAAA,EAAgC,KAAA,CAAM,IAAI,CAAA;AAC7F,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,MAAA,GAAS,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA;AAC1B,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AACnC,MAAA,MAAM,SAAS,QAAA,GAAW,CAAA,GAAI,OAAO,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,GAAI,EAAA;AAC1D,MAAA,MAAM,OAAO,QAAA,GAAW,CAAA,GAAI,OAAO,KAAA,CAAM,QAAA,GAAW,CAAC,CAAA,GAAI,EAAA;AACzD,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,IAAA,EAAM;AACpB,QAAA,eAAA,CAAgB,GAAA,EAAK,iDAAA,EAA8C,MAAA,EAAW,KAAA,CAAM,IAAI,CAAA;AACxF,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,CAAa,CAAA,UAAA,EAAa,MAAM,CAAA,CAAA,EAAI,kBAAA,CAAmB,IAAI,CAAC,CAAA,UAAA,CAAA,EAAc,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAS,CAAA;AAE1G,QAAA,IAAI,MAAM,IAAA,EAAM;AACd,UAAA,GAAA,CAAI,IAAI,IAAA,GAAO,EAAE,UAAA,EAAY,IAAA,EAAM,KAAK,CAAA;AACxC,UAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,QACvB;AAEA,QAAA,MAAM,KAAA,GAAQ;AAAA,UACZ,qCAAA;AAAA,UACA,kEAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,IAAI,MAAM,OAAA,EAAS;AACjB,UAAA,KAAA,CAAM,IAAA,CAAK,CAAA,SAAA,EAAY,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,QACxC;AAEA,QAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,WAAA,CAAA,EAAe;AAAA,UACrC,UAAU,CAAC,EAAE,MAAA,EAAQ,iBAAA,EAAmB,OAAO,CAAA;AAAA,UAC/C,IAAA,EAAM,mEAAA;AAAA,UACN,MAAA,EAAQ,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,SACtB,CAAA;AAED,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB,SAAS,GAAA,EAAK;AACZ,QAAA,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA;AAChC,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAAA,IACF;AAAA;AAEJ,CAAC","file":"deprecate.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface DeprecateFlags {\n message?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<DeprecateFlags>, { exitCode: number }>({\n id: 'marketplace:deprecate',\n description: 'Deprecate a package (removed from catalog, install shows warning)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<DeprecateFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace deprecate kb:handle/name [--message \"reason\"]', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });\n\n if (flags.json) {\n ctx.ui?.json?.({ deprecated: true, pkg });\n return { exitCode: 0 };\n }\n\n const items = [\n 'Hidden from the marketplace catalog',\n 'Existing installations still work but show a deprecation warning',\n 'New installs are allowed but show a warning',\n ];\n if (flags.message) {\n items.push(`Message: ${flags.message}`);\n }\n\n ctx.ui?.success?.(`${pkg} deprecated`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To block a specific version only, use kb marketplace yank instead',\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/deprecate.ts"],"names":[],"mappings":"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","file":"deprecate.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface DeprecateFlags {\n message?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<DeprecateFlags>, unknown>({\n id: 'marketplace:deprecate',\n description: 'Deprecate a package (removed from catalog, install shows warning)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<DeprecateFlags>): Promise<CommandResult> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace deprecate kb:handle/name [--message \"reason\"]', flags.json);\n return { ok: false, error: 'Package spec is required' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });\n\n if (flags.json) {\n ctx.ui?.json?.({ deprecated: true, pkg });\n return { ok: true };\n }\n\n const items = [\n 'Hidden from the marketplace catalog',\n 'Existing installations still work but show a deprecation warning',\n 'New installs are allowed but show a warning',\n ];\n if (flags.message) {\n items.push(`Message: ${flags.message}`);\n }\n\n ctx.ui?.success?.(`${pkg} deprecated`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To block a specific version only, use kb marketplace yank instead',\n timing: Date.now() - t0,\n });\n\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
@@ -7,8 +7,15 @@ interface PublishFlags {
7
7
  metaOnly?: boolean;
8
8
  json?: boolean;
9
9
  }
10
- declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<PublishFlags>, {
11
- exitCode: number;
12
- }>;
10
+ interface PublishResultData {
11
+ handle: string;
12
+ name: string;
13
+ version: string;
14
+ visibility: string;
15
+ trust: string;
16
+ installCommand: string;
17
+ pageUrl?: string;
18
+ }
19
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<PublishFlags>, PublishResultData>;
13
20
 
14
21
  export { _default as default };
@@ -151,11 +151,11 @@ var publish_default = defineCommand({
151
151
  pkgJson = JSON.parse(content);
152
152
  } catch {
153
153
  validationError(ctx, "Cannot read package.json in current directory", "Run this command from the plugin root directory", flags.json);
154
- return { exitCode: 1 };
154
+ return { ok: false, error: "Cannot read package.json" };
155
155
  }
156
156
  if (!pkgJson.name || !pkgJson.version) {
157
157
  validationError(ctx, "package.json must have name and version fields", void 0, flags.json);
158
- return { exitCode: 1 };
158
+ return { ok: false, error: "package.json must have name and version fields" };
159
159
  }
160
160
  const kb = pkgJson["kb"];
161
161
  if (!kb?.manifest && !kb?.adapter) {
@@ -165,7 +165,7 @@ var publish_default = defineCommand({
165
165
  "Add a kb.manifest or kb.adapter field to package.json",
166
166
  flags.json
167
167
  );
168
- return { exitCode: 1 };
168
+ return { ok: false, error: "Not a KB Labs plugin or adapter" };
169
169
  }
170
170
  let readme;
171
171
  for (const candidate of ["README.md", "README.mdx", "readme.md", "Readme.md"]) {
@@ -197,10 +197,10 @@ var publish_default = defineCommand({
197
197
  sections: [{ header: "Package", items: [`${meta.name} @ ${handle}`] }],
198
198
  timing: Date.now() - t0
199
199
  });
200
- return { exitCode: 0 };
200
+ return { ok: true };
201
201
  } catch (err) {
202
202
  handleError(ctx, err, flags.json);
203
- return { exitCode: 1 };
203
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
204
204
  }
205
205
  }
206
206
  const primaryKind = kb?.adapter ? "adapter" : "plugin";
@@ -212,7 +212,7 @@ var publish_default = defineCommand({
212
212
  packMs = Date.now() - t1;
213
213
  } catch (err) {
214
214
  handleError(ctx, err, flags.json);
215
- return { exitCode: 1 };
215
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
216
216
  }
217
217
  try {
218
218
  const result = await registryPostMultipart(
@@ -222,7 +222,7 @@ var publish_default = defineCommand({
222
222
  );
223
223
  if (flags.json) {
224
224
  ctx.ui?.json?.(result);
225
- return { exitCode: 0 };
225
+ return { ok: true, result };
226
226
  }
227
227
  ctx.ui?.chain?.([
228
228
  {
@@ -241,11 +241,11 @@ var publish_default = defineCommand({
241
241
  timing: Date.now() - t0
242
242
  }
243
243
  ]);
244
- return { exitCode: 0 };
244
+ return { ok: true, result };
245
245
  } catch (err) {
246
246
  if (flags.json) {
247
247
  handleError(ctx, err, true);
248
- return { exitCode: 1 };
248
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
249
249
  }
250
250
  const message = err instanceof Error ? err.message : String(err);
251
251
  ctx.ui?.chain?.([
@@ -257,7 +257,7 @@ var publish_default = defineCommand({
257
257
  timing: Date.now() - t0
258
258
  }
259
259
  ]);
260
- return { exitCode: 1 };
260
+ return { ok: false, error: message };
261
261
  }
262
262
  }
263
263
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/registry-http.ts","../../src/pack-plugin.ts","../../src/commands/publish.ts"],"names":["path","fs2"],"mappings":"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","file":"publish.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport { execa } from 'execa';\n\n/** Runs `pnpm pack` in the given directory and returns the tarball buffer. */\nexport async function packPlugin(dir: string): Promise<Buffer> {\n const { stdout } = await execa('pnpm', ['pack', '--pack-destination', '/tmp'], { cwd: dir });\n const tarballPath = stdout.trim().split('\\n').at(-1)!.trim();\n const tarball = await fs.readFile(tarballPath);\n await fs.unlink(tarballPath).catch(() => { /* ignore cleanup failure */ });\n return tarball;\n}\n","import * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPostMultipart, registryPatch, resolveRegistryHandle } from '../registry-http.js';\nimport { packPlugin } from '../pack-plugin.js';\n\ninterface PublishFlags {\n private?: boolean;\n path?: string;\n metaOnly?: boolean;\n json?: boolean;\n}\n\ninterface PublishResultData {\n handle: string;\n name: string;\n version: string;\n visibility: string;\n trust: string;\n installCommand: string;\n pageUrl?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<PublishFlags>, { exitCode: number }>({\n id: 'marketplace:publish',\n description: 'Publish plugin to KB Labs Registry',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<PublishFlags>): Promise<{ exitCode: number }> {\n const { flags = {} } = input;\n const pluginDir = path.resolve(ctx.cwd, flags.path ?? '.');\n const visibility = flags.private ? 'private' : 'public';\n const t0 = Date.now();\n\n let pkgJson: Record<string, unknown>;\n try {\n const content = await fs.readFile(path.join(pluginDir, 'package.json'), 'utf-8');\n pkgJson = JSON.parse(content) as Record<string, unknown>;\n } catch {\n validationError(ctx, 'Cannot read package.json in current directory', 'Run this command from the plugin root directory', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkgJson.name || !pkgJson.version) {\n validationError(ctx, 'package.json must have name and version fields', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n const kb = pkgJson['kb'] as Record<string, unknown> | undefined;\n if (!kb?.manifest && !kb?.adapter) {\n validationError(\n ctx,\n 'Not a KB Labs plugin or adapter',\n 'Add a kb.manifest or kb.adapter field to package.json',\n flags.json,\n );\n return { exitCode: 1 };\n }\n\n // Read README (non-fatal)\n let readme: string | undefined;\n for (const candidate of ['README.md', 'README.mdx', 'readme.md', 'Readme.md']) {\n readme = await fs.readFile(path.join(pluginDir, candidate), 'utf-8').catch(() => undefined);\n if (readme) break;\n }\n\n // Extract manifest fields for the detail page\n const manifest = (kb?.manifest ?? {}) as Record<string, unknown>;\n const manifestCommands = Array.isArray(manifest['commands'])\n ? (manifest['commands'] as Array<{ id?: string; name?: string }>).map(c => c.id ?? c.name ?? '').filter(Boolean)\n : undefined;\n\n const meta = {\n name: pkgJson.name as string,\n version: pkgJson.version as string,\n description: pkgJson.description as string | undefined,\n author: pkgJson.author as unknown,\n repository: pkgJson.repository as unknown,\n keywords: pkgJson.keywords as string[] | undefined,\n license: pkgJson.license as string | undefined,\n homepage: pkgJson.homepage as string | undefined,\n readme,\n permissions: manifest['permissions'] as string[] | undefined,\n envVars: manifest['envVars'] as string[] | undefined,\n allowedHosts: manifest['allowedHosts'] as string[] | undefined,\n commands: manifestCommands,\n };\n\n if (flags.metaOnly) {\n try {\n const handle = await resolveRegistryHandle();\n await registryPatch(`/packages/${handle}/${meta.name}/meta`, meta);\n ctx.ui?.success?.('Metadata updated', {\n sections: [{ header: 'Package', items: [`${meta.name} @ ${handle}`] }],\n timing: Date.now() - t0,\n });\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n }\n\n const primaryKind = kb?.adapter ? 'adapter' : 'plugin';\n\n const t1 = Date.now();\n let tarball: Buffer;\n let packMs: number;\n try {\n tarball = await packPlugin(pluginDir);\n packMs = Date.now() - t1;\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n const result = await registryPostMultipart<PublishResultData>(\n '/packages/publish',\n tarball,\n { meta: JSON.stringify({ meta, visibility, primaryKind }) },\n );\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { exitCode: 0 };\n }\n\n ctx.ui?.chain?.([\n {\n title: `Packed ${meta.name}@${meta.version}`,\n timing: packMs,\n },\n {\n title: `${result.name}@${result.version} published`,\n status: 'success',\n summary: {\n 'Visibility': result.visibility,\n 'Trust': result.trust === 'trusted' ? 'KB Labs Platform ✓' : 'community',\n ...(result.pageUrl ? { 'Page': result.pageUrl } : {}),\n },\n sections: [{ header: 'Install', items: [{ text: result.installCommand, truncate: 500 }] }],\n timing: Date.now() - t0,\n },\n ]);\n\n return { exitCode: 0 };\n } catch (err) {\n if (flags.json) {\n handleError(ctx, err, true);\n return { exitCode: 1 };\n }\n const message = err instanceof Error ? err.message : String(err);\n ctx.ui?.chain?.([\n { title: `Packed ${meta.name}@${meta.version}`, timing: packMs },\n {\n title: 'Publish failed',\n status: 'error',\n sections: [{ items: [message] }],\n timing: Date.now() - t0,\n },\n ]);\n return { exitCode: 1 };\n }\n },\n },\n});\n\n"]}
1
+ {"version":3,"sources":["../../src/registry-http.ts","../../src/pack-plugin.ts","../../src/commands/publish.ts"],"names":["path","fs2"],"mappings":"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","file":"publish.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport { execa } from 'execa';\n\n/** Runs `pnpm pack` in the given directory and returns the tarball buffer. */\nexport async function packPlugin(dir: string): Promise<Buffer> {\n const { stdout } = await execa('pnpm', ['pack', '--pack-destination', '/tmp'], { cwd: dir });\n const tarballPath = stdout.trim().split('\\n').at(-1)!.trim();\n const tarball = await fs.readFile(tarballPath);\n await fs.unlink(tarballPath).catch(() => { /* ignore cleanup failure */ });\n return tarball;\n}\n","import * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPostMultipart, registryPatch, resolveRegistryHandle } from '../registry-http.js';\nimport { packPlugin } from '../pack-plugin.js';\n\ninterface PublishFlags {\n private?: boolean;\n path?: string;\n metaOnly?: boolean;\n json?: boolean;\n}\n\ninterface PublishResultData {\n handle: string;\n name: string;\n version: string;\n visibility: string;\n trust: string;\n installCommand: string;\n pageUrl?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<PublishFlags>, PublishResultData>({\n id: 'marketplace:publish',\n description: 'Publish plugin to KB Labs Registry',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<PublishFlags>): Promise<CommandResult<PublishResultData>> {\n const { flags = {} } = input;\n const pluginDir = path.resolve(ctx.cwd, flags.path ?? '.');\n const visibility = flags.private ? 'private' : 'public';\n const t0 = Date.now();\n\n let pkgJson: Record<string, unknown>;\n try {\n const content = await fs.readFile(path.join(pluginDir, 'package.json'), 'utf-8');\n pkgJson = JSON.parse(content) as Record<string, unknown>;\n } catch {\n validationError(ctx, 'Cannot read package.json in current directory', 'Run this command from the plugin root directory', flags.json);\n return { ok: false, error: 'Cannot read package.json' };\n }\n\n if (!pkgJson.name || !pkgJson.version) {\n validationError(ctx, 'package.json must have name and version fields', undefined, flags.json);\n return { ok: false, error: 'package.json must have name and version fields' };\n }\n\n const kb = pkgJson['kb'] as Record<string, unknown> | undefined;\n if (!kb?.manifest && !kb?.adapter) {\n validationError(\n ctx,\n 'Not a KB Labs plugin or adapter',\n 'Add a kb.manifest or kb.adapter field to package.json',\n flags.json,\n );\n return { ok: false, error: 'Not a KB Labs plugin or adapter' };\n }\n\n // Read README (non-fatal)\n let readme: string | undefined;\n for (const candidate of ['README.md', 'README.mdx', 'readme.md', 'Readme.md']) {\n readme = await fs.readFile(path.join(pluginDir, candidate), 'utf-8').catch(() => undefined);\n if (readme) break;\n }\n\n // Extract manifest fields for the detail page\n const manifest = (kb?.manifest ?? {}) as Record<string, unknown>;\n const manifestCommands = Array.isArray(manifest['commands'])\n ? (manifest['commands'] as Array<{ id?: string; name?: string }>).map(c => c.id ?? c.name ?? '').filter(Boolean)\n : undefined;\n\n const meta = {\n name: pkgJson.name as string,\n version: pkgJson.version as string,\n description: pkgJson.description as string | undefined,\n author: pkgJson.author as unknown,\n repository: pkgJson.repository as unknown,\n keywords: pkgJson.keywords as string[] | undefined,\n license: pkgJson.license as string | undefined,\n homepage: pkgJson.homepage as string | undefined,\n readme,\n permissions: manifest['permissions'] as string[] | undefined,\n envVars: manifest['envVars'] as string[] | undefined,\n allowedHosts: manifest['allowedHosts'] as string[] | undefined,\n commands: manifestCommands,\n };\n\n if (flags.metaOnly) {\n try {\n const handle = await resolveRegistryHandle();\n await registryPatch(`/packages/${handle}/${meta.name}/meta`, meta);\n ctx.ui?.success?.('Metadata updated', {\n sections: [{ header: 'Package', items: [`${meta.name} @ ${handle}`] }],\n timing: Date.now() - t0,\n });\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n }\n\n const primaryKind = kb?.adapter ? 'adapter' : 'plugin';\n\n const t1 = Date.now();\n let tarball: Buffer;\n let packMs: number;\n try {\n tarball = await packPlugin(pluginDir);\n packMs = Date.now() - t1;\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n try {\n const result = await registryPostMultipart<PublishResultData>(\n '/packages/publish',\n tarball,\n { meta: JSON.stringify({ meta, visibility, primaryKind }) },\n );\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { ok: true, result };\n }\n\n ctx.ui?.chain?.([\n {\n title: `Packed ${meta.name}@${meta.version}`,\n timing: packMs,\n },\n {\n title: `${result.name}@${result.version} published`,\n status: 'success',\n summary: {\n 'Visibility': result.visibility,\n 'Trust': result.trust === 'trusted' ? 'KB Labs Platform ✓' : 'community',\n ...(result.pageUrl ? { 'Page': result.pageUrl } : {}),\n },\n sections: [{ header: 'Install', items: [{ text: result.installCommand, truncate: 500 }] }],\n timing: Date.now() - t0,\n },\n ]);\n\n return { ok: true, result };\n } catch (err) {\n if (flags.json) {\n handleError(ctx, err, true);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n const message = err instanceof Error ? err.message : String(err);\n ctx.ui?.chain?.([\n { title: `Packed ${meta.name}@${meta.version}`, timing: packMs },\n {\n title: 'Publish failed',\n status: 'error',\n sections: [{ items: [message] }],\n timing: Date.now() - t0,\n },\n ]);\n return { ok: false, error: message };\n }\n },\n },\n});\n"]}
@@ -7,8 +7,11 @@ interface ShareFlags {
7
7
  ttl?: string;
8
8
  json?: boolean;
9
9
  }
10
- declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ShareFlags>, {
11
- exitCode: number;
12
- }>;
10
+ interface ShareTokenResult {
11
+ token?: string;
12
+ pkg?: string;
13
+ expiresAt?: string;
14
+ }
15
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ShareFlags>, ShareTokenResult>;
13
16
 
14
17
  export { _default as default };
@@ -99,15 +99,15 @@ var share_default = defineCommand({
99
99
  const t0 = Date.now();
100
100
  if (!pkg) {
101
101
  validationError(ctx, "Package spec is required", "Usage: kb marketplace share kb:handle/name [--with handle | --link]", flags.json);
102
- return { exitCode: 1 };
102
+ return { ok: false, error: "Package spec is required" };
103
103
  }
104
104
  if (!flags.with && !flags.link) {
105
105
  validationError(ctx, "Specify --with <handle> to grant access, or --link to generate a share token", void 0, flags.json);
106
- return { exitCode: 1 };
106
+ return { ok: false, error: "Specify --with or --link" };
107
107
  }
108
108
  if (!pkg.startsWith("kb:")) {
109
109
  validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
110
- return { exitCode: 1 };
110
+ return { ok: false, error: "Package must be a kb: spec" };
111
111
  }
112
112
  const sliced = pkg.slice(3);
113
113
  const slashIdx = sliced.indexOf("/");
@@ -115,14 +115,14 @@ var share_default = defineCommand({
115
115
  const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
116
116
  if (!handle || !name) {
117
117
  validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
118
- return { exitCode: 1 };
118
+ return { ok: false, error: "Invalid kb: spec" };
119
119
  }
120
120
  try {
121
121
  if (flags.with) {
122
122
  await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });
123
123
  if (flags.json) {
124
124
  ctx.ui?.json?.({ added: flags.with, pkg });
125
- return { exitCode: 0 };
125
+ return { ok: true };
126
126
  }
127
127
  ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {
128
128
  sections: [
@@ -134,13 +134,13 @@ var share_default = defineCommand({
134
134
  hint: "For one-time access without an account, use --link instead",
135
135
  timing: Date.now() - t0
136
136
  });
137
- return { exitCode: 0 };
137
+ return { ok: true };
138
138
  }
139
139
  const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;
140
140
  const result = await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });
141
141
  if (flags.json) {
142
142
  ctx.ui?.json?.(result);
143
- return { exitCode: 0 };
143
+ return { ok: true, result };
144
144
  }
145
145
  const expiry = result.expiresAt ? new Date(result.expiresAt).toLocaleDateString() : `${ttlDays} days`;
146
146
  ctx.ui?.success?.("Share link created", {
@@ -155,10 +155,10 @@ var share_default = defineCommand({
155
155
  }],
156
156
  timing: Date.now() - t0
157
157
  });
158
- return { exitCode: 0 };
158
+ return { ok: true, result };
159
159
  } catch (err) {
160
160
  handleError(ctx, err, flags.json);
161
- return { exitCode: 1 };
161
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
162
162
  }
163
163
  }
164
164
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/share.ts"],"names":[],"mappings":"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","file":"share.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface ShareFlags {\n with?: string;\n link?: boolean;\n ttl?: string;\n json?: boolean;\n}\n\ninterface ShareTokenResult {\n token?: string;\n pkg?: string;\n expiresAt?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<ShareFlags>, { exitCode: number }>({\n id: 'marketplace:share',\n description: 'Share a private plugin (--with or --link)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ShareFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace share kb:handle/name [--with handle | --link]', flags.json);\n return { exitCode: 1 };\n }\n\n if (!flags.with && !flags.link) {\n validationError(ctx, 'Specify --with <handle> to grant access, or --link to generate a share token', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n if (flags.with) {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });\n\n if (flags.json) {\n ctx.ui?.json?.({ added: flags.with, pkg });\n return { exitCode: 0 };\n }\n\n ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {\n sections: [\n {\n header: 'Install command for them',\n items: [{ text: `kb marketplace install ${pkg}`, truncate: 500 }],\n },\n ],\n hint: 'For one-time access without an account, use --link instead',\n timing: Date.now() - t0,\n });\n return { exitCode: 0 };\n }\n\n const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;\n const result = await registryPost<ShareTokenResult>(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { exitCode: 0 };\n }\n\n const expiry = result.expiresAt\n ? new Date(result.expiresAt).toLocaleDateString()\n : `${ttlDays} days`;\n\n ctx.ui?.success?.('Share link created', {\n summary: {\n 'Token': result.token ?? '–',\n 'Expires': expiry,\n 'Package': pkg,\n },\n sections: [{\n header: 'Send this command to share',\n items: [{ text: `kb marketplace install ${pkg} --token ${result.token}`, truncate: 500 }],\n }],\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/share.ts"],"names":[],"mappings":"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","file":"share.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface ShareFlags {\n with?: string;\n link?: boolean;\n ttl?: string;\n json?: boolean;\n}\n\ninterface ShareTokenResult {\n token?: string;\n pkg?: string;\n expiresAt?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<ShareFlags>, ShareTokenResult>({\n id: 'marketplace:share',\n description: 'Share a private plugin (--with or --link)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ShareFlags>): Promise<CommandResult<ShareTokenResult>> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace share kb:handle/name [--with handle | --link]', flags.json);\n return { ok: false, error: 'Package spec is required' };\n }\n\n if (!flags.with && !flags.link) {\n validationError(ctx, 'Specify --with <handle> to grant access, or --link to generate a share token', undefined, flags.json);\n return { ok: false, error: 'Specify --with or --link' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n if (flags.with) {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });\n\n if (flags.json) {\n ctx.ui?.json?.({ added: flags.with, pkg });\n return { ok: true };\n }\n\n ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {\n sections: [\n {\n header: 'Install command for them',\n items: [{ text: `kb marketplace install ${pkg}`, truncate: 500 }],\n },\n ],\n hint: 'For one-time access without an account, use --link instead',\n timing: Date.now() - t0,\n });\n return { ok: true };\n }\n\n const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;\n const result = await registryPost<ShareTokenResult>(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { ok: true, result };\n }\n\n const expiry = result.expiresAt\n ? new Date(result.expiresAt).toLocaleDateString()\n : `${ttlDays} days`;\n\n ctx.ui?.success?.('Share link created', {\n summary: {\n 'Token': result.token ?? '–',\n 'Expires': expiry,\n 'Package': pkg,\n },\n sections: [{\n header: 'Send this command to share',\n items: [{ text: `kb marketplace install ${pkg} --token ${result.token}`, truncate: 500 }],\n }],\n timing: Date.now() - t0,\n });\n\n return { ok: true, result };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
@@ -5,8 +5,6 @@ interface YankFlags {
5
5
  reason?: string;
6
6
  json?: boolean;
7
7
  }
8
- declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<YankFlags>, {
9
- exitCode: number;
10
- }>;
8
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<YankFlags>, unknown>;
11
9
 
12
10
  export { _default as default };
@@ -99,11 +99,11 @@ var yank_default = defineCommand({
99
99
  const t0 = Date.now();
100
100
  if (!pkg || !version) {
101
101
  validationError(ctx, "Package spec and version are required", "Usage: kb marketplace yank kb:handle/name <version>", flags.json);
102
- return { exitCode: 1 };
102
+ return { ok: false, error: "Package spec and version are required" };
103
103
  }
104
104
  if (!pkg.startsWith("kb:")) {
105
105
  validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
106
- return { exitCode: 1 };
106
+ return { ok: false, error: "Package must be a kb: spec" };
107
107
  }
108
108
  const sliced = pkg.slice(3);
109
109
  const slashIdx = sliced.indexOf("/");
@@ -111,13 +111,13 @@ var yank_default = defineCommand({
111
111
  const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
112
112
  if (!handle || !name) {
113
113
  validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
114
- return { exitCode: 1 };
114
+ return { ok: false, error: "Invalid kb: spec" };
115
115
  }
116
116
  try {
117
117
  await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });
118
118
  if (flags.json) {
119
119
  ctx.ui?.json?.({ yanked: true, pkg, version });
120
- return { exitCode: 0 };
120
+ return { ok: true };
121
121
  }
122
122
  const items = [
123
123
  "Fresh installs of this version are blocked",
@@ -131,10 +131,10 @@ var yank_default = defineCommand({
131
131
  hint: "To yank all versions, deprecate the package instead",
132
132
  timing: Date.now() - t0
133
133
  });
134
- return { exitCode: 0 };
134
+ return { ok: true };
135
135
  } catch (err) {
136
136
  handleError(ctx, err, flags.json);
137
- return { exitCode: 1 };
137
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
138
138
  }
139
139
  }
140
140
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/yank.ts"],"names":[],"mappings":"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","file":"yank.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface YankFlags {\n reason?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<YankFlags>, { exitCode: number }>({\n id: 'marketplace:yank',\n description: 'Yank a specific version (soft-remove — tarball stays, fresh installs blocked)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<YankFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const [pkg, version] = argv;\n const t0 = Date.now();\n\n if (!pkg || !version) {\n validationError(ctx, 'Package spec and version are required', 'Usage: kb marketplace yank kb:handle/name <version>', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });\n\n if (flags.json) {\n ctx.ui?.json?.({ yanked: true, pkg, version });\n return { exitCode: 0 };\n }\n\n const items = [\n 'Fresh installs of this version are blocked',\n 'Existing installations continue to work',\n ];\n if (flags.reason) {\n items.push(`Reason: ${flags.reason}`);\n }\n\n ctx.ui?.success?.(`${pkg}@${version} yanked`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To yank all versions, deprecate the package instead',\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/registry-http.ts","../../src/commands/yank.ts"],"names":[],"mappings":"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","file":"yank.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface YankFlags {\n reason?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<YankFlags>, unknown>({\n id: 'marketplace:yank',\n description: 'Yank a specific version (soft-remove — tarball stays, fresh installs blocked)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<YankFlags>): Promise<CommandResult> {\n const { flags = {}, argv = [] } = input;\n const [pkg, version] = argv;\n const t0 = Date.now();\n\n if (!pkg || !version) {\n validationError(ctx, 'Package spec and version are required', 'Usage: kb marketplace yank kb:handle/name <version>', flags.json);\n return { ok: false, error: 'Package spec and version are required' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });\n\n if (flags.json) {\n ctx.ui?.json?.({ yanked: true, pkg, version });\n return { ok: true };\n }\n\n const items = [\n 'Fresh installs of this version are blocked',\n 'Existing installations continue to work',\n ];\n if (flags.reason) {\n items.push(`Reason: ${flags.reason}`);\n }\n\n ctx.ui?.success?.(`${pkg}@${version} yanked`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To yank all versions, deprecate the package instead',\n timing: Date.now() - t0,\n });\n\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/marketplace-registry-entry",
3
3
  "description": "CLI commands for publishing and managing plugins in KB Labs Registry",
4
- "version": "2.109.0",
4
+ "version": "2.111.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",