nexus-ai-pro 0.8.0 → 0.9.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.
Files changed (93) hide show
  1. package/API_STABILITY.md +32 -0
  2. package/CHANGELOG.md +35 -0
  3. package/README.md +30 -7
  4. package/ROADMAP.md +188 -0
  5. package/SECURITY.md +15 -0
  6. package/dist/agent/tool.js +3 -1
  7. package/dist/cache/adapters.js +3 -1
  8. package/dist/cli.js +29 -13
  9. package/dist/connectors/web.d.ts +12 -0
  10. package/dist/connectors/web.js +359 -22
  11. package/dist/context/window.js +10 -15
  12. package/dist/core/nexus.d.ts +2 -2
  13. package/dist/core/nexus.js +61 -20
  14. package/dist/core/response-format.js +32 -53
  15. package/dist/core/secure-stream.d.ts +1 -1
  16. package/dist/core/secure-stream.js +135 -26
  17. package/dist/embeddings/providers.js +3 -3
  18. package/dist/evals/judge.js +1 -3
  19. package/dist/evals/metrics.js +2 -4
  20. package/dist/evals/runner.js +2 -6
  21. package/dist/hallucination/consistency.js +1 -3
  22. package/dist/hallucination/factual.js +4 -6
  23. package/dist/hallucination/knowledge-graph.js +7 -9
  24. package/dist/hallucination/rag.js +4 -2
  25. package/dist/hallucination/verification.js +32 -9
  26. package/dist/next/route-handler.js +1 -1
  27. package/dist/ops/audit-logger.js +29 -1
  28. package/dist/ops/health.js +1 -3
  29. package/dist/ops/metrics.js +5 -2
  30. package/dist/optimizer/cost.js +2 -2
  31. package/dist/optimizer/densifier.js +7 -4
  32. package/dist/optimizer/index.js +2 -3
  33. package/dist/pipeline/types.d.ts +1 -1
  34. package/dist/providers/anthropic.js +4 -2
  35. package/dist/providers/base.js +76 -18
  36. package/dist/providers/cohere.js +2 -2
  37. package/dist/providers/errors.js +8 -10
  38. package/dist/providers/google.js +6 -4
  39. package/dist/providers/groq.js +1 -1
  40. package/dist/providers/mistral.js +1 -1
  41. package/dist/providers/openai.js +22 -12
  42. package/dist/rag/file-ingestion.js +1 -1
  43. package/dist/rag/ingestion.js +5 -4
  44. package/dist/router/auto-router.js +13 -9
  45. package/dist/router/failover.d.ts +10 -3
  46. package/dist/router/failover.js +250 -50
  47. package/dist/security/index.d.ts +3 -2
  48. package/dist/security/index.js +45 -6
  49. package/dist/security/injection-calibration.js +6 -2
  50. package/dist/security/injection-detector.js +21 -7
  51. package/dist/security/input-guard.js +28 -14
  52. package/dist/security/output-guard.d.ts +8 -0
  53. package/dist/security/output-guard.js +146 -57
  54. package/dist/security/prompt-hardening.js +2 -1
  55. package/dist/security/schema-validator.js +5 -8
  56. package/dist/security/upload-scanner.js +3 -1
  57. package/dist/telephony/providers/twilio.js +14 -10
  58. package/dist/testing/provider-conformance.js +4 -4
  59. package/dist/types/config.d.ts +6 -0
  60. package/dist/types/providers.d.ts +1 -1
  61. package/dist/types/providers.js +130 -25
  62. package/dist/utils/ids.js +1 -1
  63. package/dist/utils/tokenizer.js +17 -14
  64. package/dist/voice/manager.js +1 -3
  65. package/dist/voice/providers/openai.js +4 -2
  66. package/dist/voice/session.js +6 -14
  67. package/dist/workflow/chains.js +19 -8
  68. package/dist/workflow/domain.js +28 -12
  69. package/package.json +133 -43
  70. package/EXPLANATION.md +0 -434
  71. package/assets/nexus-ai-pro-presentation.jpg +0 -0
  72. package/examples/agent.ts +0 -69
  73. package/examples/basic.ts +0 -37
  74. package/examples/bullmq-worker.ts +0 -36
  75. package/examples/classifier-calibration.ts +0 -7
  76. package/examples/cli-eval.json +0 -16
  77. package/examples/config-builder.ts +0 -18
  78. package/examples/create-nexus.ts +0 -15
  79. package/examples/custom-provider.ts +0 -16
  80. package/examples/domain-workflows.ts +0 -38
  81. package/examples/exports/README.md +0 -10
  82. package/examples/exports/config.ts +0 -18
  83. package/examples/exports/providers.ts +0 -33
  84. package/examples/exports/root.ts +0 -54
  85. package/examples/exports/runtime-modules.ts +0 -40
  86. package/examples/feature-flags.ts +0 -65
  87. package/examples/minimal.ts +0 -45
  88. package/examples/ocr-pdf-ingestion.ts +0 -42
  89. package/examples/optimizer.ts +0 -43
  90. package/examples/otel-express.ts +0 -47
  91. package/examples/otel-node-http.ts +0 -46
  92. package/examples/persisted-vector-store.ts +0 -42
  93. package/examples/security.ts +0 -69
