nexgenr 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +28 -13
  2. package/dist/main.mjs +7 -174
  3. package/package.json +9 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nexgenr
2
2
 
3
- NexgenR CLI is a terminal AI coding agent wired to **NexgenRouter**.
3
+ NexgenR CLI is a terminal AI coding agent wired to the **NexgenR red-team** surface.
4
4
 
5
5
  ## Install
6
6
 
@@ -18,22 +18,33 @@ pnpm add -g nexgenr
18
18
 
19
19
  ## Configure
20
20
 
21
- NexgenR authenticates with a NexgenRouter API key:
21
+ NexgenR signs in with an API key. There is no OAuth and no device flow:
22
22
 
23
23
  ```sh
24
24
  export NEXGENR_API_KEY="<your key>"
25
- # optional, defaults to https://ia.nexgen.systems/v1
26
- export NEXGENR_BASE_URL="https://ia.nexgen.systems/v1"
25
+ # optional, defaults to https://redteam.nexgen.systems/v1
26
+ export NEXGENR_BASE_URL="https://redteam.nexgen.systems/v1"
27
27
  ```
28
28
 
29
- Validate the key and provision the model catalog:
30
-
31
29
  ```sh
32
30
  nexgenr login # reads NEXGENR_API_KEY
33
31
  nexgenr login --api-key <your key> # or pass it explicitly
34
32
  ```
35
33
 
36
- This reads `GET /v1/models`, writes `~/.nexgenr/config.toml`, and selects `nexgen-auto` as the default model.
34
+ The same key works on both surfaces; the header is what changes:
35
+
36
+ | Surface | Send the key as | Rejected |
37
+ |---|---|---|
38
+ | `/v1/…` inference and catalog | `Authorization: Bearer <key>` or `x-api-key: <key>` | `x-bf-vk` answers 401 here |
39
+ | `/mcp` gateway | `x-bf-vk: <key>` or `Authorization: Bearer <key>` | — |
40
+
41
+ The key must be provisioned for the `vllm` provider and the `nexgen-redteam` model.
42
+ Without that grant `GET /v1/models` answers 200 with an empty catalog and chat fails
43
+ with `400 modelo-desconocido`.
44
+
45
+ `nexgenr login` writes `~/.nexgenr/config.toml` with the `redteam` provider and its single
46
+ model `nexgen-redteam` (262 144 tokens of context), and `~/.nexgenr/mcp.json` with the
47
+ gateway. It does not call the catalog: the model list is static.
37
48
 
38
49
  ## Quick start
39
50
 
@@ -47,13 +58,17 @@ nexgenr # interactive terminal UI
47
58
 
48
59
  | Capability | Endpoint |
49
60
  |---|---|
50
- | Chat (OpenAI, Responses, Anthropic) | `POST /v1/chat/completions`, `/v1/responses`, `/v1/messages` |
61
+ | Chat, streaming only | `POST /v1/chat/completions` |
51
62
  | Model catalog | `GET /v1/models` |
52
- | Web search | `POST /v1/tools/search` |
53
- | URL fetch | `POST /v1/tools/fetch` |
54
- | Server tools | `openrouter:*` declared in `tools[]` |
63
+ | Health and published limits | `GET /health`, no credential |
64
+ | MCP gateway | `POST /mcp` — 24 tools (8 Brave_Search, 16 Crawl4AI) |
65
+
66
+ `POST /v1/completions` and `POST /v1/embeddings` are in the edge allowlist but the engine
67
+ answers 404: `POST /v1/chat/completions` is the only inference route.
55
68
 
56
- Authentication uses `Authorization: Bearer <key>` (and `x-api-key` on the Anthropic wire).
69
+ Limits, as published by `GET /health`: 4 requests in flight per consumer with `429` and
70
+ `Retry-After: 10` beyond that, a 12 MiB request body, and 262 144 tokens of context. A
71
+ prefill can take minutes, so requests stream and wait up to 3 600 s for the first byte.
57
72
 
58
73
  ## Features
59
74
 
