@nettoolskit/memory 0.0.1-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NetToolsKit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,791 @@
1
+ # NetToolsKit Memory
2
+
3
+ > Knowledge ingestion, local memory, RAG, HyDE, retrieval, context packages, and
4
+ > vault materialization for NetToolsKit.
5
+
6
+ ---
7
+
8
+ ## Introduction
9
+
10
+ `nettoolskit-memory` is the dedicated NetToolsKit repository for memory and
11
+ knowledge workflows that are currently being extracted from the historical
12
+ `nettoolskit-copilot` umbrella workspace.
13
+
14
+ This repository owns reusable memory capabilities and integrates with the rest
15
+ of the NetToolsKit ecosystem through explicit contracts, manifests, APIs, and
16
+ generated artifacts. It does not own agent instruction policy, machine control,
17
+ code generation, DevOps deployment, assurance testing, or product orchestration.
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - Knowledge record ingestion and normalized document contracts.
24
+ - Chunking, deterministic embedding contracts, injectable local embedding
25
+ provider boundary, provider-scoped vector retrieval, graph expansion, and
26
+ bounded context package assembly.
27
+ - Memory-owned LocalFirst SQLite vector functions for deterministic semantic
28
+ query readiness without a native extension dependency in the default build.
29
+ - Typed HyDE generator contract with deterministic default generation, stable
30
+ generator id/version provenance, orchestrator-supplied hypothesis intake,
31
+ cache-key isolation, and local-first query expansion.
32
+ - Request-bounded reusable Memory OS recall for validated or published
33
+ semantic/procedural records inside context packages and query answers.
34
+ - Repository-local operational memory for sessions, events, artifacts, and
35
+ replayable recall.
36
+ - Typed local operational memory APIs for sessions, runs, tool calls,
37
+ artifacts, validations, route decisions, and selected memory-record pruning.
38
+ - Durable CAG/cache contracts, SQLite persistence, and automatic LocalFirst
39
+ reuse for retrieval results, context packages, rerank results, and
40
+ groundedness-linked verified answers across process boundaries.
41
+ - Optional feature-gated shared PostgreSQL profile with pgvector-backed vector
42
+ search, PostgreSQL-backed graph expansion, persistent CAG/cache reuse,
43
+ reusable Memory OS records, and operational-memory persistence for enterprise
44
+ deployments.
45
+ - Vault materialization for grouped Markdown knowledge records and generated
46
+ vault manifests.
47
+ - Explicit memory-engine facade for downstream command adapters and product
48
+ runtimes.
49
+ - Contract-aligned `nettoolskit.manifest.json` for service discovery by
50
+ NetToolsKit orchestrators and control surfaces.
51
+ - Local `ntk-memory` CLI commands for manifest rendering, workspace
52
+ materialization, vault materialization, and bounded knowledge queries.
53
+ - Optional caller-gated verified answer cache reuse for `ntk-memory query`
54
+ request files that provide a verification token and pass deterministic
55
+ groundedness validation.
56
+ - Dedicated `ntk-memory context-package` command for RAG/CAG/HyDE context
57
+ assembly without answer text.
58
+ - Hybrid Search V2 contracts for deterministic BM25-style lexical scoring,
59
+ normalized vector plus lexical fusion, field-match explainability, and
60
+ bounded context-package candidate windows.
61
+ - Deterministic reranker contracts with score-component explainability,
62
+ request-activated execution, and typed rerank-result cache keys.
63
+ - Contextual compression contracts that retain source-backed spans, citations,
64
+ source text hashes, matched query terms, and compression metrics without
65
+ generating answer text.
66
+ - Deterministic groundedness validation for caller-provided answer text against
67
+ retained context-package evidence, with supported terms, unsupported terms,
68
+ evidence matches, and machine-readable reason codes.
69
+ - Content-free RAG quality observability contracts for stage latency, counts,
70
+ cache hit/miss, scores, compression ratio, groundedness score, and bounded
71
+ reason codes without raw prompts, answers, snippets, or evidence text.
72
+ - Sanitized DET context evidence export contract, golden example, fixture, and
73
+ runbook for local effectiveness evidence, including DET `use_det`, `hold`,
74
+ and `blocked` package decisions plus sanitized metrics host/provider binding
75
+ without raw prompts, secrets, provider payloads, local paths, or unredacted
76
+ user content.
77
+ - Local `ntk-memory` CLI commands for operational memory write, read, and
78
+ prune operations.
79
+ - Profile-aware `ntk-memory memory-record-*` CLI commands for reusable Memory OS
80
+ record write, read, promotion, and prune operations.
81
+ - Deterministic `ntk-memory doctor` readiness checks for LocalFirst and shared
82
+ PostgreSQL stores, persistent CAG/cache table and indexes, round-trip cache
83
+ writes, query lanes, and enterprise memory-lane selection.
84
+ - Experimental Rust crate implementation extracted from the historical
85
+ `nettoolskit-copilot` knowledge foundation.
86
+
87
+ ---
88
+
89
+ ## Contents
90
+
91
+ - [Introduction](#introduction)
92
+ - [Features](#features)
93
+ - [Architecture](#architecture)
94
+ - [Responsibility Boundary](#responsibility-boundary)
95
+ - [Source Extraction Map](#source-extraction-map)
96
+ - [Storage Model](#storage-model)
97
+ - [Persistent CAG Cache API](#persistent-cag-cache-api)
98
+ - [Local Operational Memory API](#local-operational-memory-api)
99
+ - [Control Plane Model](#control-plane-model)
100
+ - [Rust Crate](#rust-crate)
101
+ - [Local CLI](#local-cli)
102
+ - [Compatibility and Support](#compatibility-and-support)
103
+ - [Operations](#operations)
104
+ - [Planning](#planning)
105
+ - [Governance and Security](#governance-and-security)
106
+ - [Build and Tests](#build-and-tests)
107
+ - [Contributing](#contributing)
108
+ - [Dependencies](#dependencies)
109
+ - [References](#references)
110
+ - [License](#license)
111
+
112
+ ---
113
+
114
+ ## Architecture
115
+
116
+ ```mermaid
117
+ flowchart TD
118
+ agent[nettoolskit-agent]
119
+ memory[nettoolskit-memory]
120
+ copilot[nettoolskit-copilot]
121
+ control[nettoolskit-control]
122
+ rust[nettoolskit-rust]
123
+ docs[docs/knowledge-base]
124
+ store[.build/knowledge/store]
125
+ local[.temp/context-memory]
126
+ vault[.deployment/artifacts/knowledge-vault]
127
+
128
+ agent -->|policy and validation rules| copilot
129
+ copilot -->|runtime decisions| memory
130
+ copilot --> control
131
+ memory --> rust
132
+ memory --> docs
133
+ memory --> store
134
+ memory --> local
135
+ memory --> vault
136
+ ```
137
+
138
+ `nettoolskit-memory` is the memory execution boundary. It consumes policy and
139
+ contracts from other repositories but keeps ingestion, retrieval, persistence,
140
+ and context-package behavior behind memory-owned APIs.
141
+
142
+ The current Rust implementation is intentionally extracted without deleting the
143
+ historical `nettoolskit-copilot` sources. A later compatibility-adapter PR will
144
+ decide when `nettoolskit-copilot` starts consuming this repository directly.
145
+
146
+ ---
147
+
148
+ ## Responsibility Boundary
149
+
150
+ | Repository | Owns |
151
+ | --- | --- |
152
+ | `nettoolskit-agent` | Instructions, prompts, governance, validation, model-routing policy, context-economy policy, and memory/RAG/HyDE usage rules. |
153
+ | `nettoolskit-memory` | Knowledge ingestion, chunking, embeddings, retrieval, graph expansion, HyDE, context packages, local memory, and vault materialization. |
154
+ | `nettoolskit-copilot` | Runtime orchestration, prompt middleware, model selection, approval coordination, and product workflow composition. |
155
+ | `nettoolskit-control` | Machine workers, leases, command execution, approvals, and evidence collection. |
156
+ | `nettoolskit-codegen` | Code generation, scaffolding, refactor planning, and architecture validation. |
157
+ | `nettoolskit-assurance` | Security, performance, benchmark, OpenAPI, frontend, and quality gate validation. |
158
+ | `nettoolskit-devops` | Docker, images, deployment, backup, observability, proxy, and operations. |
159
+ | `nettoolskit-rust` | Generic Rust core, contracts, CLI, observability, adapters, validation, and specification foundations. |
160
+
161
+ ---
162
+
163
+ ## Source Extraction Map
164
+
165
+ Initial source material comes from `nettoolskit-copilot`:
166
+
167
+ | Current source | Target ownership |
168
+ | --- | --- |
169
+ | `crates/knowledge` | Move to `nettoolskit-memory` as the primary knowledge and retrieval crate. |
170
+ | `crates/memory/engine` | Replace with `nettoolskit_memory::engine` as the memory facade. |
171
+ | `crates/control/runtime/src/continuity/local_context.rs` | Split memory-owned persistence/retrieval from runtime command orchestration. |
172
+ | `crates/control/runtime/src/maintenance/prune_local_memory.rs` | Move local memory retention logic to `nettoolskit-memory`; keep runtime command wiring in the caller. |
173
+ | `docs/knowledge-base/**` | Keep durable authored knowledge records versioned in the owning product repository; memory provides validation and processing APIs. |
174
+
175
+ Do not delete or deprecate the existing `nettoolskit-copilot` sources until the
176
+ new memory crate has mirrored tests, a compatibility adapter, and a confirmed
177
+ consumer integration path.
178
+
179
+ ---
180
+
181
+ ## Storage Model
182
+
183
+ Generated stores are rebuildable runtime artifacts and must not be committed.
184
+
185
+ | Store | Purpose |
186
+ | --- | --- |
187
+ | `.build/knowledge/store/knowledge.db` | Rebuildable knowledge store for ingestion, vector retrieval, durable graph state, persistent CAG/cache entries, and materialized workspace state. |
188
+ | Shared PostgreSQL schema | External shared store selected only through `SharedPostgresqlSettings` and a connection-string environment variable. |
189
+ | `.temp/context-memory/context.db` | Rebuildable local operational memory for sessions, events, artifacts, and recall. |
190
+ | `.deployment/artifacts/knowledge-vault/**` | Generated vault and validation artifacts for review or publication. |
191
+ | `docs/knowledge-base/**` | Durable authored knowledge records owned by the product or domain repository. |
192
+
193
+ The default Rust crate writes local operational-memory, graph, and persistent
194
+ CAG/cache API data to the repository-local SQLite schema under
195
+ `.build/knowledge/store/knowledge.db`. The optional `shared-postgresql` Cargo
196
+ feature adds `SharedPostgresqlSettings`, `PostgresVectorRepository`,
197
+ `PostgresGraphRepository`, `PostgresPersistentCacheBackend`,
198
+ `PostgresMemoryRecordBackend`, and `PostgresOperationalMemoryBackend` for
199
+ explicit shared deployments. Shared PostgreSQL configuration names the
200
+ environment variable that contains the connection string; the value itself must
201
+ never be committed, logged, or emitted in artifacts. Shared operational memory
202
+ for sessions, runs, tool calls, artifacts, validations, and route decisions uses
203
+ the same `persistence_profile`/`shared_postgresql` request shape in the
204
+ contract pack. Legacy
205
+ `.temp/context-memory/context.db` remains listed as extraction source material
206
+ until downstream runtime adapters move to the memory-owned API.
207
+
208
+ ---
209
+
210
+ ## Persistent CAG Cache API
211
+
212
+ The persistent cache API is the durable boundary for reusable CAG state. It
213
+ stores typed cache entries as JSON payloads with deterministic keys, stable
214
+ payload hashes, creation timestamps, optional expiration timestamps, and schema
215
+ versions.
216
+
217
+ The API exposes:
218
+
219
+ | Contract | Purpose |
220
+ | --- | --- |
221
+ | `PersistentCacheEntry` | Validated durable cache row for retrieval results, context packages, or verified idempotent results. |
222
+ | `PersistentCachePolicy` | Materialized-workspace policy that enables/disables durable cache kinds and sets per-kind TTLs. |
223
+ | `PersistentCacheReadRequest` | Reads one cache entry and treats expired rows as misses unless `include_expired` is explicit. |
224
+ | `PersistentCachePruneRequest` | Selects entries by kind, expiration, schema version, or payload hash and supports dry-run mode. |
225
+ | `persist_persistent_cache_entry` | Upserts one validated cache entry into the repository-local SQLite store. |
226
+ | `read_persistent_cache_entry` | Reads one cache entry through the TTL-aware typed read path. |
227
+ | `prune_persistent_cache_entries` | Deletes or previews selected cache rows without exposing a shell-like deletion surface. |
228
+ | `probe_persistent_cache_readiness` | Validates the persistent-cache table, required indexes, TTL-aware reads, and doctor-owned write/read/prune round-trip. |
229
+
230
+ This API does not decide which model, prompt, or orchestration lane should use
231
+ a cached value. That decision remains in `nettoolskit-copilot`; this repository
232
+ owns the deterministic storage and validation surface. Within
233
+ `nettoolskit-memory`, materialized workspaces automatically read and write
234
+ durable cache entries when the selected repository resolver provides a
235
+ `PersistentCacheBackend`. LocalFirst attaches the SQLite backend by default;
236
+ the feature-gated shared PostgreSQL profile attaches
237
+ `PostgresPersistentCacheBackend` when explicit safe settings are provided. The
238
+ same resolver selects the reusable Memory OS backend, so materialization can
239
+ publish and recall reusable memory records through SQLite or shared PostgreSQL
240
+ without changing caller code. Both profiles use a workspace content fingerprint
241
+ to avoid stale reuse after source changes.
242
+
243
+ Automatic LocalFirst cache writes use kind-specific TTLs by default:
244
+
245
+ | Cache kind | Default TTL |
246
+ | --- | --- |
247
+ | `query_embedding` | 21,600 seconds |
248
+ | `retrieval_result` | 21,600 seconds |
249
+ | `rerank_result` | 21,600 seconds |
250
+ | `context_package` | 86,400 seconds |
251
+ | `verified_idempotent_result` | 604,800 seconds |
252
+
253
+ `PersistentCachePolicy` can disable individual durable cache kinds or set a
254
+ custom positive TTL. A `ttl_seconds` value of `null` keeps that kind enabled
255
+ without an automatic expiration timestamp. Manual `ntk-memory cache-write`
256
+ requests remain explicit `PersistentCacheEntry` payloads and can still provide
257
+ their own `expires_at_unix_seconds` per entry.
258
+
259
+ Retrieval and context-package cache keys include an explicit enterprise
260
+ filter-scope fingerprint. Tenant, access role, document version, domain,
261
+ publication date windows, content root, source path, language, document kind,
262
+ and lexical shortlist filters therefore cannot reuse cache entries across
263
+ different retrieval scopes. Context-package cache keys also include the HyDE
264
+ generator id and version when HyDE mode is active, the contextual compression
265
+ profile scope when compression is enabled, and the rerank profile plus result
266
+ budget when reranking is enabled, so generator, compression, or rerank changes
267
+ do not reuse stale packages from a different evidence shape.
268
+
269
+ Query embedding cache keys are narrower by design. They include provider id,
270
+ provider version, vector dimension, and a query text hash, but never the raw
271
+ query text. This allows the same query vector to be reused across different
272
+ tenant/filter/budget scopes while retrieval-result cache entries remain scoped
273
+ to the full request.
274
+
275
+ Rerank-result cache keys include reranker id, reranker version, profile id,
276
+ query text, result budget, and a fingerprint of the candidate window. The
277
+ deterministic reranker runs when `KnowledgeQueryRequestInput` sets
278
+ `enable_rerank: true` with a positive `max_rerank_hits`; selecting a
279
+ model-assisted reranker or fallback policy remains the responsibility of the
280
+ calling orchestrator.
281
+
282
+ Verified answer reuse is always caller-gated. The memory service stores and
283
+ reuses verified idempotent answer text only when the query request includes a
284
+ non-empty `verification_token` and deterministic groundedness validation accepts
285
+ the answer against the retained context package. Verified answer cache keys also
286
+ include `answer_generation_scope`: the safe provider/model/model version surface
287
+ that produced the answer candidate. This prevents verified answers generated by
288
+ different providers, models, or model versions from reusing the same cache row.
289
+ The durable payload is a `VerifiedAnswerCacheEntry` with answer hash,
290
+ context-package hash, verification-token fingerprint, answer generation scope,
291
+ and the accepted groundedness result. Provider answers produced outside memory
292
+ must be persisted through `ntk-memory verified-answer-cache-write`, which
293
+ rebuilds the query context and computes Memory-owned cache keys and hashes
294
+ instead of asking callers to submit low-level `PersistentCacheEntry` rows. The
295
+ command output contains only cache metadata and hashes; it does not echo answer
296
+ text or verification tokens. Deciding when to call providers, retry, degrade, or
297
+ expose cached answers remains in the calling orchestrator.
298
+
299
+ Provider and model identifiers in `answer_generation_scope` are cache scope
300
+ tokens, not configuration channels. They must be stable, non-secret identifiers
301
+ and must not contain credentials, bearer tokens, prompts, answer text,
302
+ transcripts, request headers, customer data, local filesystem paths, database
303
+ URLs, or other environment-specific secrets.
304
+
305
+ `ntk-memory doctor` uses a controlled persistent-cache probe to verify the
306
+ table, indexes, TTL miss behavior, and write/read/prune behavior. The probe
307
+ removes its doctor-owned row before reporting success and does not prune
308
+ runtime cache rows.
309
+
310
+ ---
311
+
312
+ ## Local Operational Memory API
313
+
314
+ The local operational memory API is adapter-facing and deterministic. It writes
315
+ sessions, runs, tool calls, artifacts, validations, and route decisions through
316
+ `OperationalMemoryWriteBatch`. Batch writes are atomic: if one child row fails,
317
+ the full write is rolled back.
318
+
319
+ `OperationalMemoryReadRequest` applies session and run filters as an
320
+ intersection. Session filters constrain matching runs and child rows; run
321
+ filters constrain parent sessions and child rows. Route decisions are filtered
322
+ independently by `route_kind`.
323
+
324
+ Operational payloads must be sanitized before persistence. The crate rejects
325
+ null payloads, artifact paths outside repository-relative form, common local
326
+ path markers, and secret-like token markers. Runtime adapters must summarize
327
+ large logs before calling this API.
328
+
329
+ `MemoryRecordPruneRequest` requires at least one explicit selection filter and
330
+ supports dry-run mode. Non-dry-run prune deletes selected memory records and
331
+ their source-memory promotion rows in one transaction.
332
+
333
+ ---
334
+
335
+ ## Control Plane Model
336
+
337
+ `nettoolskit-memory` exposes deterministic memory capabilities through typed
338
+ contracts and command-ready APIs. It does not decide which model to use, when to
339
+ call an LLM, which worker executes a task, or whether an approval gate passes.
340
+
341
+ Runtime orchestration belongs to `nettoolskit-copilot`. Machine execution
342
+ belongs to `nettoolskit-control`. Generic CLI building blocks belong to
343
+ `nettoolskit-rust`.
344
+
345
+ ---
346
+
347
+ ## Rust Crate
348
+
349
+ This repository uses the product-repository single-crate layout.
350
+
351
+ | Path | Package | Responsibility |
352
+ | --- | --- | --- |
353
+ | `src/**` | `nettoolskit-memory` | Knowledge ingestion, retrieval, context packages, local memory, and vault materialization. |
354
+ | `src/engine/**` | `nettoolskit-memory` | Grouped public facade for downstream adapters and product runtimes. |
355
+ | `src/local/**` | `nettoolskit-memory` | Local operational memory contracts for sessions, runs, artifacts, validations, route decisions, and prune requests. |
356
+ | `tests/**` | `nettoolskit-memory` | Mirrored integration tests for the source modules. |
357
+
358
+ Cargo build output is configured under `.build/target` through
359
+ `.cargo/config.toml`.
360
+
361
+ The crate exposes the typed HyDE generator boundary through `HydeGenerator`,
362
+ `DeterministicHydeGenerator`, `SuppliedHydeGenerator`, `HydeHypothesis`, and
363
+ `SuppliedHydeHypothesis`, with generator id/version provenance retained in
364
+ context package output. Supplied HyDE is a data-only contract for external
365
+ orchestrators such as `nettoolskit-copilot`; memory validates the query match
366
+ and provenance fields, then uses the hypothesis for retrieval and cache scope.
367
+ The cache scope preserves the external generator id/version and adds a
368
+ hypothesis-text fingerprint so different supplied hypotheses cannot reuse the
369
+ same context package accidentally. Prompt templates, model routing,
370
+ credentials, retries, and orchestration policy remain outside this repository.
371
+
372
+ The default local orchestrator uses `HashBucketEmbeddingProvider` for
373
+ deterministic development and test runs. Downstream Rust consumers can inject a
374
+ custom local `EmbeddingProvider` through `LocalKnowledgeOrchestrator` while
375
+ keeping provider id/version provenance in embeddings, retrieval explanations,
376
+ and cache keys. This crate does not implement network embedding providers or
377
+ own provider secrets.
378
+
379
+ ---
380
+
381
+ ## Local CLI
382
+
383
+ The repository builds a local-process binary named `ntk-memory`. It is the
384
+ preferred adapter boundary for product orchestrators that should call memory
385
+ capabilities without linking to memory internals.
386
+
387
+ Supported commands:
388
+
389
+ | Command | Purpose |
390
+ | --- | --- |
391
+ | `ntk-memory manifest [--output <path>]` | Render the service manifest as deterministic JSON. |
392
+ | `ntk-memory materialize --request <path> [--output <path>]` | Ingest and index a bounded workspace through the request-selected memory persistence profile. |
393
+ | `ntk-memory query --request <path> [--output <path>]` | Run vector retrieval, graph expansion, HyDE, reusable memory recall, context package assembly, profile-backed persistence, and optional caller-gated verified answer reuse. |
394
+ | `ntk-memory context-package --request <path> [--output <path>]` | Assemble a bounded context package with retrieval evidence, reusable memory recall, and profile-backed cache metadata without answer text. |
395
+ | `ntk-memory groundedness-validate --request <path> [--output <path>]` | Validate caller-provided answer text against retained context-package evidence without model routing or answer generation. |
396
+ | `ntk-memory verified-answer-cache-write --request <path> [--output <path>]` | Rebuild the query context, validate a provider answer, and persist verified answer cache state with Memory-owned keys and hashes. |
397
+ | `ntk-memory vault-materialize --request <path> [--output <path>]` | Materialize grouped Markdown knowledge vault records and a vault manifest. |
398
+ | `ntk-memory doctor --repo-root <path> [--request <path>] [--output <path>]` | Report LocalFirst or request-selected shared PostgreSQL runtime readiness for enterprise RAG/CAG/HyDE/context/verified-cache/operational-memory lanes. |
399
+ | `ntk-memory cache-write --repo-root <path> --request <path> [--output <path>]` | Persist one durable CAG/cache entry. |
400
+ | `ntk-memory cache-read --repo-root <path> --request <path> [--output <path>]` | Read one durable CAG/cache entry with TTL-aware miss semantics. |
401
+ | `ntk-memory cache-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected durable CAG/cache entries with explicit filters and dry-run support. |
402
+ | `ntk-memory local-write --repo-root <path> --request <path> [--output <path>]` | Persist a repository-local operational memory write batch. |
403
+ | `ntk-memory local-read --repo-root <path> --request <path> [--output <path>]` | Read repository-local operational memory rows with deterministic filters. |
404
+ | `scripts/operations/write-det-local-first-use-memory.ps1` | Write `.deployment/artifacts/memory/det-local-first-use-write.json` for DET `runtime-wrapper` readiness. |
405
+ | `ntk-memory local-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected Memory OS records with explicit filters and dry-run support. |
406
+ | `ntk-memory memory-record-write --repo-root <path> --request <path> [--output <path>]` | Persist validated reusable Memory OS records through the request-selected profile. |
407
+ | `ntk-memory memory-record-read --repo-root <path> --request <path> [--output <path>]` | Read reusable Memory OS records and optional promotion metadata through the request-selected profile. |
408
+ | `ntk-memory memory-record-promote --repo-root <path> --request <path> [--output <path>]` | Persist an explicit Memory OS promotion and its target record through the request-selected profile. |
409
+ | `ntk-memory memory-record-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected Memory OS records through the public profile-aware record adapter surface. |
410
+
411
+ Request files use the Rust API payloads `KnowledgeWorkspaceRequestInput`,
412
+ `KnowledgeQueryRequestInput`, and `KnowledgeVaultBuildRequestInput`. The
413
+ `query` command returns answer text plus the context package; `context-package`
414
+ returns only retrieval package data and cache metadata. `vault-materialize`
415
+ uses `output_root` from the request JSON as the Markdown vault destination;
416
+ the CLI `--output` flag is only the machine-readable JSON report destination.
417
+ Outputs are machine-readable JSON. When `--output` is omitted, the command
418
+ writes JSON to stdout.
419
+
420
+ Workspace-backed commands default to `local_first`. Callers can select
421
+ `shared_postgresql` by adding `persistence_profile: "shared_postgresql"` and a
422
+ secret-safe `shared_postgresql` settings object to the workspace request. The
423
+ settings object names the environment variable containing the connection string
424
+ and never carries the secret value itself. If the optional
425
+ `shared-postgresql` Cargo feature or required environment variable is missing,
426
+ the command fails closed with a sanitized profile/readiness error and does not
427
+ bootstrap the repository-local SQLite store.
428
+
429
+ `KnowledgeQueryRequestInput` can opt into reusable Memory OS recall with
430
+ `enable_reusable_memory_recall: true` and a positive
431
+ `max_reusable_memory_hits` budget. When enabled, local-first materialization
432
+ loads validated or published `semantic` and `procedural` records from
433
+ `memory_items`; recalled records appear as `memory_record` snippets, evidence,
434
+ and the optional `reusable_memory_recall` output block. The cache key includes
435
+ a reusable-memory scope fingerprint so changed memory records cannot reuse a
436
+ stale context package.
437
+
438
+ `KnowledgeQueryRequestInput` can also apply enterprise retrieval scope filters:
439
+ `tenant_id`, `access_roles`, `document_version`, `domain`,
440
+ `min_published_at_unix_seconds`, and `max_published_at_unix_seconds`. These
441
+ filters are optional for compatibility, but when a caller supplies them memory
442
+ fails closed: a chunk without matching metadata is excluded from lexical
443
+ prefiltering, vector retrieval, context packages, and cache reuse.
444
+
445
+ When `enable_lexical_prefilter` is true with a positive `max_lexical_hits`,
446
+ memory scores the lexical corpus with the `LexicalScoringProfile` contract and
447
+ applies the same enterprise filters before scoring. Context-package assembly
448
+ then uses `HybridFusionProfile` to normalize and fuse vector and lexical
449
+ scores, emitting `vector_score`, `lexical_score`, `fusion_score`, ranking
450
+ stages, matched lexical fields, and the fusion profile in retrieval
451
+ explanations. Default behavior remains semantic-only unless the request enables
452
+ lexical prefiltering.
453
+
454
+ Contextual compression is exposed as a memory-owned package assembly primitive.
455
+ When a caller supplies `context_compression_profile`, memory replaces package
456
+ snippets with retained source spans and emits `compression.retained_spans` plus
457
+ `compression.metrics`. The retained text is copied from source snippets only;
458
+ model routing, deciding whether compression is worth the latency/cost tradeoff,
459
+ and answer generation remain caller responsibilities.
460
+
461
+ Deterministic reranking is request-activated. When `enable_rerank` is true,
462
+ memory applies `rerank_profile` or the default deterministic profile after
463
+ semantic or hybrid retrieval, caps output with `max_rerank_hits`, emits the
464
+ optional `context_package.rerank` block, and updates retained snippets and
465
+ evidence ordering before optional compression.
466
+
467
+ Groundedness validation is exposed as `GroundednessValidationRequest`,
468
+ `GroundednessValidationResult`, and `ntk-memory groundedness-validate`. The
469
+ validator compares caller-provided answer text against retained context-package
470
+ snippets or compression spans, emits supported and unsupported terms plus
471
+ reason codes, and never calls an LLM. Retry, degrade, or final-answer policy
472
+ remains owned by the caller.
473
+
474
+ RAG quality observability is exposed as `RagQualityReport`,
475
+ `RagQualityStageMetric`, and the `rag-quality-report` contract. Reports are
476
+ intentionally content-free: they use hashes for request, tenant, and query
477
+ scope and only store stage status, latency, counts, cache hit/miss, normalized
478
+ scores, compression ratio, token/cost counters, profile ids, and bounded reason
479
+ codes. Prompt text, answer text, HyDE text, snippets, retained spans, evidence
480
+ text, workstation paths, and secret values must stay out of these reports.
481
+ `query` and `context-package` attach `quality_report` only when
482
+ `emit_quality_report` is true.
483
+
484
+ DET context evidence export is represented by `det-context-evidence-export`.
485
+ It is a pending contract and fixture for DET, Harness, and Analytics local
486
+ effectiveness evidence derived from existing context-package, quality-report,
487
+ groundedness, and cache metadata. The export is content-free by contract and
488
+ uses only hashes, counts, booleans, bounded reason codes, safe identifiers, and
489
+ normalized scores. It must not include prompts, query text, snippets, retained
490
+ spans, provider payloads, answer text, secrets, local paths, or unredacted user
491
+ content. The optional `effectiveness.det_local_effectiveness_package` object
492
+ models DET's local effectiveness bridge with a `use_det`, `hold`, or `blocked`
493
+ decision and sanitized metrics binding where the host is hashed and the metrics
494
+ provider is represented only by safe identifiers.
495
+
496
+ For LocalFirst workspaces, query embeddings, retrieval results, context
497
+ packages, rerank results, and verified answers can reuse durable cache rows
498
+ from previous processes. Public response status fields currently expose
499
+ `cache_status.retrieval_result_cache_hit`,
500
+ `cache_status.context_package_cache_hit`, and
501
+ `cache_status.verified_idempotent_result_cache_hit` may reflect durable hits
502
+ from a previous process. Verified answer reuse still requires an explicit
503
+ `verification_token` in the `KnowledgeQueryRequestInput` JSON plus a validated
504
+ groundedness-linked cache payload, so unverified or unsupported `query` calls
505
+ never reuse answer text across processes.
506
+
507
+ CLI query and context-package commands use the deterministic HyDE generator by
508
+ default and include HyDE generator provenance in returned context metadata when
509
+ HyDE mode is active. Request JSON can instead provide
510
+ `supplied_hyde_hypothesis` with `query_text`, `hypothesis_text`,
511
+ `generator_id`, `generator_version`, and `provenance`. Memory rejects blank
512
+ fields, rejects query mismatches, and accepts supplied HyDE only for
513
+ HyDE-assisted retrieval.
514
+
515
+ Operational-memory commands keep payload hygiene fail-closed for local paths
516
+ and secret-like values before any write reaches persistence. Their current
517
+ LocalFirst request shape remains valid; the contract pack also publishes
518
+ shared PostgreSQL examples for `local-write` and `local-read` using
519
+ `persistence_profile: "shared_postgresql"` plus secret-safe
520
+ `shared_postgresql` settings.
521
+
522
+ Persistent-cache command request files use the Rust API payloads
523
+ `PersistentCacheEntry`, `PersistentCacheReadRequest`, and
524
+ `PersistentCachePruneRequest`. `cache-write` returns the persisted entry
525
+ identity, and `cache-read` returns `null` when an entry does not exist or is
526
+ expired and `include_expired` is false.
527
+
528
+ Verified provider answer cache writes use
529
+ `VerifiedAnswerCacheWriteCommandRequest`, which wraps the original
530
+ `KnowledgeQueryRequestInput`, provider `answer_text`, and
531
+ `answer_generation_scope` with provider/model/model version identifiers. The
532
+ nested query must include `verification_token`; if it also includes
533
+ `query.answer_generation_scope`, the two scopes must match. Memory rebuilds the
534
+ context package, validates groundedness, writes the provider/model/model-version
535
+ scoped verified cache row, and returns `VerifiedAnswerCacheWriteResult` with
536
+ only cache metadata and hashes.
537
+
538
+ Operational command request files use the Rust API payloads
539
+ `OperationalMemoryWriteBatch`, `OperationalMemoryReadRequest`, and
540
+ `MemoryRecordPruneRequest`. The operational-memory schemas accept both the
541
+ current LocalFirst shape and the profile-aware shared PostgreSQL shape so
542
+ callers can prepare requests without changing command names.
543
+
544
+ ### Adapter Contract Pack
545
+
546
+ Versioned adapter contracts live under [contracts](contracts/README.md).
547
+ The pack publishes JSON schemas in `contracts/schemas/v1` and sanitized golden
548
+ examples in `contracts/examples/v1` for query, context-package, supplied HyDE,
549
+ doctor, RAG quality reports, DET context evidence exports, persistent cache,
550
+ reusable memory records, local operational memory, and CLI error envelopes.
551
+ `nettoolskit.manifest.json` references these files through its `contracts`
552
+ array so orchestrators can discover request and response shapes without
553
+ linking to memory internals.
554
+
555
+ Consumers should call `ntk-memory doctor --repo-root <path>` before expensive
556
+ query paths, or `ntk-memory doctor --repo-root <path> --request <path>` when
557
+ checking a request-selected shared PostgreSQL profile. They should then call
558
+ `ntk-memory query` or `ntk-memory context-package` with request JSON that
559
+ matches the published schema. Runtime outputs, stdout, stderr, and reports
560
+ should be stored as harness evidence instead of reading the SQLite or
561
+ PostgreSQL store directly.
562
+
563
+ `doctor` is designed for orchestrators and operators. It requires an explicit
564
+ repository root. Without a request file it initializes the real
565
+ `.build/knowledge/store/knowledge.db` store, validates persistent-cache
566
+ table/index/TTL/prune readiness, registers the Memory-owned SQLite vector
567
+ function lane, and returns a stable LocalFirst readiness report. With a
568
+ `memory-doctor-request` file that selects `shared_postgresql`, it validates only
569
+ secret-safe settings, probes shared PostgreSQL pgvector, persistent-cache, and
570
+ operational-memory readiness, and does not bootstrap the LocalFirst SQLite
571
+ store. Shared PostgreSQL readiness failures are reported as `degraded` JSON
572
+ with exit code zero so the caller can decide whether to fail, retry, or fall
573
+ back before running an expensive query path.
574
+
575
+ ### Doctor Readiness JSON
576
+
577
+ The readiness report is intentionally repo-relative and safe for generated
578
+ artifacts. It does not expose workstation absolute paths. The current schema
579
+ includes:
580
+
581
+ | Field | Purpose |
582
+ | --- | --- |
583
+ | `schemaVersion` | Readiness report contract version. |
584
+ | `service` | Memory service name, kind, version, manifest schema, and binary name. |
585
+ | `scope` | Repo-relative scope and effective persistence profile. |
586
+ | `store` | Profile backend readiness. LocalFirst reports `.build/knowledge/store`; shared PostgreSQL reports the safe `shared_postgresql` backend token. |
587
+ | `sqlite` | SQLite engine version and LocalFirst vector semantic query capability. |
588
+ | `sharedPostgresql` | Optional shared PostgreSQL readiness metadata containing only env-var name, schema, application name, and readiness state. |
589
+ | `capabilities` | Capability readiness states for ingest, query, context package, RAG quality report, persistent cache, and local memory. |
590
+ | `readiness` | Enterprise lane matrix for `rag`, `cag`, `hyde_assisted`, `context_package`, `verified_answer_cache`, `operational_memory`, and `quality_observability`, including required and degraded check ids. |
591
+ | `checks` | Ordered deterministic checks with `blocking` or `degrading` severity, including persistent-cache table, index, TTL, and round-trip checks. |
592
+ | `summary` | Aggregated ready/degraded flags and failed check IDs. |
593
+
594
+ Readiness lane status uses a strict machine contract:
595
+
596
+ - `ready` means every required check for that lane passed.
597
+ - `degraded` means the lane can still run through a local-first fallback, but
598
+ the caller should inspect `degradedCheckIds` before selecting it.
599
+ - `unavailable` means the orchestrator must not select that lane.
600
+
601
+ `requiredCheckIds` lists the checks that control a lane. `degradedCheckIds`
602
+ must be a subset of those required checks and names the failed checks from the
603
+ same report.
604
+
605
+ ---
606
+
607
+ ## Compatibility and Support
608
+
609
+ The initial compatibility target is the existing implementation in
610
+ `nettoolskit-copilot`. Extraction must preserve the current command and runtime
611
+ behavior until downstream consumers are migrated.
612
+
613
+ The current crate starts from the existing `nettoolskit-copilot` knowledge
614
+ foundation and keeps the same deterministic behavior while the ecosystem moves
615
+ to explicit memory-owned APIs.
616
+
617
+ `build_hyde_hypothesis` remains backward-compatible for existing callers while
618
+ new integrations can attach a typed local `HydeGenerator`.
619
+
620
+ Downstream consumers should prefer `nettoolskit_memory::engine` for new adapter
621
+ work. The facade keeps grouped surfaces for contracts, persistence, retrieval,
622
+ orchestration, context packages, vault materialization, and authored knowledge
623
+ records without exposing runtime orchestration policy.
624
+
625
+ Embedding provider selection belongs to the calling product runtime. This
626
+ repository owns the deterministic provider contract and local execution wiring;
627
+ external provider implementations, credential resolution, and model routing
628
+ belong outside `nettoolskit-memory`.
629
+
630
+ The local-first SQLite query path is capability-gated. Materialization
631
+ initializes the repository-local store with bundled SQLite and registers
632
+ deterministic Memory-owned vector SQL functions on each opened knowledge-store
633
+ connection. Operators and orchestrators should call `ntk-memory doctor
634
+ --repo-root <path>` before invoking semantic query workloads.
635
+ Vector retrieval is scoped by `provider_id` and `provider_version`, so multiple
636
+ same-dimension embeddings for the same chunk can coexist without cross-provider
637
+ or cross-version result contamination. Verified answer reuse is separately
638
+ scoped by `answer_generation_scope.provider_id`, `.model_id`, and
639
+ `.model_version`, so generated answers are never reused across provider/model
640
+ surfaces.
641
+
642
+ `SemanticRetriever::query_with_cache` first checks the retrieval-result cache.
643
+ On retrieval-result misses, it resolves the query vector through the
644
+ `query_embedding` cache before calling the embedding provider. Query embedding
645
+ entries store provider identity, dimension, query hash, vector, and a stable
646
+ embedding cache key only.
647
+
648
+ Automatic persistent cache reuse is selected through the repository resolver.
649
+ LocalFirst uses the repository-local SQLite backend. Shared PostgreSQL uses the
650
+ feature-gated `PostgresPersistentCacheBackend` when callers provide
651
+ secret-safe shared settings. Custom in-memory repository resolvers remain
652
+ SQLite-free unless they explicitly attach a persistent-cache backend.
653
+
654
+ Reusable Memory OS record persistence is selected through the same resolver.
655
+ LocalFirst uses `SqliteMemoryRecordBackend`; shared PostgreSQL uses
656
+ `PostgresMemoryRecordBackend` and stores `memory_items` plus
657
+ `memory_promotions` as validated JSONB payloads with indexed filter columns.
658
+ The `memory-record-*` command requests accept the same
659
+ `persistence_profile`/`shared_postgresql` shape and fail closed when shared
660
+ settings are incomplete or the Cargo feature is unavailable.
661
+
662
+ Operational-memory `local-write` and `local-read` contracts accept the same
663
+ profile/settings shape and route through `SqliteOperationalMemoryBackend` or
664
+ `PostgresOperationalMemoryBackend`. The LocalFirst form without profile fields
665
+ remains the compatibility baseline.
666
+
667
+ The Rust API and CLI expose an optional `shared-postgresql` feature for
668
+ explicit shared deployments through
669
+ `PersistentKnowledgeRepositoryResolver::for_shared_postgresql` and workspace
670
+ request profile selection. Bare `PersistenceProfile::SharedPostgresql` still
671
+ fails closed before SQLite bootstrap because it has no secret-safe settings.
672
+ CLI request JSON rejects unknown fields so misspelled profile fields such as
673
+ `persistenceProfile` cannot be silently ignored and executed as LocalFirst.
674
+
675
+ Persistent-cache readiness and semantic vector readiness are separate gates.
676
+ `memory.cache.persist`, `memory.knowledge.query`, and `memory.context.package`
677
+ are reported independently so orchestrators can fail closed on the exact lane
678
+ they need.
679
+ Persistent cache payload hashes are built from canonical JSON so object order
680
+ and floating-point hydration differences do not invalidate durable cache rows
681
+ after they are read back from SQLite or PostgreSQL.
682
+
683
+ ---
684
+
685
+ ## Operations
686
+
687
+ Generated build output belongs under `.build/` and must not be committed.
688
+
689
+ Generated validation, packaging, publication, or release-candidate artifacts
690
+ belong under `.deployment/artifacts/` and must not be committed unless the
691
+ repository-specific release process explicitly publishes sanitized outputs.
692
+
693
+ The CI workflow runs automatically only for pushes to `main` and can also be
694
+ started with `workflow_dispatch`. It uses changed-file routing so docs-only
695
+ changes do not run Rust build or test stages.
696
+
697
+ ---
698
+
699
+ ## Planning
700
+
701
+ Use `planning/` for active plans, workstream status, release checklists, and
702
+ implementation checkpoints when the repository owns planning state.
703
+
704
+ Planning files must stay checklist-backed and evidence-backed. Close plans only
705
+ after the implementation, validation, review, and release or PR evidence are
706
+ recorded.
707
+
708
+ Completed enterprise RAG quality work is tracked in
709
+ `planning/completed/2026-05/202605210848-plan-memory-enterprise-rag-quality-pipeline.md`.
710
+ That plan covers Hybrid Search V2, reranking, contextual compression,
711
+ groundedness primitives, enterprise filters, CAG key scoping, and RAG quality
712
+ observability while keeping orchestration in `nettoolskit-copilot`. Hybrid
713
+ lexical ranking is BM25-style deterministic scoring and fusion; full
714
+ storage-backed search engines and conditional model decisions remain caller
715
+ architecture choices.
716
+
717
+ ---
718
+
719
+ ## Governance and Security
720
+
721
+ Use semantic branches such as `feat/...`, `fix/...`, `docs/...`,
722
+ `refactor/...`, `test/...`, `chore/...`, `ci/...`, and `release/...`.
723
+
724
+ Do not publish directly to `main` unless the repository owner explicitly asks
725
+ for that operation. Prefer PRs for all repository changes.
726
+
727
+ Do not commit secrets, tokens, usernames, database hostnames, connection
728
+ strings, machine-local paths, raw logs, local SQLite stores, vector indexes,
729
+ graph stores, `.env` files, or unsanitized release artifacts. Shared PostgreSQL
730
+ examples must reference environment variable names only. Release assets must be
731
+ reviewed for metadata leaks before publication.
732
+
733
+ ---
734
+
735
+ ## Build and Tests
736
+
737
+ Use targeted local validation for crate changes.
738
+
739
+ ```powershell
740
+ cargo metadata --locked --format-version 1 --no-deps
741
+ cargo fmt --all --check
742
+ cargo clippy --locked --all-targets
743
+ cargo test --locked --no-fail-fast
744
+ cargo test --locked --features shared-postgresql --all-targets --no-fail-fast
745
+ git diff --check
746
+ ```
747
+
748
+ ---
749
+
750
+ ## Contributing
751
+
752
+ Work from a semantic branch and keep changes scoped to this repository's
753
+ responsibility. Update `CHANGELOG.md` for user-visible, contract-level,
754
+ release, CI/CD, governance, or dependency changes.
755
+
756
+ Keep generated outputs under `.build/` and local artifacts under
757
+ `.deployment/artifacts/`.
758
+
759
+ ---
760
+
761
+ ## Dependencies
762
+
763
+ - Runtime: none in the foundation PR.
764
+ - Development: GitHub template baseline.
765
+
766
+ ---
767
+
768
+ ## References
769
+
770
+ - [Changelog](CHANGELOG.md)
771
+ - [Planning](planning/README.md)
772
+ - [GitHub Repository](https://github.com/NetToolsKit/nettoolskit-memory)
773
+
774
+ ---
775
+
776
+ ## License
777
+
778
+ This project is licensed under the MIT License. See the LICENSE file at the
779
+ repository root for details.
780
+
781
+ ## npm and npx
782
+
783
+ This repository exposes the `ntk-memory` command through the `@nettoolskit/memory` npm package for local installation and `npx` execution.
784
+
785
+ ```powershell
786
+ npm install -g @nettoolskit/memory
787
+ ntk-memory --help
788
+ npx @nettoolskit/memory --help
789
+ ```
790
+
791
+ The npm wrapper executes a native `ntk-memory` binary from `npm/native/` when release packaging stages one. For development or private release validation, set `NTK_MEMORY_BINARY` to an already built local binary. Use `npm run stage:native -- <path-to-binary>` before packaging a native tarball.
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawnSync } = require("node:child_process");
5
+ const fs = require("node:fs");
6
+ const path = require("node:path");
7
+
8
+ const repoRoot = path.resolve(__dirname, "..", "..");
9
+ const nativeName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
10
+ const bundledBinary = path.join(repoRoot, "npm", "native", nativeName);
11
+ const explicitBinary = process.env.NTK_MEMORY_BINARY || process.env.NETTOOLSKIT_MEMORY_BINARY;
12
+
13
+ function executableExists(candidate) {
14
+ return Boolean(candidate) && fs.existsSync(candidate);
15
+ }
16
+
17
+ function spawnPath(candidate) {
18
+ return process.platform === "win32" ? path.toNamespacedPath(candidate) : candidate;
19
+ }
20
+
21
+ function failMissingBinary(detail) {
22
+ console.error("ntk-memory binary was not found.");
23
+ if (detail) {
24
+ console.error(detail);
25
+ }
26
+ console.error("Set NTK_MEMORY_BINARY to a local binary or install a package built with npm/native/ntk-memory.");
27
+ process.exit(127);
28
+ }
29
+
30
+ let binary;
31
+ if (explicitBinary) {
32
+ if (!executableExists(explicitBinary)) {
33
+ failMissingBinary("Configured ntk-memory binary does not exist: " + explicitBinary);
34
+ }
35
+ binary = explicitBinary;
36
+ } else if (executableExists(bundledBinary)) {
37
+ binary = bundledBinary;
38
+ } else {
39
+ failMissingBinary("Expected bundled binary at: " + bundledBinary);
40
+ }
41
+
42
+ const result = spawnSync(spawnPath(binary), process.argv.slice(2), {
43
+ stdio: "inherit",
44
+ windowsHide: true,
45
+ });
46
+
47
+ if (result.error) {
48
+ failMissingBinary(result.error.message);
49
+ }
50
+
51
+ if (typeof result.status === "number") {
52
+ process.exit(result.status);
53
+ }
54
+
55
+ process.exit(1);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@nettoolskit/memory",
3
+ "version": "0.0.1-preview.1",
4
+ "description": "Knowledge ingestion, local memory, RAG, HyDE, retrieval, context packages, and vault materialization for NetToolsKit.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "nettoolskit",
8
+ "memory",
9
+ "cli",
10
+ "npx"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/NetToolsKit/nettoolskit-memory.git"
15
+ },
16
+ "homepage": "https://github.com/NetToolsKit/nettoolskit-memory#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/NetToolsKit/nettoolskit-memory/issues"
19
+ },
20
+ "bin": {
21
+ "ntk-memory": "npm/cli/ntk-memory.js"
22
+ },
23
+ "files": [
24
+ "LICENSE",
25
+ "README.md",
26
+ "npm/cli/ntk-memory.js",
27
+ "npm/native/",
28
+ "scripts/npm/postinstall.js",
29
+ "scripts/npm/stage-native.js"
30
+ ],
31
+ "scripts": {
32
+ "postinstall": "node scripts/npm/postinstall.js",
33
+ "stage:native": "node scripts/npm/stage-native.js",
34
+ "pack:dry-run": "npm pack --ignore-scripts --dry-run"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const nativeName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
8
+ const nativePath = path.resolve(__dirname, "..", "..", "npm", "native", nativeName);
9
+
10
+ if (process.env.NTK_MEMORY_SKIP_POSTINSTALL === "1") {
11
+ process.exit(0);
12
+ }
13
+
14
+ if (fs.existsSync(nativePath)) {
15
+ process.exit(0);
16
+ }
17
+
18
+ console.warn("ntk-memory native binary is not bundled in this installation.");
19
+ console.warn("Use NTK_MEMORY_BINARY to point to a local binary or run npm run stage:native before publishing a native package.");
20
+ process.exit(0);
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const binaryName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
8
+ const repoRoot = path.resolve(__dirname, "..", "..");
9
+ const explicitSource = process.argv[2] || process.env.NTK_MEMORY_STAGE_BINARY;
10
+ const candidates = [
11
+ explicitSource,
12
+ path.join(repoRoot, "target", "release", binaryName),
13
+ path.join(repoRoot, "target", "x86_64-pc-windows-msvc", "release", "ntk-memory.exe"),
14
+ path.join(repoRoot, "target", "x86_64-unknown-linux-gnu", "release", "ntk-memory"),
15
+ ].filter(Boolean);
16
+
17
+ const source = candidates.find((candidate) => fs.existsSync(candidate));
18
+ if (!source) {
19
+ console.error("No ntk-memory release binary found to stage.");
20
+ console.error("Build the release binary first or set NTK_MEMORY_STAGE_BINARY.");
21
+ process.exit(1);
22
+ }
23
+
24
+ const nativeDir = path.join(repoRoot, "npm", "native");
25
+ fs.mkdirSync(nativeDir, { recursive: true });
26
+ const destination = path.join(nativeDir, binaryName);
27
+ fs.copyFileSync(source, destination);
28
+ if (process.platform !== "win32") {
29
+ fs.chmodSync(destination, 0o755);
30
+ }
31
+ console.log("Staged " + source + " -> " + destination);