@@ -0,0 +1,32 @@
1
+ # API Stability Policy
2
+
3
+ This policy describes compatibility guarantees for `nexus-ai-pro` beginning with version 0.9.0.
4
+
5
+ ## Release stages
6
+
7
+ The package is pre-1.0. Minor releases may contain breaking changes when they are necessary, but those changes will be called out in the changelog with migration guidance. Patch releases are intended to remain backward compatible.
8
+
9
+ The following surfaces are public and covered by this policy:
10
+
11
+ - exports documented in the root package or an explicit `package.json` subpath;
12
+ - exported TypeScript types and runtime symbols;
13
+ - documented configuration keys, response shapes, and CLI commands.
14
+
15
+ Source files, `dist` file paths, examples, test helpers that are not exported, and undocumented implementation details are not public API. Import only from `nexus-ai-pro` or one of its explicit subpaths.
16
+
17
+ ## Compatibility rules
18
+
19
+ - A public symbol will not be removed or incompatibly changed in a patch release.
20
+ - Deprecations will be documented before removal whenever practical.
21
+ - New optional fields, providers, exports, error subclasses, and enum-like union members may be added in a minor release.
22
+ - TypeScript improvements that expose previously invalid usage may arrive in a patch release.
23
+ - Security fixes may tighten validation or blocking behavior in a patch release when preserving the old behavior would leave users exposed.
24
+ - Provider behavior can change when an upstream API changes; Nexus will preserve its normalized request and response contracts where possible.
25
+
26
+ The package is ESM-only and supports Node.js 22 or newer. CommonJS `require()` and deep imports into `dist` or `src` are not supported.
27
+
28
+ ## Deprecation process
29
+
30
+ Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. During the 0.x series, removal will not normally occur earlier than the next minor release. After 1.0, removals will be reserved for major releases, except when an urgent security issue requires otherwise.
31
+
32
+ Report accidental compatibility regressions through the project issue tracker. Security issues should follow [SECURITY.md](./SECURITY.md).
package/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ Notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use semantic versioning while accounting for the pre-1.0 stability policy.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.9.0] - 2026-07-15
8
+
9
+ ### Added
10
+
11
+ - Full JSON Schema validation through Ajv and standard format validation through `ajv-formats`.
12
+ - Node.js 22 and 24 CI gates for linting, builds, tests, consumer type checks, and packed-package installation.
13
+ - OIDC trusted publishing with npm provenance for tagged releases.
14
+ - API stability, security, and contribution policies.
15
+ - Biome formatting/lint gates, test/example type checks, and built-in Node.js coverage thresholds.
16
+
17
+ ### Changed
18
+
19
+ - The supported runtime is now Node.js 22 or newer and the package is explicitly ESM-only.
20
+ - Provider, cache, and job entry points now use an explicit export map instead of wildcard exports.
21
+ - Published tarballs contain the runtime and essential package documentation, excluding repository examples and marketing assets.
22
+ - Provider peer dependency ranges are bounded to tested SDK lines.
23
+ - Build and publish scripts always clean and rebuild `dist` before packing.
24
+ - Security-enabled output streams validate the complete bounded response before yielding chunks.
25
+
26
+ ### Fixed
27
+
28
+ - Blocking output policies now stop unsafe completions instead of returning blocked content as successful output.
29
+ - Streaming redaction protects values that cross provider chunk boundaries.
30
+ - Provider timeouts abort in-flight completion and streaming requests.
31
+ - URL fetching rejects unsafe private-network targets and limits response reads.
32
+ - CLI and audit findings no longer disclose detected secret values.
33
+
34
+ [Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v0.9.0...HEAD
35
+ [0.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v0.9.0
package/README.md CHANGED
@@ -7,6 +7,7 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
7
7
  - NPM: https://www.npmjs.com/package/nexus-ai-pro
8
8
  - GitHub: https://github.com/mkhitar-abrahamyan/nexus-ai
9
9
  - Full technical notes and manual test cases: [NEXUS.md](./NEXUS.md)
10
+ - Planned image generation and infrastructure work: [ROADMAP.md](./ROADMAP.md)
10
11
 
11
12
  ## Install
12
13
 
@@ -14,6 +15,8 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
14
15
  npm install nexus-ai-pro
15
16
  ```
16
17
 
18
+ Requires Node.js 22 or newer. `nexus-ai-pro` is ESM-only: use `import` from an ES module rather than CommonJS `require()`.
19
+
17
20
  Install only the provider SDKs your app uses. The OpenAI SDK also powers OpenAI-compatible adapters such as OpenRouter, Groq, Mistral, DeepSeek, Azure OpenAI, LM Studio, and llama.cpp.
18
21
 
19
22
  ```bash
@@ -246,6 +249,12 @@ for await (const chunk of stream) {
246
249
 
247
250
  All providers normalize streaming chunks to `text`, `tool_call`, `done`, or `error`.
248
251
 
252
+ When security is enabled, output streams are correctness-first: Nexus buffers and validates the
253
+ complete output before yielding any chunk, up to 1 MiB or 100,000 chunks. This prevents secrets,
254
+ PII, and blocked phrases split across provider chunks from leaking partially, at the cost of
255
+ token-by-token latency. `security: 'off'` preserves immediate streaming when that trade-off is
256
+ explicitly acceptable for the application.
257
+
249
258
  ### Tools and Agents
250
259
 
251
260
  ```ts
@@ -559,6 +568,12 @@ Useful helpers:
559
568
  - URL and tool allowlist checks
560
569
  - reusable policies through `guardrailPolicy(...)`
561
570
  - `hardenPrompt(...)` for clearly delimiting untrusted input
571
+ - `createFetchUrlTool(...)` with DNS pinning, redirect validation, private-network blocking, and
572
+ bounded response reads
573
+
574
+ CLI scans and audit records redact detected values by default. `nexus scan --reveal-values` is
575
+ restricted to an interactive terminal; raw audit data requires both `includeSensitiveData: true`
576
+ and an explicit custom sink.
562
577
 
563
578
  ## Caching, Jobs, and Evals
564
579
 
@@ -670,7 +685,7 @@ import { RedisCacheAdapter } from 'nexus-ai-pro/cache';
670
685
  import { DeepSeekProvider } from 'nexus-ai-pro/providers/deepseek';
671
686
  ```
672
687
 
673
- Provider SDKs are optional peer dependencies. The package is ESM-first and marked with `sideEffects: false`.
688
+ Provider SDKs are optional peer dependencies. The package is ESM-only, supports Node.js 22+, and is marked with `sideEffects: false`. Only the entry points listed in the package export map are public; deep imports into `dist` or `src` are unsupported.
674
689
 
675
690
  ## Examples
676
691
 
@@ -686,7 +701,7 @@ npm run example:optimizer
686
701
  npm run example:agent
687
702
  ```
688
703
 
689
- Included example files cover:
704
+ Repository example files cover:
690
705
 
691
706
  - OpenTelemetry with Node HTTP and Express
692
707
  - BullMQ workers
@@ -701,19 +716,27 @@ Included example files cover:
701
716
 
702
717
  ```bash
703
718
  npm install
704
- npm run build
705
- npm test
706
- npm run test:types
707
- npm run test:clean-install
708
- npm run test:conformance:mock
719
+ npm run check
720
+ npm run check:release
709
721
  ```
710
722
 
723
+ `check` runs formatting and lint gates, source/test/example type checks, the build, unit and mock
724
+ conformance tests, coverage thresholds, package import checks, and an external type-consumer test.
725
+ `check:release` additionally verifies the dry-run tarball and a clean packed-package install.
726
+
711
727
  Real provider conformance is opt-in:
712
728
 
713
729
  ```bash
714
730
  npm run test:conformance:real
715
731
  ```
716
732
 
733
+ ## Roadmap
734
+
735
+ The next recommended feature family is first-class image generation and editing through a
736
+ provider-neutral `ImageManager`, portable asset types, durable operation handles, visual safety,
737
+ asset storage, and media-specific evaluations. The design and prioritized infrastructure backlog
738
+ are in [ROADMAP.md](./ROADMAP.md).
739
+
717
740
  ## Production Notes
718
741
 
719
742
  - Use direct or rules-based routing when model choice is already known.
package/ROADMAP.md ADDED
@@ -0,0 +1,188 @@
1
+ # nexus-ai-pro Roadmap
2
+
3
+ This roadmap is a design proposal, not a compatibility promise. Stable and experimental
4
+ surfaces are defined in [API_STABILITY.md](./API_STABILITY.md).
5
+
6
+ ## Recommended next release: first-class image generation
7
+
8
+ Image generation should be a separate operation family rather than another variation of
9
+ `complete()`. Text completions and generated assets have different request shapes, response
10
+ lifecycles, costs, safety checks, storage needs, and retry semantics.
11
+
12
+ The first public surface could look like this:
13
+
14
+ ```ts
15
+ const result = await ai.images.generate({
16
+ model: 'auto',
17
+ prompt: 'A clean product photograph of a red mechanical keyboard',
18
+ aspectRatio: '16:9',
19
+ quality: 'high',
20
+ delivery: { kind: 'bytes', format: 'png' },
21
+ });
22
+
23
+ await ai.images.edit({
24
+ model: 'auto',
25
+ prompt: 'Replace the background with a softly lit studio wall',
26
+ input: result.assets[0],
27
+ mask: {
28
+ location: { kind: 'bytes', data: maskBytes },
29
+ mimeType: 'image/png',
30
+ polarity: 'white-is-editable',
31
+ },
32
+ references: [styleReference],
33
+ });
34
+ ```
35
+
36
+ `auto` should resolve through versioned, verified aliases instead of making a model name part of
37
+ the durable API. OpenAI currently supports one-shot generation and editing through the Image API,
38
+ while the Responses API supports conversational, multi-turn image workflows. See the
39
+ [official image generation guide](https://developers.openai.com/api/docs/guides/image-generation)
40
+ and [GPT Image 2 model page](https://developers.openai.com/api/docs/models/gpt-image-2).
41
+
42
+ ### Recommended API boundary
43
+
44
+ - Add a lightweight `ImageManager` in `nexus-ai-pro/images`, following the voice manager pattern.
45
+ - Expose `ai.images.generate()`, `ai.images.edit()`, and `ai.images.submit()`.
46
+ - Let `generate()` and `edit()` wait for a result. Let `submit()` return an
47
+ `OperationHandle<TResult>` with `status()`, `result()`, `cancel()`, and `events()`.
48
+ - Add `registerImageProvider()`, `hasImageProvider()`, and `listImageProviders()`.
49
+ - Keep provider-neutral types in the core export and optional integrations in exports such as
50
+ `nexus-ai-pro/images/openai` and `nexus-ai-pro/images/comfyui`.
51
+
52
+ ### Media types
53
+
54
+ - Prefer `Uint8Array`, `Blob`, URLs, and web streams in public types; keep Node `Buffer` as a
55
+ convenience input rather than the portable core type.
56
+ - Use discriminated asset locations instead of several optional fields:
57
+ `{ kind: 'bytes'; data: Uint8Array }`, `{ kind: 'url'; url; expiresAt? }`, or
58
+ `{ kind: 'stored'; uri; assetId }`.
59
+ - Define `AssetInput`, `AssetDescriptor`, `ImageGenerateRequest`, `ImageEditRequest`,
60
+ `ImageResult`, `MediaUsage`, `MediaSafetyFinding`, `OperationEvent`, and
61
+ `OperationHandle<TResult>`.
62
+ - Keep dimensions, MIME type, checksum, storage location, and provenance on each asset. Put
63
+ latency, cost, route, and usage in result-level `OperationMeta`.
64
+ - Make `input`, `mask`, and `references` explicit for editing. Define mask polarity, sizing, and
65
+ resize rules so adapters cannot silently reinterpret a request.
66
+ - Model generation, editing, masking/inpainting, variations, and background transparency as
67
+ explicit capabilities.
68
+ - Split model capabilities into `inputModalities` and `outputModalities`, and retire the current
69
+ semantic overlap between `vision`, `image`, and `pdf`.
70
+
71
+ ### Provider architecture
72
+
73
+ - Introduce `ImageProvider` independently of the completion-shaped `BaseProvider`.
74
+ - Give every provider family a shared internal `ProviderCallContext` containing abort signal,
75
+ deadline, request ID, trace context, and idempotency key.
76
+ - Start with a deterministic mock provider and one hosted provider supporting generation and edit.
77
+ - Add a second cloud adapter and local ComfyUI before stabilizing the API; this exposes assumptions
78
+ around masks, seeds, negative prompts, polling, formats, and quality controls.
79
+ - Negotiate operation, input MIME types, mask support, dimensions, aspect ratio, transparency,
80
+ output format, and count. Unsupported options must fail or produce an explicit warning.
81
+ - Route by capability, latency, cost, quality, residency, and safety policy.
82
+
83
+ ### Asset and job pipeline
84
+
85
+ - Add an `AssetStore` interface with `put`, `get`, `stat`, `delete`, `sign`, retention, tenant
86
+ ownership, checksums, and streaming. Start with bounded memory/filesystem adapters, then add
87
+ S3-compatible storage.
88
+ - Treat provider URLs as temporary delivery locations, never as durable storage.
89
+ - Resolve remote inputs with SSRF protection, MIME sniffing, byte/pixel limits,
90
+ decompression-bomb protection, and a redirect policy.
91
+ - Put metadata stripping, provenance, and image transforms behind optional `AssetTransformer`
92
+ adapters so the core install stays small.
93
+ - Add visual input and output moderation; text-only security checks are not sufficient.
94
+ - Keep idempotency separate from generative caching. An idempotency key replays the same accepted
95
+ operation. Caching remains opt-in and keys on model version, policy version, parameters, and
96
+ source-asset hashes.
97
+ - Build a real operation state machine: queued, running, succeeded, failed, cancelling, cancelled,
98
+ and expired. Add leases/heartbeats, progress events, delayed retry, dead-letter handling,
99
+ cancellation, timestamps, signed webhooks, and trace propagation.
100
+ - Queue asset references only; never JSON-serialize binary media into job payloads.
101
+ - Reserve and reconcile budget using provider-appropriate pricing such as per-image, megapixel, or
102
+ compute time. Ambiguous timeouts must not create duplicate assets or charges.
103
+
104
+ ### Image evaluation
105
+
106
+ - Prompt/image semantic alignment and OCR accuracy for generated text.
107
+ - Perceptual similarity for edit preservation.
108
+ - Safety-policy pass rate and false-positive tracking.
109
+ - Latency, cost, retry, and provider failover metrics.
110
+ - Repeated-run statistical baselines for stochastic output, plus human-review queues.
111
+ - Brand/style reference kits, campaign variant matrices, prompt presets, and reproducibility
112
+ manifests.
113
+ - A generic evaluation target or parallel `MediaEvalRunner`; string-only golden-file tests are not
114
+ a useful image-quality gate.
115
+
116
+ ## Infrastructure improvements
117
+
118
+ ### One lifecycle for every operation
119
+
120
+ Create an internal typed lifecycle and adapt existing operations to it incrementally:
121
+
122
+ `validate -> authorize -> input policy -> resolve assets -> route -> reserve budget -> execute ->`
123
+ `output policy -> persist -> reconcile cost -> audit`
124
+
125
+ Completions, streams, embeddings, voice, images, and jobs should share the same authorization,
126
+ budget, hooks, audit, metrics, and finalization stages, including cache hits. Transport-specific
127
+ code should only perform the provider call and normalize its result.
128
+
129
+ ### Provider compatibility automation
130
+
131
+ - Maintain provider contract tests for minimum and latest supported SDK versions.
132
+ - Generate the model registry from versioned provider data with `verifiedAt` and source fields.
133
+ - Mark aliases as stable, preview, or deprecated and emit opt-in deprecation warnings.
134
+ - Record/replay provider fixtures so most conformance tests run without credentials.
135
+ - Detect capability drift so provider option loss cannot happen silently.
136
+
137
+ ### Durable production primitives
138
+
139
+ - Distributed rate-limit and circuit-breaker adapters.
140
+ - Idempotency, request deduplication, cancellation, progress, and operation-event adapters.
141
+ - Persistent conversation/session stores.
142
+ - Webhook delivery with signatures, retries, and a dead-letter queue.
143
+ - Resumable background operations for image/video generation and large eval runs.
144
+ - GPU-aware local scheduling, leases, heartbeats, and backpressure.
145
+
146
+ ### Observability and governance
147
+
148
+ - Standard operation spans and metrics across provider, model, modality, cache, retry, and cost.
149
+ - Tenant/project budget policies with reservation and reconciliation of actual usage.
150
+ - Redaction-safe audit records with stable finding IDs rather than sensitive values.
151
+ - OpenTelemetry semantic conventions plus trace propagation through queues and webhooks.
152
+ - An optional local control plane for approvals, traces, evals, costs, provider health, assets,
153
+ retention, and queued operations.
154
+
155
+ ### Smaller install surface
156
+
157
+ - Keep a small provider-neutral core.
158
+ - Move heavy or environment-specific integrations into optional exports or a future scoped package
159
+ family, including OpenTelemetry, BullMQ, image transforms, and provider adapters.
160
+ - Make browser/edge compatibility explicit by isolating Node filesystem, crypto, DNS, and stream
161
+ dependencies behind adapters.
162
+
163
+ ## Additional feature backlog
164
+
165
+ 1. True mixed text/asset outputs and tool results that pass asset references without base64 JSON.
166
+ 2. OCR, captioning, visual question answering, image embeddings, and visual moderation.
167
+ 3. Realtime voice/video sessions with interruption handling, turn detection, and live tool calls.
168
+ 4. Video generation through the same asynchronous operation, job, and asset contracts.
169
+ 5. Media search and RAG using image embeddings.
170
+ 6. MCP client/server adapters with asset and tool interoperability.
171
+ 7. Human approval checkpoints for high-impact tools and generated-media publication.
172
+ 8. Policy-as-code presets versioned independently from the runtime.
173
+ 9. Prompt/workflow versioning with offline replay and A/B evaluation.
174
+ 10. Multi-tenant credential-vault adapters and per-provider residency routing.
175
+
176
+ ## Suggested delivery order
177
+
178
+ 1. Stabilize the shared operation lifecycle and provider conformance suite.
179
+ 2. Add portable media types, `ImageManager`, `ImageProvider`, and a deterministic mock provider.
180
+ 3. Ship one hosted generate/edit adapter, bounded local asset storage, and visual safety hooks as
181
+ experimental APIs.
182
+ 4. Add the production asset store and operation state machine with progress, cancellation,
183
+ idempotency, and cost reconciliation.
184
+ 5. Add a second cloud provider and local ComfyUI to validate portability.
185
+ 6. Add true multimodal outputs and media evaluation.
186
+ 7. Promote the media API only after packed-package tests, provider conformance, and image evals
187
+ cover the supported capability matrix.
188
+
package/SECURITY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are provided for the latest published minor release. Users should upgrade to the newest `0.9.x` patch as fixes become available.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please use [GitHub private vulnerability reporting](https://github.com/mkhitar-abrahamyan/nexus-ai/security/advisories/new). Do not open a public issue for an undisclosed vulnerability and do not include real credentials, personal data, or exploit targets in a report.
10
+
11
+ Include the affected version, impact, a minimal reproduction, and any suggested mitigation. You can expect an acknowledgement within five business days. A confirmed issue will be coordinated privately until a fix and disclosure plan are ready.
12
+
13
+ ## Scope and safe operation
14
+
15
+ Nexus guardrails reduce common AI application risks, but they are not a complete authorization or security boundary. Applications remain responsible for access control, provider-side safety controls, tool authorization, network egress policy, secret storage, and review of high-impact model actions.
@@ -9,7 +9,9 @@ export function tool(definition) {
9
9
  export class ToolExecutor {
10
10
  tools = new Map();
11
11
  constructor(tools = []) {
12
- tools.forEach((toolDefinition) => this.register(toolDefinition));
12
+ for (const toolDefinition of tools) {
13
+ this.register(toolDefinition);
14
+ }
13
15
  }
14
16
  register(toolDefinition) {
15
17
  this.tools.set(toolDefinition.name, toolDefinition);
@@ -64,7 +64,9 @@ export class SQLiteCacheAdapter {
64
64
  return JSON.parse(row.value);
65
65
  }
66
66
  set(key, value, ttlSeconds = 300) {
67
- this.db.prepare(`INSERT OR REPLACE INTO ${this.table} (key, value, expires_at) VALUES (?, ?, ?)`).run?.(key, JSON.stringify(value), Date.now() + ttlSeconds * 1000);
67
+ this.db
68
+ .prepare(`INSERT OR REPLACE INTO ${this.table} (key, value, expires_at) VALUES (?, ?, ?)`)
69
+ .run?.(key, JSON.stringify(value), Date.now() + ttlSeconds * 1000);
68
70
  }
69
71
  delete(key) {
70
72
  this.db.prepare(`DELETE FROM ${this.table} WHERE key = ?`).run?.(key);
package/dist/cli.js CHANGED
@@ -7,11 +7,12 @@ import { EvalRunner } from './evals/runner.js';
7
7
  import { NexusAI } from './core/nexus.js';
8
8
  import { listKnownModels, listModelsForProvider, getModelCapabilities } from './models/registry.js';
9
9
  import { SecurityPipeline } from './security/index.js';
10
+ import { redactSensitiveText } from './security/output-guard.js';
10
11
  import { UploadScanner } from './security/upload-scanner.js';
11
12
  import { TokenOptimizer } from './optimizer/index.js';
12
13
  const DEFAULT_SCAN_MAX_BYTES = 1_000_000;
13
14
  const IGNORED_DIRS = new Set(['.git', 'node_modules', 'dist', 'coverage', '.next', '.turbo']);
14
- const BOOLEAN_FLAGS = new Set(['all', 'densify', 'fail', 'help', 'json', 'print']);
15
+ const BOOLEAN_FLAGS = new Set(['all', 'densify', 'fail', 'help', 'json', 'print', 'reveal-values']);
15
16
  async function main() {
16
17
  const [command, ...rest] = process.argv.slice(2);
17
18
  const parsed = parseArgs(rest);
@@ -37,6 +38,13 @@ async function main() {
37
38
  }
38
39
  }
39
40
  async function runScan({ positionals, flags }) {
41
+ const revealValues = flagBool(flags, 'reveal-values');
42
+ if (revealValues && flagBool(flags, 'json')) {
43
+ throw new Error('--reveal-values cannot be combined with --json because structured output is commonly persisted');
44
+ }
45
+ if (revealValues && !process.stdout.isTTY) {
46
+ throw new Error('--reveal-values requires an interactive terminal');
47
+ }
40
48
  const roots = positionals.length ? positionals : ['.'];
41
49
  const maxBytes = numberFlag(flags, 'max-bytes') ?? DEFAULT_SCAN_MAX_BYTES;
42
50
  const files = await collectFiles(roots, flagBool(flags, 'all'));
@@ -65,16 +73,20 @@ async function runScan({ positionals, flags }) {
65
73
  }
66
74
  }
67
75
  const ok = !findings.some((finding) => finding.severity === 'high' || finding.severity === 'critical');
76
+ const displayedFindings = revealValues ? findings : findings.map(sanitizeCliFinding);
68
77
  if (flagBool(flags, 'json')) {
69
- writeJson({ ok, scannedFiles: files.length, findings });
78
+ writeJson({ ok, scannedFiles: files.length, findings: displayedFindings });
70
79
  }
71
80
  else {
72
81
  console.log(`Scanned ${files.length} file${files.length === 1 ? '' : 's'}.`);
73
- if (!findings.length) {
82
+ if (!displayedFindings.length) {
74
83
  console.log('No secrets, PII, or prompt-injection risks found.');
75
84
  }
76
85
  else {
77
- for (const finding of findings) {
86
+ if (revealValues) {
87
+ console.error('WARNING: displaying raw sensitive finding values in this interactive terminal.');
88
+ }
89
+ for (const finding of displayedFindings) {
78
90
  const value = finding.value ? ` (${truncate(finding.value, 96)})` : '';
79
91
  console.log(`${finding.severity.toUpperCase()} ${finding.type} ${finding.file}: ${finding.message}${value}`);
80
92
  }
@@ -249,9 +261,7 @@ async function readRequest(file, flags) {
249
261
  };
250
262
  }
251
263
  function isCompletionRequest(value) {
252
- return isRecord(value)
253
- && typeof value.model === 'string'
254
- && Array.isArray(value.messages);
264
+ return isRecord(value) && typeof value.model === 'string' && Array.isArray(value.messages);
255
265
  }
256
266
  async function loadEvalFile(file) {
257
267
  const fullPath = path.resolve(file);
@@ -311,6 +321,14 @@ function isUsefulCliFinding(finding) {
311
321
  const digits = finding.value?.replace(/\D/g, '') || '';
312
322
  return digits.length >= 10;
313
323
  }
324
+ function sanitizeCliFinding(finding) {
325
+ return {
326
+ ...finding,
327
+ file: redactSensitiveText(finding.file),
328
+ message: redactSensitiveText(finding.message),
329
+ value: finding.value === undefined ? undefined : '[REDACTED]',
330
+ };
331
+ }
314
332
  function parseArgs(args) {
315
333
  const positionals = [];
316
334
  const flags = {};
@@ -385,10 +403,7 @@ function writeJson(value) {
385
403
  console.log(JSON.stringify(value, null, 2));
386
404
  }
387
405
  function printTable(rows, columns) {
388
- const widths = Object.fromEntries(columns.map((column) => [
389
- column,
390
- Math.max(column.length, ...rows.map((row) => row[column].length)),
391
- ]));
406
+ const widths = Object.fromEntries(columns.map((column) => [column, Math.max(column.length, ...rows.map((row) => row[column].length))]));
392
407
  console.log(columns.map((column) => column.padEnd(widths[column])).join(' '));
393
408
  console.log(columns.map((column) => '-'.repeat(widths[column])).join(' '));
394
409
  for (const row of rows) {
@@ -405,7 +420,7 @@ function printHelp() {
405
420
  console.log(`nexus-ai-pro CLI
406
421
 
407
422
  Usage:
408
- nexus scan [paths...] [--json] [--max-bytes 1000000] [--no-fail]
423
+ nexus scan [paths...] [--json] [--max-bytes 1000000] [--no-fail] [--reveal-values]
409
424
  nexus models [--provider openai] [--json]
410
425
  nexus eval <eval.json|eval.mjs> [--json]
411
426
  nexus optimize [request.json|prompt.txt] [--model gpt-5-mini] [--max-input-tokens 4000] [--densify] [--json]
@@ -413,6 +428,7 @@ Usage:
413
428
  Eval files can export { cases, client } or { cases, config }. JSON cases may use "expected", "contains", and "match": "includes" | "exact" | "regex".`);
414
429
  }
415
430
  main().catch((error) => {
416
- console.error(error instanceof Error ? error.message : error);
431
+ const message = error instanceof Error ? error.message : String(error);
432
+ console.error(redactSensitiveText(message));
417
433
  process.exitCode = 1;
418
434
  });
@@ -1,8 +1,20 @@
1
1
  import type { ToolDefinition } from '../types/messages.js';
2
+ export type WebResolvedAddress = string | {
3
+ address: string;
4
+ family?: 4 | 6;
5
+ };
2
6
  export interface WebConnectorOptions {
3
7
  allowedDomains?: string[];
4
8
  timeoutMs?: number;
5
9
  userAgent?: string;
10
+ maxResponseBytes?: number;
11
+ maxRedirects?: number;
12
+ /** Explicitly allow loopback/private targets, for example a trusted local development service. */
13
+ allowPrivateNetworks?: boolean;
14
+ /** Cloud metadata endpoints remain denied unless this separate high-risk opt-in is enabled. */
15
+ allowCloudMetadata?: boolean;
16
+ /** Optional resolver for split-horizon DNS or deterministic tests. Every returned address is validated. */
17
+ resolveHostname?: (hostname: string) => Promise<readonly WebResolvedAddress[]>;
6
18
  }
7
19
  export declare function createFetchUrlTool(options?: WebConnectorOptions): ToolDefinition;
8
20
  export declare function createSearchTool(search: (query: string) => Promise<unknown>, name?: string): ToolDefinition;