@nettoolskit/det 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,253 @@
1
+ # NetToolsKit DET
2
+
3
+ > Semantic execution runtime for governed AI.
4
+
5
+ ---
6
+
7
+ ## Introduction
8
+
9
+ DET — Decision, Execution & Traceability — is the NetToolsKit semantic
10
+ execution runtime for governed AI. It orchestrates, optimizes, and governs AI
11
+ task execution through meaning, memory, verification, and metacognitive
12
+ control.
13
+
14
+ DET coordinates AI models, MEVRA, Meaning Memory, tools, retrieval,
15
+ verification, evaluation, policy, and metacognitive awareness so AI tasks can
16
+ run with semantic grounding, traceability, safety, and measurable performance.
17
+ It is not an agent framework and it does not own provider execution, memory
18
+ storage, machine control, or downstream product orchestration.
19
+
20
+ MEVRA proposes operational meaning. Meaning Memory validates and persists
21
+ meaning. Metacognition monitors objective, focus, uncertainty, conflict, and
22
+ risk. Verification validates. Anti-Deception protects. The LLM verbalizes. DET
23
+ arbitrates and executes.
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ - ✅ Semantic execution runtime for governed AI task planning and execution.
30
+ - ✅ Decision, execution, verification, traceability, and policy arbitration contracts.
31
+ - ✅ Meaning Memory integration boundaries for global, catalog, project-registry, and project-local memory layers.
32
+ - ✅ Agent and Codegen consumption boundaries that avoid duplicating deterministic function implementations.
33
+ - ✅ Operational `det run --task` dry-run entrypoint for governed route planning and traceability.
34
+ - ✅ Harness-derived evidence, benchmark, and effectiveness contracts inside the DET workspace.
35
+ - ✅ River-first validation model for Rust quality, package validation, and CI/CD governance.
36
+
37
+ ---
38
+
39
+ ## Contents
40
+
41
+ - [Introduction](#introduction)
42
+ - [Features](#features)
43
+ - [Architecture](#architecture)
44
+ - [Architecture](#architecture-1)
45
+ - [Agentic Surfaces](#agentic-surfaces)
46
+ - [Crates](#crates)
47
+ - [Compatibility and Support](#compatibility-and-support)
48
+ - [Operations](#operations)
49
+ - [Planning](#planning)
50
+ - [Governance and Security](#governance-and-security)
51
+ - [Build and Tests](#build-and-tests)
52
+ - [Contributing](#contributing)
53
+ - [Dependencies](#dependencies)
54
+ - [References](#references)
55
+ - [License](#license)
56
+
57
+ ---
58
+
59
+ ## Architecture
60
+
61
+ ### Architecture
62
+
63
+ ```mermaid
64
+ flowchart LR
65
+ User[Operator or host application] --> DET[DET runtime\nDecision, Execution & Traceability]
66
+ DET --> MEVRA[MEVRA\nMeaning proposal]
67
+ DET --> Memory[nettoolskit-memory\nMeaning Memory]
68
+ DET --> Agent[nettoolskit-agent\nDeterministic functions]
69
+ DET --> Codegen[nettoolskit-codegen\nComplex deterministic code architecture functions]
70
+ DET --> Analytics[nettoolskit-analytics\nEvaluation and effectiveness signals]
71
+ DET --> Harness[DET harness contracts\nEvidence and benchmark reproducibility]
72
+ DET --> Rust[nettoolskit-rust\nShared Rust foundation]
73
+ Copilot[nettoolskit-copilot] --> DET
74
+ Copilot --> Control[nettoolskit-control\nRemote machine control]
75
+ ```
76
+
77
+ DET owns semantic arbitration, execution planning, traceability, governance,
78
+ and verification boundaries. It consumes `nettoolskit-agent` and
79
+ `nettoolskit-codegen` deterministic functions without duplicating their code.
80
+ It integrates with `nettoolskit-memory` through Meaning Memory contracts and
81
+ keeps storage, indexing, retrieval, and persistence in Memory.
82
+
83
+ `nettoolskit-copilot` is a product surface that can use DET and remote control
84
+ services. DET does not depend on Copilot or Control.
85
+
86
+ ### Agentic Surfaces
87
+
88
+ DET uses agentic ecosystem components through explicit boundaries:
89
+
90
+ - `nettoolskit-agent` owns canonical deterministic function catalogs,
91
+ commands, instruction contracts, and runtime guidance.
92
+ - `nettoolskit-codegen` owns complex deterministic architecture/code-generation
93
+ functions that DET can select and orchestrate.
94
+ - `nettoolskit-memory` owns Meaning Memory storage, retrieval, validation,
95
+ persistence, and project-local memory.
96
+ - `nettoolskit-analytics` owns analytics and evaluation signals that DET can
97
+ use for measured effectiveness.
98
+ - `nettoolskit-copilot` owns user-facing product orchestration and can call DET.
99
+ - `nettoolskit-control` owns remote machine command execution and is not called
100
+ directly by DET.
101
+
102
+ Detailed architecture is maintained in [ARCHITECTURE.md](ARCHITECTURE.md) and
103
+ [docs/architecture-overview.md](docs/architecture-overview.md).
104
+
105
+ ---
106
+
107
+ ## Crates
108
+
109
+ The DET workspace is organized by owned crates under `crates/*`.
110
+
111
+ | Crate | Purpose | README |
112
+ | --- | --- | --- |
113
+ | `agentic-rag` | Agentic RAG planning and policy contracts. | [README](crates/agentic-rag/README.md) |
114
+ | `cli` | Public CLI and compatibility facade. | [README](crates/cli/README.md) |
115
+ | `core` | Core semantic execution and repository profile contracts. | [README](crates/core/README.md) |
116
+ | `harness` | Harness-derived evidence and reproducibility contracts. | [README](crates/harness/README.md) |
117
+ | `integrations` | Agent, Memory, analytics, and ecosystem integration boundaries. | [README](crates/integrations/README.md) |
118
+ | `language` | DET language parsing and runtime-language contracts. | [README](crates/language/README.md) |
119
+ | `runtime` | Runtime admission, DET home, wrapper, benchmark, and registry contracts. | [README](crates/runtime/README.md) |
120
+
121
+ ---
122
+
123
+ ## Compatibility and Support
124
+
125
+ DET is in MVP implementation and should be consumed through committed Rust
126
+ contracts, documented CLI surfaces, and explicit JSON request/response shapes.
127
+ Distribution targets npm/npx, Docker, GitHub Releases, and Winget; Cargo
128
+ publication is not the preferred operator install path for this product stage.
129
+
130
+ Supported operator paths and release-readiness details live in
131
+ [docs/install.md](docs/install.md), [docs/release.md](docs/release.md).
132
+
133
+ ---
134
+
135
+ ## Operations
136
+
137
+ Operational details are intentionally kept out of the root README:
138
+
139
+ - Basic usage: [docs/getting-started/basic-usage.md](docs/getting-started/basic-usage.md)
140
+ - Operational task runtime: `det run --task --json <run-task-request.json>`
141
+ - DET home and Meaning Memory layers: [docs/det-home-memory.md](docs/det-home-memory.md)
142
+ - Local validation and CI/CD routing: [docs/operations/local-validation.md](docs/operations/local-validation.md)
143
+ - River CI policy: [docs/operations/river-ci.md](docs/operations/river-ci.md)
144
+ - Runtime wrapper: [docs/runtime-wrapper.md](docs/runtime-wrapper.md)
145
+ - Benchmark evidence: [docs/local-det-vs-baseline-benchmark.md](docs/local-det-vs-baseline-benchmark.md)
146
+ - Guarded DET dogfood with Agent and Meaning Memory: [docs/guarded-det-dogfood.md](docs/guarded-det-dogfood.md)
147
+
148
+ ---
149
+
150
+ ## Planning
151
+
152
+ Planning state is kept under `planning/` and should remain tied to concrete
153
+ workstreams, validation evidence, and PR closeout.
154
+
155
+ Useful entry points:
156
+
157
+ - [Planning index](planning/README.md)
158
+ - [Active DET semantic execution spec](planning/specs/active/202605272037-spec-nettoolskit-det-semantic-execution-engine.md)
159
+ - [Memory and model evaluation plan](planning/plans/completed/2026-06/202606081130-plan-det-memory-as-model-evaluation.md)
160
+ - [Benchmark artifact manifest plan](planning/plans/completed/2026-06/202606091205-plan-det-benchmark-artifact-manifest.md)
161
+
162
+ ---
163
+
164
+ ## Governance and Security
165
+
166
+ DET keeps execution ownership explicit:
167
+
168
+ - DET arbitrates and plans; it does not duplicate provider, Agent, Codegen,
169
+ Memory, Control, Copilot, DevOps, Assurance, or Analytics implementation code.
170
+ - Memory owns retrieval, validation, persistence, indexing, and storage.
171
+ - Agent owns deterministic function catalogs and command contracts.
172
+ - Codegen owns complex deterministic architecture/code-generation functions.
173
+ - Control owns remote machine command execution and is not a DET dependency.
174
+ - Provider calls, MCP invocation, shell execution, persistence, and runtime IO
175
+ require explicit host-owned boundaries.
176
+
177
+ See [docs/det-ecosystem-ownership-model.md](docs/det-ecosystem-ownership-model.md)
178
+ and [docs/ci-gitriver.md](docs/ci-gitriver.md) for the detailed governance
179
+ model.
180
+
181
+ ---
182
+
183
+ ## Build and Tests
184
+
185
+ Local validation should mirror the River Rust quality gate:
186
+
187
+ ```powershell
188
+ cargo fmt --all --check
189
+ cargo test --all-targets --locked
190
+ cargo clippy --all-targets --locked -- -D warnings
191
+ cargo doc --no-deps --locked
192
+ git diff --check
193
+ ```
194
+
195
+ Package/security validation is separate from Rust quality. PR runs should keep
196
+ package security bounded by auditing dependencies, building docs, listing Cargo
197
+ package contents, and generating allowlisted tarballs without repeating full
198
+ workspace package verification. Full Cargo package verification is reserved for
199
+ explicit release or manual proof.
200
+
201
+ The source-owned River validation path is documented in
202
+ [docs/operations/local-validation.md](docs/operations/local-validation.md) and
203
+ [docs/operations/river-ci.md](docs/operations/river-ci.md).
204
+
205
+ ---
206
+
207
+ ## Contributing
208
+
209
+ Use a dedicated branch or worktree for each change-bearing workstream. Keep
210
+ changes scoped to the active plan, update README/manifest/changelog only when
211
+ the implemented behavior changes, and record validation evidence before opening
212
+ or updating a pull request.
213
+
214
+ Every completed workstream should leave the local worktree clean, planning
215
+ state updated, and validation results reproducible from committed source.
216
+
217
+ ---
218
+
219
+ ## Dependencies
220
+
221
+ Runtime dependencies are intentionally small:
222
+
223
+ | Dependency | Purpose |
224
+ | --- | --- |
225
+ | `serde` | Public contract serialization and deserialization. |
226
+ | `serde_json` | JSON registry, manifest, and test serialization support. |
227
+
228
+ Development and validation depend on the Rust toolchain, Cargo, `cargo audit`,
229
+ and Git.
230
+
231
+ ---
232
+
233
+ ## References
234
+
235
+ - [Changelog](CHANGELOG.md)
236
+ - [Architecture](ARCHITECTURE.md)
237
+ - [Documentation index](docs/README.md)
238
+ - [Planning](planning/README.md)
239
+ - [Service manifest](nettoolskit.manifest.json)
240
+ - [River CI gates](scripts/ci/river/README.md)
241
+ - [GitHub repository](https://github.com/NetToolsKit/nettoolskit-det)
242
+ - [Apache DataFusion Query Optimizer](https://datafusion.apache.org/library-user-guide/query-optimizer.html)
243
+ - [Qdrant Indexing](https://qdrant.tech/documentation/concepts/indexing/)
244
+ - [OpenTelemetry](https://opentelemetry.io/docs/)
245
+
246
+ ---
247
+
248
+ ## License
249
+
250
+ This project is licensed under the MIT License. See the LICENSE file at the
251
+ repository root for details.
252
+
253
+ ---
package/npm/cli/det.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+ const { initializeRuntimeHome } = require("../runtime/bootstrap");
7
+
8
+ const repoRoot = path.resolve(__dirname, "..", "..");
9
+ const nativeName = process.platform === "win32" ? "det.exe" : "det";
10
+ const bundledBinary = path.join(repoRoot, "npm", "native", nativeName);
11
+ const explicitBinary = process.env.NTK_DET_BINARY || process.env.NETTOOLSKIT_DET_BINARY;
12
+
13
+ try {
14
+ initializeRuntimeHome();
15
+ } catch (error) {
16
+ console.error(`DET runtime bootstrap failed: ${error.message}`);
17
+ process.exit(126);
18
+ }
19
+
20
+ function executableExists(candidate) {
21
+ return Boolean(candidate) && fs.existsSync(candidate);
22
+ }
23
+
24
+ function failMissingBinary(detail) {
25
+ console.error("DET binary was not found.");
26
+ if (detail) {
27
+ console.error(detail);
28
+ }
29
+ console.error("Set NTK_DET_BINARY to a GitHub Release binary or reinstall @nettoolskit/det.");
30
+ process.exit(127);
31
+ }
32
+
33
+ let binary;
34
+ if (explicitBinary) {
35
+ if (!executableExists(explicitBinary)) {
36
+ failMissingBinary(`Configured DET binary does not exist: ${explicitBinary}`);
37
+ }
38
+ binary = explicitBinary;
39
+ } else if (executableExists(bundledBinary)) {
40
+ binary = bundledBinary;
41
+ } else {
42
+ failMissingBinary(`Expected bundled binary at: ${bundledBinary}`);
43
+ }
44
+
45
+ const executableBinary = process.platform === "win32" ? path.toNamespacedPath(binary) : binary;
46
+ const result = spawnSync(executableBinary, process.argv.slice(2), {
47
+ stdio: "inherit",
48
+ windowsHide: true,
49
+ });
50
+
51
+ if (result.error) {
52
+ failMissingBinary(result.error.message);
53
+ }
54
+
55
+ if (typeof result.status === "number") {
56
+ process.exit(result.status);
57
+ }
58
+
59
+ process.exit(1);
File without changes
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const os = require("node:os");
5
+ const path = require("node:path");
6
+
7
+ const SCHEMA_VERSION = "det.runtime_install_bootstrap.v1";
8
+ const DET_HOME_DIR_NAME = ".det";
9
+ const MEMORY_DIR_NAME = "memory";
10
+ const PROJECT_MEMORY_DIR = path.join(".det", "project-memory");
11
+ const SKIP_ENV_VARS = [
12
+ "NETTOOLSKIT_DET_SKIP_RUNTIME_BOOTSTRAP",
13
+ "NTK_DET_SKIP_RUNTIME_BOOTSTRAP",
14
+ ];
15
+
16
+ function shouldSkipRuntimeBootstrap(env = process.env) {
17
+ return SKIP_ENV_VARS.some((name) => env[name] === "1" || env[name] === "true");
18
+ }
19
+
20
+ function initializeRuntimeHome(options = {}) {
21
+ const env = options.env || process.env;
22
+
23
+ if (options.allowSkip !== false && shouldSkipRuntimeBootstrap(env)) {
24
+ return {
25
+ schemaVersion: SCHEMA_VERSION,
26
+ status: "skipped",
27
+ skipped: true,
28
+ reason: "runtime bootstrap disabled by environment",
29
+ };
30
+ }
31
+
32
+ const detHome = resolveDetHome(options.detHome || env.DET_HOME);
33
+ assertSafeRuntimePath(detHome, "DET_HOME");
34
+
35
+ const memoryRoot = path.join(detHome, MEMORY_DIR_NAME);
36
+ const memoryLayers = [
37
+ layer("global", path.join(memoryRoot, "global")),
38
+ layer("global_catalogs", path.join(memoryRoot, "catalogs")),
39
+ layer("global_projects", path.join(memoryRoot, "projects")),
40
+ ];
41
+
42
+ ensureDirectory(detHome);
43
+ ensureDirectory(memoryRoot);
44
+ for (const memoryLayer of memoryLayers) {
45
+ ensureDirectory(memoryLayer.path);
46
+ }
47
+
48
+ let projectMemory = null;
49
+ const projectRoot = options.projectRoot || env.DET_PROJECT_ROOT;
50
+ if (projectRoot) {
51
+ const resolvedProjectRoot = path.resolve(projectRoot);
52
+ assertSafeRuntimePath(resolvedProjectRoot, "DET_PROJECT_ROOT");
53
+ projectMemory = path.join(resolvedProjectRoot, PROJECT_MEMORY_DIR);
54
+ ensureDirectory(projectMemory);
55
+ }
56
+
57
+ const report = {
58
+ schemaVersion: SCHEMA_VERSION,
59
+ status: "ready",
60
+ detHome,
61
+ memoryRoot,
62
+ memoryLayers,
63
+ projectMemory,
64
+ memoryExecutable: env.DET_NTK_MEMORY_EXECUTABLE || "ntk-memory",
65
+ storageOwner: "nettoolskit-memory",
66
+ createdBy: "@nettoolskit/det",
67
+ writesProviderPayloads: false,
68
+ writesSecrets: false,
69
+ mutatesShellProfiles: false,
70
+ };
71
+
72
+ if (options.writeState !== false) {
73
+ fs.writeFileSync(
74
+ path.join(detHome, "install-state.json"),
75
+ `${JSON.stringify(report, null, 2)}\n`,
76
+ "utf8",
77
+ );
78
+ }
79
+
80
+ return report;
81
+ }
82
+
83
+ function resolveDetHome(configuredHome) {
84
+ if (configuredHome && configuredHome.trim()) {
85
+ return path.resolve(configuredHome.trim());
86
+ }
87
+
88
+ const home = os.homedir();
89
+ if (!home) {
90
+ throw new Error("DET_HOME could not be resolved because the user home directory is unavailable");
91
+ }
92
+
93
+ return path.join(home, DET_HOME_DIR_NAME);
94
+ }
95
+
96
+ function layer(scope, layerPath) {
97
+ return {
98
+ scope,
99
+ path: layerPath,
100
+ global: true,
101
+ projectLocal: false,
102
+ versioned: false,
103
+ };
104
+ }
105
+
106
+ function ensureDirectory(directory) {
107
+ fs.mkdirSync(directory, { recursive: true });
108
+ }
109
+
110
+ function assertSafeRuntimePath(candidate, label) {
111
+ const normalized = candidate.replace(/\\/g, "/").toLowerCase();
112
+ if (
113
+ !normalized ||
114
+ normalized.includes("/../") ||
115
+ normalized.endsWith("/..") ||
116
+ normalized.startsWith("../") ||
117
+ normalized.includes("raw_prompt") ||
118
+ normalized.includes("provider_payload") ||
119
+ normalized.includes("secret") ||
120
+ normalized.includes("token")
121
+ ) {
122
+ throw new Error(`${label} is not safe for DET runtime bootstrap`);
123
+ }
124
+ }
125
+
126
+ if (require.main === module) {
127
+ const report = initializeRuntimeHome();
128
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
129
+ }
130
+
131
+ module.exports = {
132
+ SCHEMA_VERSION,
133
+ initializeRuntimeHome,
134
+ shouldSkipRuntimeBootstrap,
135
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@nettoolskit/det",
3
+ "version": "0.0.1-preview.1",
4
+ "description": "NetToolsKit DET command-line wrapper.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "nettoolskit",
8
+ "det",
9
+ "cli",
10
+ "semantic-runtime"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/NetToolsKit/nettoolskit-det.git"
15
+ },
16
+ "homepage": "https://github.com/NetToolsKit/nettoolskit-det#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/NetToolsKit/nettoolskit-det/issues"
19
+ },
20
+ "bin": {
21
+ "det": "npm/cli/det.js",
22
+ "ntk-det": "npm/cli/det.js"
23
+ },
24
+ "files": [
25
+ "LICENSE",
26
+ "README.md",
27
+ "npm/cli/det.js",
28
+ "npm/native/",
29
+ "npm/runtime/bootstrap.js",
30
+ "scripts/npm/postinstall.js"
31
+ ],
32
+ "scripts": {
33
+ "test:postinstall-integrity": "node scripts/npm/test-postinstall-integrity.js",
34
+ "postinstall": "node scripts/npm/postinstall.js"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+
3
+ const crypto = require("node:crypto");
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const packageJson = require("../../package.json");
8
+ const { initializeRuntimeHome } = require("../../npm/runtime/bootstrap");
9
+ const metadataAsset = "det-distribution-artifact-metadata.json";
10
+
11
+ class DetBinaryIntegrityError extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "DetBinaryIntegrityError";
15
+ }
16
+ }
17
+
18
+ if (require.main === module) {
19
+ main().catch(handlePostinstallFailure);
20
+ }
21
+
22
+ async function main() {
23
+ try {
24
+ initializeRuntimeHome();
25
+ } catch (error) {
26
+ console.warn(`DET runtime bootstrap failed: ${error.message}`);
27
+ process.exit(1);
28
+ }
29
+
30
+ if (process.env.NETTOOLSKIT_DET_SKIP_DOWNLOAD === "1" || process.env.NTK_DET_SKIP_DOWNLOAD === "1") {
31
+ return;
32
+ }
33
+
34
+ const target = releaseTarget();
35
+ if (target && target.unsupported) {
36
+ console.warn(target.message);
37
+ console.warn("Use Docker, a Windows/Linux GitHub Release binary, or set NTK_DET_BINARY to a compatible locally built binary.");
38
+ return;
39
+ }
40
+ if (!target) {
41
+ console.warn(`No DET GitHub Release binary is declared for ${process.platform}/${process.arch}.`);
42
+ console.warn("Set NTK_DET_BINARY to a local binary before running det.");
43
+ return;
44
+ }
45
+
46
+ const nativeDir = path.resolve(__dirname, "..", "..", "npm", "native");
47
+ const binaryPath = path.join(nativeDir, process.platform === "win32" ? "det.exe" : "det");
48
+ const releaseVersion = `v${packageJson.version}`;
49
+ fs.mkdirSync(nativeDir, { recursive: true });
50
+
51
+ const expectedSha256 = await resolveExpectedSha256(releaseVersion, target.asset);
52
+
53
+ if (fs.existsSync(binaryPath)) {
54
+ const existingSha256 = sha256File(binaryPath);
55
+ if (existingSha256 === expectedSha256) {
56
+ if (process.platform !== "win32") {
57
+ fs.chmodSync(binaryPath, 0o755);
58
+ }
59
+ return;
60
+ }
61
+ fs.rmSync(binaryPath, { force: true });
62
+ console.warn("Existing DET binary was removed because release checksum verification failed.");
63
+ }
64
+
65
+ const url = `https://github.com/NetToolsKit/nettoolskit-det/releases/download/${releaseVersion}/${target.asset}`;
66
+
67
+ await downloadVerified(url, binaryPath, expectedSha256);
68
+ }
69
+
70
+ async function download(url, destination) {
71
+ assertTrustedReleaseUrl(url);
72
+ const timeoutMs = Number.parseInt(process.env.NTK_DET_DOWNLOAD_TIMEOUT_MS || "120000", 10);
73
+ const controller = new AbortController();
74
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
75
+ const temporaryDestination = `${destination}.tmp-${process.pid}`;
76
+
77
+ try {
78
+ const response = await fetch(url, { redirect: "follow", signal: controller.signal });
79
+ if (!response.ok) {
80
+ throw new Error(`HTTP ${response.status}`);
81
+ }
82
+
83
+ const body = Buffer.from(await response.arrayBuffer());
84
+ fs.writeFileSync(temporaryDestination, body);
85
+ fs.renameSync(temporaryDestination, destination);
86
+ if (process.platform !== "win32") {
87
+ fs.chmodSync(destination, 0o755);
88
+ }
89
+ } finally {
90
+ clearTimeout(timeout);
91
+ fs.rmSync(temporaryDestination, { force: true });
92
+ }
93
+ }
94
+
95
+ async function downloadVerified(url, destination, expectedSha256) {
96
+ await download(url, destination);
97
+ const actualSha256 = sha256File(destination);
98
+
99
+ if (actualSha256 !== expectedSha256) {
100
+ fs.rmSync(destination, { force: true });
101
+ throw new DetBinaryIntegrityError(
102
+ `DET binary checksum mismatch for ${path.basename(destination)}; expected ${expectedSha256}, got ${actualSha256}`
103
+ );
104
+ }
105
+ }
106
+
107
+ async function resolveExpectedSha256(releaseVersion, assetName) {
108
+ const metadataUrl = `https://github.com/NetToolsKit/nettoolskit-det/releases/download/${releaseVersion}/${metadataAsset}`;
109
+ const metadata = await downloadJson(metadataUrl);
110
+ return findReleaseAssetSha256(metadata, releaseVersion, assetName);
111
+ }
112
+
113
+ async function downloadJson(url) {
114
+ const temporaryDestination = path.join(
115
+ path.resolve(__dirname, "..", "..", "npm", "native"),
116
+ `${metadataAsset}.tmp-${process.pid}`
117
+ );
118
+
119
+ await download(url, temporaryDestination);
120
+
121
+ try {
122
+ return JSON.parse(fs.readFileSync(temporaryDestination, "utf8"));
123
+ } catch (error) {
124
+ throw new DetBinaryIntegrityError(`Invalid DET release metadata JSON: ${error.message}`);
125
+ } finally {
126
+ fs.rmSync(temporaryDestination, { force: true });
127
+ }
128
+ }
129
+
130
+ function findReleaseAssetSha256(metadata, releaseVersion, assetName) {
131
+ if (!metadata || typeof metadata !== "object") {
132
+ throw new DetBinaryIntegrityError("DET release metadata is empty or invalid.");
133
+ }
134
+
135
+ if (metadata.releaseTag !== releaseVersion) {
136
+ throw new DetBinaryIntegrityError(
137
+ `DET release metadata tag mismatch; expected ${releaseVersion}, got ${metadata.releaseTag || "<missing>"}`
138
+ );
139
+ }
140
+
141
+ const channels = Array.isArray(metadata.channels) ? metadata.channels : [];
142
+ const githubRelease = channels.find((channel) => channel && channel.id === "github_release_binary");
143
+
144
+ if (!githubRelease || !Array.isArray(githubRelease.assets)) {
145
+ throw new DetBinaryIntegrityError("DET release metadata does not contain github_release_binary assets.");
146
+ }
147
+
148
+ const asset = githubRelease.assets.find((candidate) => candidate && candidate.name === assetName);
149
+ if (!asset || typeof asset.sha256 !== "string") {
150
+ throw new DetBinaryIntegrityError(`DET release metadata does not contain SHA-256 for ${assetName}.`);
151
+ }
152
+
153
+ const sha256 = asset.sha256.toLowerCase();
154
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
155
+ throw new DetBinaryIntegrityError(`DET release metadata contains an invalid SHA-256 for ${assetName}.`);
156
+ }
157
+
158
+ return sha256;
159
+ }
160
+
161
+ function assertTrustedReleaseUrl(url) {
162
+ const parsed = new URL(url);
163
+ if (parsed.protocol !== "https:" || parsed.hostname !== "github.com") {
164
+ throw new DetBinaryIntegrityError(`Untrusted DET release URL: ${url}`);
165
+ }
166
+ }
167
+
168
+ function sha256File(filePath) {
169
+ return sha256Buffer(fs.readFileSync(filePath));
170
+ }
171
+
172
+ function sha256Buffer(buffer) {
173
+ return crypto.createHash("sha256").update(buffer).digest("hex");
174
+ }
175
+
176
+ function handlePostinstallFailure(error) {
177
+ const message = error instanceof Error ? error.message : String(error);
178
+ console.warn(`DET binary download failed: ${message}`);
179
+ console.warn("Set NTK_DET_BINARY to a local binary or install from a GitHub Release asset.");
180
+
181
+ if (error instanceof DetBinaryIntegrityError) {
182
+ process.exitCode = 1;
183
+ }
184
+ }
185
+
186
+ function releaseTarget() {
187
+ const platform = process.platform;
188
+ const arch = process.arch;
189
+
190
+ if (platform === "win32" && arch === "x64") {
191
+ return { asset: "det-x86_64-pc-windows-msvc.exe" };
192
+ }
193
+ if (platform === "linux" && arch === "x64") {
194
+ return { asset: "det-x86_64-unknown-linux-gnu" };
195
+ }
196
+ if (platform === "darwin") {
197
+ return {
198
+ unsupported: true,
199
+ message: `macOS GitHub Release binary assets are pending for DET v${packageJson.version}.`,
200
+ };
201
+ }
202
+
203
+ return null;
204
+ }
205
+
206
+ module.exports = {
207
+ DetBinaryIntegrityError,
208
+ findReleaseAssetSha256,
209
+ releaseTarget,
210
+ sha256Buffer,
211
+ };