@@ -68,7 +83,7 @@ Authentication uses `Authorization: Bearer <key>` (and `x-api-key` on the Anthro
68
83
  - Remote Control (requires a relay service).
69
84
  - CDN-based auto-update; upgrade with `npm install -g nexgenr@latest`.
70
85
  - The bundled browser UI; `nexgenr web` serves the API plus a minimal landing page.
71
- - Device-flow OAuth; `nexgenr login` validates an API key and writes the provider entry.
86
+ - SSO: NexgenR signs in with an API key only.
72
87
 
73
88
  ## License
74
89
 
package/dist/main.mjs CHANGED
@@ -62532,19 +62532,7 @@ var init_open_platform = __esmMin((() => {
62532
62532
  init_identity();
62533
62533
  init_managed_nexgenr();
62534
62534
  init_model_alias_merge();
62535
- OPEN_PLATFORMS = [{
62536
- id: "nexgen-cn",
62537
- name: "Nexgen Platform (API key · platform.nexgenr.com)",
62538
- baseUrl: "https://ia.nexgen.systems/v1",
62539
- consoleUrl: "https://ia.nexgen.systems",
62540
- allowedPrefixes: ["nexgenr-k"]
62541
- }, {
62542
- id: "nexgen-ai",
62543
- name: "Nexgen Platform (API key · platform.nexgenr.ai)",
62544
- baseUrl: "https://ia.nexgen.systems/v1",
62545
- consoleUrl: "https://ia.nexgen.systems",
62546
- allowedPrefixes: ["nexgenr-k"]
62547
- }];
62535
+ OPEN_PLATFORMS = [];
62548
62536
  OpenPlatformApiError = class extends Error {
62549
62537
  status;
62550
62538
  constructor(message, status) {
@@ -63043,6 +63031,8 @@ var init_custom_registry = __esmMin((() => {
63043
63031
  RESERVED_PROVIDER_IDS = /* @__PURE__ */ new Set([
63044
63032
  NEXGENR_PLATFORM_ID,
63045
63033
  NEXGENR_PROVIDER_NAME,
63034
+ "nexgen-cn",
63035
+ "nexgen-ai",
63046
63036
  ...OPEN_PLATFORMS.map((platform) => platform.id)
63047
63037
  ]);
63048
63038
  CustomRegistryApiError = class extends Error {
@@ -323009,9 +322999,6 @@ init_src$8();
323009
322999
  init_mcp_provision();
323010
323000
  init_provision();
323011
323001
  const PROBE_TIMEOUT_MS$1 = 15e3;
323012
- function isVirtualKey(key) {
323013
- return key !== void 0 && key.startsWith("sk-bf-");
323014
- }
323015
323002
  function mcpHeaders(apiKey) {
323016
323003
  if (apiKey === void 0 || apiKey === "") return {};
323017
323004
  const headers = redteamAuthHeaders(apiKey);
@@ -323080,21 +323067,15 @@ async function probeModels(doFetch, baseUrl, apiKey, timeoutMs) {
323080
323067
  detail: "no API key in config.toml — run `nexgenr login --api-key <token>`"
323081
323068
  };
323082
323069
  try {
323083
- const headers = redteamAuthHeaders(apiKey);
323084
323070
  const response = await timedFetch(doFetch, `${baseUrl}/models`, {
323085
323071
  method: "GET",
323086
- headers
323072
+ headers: { authorization: `Bearer ${apiKey}` }
323087
323073
  }, timeoutMs);
323088
- if (response.status === 401 || response.status === 403) return isVirtualKey(apiKey) ? {
323089
- name: "models",
323090
- kind: "probe",
323091
- state: "BLOQUEADO",
323092
- detail: `HTTP ${response.status} — a Bifrost virtual key cannot use /v1; the consumer token (64 hex) is a different credential`
323093
- } : {
323074
+ if (response.status === 401 || response.status === 403) return {
323094
323075
  name: "models",
323095
323076
  kind: "probe",
323096
323077
  state: "DENEGADO",
323097
- detail: `HTTP ${response.status} — the consumer token was rejected`
323078
+ detail: `HTTP ${response.status} — the credential was rejected on /v1`
323098
323079
  };
323099
323080
  if (!response.ok) return {
323100
323081
  name: "models",
@@ -463658,51 +463639,7 @@ var init_model_selector = __esmMin((() => {
463658
463639
  }
463659
463640
  };
463660
463641
  }));
463661
- // src/tui/components/dialogs/platform-selector.ts
463662
- function platformOptions() {
463663
- return [NEXGENR_REDTEAM_OPTION, ...OPEN_PLATFORMS.map((platform) => ({
463664
- value: platform.id,
463665
- label: platform.name
463666
- }))];
463667
- }
463668
- var NEXGENR_REDTEAM_OPTION, PlatformSelectorComponent;
463669
- var init_platform_selector = __esmMin((() => {
463670
- init_src$13();
463671
- init_choice_picker();
463672
- NEXGENR_REDTEAM_OPTION = {
463673
- value: "nexgenr",
463674
- label: "NexgenR (red-team)",
463675
- description: "Sign in to redteam.nexgen.systems with an API key"
463676
- };
463677
- PlatformSelectorComponent = class extends ChoicePickerComponent {
463678
- constructor(opts) {
463679
- super({
463680
- title: "Select a platform",
463681
- options: [...platformOptions()],
463682
- onSelect: opts.onSelect,
463683
- onCancel: opts.onCancel
463684
- });
463685
- }
463686
- };
463687
- }));
463688
463642
  // src/tui/commands/prompts.ts
463689
- function promptPlatformSelection(host) {
463690
- return new Promise((resolve) => {
463691
- const selector = new PlatformSelectorComponent({
463692
- onSelect: (platformId) => {
463693
- host.restoreEditor();
463694
- resolve(platformId);
463695
- },
463696
- onCancel: () => {
463697
- host.restoreEditor();
463698
- resolve(void 0);
463699
- }
463700
- });
463701
- host.mountEditorReplacement(selector, void 0, () => {
463702
- resolve(void 0);
463703
- });
463704
- });
463705
- }
463706
463643
  function promptLogoutProviderSelection(host, options, currentValue) {
463707
463644
  return new Promise((resolve) => {
463708
463645
  const picker = new ChoicePickerComponent({
@@ -463806,57 +463743,13 @@ function promptCatalogProviderSelection(host, catalog) {
463806
463743
  host.mountEditorReplacement(picker);
463807
463744
  });
463808
463745
  }
463809
- async function promptModelSelectionForOpenPlatform(host, models, platform) {
463810
- const modelDict = {};
463811
- for (const m of models) modelDict[`${platform.id}/${m.id}`] = {
463812
- provider: platform.id,
463813
- model: m.id,
463814
- maxContextSize: m.contextLength,
463815
- capabilities: capabilitiesForModel(m),
463816
- displayName: m.displayName
463817
- };
463818
- const selection = await runModelSelector(host, modelDict);
463819
- if (selection === void 0) return void 0;
463820
- const model = models.find((m) => `${platform.id}/${m.id}` === selection.alias);
463821
- return model ? {
463822
- model,
463823
- thinking: selection.thinking
463824
- } : void 0;
463825
- }
463826
- function runModelSelector(host, modelDict) {
463827
- return new Promise((resolve) => {
463828
- const firstAlias = Object.keys(modelDict)[0] ?? "";
463829
- const caps = modelDict[firstAlias]?.capabilities ?? [];
463830
- const initialThinking = caps.includes("always_thinking") || caps.includes("thinking");
463831
- const selector = new ModelSelectorComponent({
463832
- models: modelDict,
463833
- currentValue: firstAlias,
463834
- currentThinkingEffort: initialThinking ? "on" : "off",
463835
- searchable: true,
463836
- onSelect: ({ alias, thinking }) => {
463837
- host.restoreEditor();
463838
- resolve({
463839
- alias,
463840
- thinking
463841
- });
463842
- },
463843
- onCancel: () => {
463844
- host.restoreEditor();
463845
- resolve(void 0);
463846
- }
463847
- });
463848
- host.mountEditorReplacement(selector);
463849
- });
463850
- }
463851
463746
  var FEEDBACK_ATTACHMENT_OPTIONS;
463852
463747
  var init_prompts = __esmMin((() => {
463853
463748
  init_src$8();
463854
- init_src$13();
463855
463749
  init_api_key_input_dialog();
463856
463750
  init_choice_picker();
463857
463751
  init_feedback_input_dialog();
463858
463752
  init_model_selector();
463859
- init_platform_selector();
463860
463753
  FEEDBACK_ATTACHMENT_OPTIONS = [
463861
463754
  {
463862
463755
  value: "none",
@@ -463880,15 +463773,7 @@ var init_prompts = __esmMin((() => {
463880
463773
  async function handleLoginCommand(host) {
463881
463774
  const releaseAuthBlock = host.beginAuthBlock();
463882
463775
  try {
463883
- const platformId = await promptPlatformSelection(host);
463884
- if (platformId === void 0) return;
463885
- if (platformId === "nexgenr" || platformId === "nexgenr-global") {
463886
- await handleRedteamLogin(host);
463887
- return;
463888
- }
463889
- const platform = getOpenPlatformById(platformId);
463890
- if (platform === void 0) return;
463891
- await handleOpenPlatformLogin(host, platform);
463776
+ await handleRedteamLogin(host);
463892
463777
  } finally {
463893
463778
  releaseAuthBlock();
463894
463779
  }
@@ -463947,57 +463832,6 @@ async function writeRedteamMcp(host, apiKey) {
463947
463832
  return;
463948
463833
  }
463949
463834
  }
463950
- async function handleOpenPlatformLogin(host, platform) {
463951
- const consoleHost = platform.consoleUrl?.replace(/^https?:\/\//, "") ?? "";
463952
- const apiKey = await promptApiKey(host, consoleHost.length > 0 ? `Nexgen Platform (${consoleHost})` : "Nexgen Platform", [`${"base_url".padEnd(12)}${platform.baseUrl}`, `${"saved to".padEnd(12)}~/.nexgenr/config.toml`]);
463953
- if (apiKey === void 0) return;
463954
- const controller = new AbortController();
463955
- const cancelLogin = () => {
463956
- controller.abort();
463957
- };
463958
- host.cancelInFlight = cancelLogin;
463959
- let models;
463960
- try {
463961
- models = await fetchOpenPlatformModels(platform, apiKey, fetch, controller.signal);
463962
- models = filterModelsByPrefix(models, platform);
463963
- } catch (error) {
463964
- if (controller.signal.aborted) return;
463965
- const msg = formatErrorMessage$2(error);
463966
- host.showError(`Failed to verify API key: ${msg}`);
463967
- if (error instanceof OpenPlatformApiError && error.status === 401) host.showStatus("Hint: If your API key was obtained from NexgenR, please select \"NexgenR\" instead.");
463968
- return;
463969
- } finally {
463970
- if (host.cancelInFlight === cancelLogin) host.cancelInFlight = void 0;
463971
- }
463972
- if (models.length === 0) {
463973
- host.showError("No models available for this platform.");
463974
- return;
463975
- }
463976
- const selection = await promptModelSelectionForOpenPlatform(host, models, platform);
463977
- if (selection === void 0) return;
463978
- if ((await host.harness.getConfig()).providers[platform.id] !== void 0) await host.harness.removeProvider(platform.id);
463979
- const config = await host.harness.getConfig();
463980
- applyOpenPlatformConfig(config, {
463981
- platform,
463982
- models,
463983
- selectedModel: selection.model,
463984
- thinking: selection.thinking !== "off",
463985
- effort: selection.thinking !== "off" && selection.thinking !== "on" ? selection.thinking : void 0,
463986
- credential: { apiKey }
463987
- });
463988
- await host.harness.setConfig({
463989
- providers: config.providers,
463990
- models: config.models,
463991
- defaultModel: config.defaultModel,
463992
- thinking: config.thinking
463993
- });
463994
- await host.authFlow.refreshConfigAfterLogin();
463995
- host.track("login", {
463996
- provider: platform.id,
463997
- method: "api_key"
463998
- });
463999
- host.showStatus(`Setup complete: ${platform.name} · ${selection.model.id}`);
464000
- }
464001
463835
  async function handleLogoutCommand(host) {
464002
463836
  const hasOAuthToken = (await host.harness.auth.status(DEFAULT_OAUTH_PROVIDER_NAME)).providers.some((p) => p.providerName === "managed:nexgenr" && p.hasToken);
464003
463837
  const config = await host.harness.getConfig();
@@ -464041,7 +463875,6 @@ async function handleLogoutCommand(host) {
464041
463875
  host.showStatus(`Logged out from ${label}.`);
464042
463876
  }
464043
463877
  var init_auth = __esmMin((() => {
464044
- init_src$13();
464045
463878
  init_src$8();
464046
463879
  init_mcp_provision();
464047
463880
  init_provision();
package/package.json CHANGED
@@ -1,10 +1,17 @@
1
1
  {
2
2
  "name": "nexgenr",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "NexgenR — terminal AI coding agent",
5
5
  "license": "MIT",
6
6
  "author": "NexgenR",
7
- "homepage": "https://ia.nexgen.systems",
7
+ "homepage": "https://git.nexgen.systems/IANexgen/NexgenR",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://git.nexgen.systems/IANexgen/NexgenR.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://git.nexgen.systems/IANexgen/NexgenR/issues"
14
+ },
8
15
  "keywords": [
9
16
  "nexgenr",
10
17
  "cli",