@nm-lang/cli 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  N/M 0.2.0 Preview command-line tools for running, formatting, linting, testing,
4
4
  exporting and managing local N/M workspaces.
5
5
 
6
- Package **0.4.0** targets the N/M **0.2.0** language contract.
6
+ Package **0.5.0** targets the N/M **0.2.0** language contract.
7
7
 
8
8
  ## Install / Kurulum
9
9
 
@@ -21,12 +21,12 @@ npx --package=@nm-lang/cli nm --version
21
21
  ```
22
22
 
23
23
  An untagged install selects npm's `latest` channel. To pin this version,
24
- append `@0.4.0` to the package name. The N/M language remains
24
+ append `@0.5.0` to the package name. The N/M language remains
25
25
  Preview independently of the npm channel. npm installs the matching Core dependency.
26
26
  No repository checkout or TypeScript build is needed to use a published package.
27
27
 
28
28
  Türkçe: Etiketsiz kurulum npm'in `latest` kanalını seçer.
29
- `@0.4.0` ile sürümü sabitleyebilirsiniz. N/M dili, npm kanalından bağımsız
29
+ `@0.5.0` ile sürümü sabitleyebilirsiniz. N/M dili, npm kanalından bağımsız
30
30
  olarak Önizleme durumundadır. Core bağımlılığı otomatik kurulur; depoyu
31
31
  indirmeniz gerekmez.
32
32
 
@@ -58,10 +58,10 @@ simülasyondan gelir; gerçek kuantum donanımı kanıtı değildir.
58
58
 
59
59
  ### Selected tests and CI reports / Test seçimi ve CI raporları
60
60
 
61
- The `0.3.0` package adds test selection, watch mode and JSON, JUnit and SARIF
61
+ The CLI provides test selection, watch mode and JSON, JUnit and SARIF
62
62
  reports for CI integrations.
63
63
 
64
- Türkçe: `0.3.0` paketi test seçimini, izleme modunu ve CI entegrasyonları için
64
+ Türkçe: CLI test seçimini, izleme modunu ve CI entegrasyonları için
65
65
  JSON, JUnit ve SARIF raporlarını içerir.
66
66
 
67
67
  ```sh
