@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 +48 -14
- package/bin/bridge-host.mjs +78 -0
- package/bin/bridge-worker.mjs +27 -0
- package/bin/nm.mjs +3 -1
- package/dist/index.js +22 -22
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/python/README.md +69 -0
- package/python/examples/training.ipynb +78 -0
- package/python/nm_bridge.py +464 -0
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.
|
|
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.
|
|
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.
|
|
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
|
|
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:
|
|
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
|
-
##
|
|
134
|
-
|
|
135
|
-
This
|
|
136
|
-
|
|
137
|
-
|
|
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:
|
|
153
|
-
|
|
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
|
-
|
|
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 (
|
|
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")
|