@mrciphersmith/keryx 0.2.100 → 0.2.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +191 -93
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -298,6 +298,91 @@ var init_provider_config = __esm(() => {
298
298
  ];
299
299
  });
300
300
 
301
+ // src/lib/oauth/catalog.ts
302
+ function extraRequestHeaders(provider) {
303
+ if (provider === "github-copilot") {
304
+ return GITHUB_COPILOT_REQUEST_HEADERS;
305
+ }
306
+ return;
307
+ }
308
+ function authCatalogEntry(provider) {
309
+ return PROVIDER_AUTH_CATALOG.find((entry) => entry.provider === provider);
310
+ }
311
+ function catalogMethods(provider) {
312
+ return authCatalogEntry(provider)?.methods ?? ["api-key"];
313
+ }
314
+ function catalogAllows(provider, method) {
315
+ return catalogMethods(provider).includes(method);
316
+ }
317
+ function catalogRefusal(provider) {
318
+ return authCatalogEntry(provider)?.refusal;
319
+ }
320
+ function deviceCodeMethodLabel(provider) {
321
+ if (provider === "grok")
322
+ return "SuperGrok Subscription";
323
+ if (provider === "github-copilot")
324
+ return "Login with GitHub Copilot";
325
+ if (provider === "openai")
326
+ return "ChatGPT Plus/Pro (headless)";
327
+ return "Device authorization";
328
+ }
329
+ var XAI_GROK_DEVICE, GITHUB_COPILOT_REQUEST_HEADERS, GITHUB_COPILOT_OAUTH_CLIENT_ID = "Iv1.b507a08c87ecfe98", GITHUB_COPILOT_DEVICE, PROVIDER_AUTH_CATALOG;
330
+ var init_catalog = __esm(() => {
331
+ XAI_GROK_DEVICE = {
332
+ deviceAuthorizationEndpoint: "https://auth.x.ai/oauth2/device/code",
333
+ tokenEndpoint: "https://auth.x.ai/oauth2/token",
334
+ clientId: "b1a00492-073a-47ea-816f-4c329264a828",
335
+ scope: "openid profile email offline_access grok-cli:access api:access",
336
+ extraForm: { referrer: "keryx" },
337
+ headers: { "User-Agent": "keryx" }
338
+ };
339
+ GITHUB_COPILOT_REQUEST_HEADERS = {
340
+ Accept: "application/json",
341
+ "User-Agent": "GitHubCopilotChat/0.26.7",
342
+ "Editor-Version": "vscode/1.99.3",
343
+ "Editor-Plugin-Version": "copilot-chat/0.26.7",
344
+ "Copilot-Integration-Id": "vscode-chat"
345
+ };
346
+ GITHUB_COPILOT_DEVICE = {
347
+ deviceAuthorizationEndpoint: "https://github.com/login/device/code",
348
+ tokenEndpoint: "https://github.com/login/oauth/access_token",
349
+ clientId: GITHUB_COPILOT_OAUTH_CLIENT_ID,
350
+ scope: "read:user",
351
+ headers: GITHUB_COPILOT_REQUEST_HEADERS,
352
+ afterToken: "github-copilot"
353
+ };
354
+ PROVIDER_AUTH_CATALOG = [
355
+ {
356
+ provider: "grok",
357
+ label: "xAI (Grok)",
358
+ methods: ["device-code", "api-key"],
359
+ device: XAI_GROK_DEVICE
360
+ },
361
+ {
362
+ provider: "openai",
363
+ label: "OpenAI",
364
+ methods: ["oauth-pkce-loopback", "device-code", "api-key"]
365
+ },
366
+ {
367
+ provider: "github-copilot",
368
+ label: "GitHub Copilot",
369
+ methods: ["device-code"],
370
+ device: GITHUB_COPILOT_DEVICE
371
+ },
372
+ { provider: "anthropic", label: "Anthropic", methods: ["api-key"], refusal: "Anthropic does not permit third-party Claude Pro/Max login. Use an API key from the Anthropic Console." },
373
+ { provider: "gemini", label: "Google Gemini", methods: ["api-key"], refusal: "Gemini Google-account login is for Gemini CLI. In keryx use GEMINI_API_KEY from Google AI Studio." },
374
+ { provider: "deepseek", label: "DeepSeek", methods: ["api-key"], refusal: "DeepSeek has no consumer OAuth grant. Use DEEPSEEK_API_KEY." },
375
+ { provider: "openrouter", label: "OpenRouter", methods: ["api-key"] },
376
+ { provider: "zai", label: "Z.AI (GLM)", methods: ["api-key"] },
377
+ { provider: "zai-coding", label: "Z.AI GLM Coding Plan", methods: ["api-key"] },
378
+ { provider: "cerebras", label: "Cerebras", methods: ["api-key"] },
379
+ { provider: "groq", label: "Groq", methods: ["api-key"] },
380
+ { provider: "moonshot", label: "Moonshot (Kimi)", methods: ["api-key"] },
381
+ { provider: "ollama", label: "Ollama", methods: ["none"] },
382
+ { provider: "rapid-mlx", label: "Rapid-MLX (Local)", methods: ["none"] }
383
+ ];
384
+ });
385
+
301
386
  // src/lib/shell-config.ts