@@ -130,11 +130,29 @@ Türkçe: Yeni CLI çağrılarında varsayılan dil profili açıktır. Eski dav
130
130
  - [Support / Destek](https://quantumsoftware.tech/en/#contact)
131
131
 
132
132
 
133
- ## Hamiltonian 0.4.0 candidate / Hamiltonian 0.4.0 adayı
134
-
135
- This unpublished 0.4.0 candidate includes Hamiltonian evolution and shared-shot
136
- QWC expectations. Published npm 0.3.0 and earlier extension releases do not
137
- include these additions.
133
+ ## 0.5.0: Trainable evolution / Eğitilebilir evrim
134
+
135
+ This package adds scalar-parameter evolution time and Hamiltonian coefficients,
136
+ fixed gate topology at zero time/weight, and exact-statevector circuit/operator
137
+ derivatives. The training host supports fixed or adaptive QWC allocation with
138
+ one total shot budget, separate pilots/held-out confidence evidence, and optional
139
+ final-cost precision targets. Required-shot estimates are informational; they do
140
+ not spend extra shots, increase the 4096 limit or certify convergence. These
141
+ features require the existing explicit Hamiltonian and grouping permissions.
142
+
143
+ Türkçe: Parametreli evrim süresi/katsayıları, sıfırda korunan kapı yapısı ve kesin
144
+ statevector devre/operatör türevleri eklenir. Eğitim host'u sabit/adaptif QWC,
145
+ tek toplam ölçüm bütçesi, ayrı pilot/değerlendirme güven kanıtı ve isteğe bağlı
146
+ son maliyet hassasiyetini destekler. Ölçüm tahmini bilgi amaçlıdır; ek ölçüm almaz,
147
+ 4096 sınırını artırmaz veya yakınsamayı belgelemez. Mevcut iki açık izin korunur.
148
+
149
+ The N/M language contract remains 0.2.0; package and artifact versions are separate.
150
+ N/M dil sözleşmesi 0.2.0 olarak kalır; paket ve dosya biçimi sürümleri ayrıdır.
151
+
152
+ ## Hamiltonian 0.4.0 / Hamiltonian 0.4.0
153
+
154
+ Version 0.4.0 includes Hamiltonian evolution and shared-shot QWC expectations.
155
+ Earlier releases do not include these additions.
138
156
  Both `hamiltonianEvolution` and `measurementGrouping` require explicit permission.
139
157
  Source printing and N/M IR v0.5 preserve original source, parser context, seed and
140
158
  shot plans. Imports rebuild with caller permissions; stored flags never grant them.
@@ -149,11 +167,14 @@ CLI: `--experimental-hamiltonian-evolution`, `--experimental-measurement-groupin
149
167
  The editor offers completion/hover, closed-default diagnostics and original
150
168
  source columns for generated gates in the recorded debugger.
151
169
 
152
- Türkçe: Bunlar yayımlanmamış yerel geliştirmelerdir; iki yeni izin varsayılan
153
- kapalıdır. Yazdırma/IR özgün kaynağı ve ortak ölçüm bütçesini korur; içe aktarım
170
+ Türkçe: 0.4.0 bu geliştirmeleri içerir; iki yeni izin varsayılan kapalıdır.
171
+ Yazdırma/IR özgün kaynağı ve ortak ölçüm bütçesini korur; içe aktarım
154
172
  kaydı çalıştırma yetkisi saymaz. CLI/MCP/LSP/Monaco/VS Code aynı izinleri taşır;
155
- tanılar ve ayarlar TR/EN destekler. TR/EN laboratuvarı sitede erişilebilirdir;
156
- yeni npm/eklenti paketinin yayını ayrı aşamadır.
173
+ tanılar ve ayarlar TR/EN destekler. TR/EN laboratuvarı sitede erişilebilirdir.
174
+ N/M dil sözleşmesi 0.2.0 ve ön izleme olgunluğu korunur.
175
+
176
+ [Release notes](https://quantumsoftware.tech/en/docs/nm-language/releases) ·
177
+ [Türkçe sürüm notları](https://quantumsoftware.tech/tr/docs/nm-language/releases)
157
178
 
158
179
  ## License / Lisans
159
180
 
@@ -164,3 +185,16 @@ separate permission. Your N/M programs and results remain yours. See
164
185
 
165
186
  Türkçe: Kullanım ücretsizdir; açık kaynak lisansı verilmez. Paket kodunu
166
187
  değiştirme ve yeniden dağıtma için ayrıca izin gerekir.
188
+
189
+ ## Python/Jupyter bridge / Python/Jupyter köprüsü
190
+
191
+ Version 0.5.0 adds `nm bridge` for bounded JSON `check`, `run` and
192
+ `train` requests through stdin. The `python/nm_bridge.py` stdlib adapter and
193
+ `python/examples/training.ipynb` preserve source, explicit caller permissions,
194
+ training options and complete measurement/confidence evidence. TR/EN output is
195
+ supported; saved records never self-grant replay permissions. No separate PyPI
196
+ release is provided. See `python/README.md` and the repository's
197
+ `docs/NM_PYTHON_JUPYTER_BRIDGE_GUIDE.md`. The earlier npm 0.4.0 release does not include this bridge.
198
+ Türkçe: 0.5.0, standart kütüphaneli yerel Python/Jupyter köprüsünü içerir;
199
+ kayıtlar özgün kaynak, eğitim seçenekleri, bütçe ve güven kanıtını korur.
200
+ Kayıt okumak çalıştırma izni vermez; ayrı bir PyPI paketi yayımlanmaz.
@@ -0,0 +1,78 @@
1
+ import { Worker } from "node:worker_threads";
2
+
3
+ // Transport caps also cover stdin waiting, runtime loading and forced termination.
4
+ export const nmBridgeTransportLimits = Object.freeze({ requestBytes: 262144, responseBytes: 4194304, defaultTimeoutMs: 30000, maxTimeoutMs: 60000 });
5
+ const copy = {
6
+ en: { input: "Invalid bridge arguments, UTF-8 input, or request size.", timeout: "Bridge deadline exceeded. The Worker was terminated; no completed measurement or precision evidence is available.", execution: "Bridge Worker failed. No completed result is available.", cancel: "Bridge cancelled; no completed result is available." },
7
+ tr: { input: "Köprü bağımsız değişkenleri, UTF-8 girdisi veya istek boyutu geçersiz.", timeout: "Köprü süre sınırı aşıldı. Worker sonlandırıldı; tamamlanmış ölçüm veya hassasiyet kanıtı yoktur.", execution: "Köprü Worker hatası. Tamamlanmış sonuç yoktur.", cancel: "Köprü iptal edildi; tamamlanmış sonuç yoktur." },
8
+ };
9
+ function rejection(key, locale) {
10
+ return { exitCode: 1, stdout: [JSON.stringify({ format: "nm-python-bridge", version: 1, success: false, status: "rejected", locale,
11
+ error: { code: key === "timeout" ? "NM-PY-008" : key === "cancel" ? "NM-PY-009" : key === "execution" ? "NM-PY-007" : "NM-PY-001", message: copy[locale][key] } })], stderr: [] };
12
+ }
13
+
14
+ export async function runNMBridgeHost(args) {
15
+ const locale = args[args.indexOf("--locale") + 1] === "tr" ? "tr" : "en";
16
+ const forwarded = [], seen = new Set(), features = new Set();
17
+ let timeoutMs = nmBridgeTransportLimits.defaultTimeoutMs;
18
+ for (let index = 0; index < args.length; index++) {
19
+ const flag = args[index];
20
+ if (flag === "--allow-feature") {
21
+ const feature = args[++index];
22
+ if (!/^[A-Za-z]+$/u.test(feature ?? "") || features.has(feature)) return emit(rejection("input", locale));
23
+ features.add(feature); forwarded.push(flag, feature); continue;
24
+ }
25
+ if (seen.has(flag)) return emit(rejection("input", locale));
26
+ seen.add(flag);
27
+ if (flag === "--json") { forwarded.push(flag); continue; }
28
+ if (flag === "--locale" && ["en", "tr"].includes(args[index + 1])) { forwarded.push(flag, args[++index]); continue; }
29
+ if (flag === "--timeout-ms") {
30
+ const value = args[++index];
31
+ if (!/^\d+$/u.test(value ?? "") || Number(value) < 100 || Number(value) > nmBridgeTransportLimits.maxTimeoutMs) return emit(rejection("input", locale));
32
+ timeoutMs = Number(value); continue;
33
+ }
34
+ return emit(rejection("input", locale));
35
+ }
36
+ await new Promise(resolve => {
37
+ let worker, settled = false, size = 0;
38
+ const chunks = [];
39
+ const finish = async result => {
40
+ if (settled) return;
41
+ settled = true; clearTimeout(timer);
42
+ process.stdin.removeListener("data", onData); process.stdin.removeListener("end", onEnd); process.stdin.removeListener("error", onInputError);
43
+ process.removeListener("SIGINT", onCancel); process.removeListener("SIGTERM", onCancel);
44
+ chunks.length = 0; process.stdin.destroy();
45
+ if (worker) await worker.terminate();
46
+ emit(result); resolve();
47
+ };
48
+ const onCancel = () => void finish(rejection("cancel", locale));
49
+ const onInputError = () => void finish(rejection("input", locale));
50
+ const onData = chunk => {
51
+ size += chunk.length;
52
+ if (size > nmBridgeTransportLimits.requestBytes) return void finish(rejection("input", locale));
53
+ chunks.push(chunk);
54
+ };
55
+ const onEnd = () => {
56
+ let input;
57
+ try { input = new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks)); }
58
+ catch { return void finish(rejection("input", locale)); }
59
+ chunks.length = 0;
60
+ try {
61
+ worker = new Worker(new URL("./bridge-worker.mjs", import.meta.url), {
62
+ workerData: { args: forwarded, input }, resourceLimits: { maxOldGenerationSizeMb: 512, stackSizeMb: 8 },
63
+ });
64
+ worker.once("message", result => {
65
+ const valid = result && [0, 1].includes(result.exitCode) && result.stdout?.length === 1 && result.stderr?.length === 0
66
+ && typeof result.stdout[0] === "string" && Buffer.byteLength(result.stdout[0]) <= nmBridgeTransportLimits.responseBytes;
67
+ void finish(valid ? result : rejection("execution", locale));
68
+ });
69
+ worker.once("error", () => void finish(rejection("execution", locale)));
70
+ worker.once("exit", () => { if (!settled) void finish(rejection("execution", locale)); });
71
+ } catch { void finish(rejection("execution", locale)); }
72
+ };
73
+ const timer = setTimeout(() => void finish(rejection("timeout", locale)), timeoutMs);
74
+ process.once("SIGINT", onCancel); process.once("SIGTERM", onCancel);
75
+ process.stdin.on("data", onData); process.stdin.once("end", onEnd); process.stdin.once("error", onInputError);
76
+ });
77
+ }
78
+ function emit(result) { process.exitCode = result.exitCode; process.stdout.write(`${result.stdout.join("\n")}\n`); }
@@ -0,0 +1,27 @@
1
+ import { parentPort, workerData } from "node:worker_threads";
2
+ import Module from "node:module";
3
+ import { existsSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ // Same repository-source/installed-artifact selection as nm.mjs, inside the deadline.
8
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
9
+ const sourceCLI = path.join(root, "lib/nm/cli.ts");
10
+ let runtime;
11
+ if (existsSync(sourceCLI) && process.env.NM_CLI_FORCE_PACKED !== "1") {
12
+ const original = Module._resolveFilename;
13
+ Module._resolveFilename = function (request, ...args) {
14
+ if (typeof request === "string" && request.startsWith("@/")) {
15
+ const absolute = path.join(root, request.slice(2));
16
+ request = existsSync(`${absolute}.ts`) ? `${absolute}.ts` : absolute;
17
+ }
18
+ return original.call(this, request, ...args);
19
+ };
20
+ const { createJiti } = await import("jiti");
21
+ runtime = createJiti(import.meta.url)(sourceCLI);
22
+ } else runtime = await import("../dist/index.js");
23
+ const result = runtime.runNMCLI(["bridge", ...workerData.args], {
24
+ readStdin: () => workerData.input,
25
+ readFile: () => { throw new Error("The JSON bridge does not read filesystem sources."); },
26
+ });
27
+ parentPort.postMessage(result);
package/bin/nm.mjs CHANGED
@@ -25,7 +25,9 @@ const isPackedVersionCommand =
25
25
  process.env.NM_CLI_FORCE_PACKED === "1" &&
26
26
  (cliArgs[0] === "--version" || cliArgs[0] === "version");
27
27
 
28
- if (isPackedVersionCommand) {
28
+ if (cliArgs[0] === "bridge") {
29
+ await (await import("./bridge-host.mjs")).runNMBridgeHost(cliArgs.slice(1));
30
+ } else if (isPackedVersionCommand) {
29
31
  const { nmVersionManifest } = await import("../dist/version.js");
30
32
  process.stdout.write(
31
33
  cliArgs.includes("--json")