302
387
  import { existsSync as existsSync2 } from "fs";
303
388
  import path3 from "path";
@@ -641,8 +726,13 @@ async function fetchOpenAiCompatModelsDetailed(fetchFn, provider, apiKey, opts)
641
726
  const timer = setTimeout(() => controller.abort(), timeoutMs);
642
727
  try {
643
728
  const init = { signal: controller.signal };
729
+ const extraHeaders = extraRequestHeaders(provider.name);
730
+ const headers = extraHeaders === undefined ? {} : { ...extraHeaders };
644
731
  if (apiKey !== undefined && apiKey.length > 0) {
645
- init.headers = { authorization: `Bearer ${apiKey}` };
732
+ headers.authorization = `Bearer ${apiKey}`;
733
+ }
734
+ if (Object.keys(headers).length > 0) {
735
+ init.headers = headers;
646
736
  }
647
737
  const res = await fetchFn(url, init);
648
738
  if (!res.ok) {
@@ -890,6 +980,7 @@ with a stated reason and exits 0 \u2014 that is a normal configuration, not an e
890
980
  var DEFAULT_MODELS_PATH = "/v1/models", OPENAI_COMPAT_PROVIDERS, MODELS_FETCH_TIMEOUT_MS = 1e4, MODELS_ERROR_BODY_LIMIT = 4096, BALANCE_FETCH_TIMEOUT_MS = 8000;
891
981
  var init_providers = __esm(() => {
892
982
  init_provider_config();
983
+ init_catalog();
893
984
  init_grants();
894
985
  init_shell_config();
895
986
  init_args();
@@ -998,6 +1089,8 @@ var init_providers = __esm(() => {
998
1089
  label: "GitHub Copilot",
999
1090
  baseUrl: "https://api.githubcopilot.com",
1000
1091
  envKey: "GITHUB_COPILOT_TOKEN",
1092
+ chatPath: "/chat/completions",
1093
+ modelsPath: "/models",
1001
1094
  models: ["gpt-4o", "gpt-4.1", "gpt-4o-mini"],
1002
1095
  note: "Copilot \xB7 device login"
1003
1096
  }
@@ -8310,6 +8403,7 @@ function makeProvider(name, _model, opts) {
8310
8403
  if (needsKey && (apiKey === undefined || apiKey.length === 0)) {
8311
8404
  return new FakeProvider([]);
8312
8405
  }
8406
+ const extraHeaders = extraRequestHeaders(name);
8313
8407
  const grant = {
8314
8408
  network: true,
8315
8409
  ...compat.streamUsage === true ? { streamUsage: true } : {},
@@ -8317,7 +8411,8 @@ function makeProvider(name, _model, opts) {
8317
8411
  ...compat.allowLoopback === true ? { allowLoopback: true } : {},
8318
8412
  ...compat.allowPrivateLan === true ? { allowPrivateLan: true } : {},
8319
8413
  ...compat.chatPath !== undefined ? { chatPath: compat.chatPath } : {},
8320
- ...apiKey !== undefined ? { apiKey } : {}
8414
+ ...apiKey !== undefined ? { apiKey } : {},
8415
+ ...extraHeaders !== undefined ? { headers: extraHeaders } : {}
8321
8416
  };
8322
8417
  return new OpenAiCompatEngine({ fetch: opts.fetch, grant }, { ...OLLAMA_COMPAT_IDENTITY, providerLabel: compat.label });
8323
8418
  }
@@ -8326,6 +8421,7 @@ function makeProvider(name, _model, opts) {
8326
8421
  var OLLAMA_COMPAT_IDENTITY;
8327
8422
  var init_make_provider = __esm(() => {
8328
8423
  init_providers();
8424
+ init_catalog();
8329
8425
  init_anthropic_provider();
8330
8426
  init_openai_compat_provider();
8331
8427
  init_fake_provider();
@@ -40876,78 +40972,6 @@ async function startStdioTransport(server) {
40876
40972
  await server.connect(transport);
40877
40973
  }
40878
40974
 
40879
- // src/lib/oauth/catalog.ts
40880
- function authCatalogEntry(provider) {
40881
- return PROVIDER_AUTH_CATALOG.find((entry) => entry.provider === provider);
40882
- }
40883
- function catalogMethods(provider) {
40884
- return authCatalogEntry(provider)?.methods ?? ["api-key"];
40885
- }
40886
- function catalogAllows(provider, method) {
40887
- return catalogMethods(provider).includes(method);
40888
- }
40889
- function catalogRefusal(provider) {
40890
- return authCatalogEntry(provider)?.refusal;
40891
- }
40892
- function deviceCodeMethodLabel(provider) {
40893
- if (provider === "grok")
40894
- return "SuperGrok Subscription";
40895
- if (provider === "github-copilot")
40896
- return "Login with GitHub Copilot";
40897
- if (provider === "openai")
40898
- return "ChatGPT Plus/Pro (headless)";
40899
- return "Device authorization";
40900
- }
40901
- var XAI_GROK_DEVICE, GITHUB_COPILOT_DEVICE, PROVIDER_AUTH_CATALOG;
40902
- var init_catalog = __esm(() => {
40903
- XAI_GROK_DEVICE = {
40904
- deviceAuthorizationEndpoint: "https://auth.x.ai/oauth2/device/code",
40905
- tokenEndpoint: "https://auth.x.ai/oauth2/token",
40906
- clientId: "b1a00492-073a-47ea-816f-4c329264a828",
40907
- scope: "openid profile email offline_access grok-cli:access api:access",
40908
- extraForm: { referrer: "keryx" },
40909
- headers: { "User-Agent": "keryx" }
40910
- };
40911
- GITHUB_COPILOT_DEVICE = {
40912
- deviceAuthorizationEndpoint: "https://github.com/login/device/code",
40913
- tokenEndpoint: "https://github.com/login/oauth/access_token",
40914
- clientId: "Ov23li8tweQw6odWQebz",
40915
- scope: "read:user",
40916
- headers: { Accept: "application/json", "User-Agent": "keryx" },
40917
- afterToken: "github-copilot"
40918
- };
40919
- PROVIDER_AUTH_CATALOG = [
40920
- {
40921
- provider: "grok",
40922
- label: "xAI (Grok)",
40923
- methods: ["device-code", "api-key"],
40924
- device: XAI_GROK_DEVICE
40925
- },
40926
- {
40927
- provider: "openai",
40928
- label: "OpenAI",
40929
- methods: ["oauth-pkce-loopback", "device-code", "api-key"]
40930
- },
40931
- {
40932
- provider: "github-copilot",
40933
- label: "GitHub Copilot",
40934
- methods: ["device-code"],
40935
- device: GITHUB_COPILOT_DEVICE
40936
- },
40937
- { provider: "anthropic", label: "Anthropic", methods: ["api-key"], refusal: "Anthropic does not permit third-party Claude Pro/Max login. Use an API key from the Anthropic Console." },
40938
- { provider: "gemini", label: "Google Gemini", methods: ["api-key"], refusal: "Gemini Google-account login is for Gemini CLI. In keryx use GEMINI_API_KEY from Google AI Studio." },
40939
- { provider: "deepseek", label: "DeepSeek", methods: ["api-key"], refusal: "DeepSeek has no consumer OAuth grant. Use DEEPSEEK_API_KEY." },
40940
- { provider: "openrouter", label: "OpenRouter", methods: ["api-key"] },
40941
- { provider: "zai", label: "Z.AI (GLM)", methods: ["api-key"] },
40942
- { provider: "zai-coding", label: "Z.AI GLM Coding Plan", methods: ["api-key"] },
40943
- { provider: "cerebras", label: "Cerebras", methods: ["api-key"] },
40944
- { provider: "groq", label: "Groq", methods: ["api-key"] },
40945
- { provider: "moonshot", label: "Moonshot (Kimi)", methods: ["api-key"] },
40946
- { provider: "ollama", label: "Ollama", methods: ["none"] },
40947
- { provider: "rapid-mlx", label: "Rapid-MLX (Local)", methods: ["none"] }
40948
- ];
40949
- });
40950
-
40951
40975
  // src/lib/oauth/device-code.ts
40952
40976
  function requestInit(base, signal) {
40953
40977
  return signal === undefined ? base : { ...base, signal };
@@ -41115,38 +41139,94 @@ var init_device_code = __esm(() => {
41115
41139
  });
41116
41140
 
41117
41141
  // src/lib/oauth/copilot.ts
41142
+ function copilotApiBaseFromExchange(raw) {
41143
+ if (typeof raw !== "string" || raw.length === 0) {
41144
+ return;
41145
+ }
41146
+ try {
41147
+ const url = new URL(raw);
41148
+ if (url.protocol !== "https:" || url.username.length > 0 || url.password.length > 0) {
41149
+ return;
41150
+ }
41151
+ const host = url.hostname;
41152
+ if (host !== "api.githubcopilot.com" && !host.endsWith(".githubcopilot.com")) {
41153
+ return;
41154
+ }
41155
+ return `https://${host}${url.port.length > 0 ? `:${url.port}` : ""}`;
41156
+ } catch {
41157
+ return;
41158
+ }
41159
+ }
41160
+ function expiresInSecondsFrom(rec, now) {
41161
+ if (typeof rec.expires_at === "string") {
41162
+ const expires = Date.parse(rec.expires_at);
41163
+ if (Number.isFinite(expires)) {
41164
+ return Math.max(1, Math.floor((expires - now) / 1000));
41165
+ }
41166
+ }
41167
+ if (typeof rec.expires_at === "number" && Number.isFinite(rec.expires_at)) {
41168
+ const expiresMs = rec.expires_at < 1000000000000 ? rec.expires_at * 1000 : rec.expires_at;
41169
+ return Math.max(1, Math.floor((expiresMs - now) / 1000));
41170
+ }
41171
+ if (typeof rec.refresh_in === "number" && Number.isFinite(rec.refresh_in) && rec.refresh_in > 0) {
41172
+ return Math.floor(rec.refresh_in);
41173
+ }
41174
+ return;
41175
+ }
41176
+ function describeExchangeFailure(status, json, body) {
41177
+ if (typeof json === "object" && json !== null) {
41178
+ const rec = json;
41179
+ if (rec.error_details?.copilot_access_denied === true) {
41180
+ return `GitHub Copilot token exchange failed (HTTP ${status}): Copilot access denied \u2014 check the GitHub Copilot subscription on this account`;
41181
+ }
41182
+ if (typeof rec.message === "string" && rec.message.length > 0) {
41183
+ return `GitHub Copilot token exchange failed (HTTP ${status}): ${rec.message}`;
41184
+ }
41185
+ }
41186
+ if (/zscaler|blocked because it does not comply/i.test(body)) {
41187
+ return `GitHub Copilot token exchange failed (HTTP ${status}): request was blocked by a gateway or proxy`;
41188
+ }
41189
+ return `GitHub Copilot token exchange failed (HTTP ${status})`;
41190
+ }
41118
41191
  async function exchangeGithubTokenForCopilot(githubToken, http) {
41119
41192
  const init = {
41120
41193
  method: "GET",
41121
41194
  headers: {
41122
- Authorization: `token ${githubToken}`,
41123
- Accept: "application/json",
41124
- "User-Agent": "keryx"
41195
+ ...GITHUB_COPILOT_REQUEST_HEADERS,
41196
+ Authorization: `token ${githubToken}`
41125
41197
  }
41126
41198
  };
41127
41199
  if (http.signal !== undefined) {
41128
41200
  init.signal = http.signal;
41129
41201
  }
41130
41202
  const response = await http.fetch(COPILOT_TOKEN_URL, init);
41131
- const json = await response.json().catch(() => ({}));
41203
+ const body = await response.text().catch(() => "");
41204
+ let json = {};
41205
+ if (body.length > 0) {
41206
+ try {
41207
+ json = JSON.parse(body);
41208
+ } catch {
41209
+ json = {};
41210
+ }
41211
+ }
41132
41212
  if (!response.ok || typeof json !== "object" || json === null) {
41133
- throw new DeviceCodeError("failed", `GitHub Copilot token exchange failed (HTTP ${response.status})`);
41213
+ throw new DeviceCodeError("failed", describeExchangeFailure(response.status, json, body));
41134
41214
  }
41135
41215
  const rec = json;
41136
41216
  if (typeof rec.token !== "string" || rec.token.length === 0) {
41137
41217
  throw new DeviceCodeError("failed", "GitHub Copilot token exchange returned no token");
41138
41218
  }
41139
- let expiresInSeconds;
41140
- if (typeof rec.expires_at === "string") {
41141
- const expires = Date.parse(rec.expires_at);
41142
- if (Number.isFinite(expires)) {
41143
- expiresInSeconds = Math.max(1, Math.floor((expires - Date.now()) / 1000));
41144
- }
41145
- }
41146
- return { accessToken: rec.token, ...expiresInSeconds !== undefined ? { expiresInSeconds } : {} };
41219
+ const expiresInSeconds = expiresInSecondsFrom(rec, Date.now());
41220
+ const apiBaseUrl = copilotApiBaseFromExchange(rec.endpoints?.api);
41221
+ return {
41222
+ accessToken: rec.token,
41223
+ ...expiresInSeconds !== undefined ? { expiresInSeconds } : {},
41224
+ ...apiBaseUrl !== undefined ? { apiBaseUrl } : {}
41225
+ };
41147
41226
  }
41148
41227
  var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
41149
41228
  var init_copilot = __esm(() => {
41229
+ init_catalog();
41150
41230
  init_device_code();
41151
41231
  });
41152
41232
 
@@ -41266,6 +41346,9 @@ async function loginRfc8628(input) {
41266
41346
  }, http);
41267
41347
  if (endpoints.afterToken === "github-copilot") {
41268
41348
  const copilot = await exchangeGithubTokenForCopilot(tokens.accessToken, http);
41349
+ if (copilot.apiBaseUrl !== undefined) {
41350
+ saveProviderBaseUrl("github-copilot", copilot.apiBaseUrl, input.dir);
41351
+ }
41269
41352
  return {
41270
41353
  accessToken: copilot.accessToken,
41271
41354
  refreshToken: tokens.accessToken,
@@ -41315,6 +41398,9 @@ async function refreshProviderGrant(provider, http, dir) {
41315
41398
  const endpoints = provider === "github-copilot" ? GITHUB_COPILOT_DEVICE : XAI_GROK_DEVICE;
41316
41399
  if (provider === "github-copilot") {
41317
41400
  const copilot = await exchangeGithubTokenForCopilot(grant.refresh, http);
41401
+ if (copilot.apiBaseUrl !== undefined) {
41402
+ saveProviderBaseUrl("github-copilot", copilot.apiBaseUrl, dir);
41403
+ }
41318
41404
  const next = grantFromTokens("device-code", {
41319
41405
  accessToken: copilot.accessToken,
41320
41406
  refreshToken: grant.refresh,
@@ -41369,6 +41455,7 @@ function logoutProvider(provider, dir) {
41369
41455
  }
41370
41456
  var SESSION_REFRESHED_GRANTS;
41371
41457
  var init_login = __esm(() => {
41458
+ init_shell_config();
41372
41459
  init_catalog();
41373
41460
  init_copilot();
41374
41461
  init_device_code();
@@ -48173,7 +48260,7 @@ import path47 from "path";
48173
48260
  // package.json
48174
48261
  var package_default = {
48175
48262
  name: "@mrciphersmith/keryx",
48176
- version: "0.2.100",
48263
+ version: "0.2.102",
48177
48264
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
48178
48265
  private: false,
48179
48266
  publishConfig: {
@@ -94966,7 +95053,7 @@ function pickAuthMethodStep(otui, r, providerLabel, methods) {
94966
95053
  });
94967
95054
  });
94968
95055
  }
94969
- function runDeviceLoginInTui(otui, r, provider) {
95056
+ function runDeviceLoginInTui(otui, r, provider, dir) {
94970
95057
  return new Promise((resolve) => {
94971
95058
  const box = overlayBox(otui, r, "device-login");
94972
95059
  r.root.add(box);
@@ -94994,6 +95081,7 @@ function runDeviceLoginInTui(otui, r, provider) {
94994
95081
  provider,
94995
95082
  fetch: (input, init) => globalThis.fetch(input, init),
94996
95083
  signal: controller.signal,
95084
+ ...dir !== undefined ? { dir } : {},
94997
95085
  onChallenge: (challenge) => {
94998
95086
  status.content = otui.t`${otui.bold(challenge.userCode)}\n${otui.dim(challenge.verificationUri)}\n${otui.dim("Open that URL on any device and enter the code. Waiting for authorization\u2026")}`;
94999
95087
  openVerificationUrl(challenge.verificationUriComplete ?? challenge.verificationUri);
@@ -95110,12 +95198,14 @@ function selectProviderModelInTui(otui, r, detected, options = {}) {
95110
95198
  }
95111
95199
  continue;
95112
95200
  }
95113
- let selectedBaseUrl = options.onlyConnected || prov.baseUrl === undefined ? prov.baseUrl : await promptBaseUrlStep(otui, r, prov.label ?? prov.name, prov.baseUrl);
95114
- if (!options.onlyConnected && prov.baseUrl !== undefined && selectedBaseUrl === undefined) {
95201
+ const lockDiscoveredHost = prov.name === "github-copilot";
95202
+ let selectedBaseUrl = options.onlyConnected || prov.baseUrl === undefined || lockDiscoveredHost ? prov.baseUrl : await promptBaseUrlStep(otui, r, prov.label ?? prov.name, prov.baseUrl);
95203
+ if (!options.onlyConnected && !lockDiscoveredHost && prov.baseUrl !== undefined && selectedBaseUrl === undefined) {
95115
95204
  continue;
95116
95205
  }
95117
- if (!options.onlyConnected && selectedBaseUrl !== undefined)
95206
+ if (!options.onlyConnected && !lockDiscoveredHost && selectedBaseUrl !== undefined) {
95118
95207
  saveProviderBaseUrl(prov.name, selectedBaseUrl, options.configDir);
95208
+ }
95119
95209
  let selectedProvider = selectedBaseUrl === undefined ? prov : { ...prov, baseUrl: selectedBaseUrl };
95120
95210
  const envKey = prov.envKey;
95121
95211
  const label = prov.label ?? prov.name;
@@ -95143,7 +95233,15 @@ function selectProviderModelInTui(otui, r, detected, options = {}) {
95143
95233
  }
95144
95234
  }
95145
95235
  if (method === "device-code") {
95146
- return await runDeviceLoginInTui(otui, r, prov.name) ? "ok" : "back";
95236
+ if (!await runDeviceLoginInTui(otui, r, prov.name, options.configDir)) {
95237
+ return "back";
95238
+ }
95239
+ const saved = loadShellConfig(options.configDir).baseUrls?.[prov.name];
95240
+ if (typeof saved === "string" && saved.length > 0) {
95241
+ selectedBaseUrl = saved;
95242
+ selectedProvider = { ...prov, baseUrl: saved };
95243
+ }
95244
+ return "ok";
95147
95245
  }
95148
95246
  const kr = await promptApiKeyStep(otui, r, {
95149
95247
  label,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.100",
3
+ "version": "0.2.102",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {