@camstack/system 1.2.459 → 1.2.460
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/dist/addon-runner.js +26 -11
- package/dist/addon-runner.mjs +26 -11
- package/dist/addon-utils.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +3 -3
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +4 -4
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +4 -4
- package/dist/builtins/local-auth/local-auth.addon.mjs +3 -3
- package/dist/builtins/native-metrics/native-metrics.addon.js +38 -3
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +47 -12
- package/dist/builtins/native-metrics/node-metrics-history-recorder.d.ts +15 -0
- package/dist/builtins/platform-probe/coral-accelerators.d.ts +10 -1
- package/dist/builtins/platform-probe/index.js +6 -3
- package/dist/builtins/platform-probe/index.mjs +12 -9
- package/dist/builtins/platform-probe/platform-scorer.d.ts +4 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +19 -19
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/records/records-plan.d.ts +9 -4
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +112 -112
- package/dist/{coral-accelerators-DcnZvctM.mjs → coral-accelerators-Qhn5TOYZ.mjs} +18 -15
- package/dist/{coral-accelerators-Bi_c3Rft.js → coral-accelerators-oUXmmbc2.js} +13 -10
- package/dist/{custom-action-registry-stpC3Zy-.mjs → custom-action-registry-DStvrQKI.mjs} +37 -37
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +30 -2
- package/dist/index.mjs +248 -221
- package/dist/kernel/deps/addon-deps-manager.d.ts +9 -0
- package/dist/{restore-archive-CmP-iiG9.mjs → restore-archive-CM23Pq9B.mjs} +93 -93
- package/dist/{wal-maintenance-NKbwWovZ.mjs → wal-maintenance-Bj_MmDkr.mjs} +0 -0
- package/dist/{wal-maintenance-DUHEp_09.js → wal-maintenance-CaJjuLHq.js} +0 -0
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -39,9 +39,9 @@ let node_vm = require("node:vm");
|
|
|
39
39
|
node_vm = __toESM(node_vm);
|
|
40
40
|
let node_fs_promises = require("node:fs/promises");
|
|
41
41
|
let _trpc_client = require("@trpc/client");
|
|
42
|
+
let _camstack_types_node = require("@camstack/types/node");
|
|
42
43
|
let node_http = require("node:http");
|
|
43
44
|
let node_events = require("node:events");
|
|
44
|
-
let _camstack_types_node = require("@camstack/types/node");
|
|
45
45
|
let node_module = require("node:module");
|
|
46
46
|
let node_url = require("node:url");
|
|
47
47
|
//#region src/kernel/addon-refused-error.ts
|
|
@@ -7885,13 +7885,13 @@ var CORAL_PCI_VENDOR = "0x1ac1";
|
|
|
7885
7885
|
var CORAL_PCI_DEVICE = "0x089a";
|
|
7886
7886
|
/** A unit the apex driver bound: `/sys/class/apex/apex_<N>` ↔ `/dev/apex_<N>`. */
|
|
7887
7887
|
var APEX_ENTRY = /^apex_(\d+)$/;
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7888
|
+
function currentDelegateHost() {
|
|
7889
|
+
return {
|
|
7890
|
+
platform: process.platform,
|
|
7891
|
+
dataDir: (0, _camstack_types_node.nodeDataRootFromEnv)(process.env),
|
|
7892
|
+
override: process.env[_camstack_types_node.EDGETPU_LIB_ENV]
|
|
7893
|
+
};
|
|
7894
|
+
}
|
|
7895
7895
|
function countUsbCorals(fsx) {
|
|
7896
7896
|
let count = 0;
|
|
7897
7897
|
for (const device of fsx.listUsbDevices()) {
|
|
@@ -7946,7 +7946,7 @@ function classifyPci(fsx) {
|
|
|
7946
7946
|
* Returns `null` only when no Coral was found at all; a present-but-unusable
|
|
7947
7947
|
* Coral is reported with its typed reason, never as absent (D393/D315).
|
|
7948
7948
|
*/
|
|
7949
|
-
function classifyCoralAccelerator(fsx) {
|
|
7949
|
+
function classifyCoralAccelerator(fsx, delegateHost = currentDelegateHost()) {
|
|
7950
7950
|
const usb = countUsbCorals(fsx);
|
|
7951
7951
|
const pci = classifyPci(fsx);
|
|
7952
7952
|
const units = [];
|
|
@@ -7977,8 +7977,10 @@ function classifyCoralAccelerator(fsx) {
|
|
|
7977
7977
|
type: "coral-edgetpu",
|
|
7978
7978
|
units
|
|
7979
7979
|
};
|
|
7980
|
-
|
|
7981
|
-
|
|
7980
|
+
if ((0, _camstack_types_node.chooseEdgetpuDelegate)({
|
|
7981
|
+
...delegateHost,
|
|
7982
|
+
exists: (p) => fsx.exists(p)
|
|
7983
|
+
}) !== null) return {
|
|
7982
7984
|
type: "coral-edgetpu",
|
|
7983
7985
|
units: [{
|
|
7984
7986
|
bus: "usb",
|
|
@@ -8987,6 +8989,19 @@ var AddonDepsManager = class {
|
|
|
8987
8989
|
const pythonPath = await this.ensurePython();
|
|
8988
8990
|
if (!pythonPath) throw new Error("Cannot install Python requirements: Python is not available");
|
|
8989
8991
|
await singleFlight(this.depsDir, "python-pip", () => (0, _camstack_types_node.installPythonRequirements)(pythonPath, requirementsFile, this.logger));
|
|
8992
|
+
await this.stageNativeDepsDeclaredBy(requirementsFile);
|
|
8993
|
+
}
|
|
8994
|
+
/**
|
|
8995
|
+
* The native library a requirements file says its packages need
|
|
8996
|
+
* (`# camstack-native-dep: edgetpu-delegate`), staged under this node's
|
|
8997
|
+
* deps dir. Runs on every call — not only the first pip install — so a
|
|
8998
|
+
* node whose pip marker predates the line still gets the library. A
|
|
8999
|
+
* platform without a build answers `unavailable` (logged, not thrown); a
|
|
9000
|
+
* failed or tampered download throws, and provisioning reports it.
|
|
9001
|
+
*/
|
|
9002
|
+
async stageNativeDepsDeclaredBy(requirementsFile) {
|
|
9003
|
+
if (!(0, _camstack_types_node.declaresEdgetpuDelegate)(node_fs.readFileSync(requirementsFile, "utf8"))) return;
|
|
9004
|
+
await singleFlight(this.depsDir, "edgetpu-delegate", () => (0, _camstack_types_node.ensureEdgetpuDelegate)(this.nodeRoot, this.logger));
|
|
8990
9005
|
}
|
|
8991
9006
|
getDepsDir() {
|
|
8992
9007
|
return this.depsDir;
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -16,9 +16,9 @@ import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
|
16
16
|
import * as vm from "node:vm";
|
|
17
17
|
import { mkdir, rm, stat, unlink } from "node:fs/promises";
|
|
18
18
|
import { TRPCClientError, createTRPCClient } from "@trpc/client";
|
|
19
|
+
import { EDGETPU_LIB_ENV, chooseEdgetpuDelegate, declaresEdgetpuDelegate, ensureBinary, ensureEdgetpuDelegate, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements, nodeDataRootFromEnv } from "@camstack/types/node";
|
|
19
20
|
import { createServer as createServer$1, request } from "node:http";
|
|
20
21
|
import { once } from "node:events";
|
|
21
|
-
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
22
22
|
import { pathToFileURL } from "node:url";
|
|
23
23
|
//#region src/kernel/addon-refused-error.ts
|
|
24
24
|
/**
|
|
@@ -7861,13 +7861,13 @@ var CORAL_PCI_VENDOR = "0x1ac1";
|
|
|
7861
7861
|
var CORAL_PCI_DEVICE = "0x089a";
|
|
7862
7862
|
/** A unit the apex driver bound: `/sys/class/apex/apex_<N>` ↔ `/dev/apex_<N>`. */
|
|
7863
7863
|
var APEX_ENTRY = /^apex_(\d+)$/;
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7864
|
+
function currentDelegateHost() {
|
|
7865
|
+
return {
|
|
7866
|
+
platform: process.platform,
|
|
7867
|
+
dataDir: nodeDataRootFromEnv(process.env),
|
|
7868
|
+
override: process.env[EDGETPU_LIB_ENV]
|
|
7869
|
+
};
|
|
7870
|
+
}
|
|
7871
7871
|
function countUsbCorals(fsx) {
|
|
7872
7872
|
let count = 0;
|
|
7873
7873
|
for (const device of fsx.listUsbDevices()) {
|
|
@@ -7922,7 +7922,7 @@ function classifyPci(fsx) {
|
|
|
7922
7922
|
* Returns `null` only when no Coral was found at all; a present-but-unusable
|
|
7923
7923
|
* Coral is reported with its typed reason, never as absent (D393/D315).
|
|
7924
7924
|
*/
|
|
7925
|
-
function classifyCoralAccelerator(fsx) {
|
|
7925
|
+
function classifyCoralAccelerator(fsx, delegateHost = currentDelegateHost()) {
|
|
7926
7926
|
const usb = countUsbCorals(fsx);
|
|
7927
7927
|
const pci = classifyPci(fsx);
|
|
7928
7928
|
const units = [];
|
|
@@ -7953,8 +7953,10 @@ function classifyCoralAccelerator(fsx) {
|
|
|
7953
7953
|
type: "coral-edgetpu",
|
|
7954
7954
|
units
|
|
7955
7955
|
};
|
|
7956
|
-
|
|
7957
|
-
|
|
7956
|
+
if (chooseEdgetpuDelegate({
|
|
7957
|
+
...delegateHost,
|
|
7958
|
+
exists: (p) => fsx.exists(p)
|
|
7959
|
+
}) !== null) return {
|
|
7958
7960
|
type: "coral-edgetpu",
|
|
7959
7961
|
units: [{
|
|
7960
7962
|
bus: "usb",
|
|
@@ -8963,6 +8965,19 @@ var AddonDepsManager = class {
|
|
|
8963
8965
|
const pythonPath = await this.ensurePython();
|
|
8964
8966
|
if (!pythonPath) throw new Error("Cannot install Python requirements: Python is not available");
|
|
8965
8967
|
await singleFlight(this.depsDir, "python-pip", () => installPythonRequirements(pythonPath, requirementsFile, this.logger));
|
|
8968
|
+
await this.stageNativeDepsDeclaredBy(requirementsFile);
|
|
8969
|
+
}
|
|
8970
|
+
/**
|
|
8971
|
+
* The native library a requirements file says its packages need
|
|
8972
|
+
* (`# camstack-native-dep: edgetpu-delegate`), staged under this node's
|
|
8973
|
+
* deps dir. Runs on every call — not only the first pip install — so a
|
|
8974
|
+
* node whose pip marker predates the line still gets the library. A
|
|
8975
|
+
* platform without a build answers `unavailable` (logged, not thrown); a
|
|
8976
|
+
* failed or tampered download throws, and provisioning reports it.
|
|
8977
|
+
*/
|
|
8978
|
+
async stageNativeDepsDeclaredBy(requirementsFile) {
|
|
8979
|
+
if (!declaresEdgetpuDelegate(fs$1.readFileSync(requirementsFile, "utf8"))) return;
|
|
8980
|
+
await singleFlight(this.depsDir, "edgetpu-delegate", () => ensureEdgetpuDelegate(this.nodeRoot, this.logger));
|
|
8966
8981
|
}
|
|
8967
8982
|
getDepsDir() {
|
|
8968
8983
|
return this.depsDir;
|
package/dist/addon-utils.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as isModelDownloaded, S as isModelDownloadHttpError, _ as downloadFile, a as startEventLoopStallMonitor, f as ModelDownloadService, g as deleteModelFromDisk, h as collectModelFiles, i as attributeStall, l as parseRangeHeader, m as adoptModelRevisions, n as STALL_REPORT_MS, o as createFileDataPlaneHandler, p as ModelDownloadHttpError, r as STALL_TICK_MS, s as contentTypeFor, t as CustomActionRegistry, w as resolveFormatRevision, x as getModelFilePath, y as ensureModel } from "./custom-action-registry-
|
|
1
|
+
import { C as isModelDownloaded, S as isModelDownloadHttpError, _ as downloadFile, a as startEventLoopStallMonitor, f as ModelDownloadService, g as deleteModelFromDisk, h as collectModelFiles, i as attributeStall, l as parseRangeHeader, m as adoptModelRevisions, n as STALL_REPORT_MS, o as createFileDataPlaneHandler, p as ModelDownloadHttpError, r as STALL_TICK_MS, s as contentTypeFor, t as CustomActionRegistry, w as resolveFormatRevision, x as getModelFilePath, y as ensureModel } from "./custom-action-registry-DStvrQKI.mjs";
|
|
2
2
|
import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg, t as COURTESY_DEFAULT_WIDTH } from "./snapshot-courtesy-CyFs1M3I.mjs";
|
|
3
3
|
export { COURTESY_DEFAULT_WIDTH, CustomActionRegistry, ModelDownloadHttpError, ModelDownloadService, STALL_REPORT_MS, STALL_TICK_MS, adoptModelRevisions, attributeStall, collectModelFiles, contentTypeFor, courtesyCacheKey, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloadHttpError, isModelDownloaded, parseRangeHeader, renderCourtesyJpeg, renderCourtesyOverlayJpeg, resolveFormatRevision, startEventLoopStallMonitor };
|
|
@@ -2,7 +2,7 @@ import { Ta as EventCategory, ni as BaseAddon, ti as errMsg, yt as addonPagesCap
|
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
5
|
-
import * as fs from "node:fs";
|
|
5
|
+
import * as fs$1 from "node:fs";
|
|
6
6
|
//#region src/builtins/addon-pages-aggregator/dedupe-pages.ts
|
|
7
7
|
/** Stable identity for an addon page, independent of which node reported it. */
|
|
8
8
|
function pageKey(info) {
|
|
@@ -211,11 +211,11 @@ var AddonPagesAggregatorAddon = class extends BaseAddon {
|
|
|
211
211
|
const bundlePath = this.resolveBundlePath(addonId, bundle);
|
|
212
212
|
if (bundlePath === null) return `/api/addon-pages/${addonId}/${bundle}?v=${Math.floor(Date.now())}`;
|
|
213
213
|
try {
|
|
214
|
-
const stat = fs.statSync(bundlePath);
|
|
214
|
+
const stat = fs$1.statSync(bundlePath);
|
|
215
215
|
const cacheKey = `${bundlePath}:${stat.size}:${stat.mtimeMs}`;
|
|
216
216
|
let v = this.bundleHashCache.get(cacheKey);
|
|
217
217
|
if (v === void 0) {
|
|
218
|
-
v = createHash("sha1").update(fs.readFileSync(bundlePath)).digest("hex").slice(0, 12);
|
|
218
|
+
v = createHash("sha1").update(fs$1.readFileSync(bundlePath)).digest("hex").slice(0, 12);
|
|
219
219
|
this.bundleHashCache.set(cacheKey, v);
|
|
220
220
|
}
|
|
221
221
|
return `/api/addon-pages/${addonId}/${bundle}?v=${v}`;
|
|
@@ -2,7 +2,7 @@ import { Ta as EventCategory, ni as BaseAddon, ti as errMsg, xt as addonWidgetsC
|
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
5
|
-
import * as fs from "node:fs";
|
|
5
|
+
import * as fs$1 from "node:fs";
|
|
6
6
|
//#region src/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.ts
|
|
7
7
|
/**
|
|
8
8
|
* Addon Widgets Aggregator — hub-local builtin that owns the singleton
|
|
@@ -204,9 +204,9 @@ var AddonWidgetsAggregatorAddon = class extends BaseAddon {
|
|
|
204
204
|
if (entryPath === null) return String(Math.floor(Date.now()));
|
|
205
205
|
try {
|
|
206
206
|
const dir = path$1.dirname(entryPath);
|
|
207
|
-
const files = fs.readdirSync(dir).filter((f) => fs.statSync(path$1.join(dir, f)).isFile()).sort();
|
|
207
|
+
const files = fs$1.readdirSync(dir).filter((f) => fs$1.statSync(path$1.join(dir, f)).isFile()).sort();
|
|
208
208
|
const cacheKey = `${dir}#${files.map((f) => {
|
|
209
|
-
const s = fs.statSync(path$1.join(dir, f));
|
|
209
|
+
const s = fs$1.statSync(path$1.join(dir, f));
|
|
210
210
|
return `${f}:${s.size}:${s.mtimeMs}`;
|
|
211
211
|
}).join("|")}`;
|
|
212
212
|
const cached = this.bundleHashCache.get(cacheKey);
|
|
@@ -214,7 +214,7 @@ var AddonWidgetsAggregatorAddon = class extends BaseAddon {
|
|
|
214
214
|
const hash = createHash("sha1");
|
|
215
215
|
for (const f of files) {
|
|
216
216
|
hash.update(f);
|
|
217
|
-
hash.update(fs.readFileSync(path$1.join(dir, f)));
|
|
217
|
+
hash.update(fs$1.readFileSync(path$1.join(dir, f)));
|
|
218
218
|
}
|
|
219
219
|
const digest = hash.digest("hex").slice(0, 12);
|
|
220
220
|
this.bundleHashCache.set(cacheKey, digest);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Dt as backupCapability, Or as storageOccupancyCapability, Ta as EventCategory, Un as mayWriteToLocation, ba as toNodeId, ni as BaseAddon, oa as nodePin } from "../../dist-Wy8cTxg6.mjs";
|
|
2
2
|
import { t as require_read_all_rows } from "../../read-all-rows-TaPqdWNF.mjs";
|
|
3
|
-
import { _ as backupRecordStoresOf, a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, g as backupOrchestratorRecordKinds, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-
|
|
3
|
+
import { _ as backupRecordStoresOf, a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, g as backupOrchestratorRecordKinds, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-CM23Pq9B.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import * as fsp from "node:fs/promises";
|
|
6
6
|
import * as path$1 from "node:path";
|
|
7
|
-
import * as fs from "node:fs";
|
|
7
|
+
import * as fs$1 from "node:fs";
|
|
8
8
|
//#region src/builtins/backup-orchestrator/backup-databases.ts
|
|
9
9
|
/** Stable id of the seeded weekly schedule. */
|
|
10
10
|
var WEEKLY_SCHEDULE_ID = "weekly-events-history";
|
|
@@ -1232,7 +1232,7 @@ async function downloadArchiveToCache(input) {
|
|
|
1232
1232
|
location: input.locationId,
|
|
1233
1233
|
relativePath: input.filename
|
|
1234
1234
|
});
|
|
1235
|
-
const writeStream = fs.createWriteStream(input.cachePath);
|
|
1235
|
+
const writeStream = fs$1.createWriteStream(input.cachePath);
|
|
1236
1236
|
let offset = 0;
|
|
1237
1237
|
try {
|
|
1238
1238
|
while (offset < sizeBytes) {
|
|
@@ -2932,7 +2932,7 @@ var BackupOrchestratorAddon = class extends BaseAddon {
|
|
|
2932
2932
|
});
|
|
2933
2933
|
try {
|
|
2934
2934
|
let offset = 0;
|
|
2935
|
-
const stream = fs.createReadStream(input.cachePath, { highWaterMark: UPLOAD_CHUNK_BYTES });
|
|
2935
|
+
const stream = fs$1.createReadStream(input.cachePath, { highWaterMark: UPLOAD_CHUNK_BYTES });
|
|
2936
2936
|
for await (const rawChunk of stream) {
|
|
2937
2937
|
if (input.signal?.aborted) {
|
|
2938
2938
|
stream.destroy();
|
|
@@ -9,7 +9,7 @@ import * as crypto$1 from "node:crypto";
|
|
|
9
9
|
import { X509Certificate, createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
10
10
|
import nodeCrypto from "crypto";
|
|
11
11
|
import * as path$1 from "node:path";
|
|
12
|
-
import * as fs from "node:fs";
|
|
12
|
+
import * as fs$1 from "node:fs";
|
|
13
13
|
//#region src/auth/parse-record.ts
|
|
14
14
|
function parseRecord$2(kind, schema, data) {
|
|
15
15
|
try {
|
|
@@ -12347,8 +12347,8 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
12347
12347
|
users: this.userManager,
|
|
12348
12348
|
dataDir: this.ctx.nodeDataDir,
|
|
12349
12349
|
fs: {
|
|
12350
|
-
exists: (filePath) => fs.existsSync(filePath),
|
|
12351
|
-
remove: (filePath) => fs.rmSync(filePath, { force: true })
|
|
12350
|
+
exists: (filePath) => fs$1.existsSync(filePath),
|
|
12351
|
+
remove: (filePath) => fs$1.rmSync(filePath, { force: true })
|
|
12352
12352
|
},
|
|
12353
12353
|
logger: this.ctx.logger
|
|
12354
12354
|
});
|
|
@@ -1063,6 +1063,36 @@ var NODE_GPU_TEMPERATURE_KEY = keyOf("node-gpu-temperature");
|
|
|
1063
1063
|
var NODE_CONTAINER_CURRENT_KEY = keyOf("container-current-mib");
|
|
1064
1064
|
keyOf("process-cpu-percent");
|
|
1065
1065
|
keyOf("process-rss-mib");
|
|
1066
|
+
/**
|
|
1067
|
+
* The per-runner series are downsampled to device-history's point cadence:
|
|
1068
|
+
* one point per series per this many ms, sustained. Process snapshots arrive
|
|
1069
|
+
* at the load-series cadence (5–60 s, `load-series-config.ts`), and at 5 s
|
|
1070
|
+
* writing each one has every other batch refused whole for `rate`.
|
|
1071
|
+
*
|
|
1072
|
+
* These two numbers MIRROR `RECORD_MIN_INTERVAL_MS` / `RECORD_RATE_SLACK_MS`
|
|
1073
|
+
* of the ingest door (`device-history/ingest/producer-ingest.ts`) — a builtin
|
|
1074
|
+
* does not import another — and `node-metrics-history-cadence.spec.ts` pins
|
|
1075
|
+
* them equal, so the door moving fails a spec instead of a day of history.
|
|
1076
|
+
*/
|
|
1077
|
+
var RUNNER_SAMPLE_MIN_INTERVAL_MS = 1e4;
|
|
1078
|
+
var RUNNER_SAMPLE_RATE_SLACK_MS = 1e3;
|
|
1079
|
+
/** True when the door would take a point at `ts` after `slot`. */
|
|
1080
|
+
function sampleIsDue(slot, ts) {
|
|
1081
|
+
if (slot === void 0 || ts < slot.lastTs) return true;
|
|
1082
|
+
return ts >= slot.nextDue - RUNNER_SAMPLE_RATE_SLACK_MS;
|
|
1083
|
+
}
|
|
1084
|
+
/** The slot after a batch at `ts` was accepted — the door's own grid rule. */
|
|
1085
|
+
function nextSampleSlot(slot, ts) {
|
|
1086
|
+
if (slot === void 0) return {
|
|
1087
|
+
lastTs: ts,
|
|
1088
|
+
nextDue: ts + RUNNER_SAMPLE_MIN_INTERVAL_MS
|
|
1089
|
+
};
|
|
1090
|
+
if (ts < slot.lastTs) return slot;
|
|
1091
|
+
return {
|
|
1092
|
+
lastTs: ts,
|
|
1093
|
+
nextDue: Math.max(slot.nextDue, ts) + RUNNER_SAMPLE_MIN_INTERVAL_MS
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1066
1096
|
var DECLARATIONS = [
|
|
1067
1097
|
{
|
|
1068
1098
|
name: "runner-cpu-main-percent",
|
|
@@ -1153,6 +1183,8 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1153
1183
|
deps;
|
|
1154
1184
|
declared = false;
|
|
1155
1185
|
lastTotalsAt = /* @__PURE__ */ new Map();
|
|
1186
|
+
/** Per node: the door's slot for the per-runner batch (see {@link sampleIsDue}). */
|
|
1187
|
+
sampleSlots = /* @__PURE__ */ new Map();
|
|
1156
1188
|
/** A not-ready skip was logged and device-history has not been ready since. */
|
|
1157
1189
|
waitLogged = false;
|
|
1158
1190
|
constructor(deps) {
|
|
@@ -1172,6 +1204,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1172
1204
|
}
|
|
1173
1205
|
/** One process snapshot: per-runner sums plus the container's memory. */
|
|
1174
1206
|
async recordSample(nodeId, atMs, processes, containerMemory) {
|
|
1207
|
+
if (!sampleIsDue(this.sampleSlots.get(nodeId), atMs)) return;
|
|
1175
1208
|
const subject = {
|
|
1176
1209
|
kind: "node",
|
|
1177
1210
|
nodeId
|
|
@@ -1215,7 +1248,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1215
1248
|
points.push(point(RUNNER_PROCESSES_KEY, scope, t.count));
|
|
1216
1249
|
}
|
|
1217
1250
|
if (containerMemory !== null) points.push(point(NODE_CONTAINER_CURRENT_KEY, "", Math.round(containerMemory.currentBytes / MIB)));
|
|
1218
|
-
await this.write(nodeId, atMs, points);
|
|
1251
|
+
if (await this.write(nodeId, atMs, points) > 0) this.sampleSlots.set(nodeId, nextSampleSlot(this.sampleSlots.get(nodeId), atMs));
|
|
1219
1252
|
}
|
|
1220
1253
|
/** One resources snapshot: the node's totals, at most every {@link NODE_TOTALS_MIN_INTERVAL_MS}. */
|
|
1221
1254
|
async recordTotals(nodeId, atMs, snapshot) {
|
|
@@ -1245,8 +1278,8 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1245
1278
|
await this.write(nodeId, atMs, points);
|
|
1246
1279
|
}
|
|
1247
1280
|
async write(nodeId, atMs, points) {
|
|
1248
|
-
if (points.length === 0) return;
|
|
1249
|
-
if (!await this.ensureDeclared()) return;
|
|
1281
|
+
if (points.length === 0) return 0;
|
|
1282
|
+
if (!await this.ensureDeclared()) return 0;
|
|
1250
1283
|
try {
|
|
1251
1284
|
const result = await this.deps.deviceHistory.record({ points });
|
|
1252
1285
|
if (result.refused.length > 0) {
|
|
@@ -1257,12 +1290,14 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1257
1290
|
refused: refusalCounts(result)
|
|
1258
1291
|
} });
|
|
1259
1292
|
}
|
|
1293
|
+
return result.accepted;
|
|
1260
1294
|
} catch (err) {
|
|
1261
1295
|
this.deps.logger.warn("node metrics history sample not stored", { meta: {
|
|
1262
1296
|
nodeId,
|
|
1263
1297
|
atMs,
|
|
1264
1298
|
error: err instanceof Error ? err.message : String(err)
|
|
1265
1299
|
} });
|
|
1300
|
+
return 0;
|
|
1266
1301
|
}
|
|
1267
1302
|
}
|
|
1268
1303
|
async readContainerPoints(nodeId, sinceMs, maxPoints) {
|
|
@@ -3,7 +3,7 @@ import { access, readFile, readdir } from "node:fs/promises";
|
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import * as os$1 from "node:os";
|
|
5
5
|
import { platform } from "node:os";
|
|
6
|
-
import * as fs from "node:fs";
|
|
6
|
+
import * as fs$1 from "node:fs";
|
|
7
7
|
import { constants, readFileSync } from "node:fs";
|
|
8
8
|
import { execFile, execFileSync } from "node:child_process";
|
|
9
9
|
//#region src/builtins/native-metrics/cgroup-memory.ts
|
|
@@ -1058,6 +1058,36 @@ var NODE_GPU_TEMPERATURE_KEY = keyOf("node-gpu-temperature");
|
|
|
1058
1058
|
var NODE_CONTAINER_CURRENT_KEY = keyOf("container-current-mib");
|
|
1059
1059
|
keyOf("process-cpu-percent");
|
|
1060
1060
|
keyOf("process-rss-mib");
|
|
1061
|
+
/**
|
|
1062
|
+
* The per-runner series are downsampled to device-history's point cadence:
|
|
1063
|
+
* one point per series per this many ms, sustained. Process snapshots arrive
|
|
1064
|
+
* at the load-series cadence (5–60 s, `load-series-config.ts`), and at 5 s
|
|
1065
|
+
* writing each one has every other batch refused whole for `rate`.
|
|
1066
|
+
*
|
|
1067
|
+
* These two numbers MIRROR `RECORD_MIN_INTERVAL_MS` / `RECORD_RATE_SLACK_MS`
|
|
1068
|
+
* of the ingest door (`device-history/ingest/producer-ingest.ts`) — a builtin
|
|
1069
|
+
* does not import another — and `node-metrics-history-cadence.spec.ts` pins
|
|
1070
|
+
* them equal, so the door moving fails a spec instead of a day of history.
|
|
1071
|
+
*/
|
|
1072
|
+
var RUNNER_SAMPLE_MIN_INTERVAL_MS = 1e4;
|
|
1073
|
+
var RUNNER_SAMPLE_RATE_SLACK_MS = 1e3;
|
|
1074
|
+
/** True when the door would take a point at `ts` after `slot`. */
|
|
1075
|
+
function sampleIsDue(slot, ts) {
|
|
1076
|
+
if (slot === void 0 || ts < slot.lastTs) return true;
|
|
1077
|
+
return ts >= slot.nextDue - RUNNER_SAMPLE_RATE_SLACK_MS;
|
|
1078
|
+
}
|
|
1079
|
+
/** The slot after a batch at `ts` was accepted — the door's own grid rule. */
|
|
1080
|
+
function nextSampleSlot(slot, ts) {
|
|
1081
|
+
if (slot === void 0) return {
|
|
1082
|
+
lastTs: ts,
|
|
1083
|
+
nextDue: ts + RUNNER_SAMPLE_MIN_INTERVAL_MS
|
|
1084
|
+
};
|
|
1085
|
+
if (ts < slot.lastTs) return slot;
|
|
1086
|
+
return {
|
|
1087
|
+
lastTs: ts,
|
|
1088
|
+
nextDue: Math.max(slot.nextDue, ts) + RUNNER_SAMPLE_MIN_INTERVAL_MS
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1061
1091
|
var DECLARATIONS = [
|
|
1062
1092
|
{
|
|
1063
1093
|
name: "runner-cpu-main-percent",
|
|
@@ -1148,6 +1178,8 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1148
1178
|
deps;
|
|
1149
1179
|
declared = false;
|
|
1150
1180
|
lastTotalsAt = /* @__PURE__ */ new Map();
|
|
1181
|
+
/** Per node: the door's slot for the per-runner batch (see {@link sampleIsDue}). */
|
|
1182
|
+
sampleSlots = /* @__PURE__ */ new Map();
|
|
1151
1183
|
/** A not-ready skip was logged and device-history has not been ready since. */
|
|
1152
1184
|
waitLogged = false;
|
|
1153
1185
|
constructor(deps) {
|
|
@@ -1167,6 +1199,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1167
1199
|
}
|
|
1168
1200
|
/** One process snapshot: per-runner sums plus the container's memory. */
|
|
1169
1201
|
async recordSample(nodeId, atMs, processes, containerMemory) {
|
|
1202
|
+
if (!sampleIsDue(this.sampleSlots.get(nodeId), atMs)) return;
|
|
1170
1203
|
const subject = {
|
|
1171
1204
|
kind: "node",
|
|
1172
1205
|
nodeId
|
|
@@ -1210,7 +1243,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1210
1243
|
points.push(point(RUNNER_PROCESSES_KEY, scope, t.count));
|
|
1211
1244
|
}
|
|
1212
1245
|
if (containerMemory !== null) points.push(point(NODE_CONTAINER_CURRENT_KEY, "", Math.round(containerMemory.currentBytes / MIB)));
|
|
1213
|
-
await this.write(nodeId, atMs, points);
|
|
1246
|
+
if (await this.write(nodeId, atMs, points) > 0) this.sampleSlots.set(nodeId, nextSampleSlot(this.sampleSlots.get(nodeId), atMs));
|
|
1214
1247
|
}
|
|
1215
1248
|
/** One resources snapshot: the node's totals, at most every {@link NODE_TOTALS_MIN_INTERVAL_MS}. */
|
|
1216
1249
|
async recordTotals(nodeId, atMs, snapshot) {
|
|
@@ -1240,8 +1273,8 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1240
1273
|
await this.write(nodeId, atMs, points);
|
|
1241
1274
|
}
|
|
1242
1275
|
async write(nodeId, atMs, points) {
|
|
1243
|
-
if (points.length === 0) return;
|
|
1244
|
-
if (!await this.ensureDeclared()) return;
|
|
1276
|
+
if (points.length === 0) return 0;
|
|
1277
|
+
if (!await this.ensureDeclared()) return 0;
|
|
1245
1278
|
try {
|
|
1246
1279
|
const result = await this.deps.deviceHistory.record({ points });
|
|
1247
1280
|
if (result.refused.length > 0) {
|
|
@@ -1252,12 +1285,14 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1252
1285
|
refused: refusalCounts(result)
|
|
1253
1286
|
} });
|
|
1254
1287
|
}
|
|
1288
|
+
return result.accepted;
|
|
1255
1289
|
} catch (err) {
|
|
1256
1290
|
this.deps.logger.warn("node metrics history sample not stored", { meta: {
|
|
1257
1291
|
nodeId,
|
|
1258
1292
|
atMs,
|
|
1259
1293
|
error: err instanceof Error ? err.message : String(err)
|
|
1260
1294
|
} });
|
|
1295
|
+
return 0;
|
|
1261
1296
|
}
|
|
1262
1297
|
}
|
|
1263
1298
|
async readContainerPoints(nodeId, sinceMs, maxPoints) {
|
|
@@ -1607,7 +1642,7 @@ var NativeMetricsProvider = class {
|
|
|
1607
1642
|
let swapUsedBytes = 0;
|
|
1608
1643
|
let swapTotalBytes = 0;
|
|
1609
1644
|
if (IS_LINUX) try {
|
|
1610
|
-
const meminfo = fs.readFileSync("/proc/meminfo", "utf-8");
|
|
1645
|
+
const meminfo = fs$1.readFileSync("/proc/meminfo", "utf-8");
|
|
1611
1646
|
const swapTotal = parseInt(meminfo.match(/SwapTotal:\s+(\d+)/)?.[1] ?? "0", 10) * 1024;
|
|
1612
1647
|
const swapFree = parseInt(meminfo.match(/SwapFree:\s+(\d+)/)?.[1] ?? "0", 10) * 1024;
|
|
1613
1648
|
swapTotalBytes = swapTotal;
|
|
@@ -1685,7 +1720,7 @@ function sampleMacMemory(provider) {
|
|
|
1685
1720
|
}
|
|
1686
1721
|
function getDiskSpaceInternal(dirPath) {
|
|
1687
1722
|
return new Promise((resolve, reject) => {
|
|
1688
|
-
fs.statfs(dirPath, (err, stats) => {
|
|
1723
|
+
fs$1.statfs(dirPath, (err, stats) => {
|
|
1689
1724
|
if (err) return reject(err);
|
|
1690
1725
|
const totalBytes = stats.blocks * stats.bsize;
|
|
1691
1726
|
const availableBytes = stats.bavail * stats.bsize;
|
|
@@ -1703,7 +1738,7 @@ function getDiskSpaceInternal(dirPath) {
|
|
|
1703
1738
|
async function takeDiskIoSnapshot() {
|
|
1704
1739
|
const now = Date.now();
|
|
1705
1740
|
if (IS_LINUX) try {
|
|
1706
|
-
const data = fs.readFileSync("/proc/diskstats", "utf-8");
|
|
1741
|
+
const data = fs$1.readFileSync("/proc/diskstats", "utf-8");
|
|
1707
1742
|
let readOps = 0, readBytes = 0, writeOps = 0, writeBytes = 0;
|
|
1708
1743
|
for (const line of data.split("\n")) {
|
|
1709
1744
|
const parts = line.trim().split(/\s+/);
|
|
@@ -1734,7 +1769,7 @@ async function takeDiskIoSnapshot() {
|
|
|
1734
1769
|
async function takeNetworkIoSnapshot() {
|
|
1735
1770
|
const now = Date.now();
|
|
1736
1771
|
if (IS_LINUX) try {
|
|
1737
|
-
const data = fs.readFileSync("/proc/net/dev", "utf-8");
|
|
1772
|
+
const data = fs$1.readFileSync("/proc/net/dev", "utf-8");
|
|
1738
1773
|
let rxBytes = 0, txBytes = 0, rxPackets = 0, txPackets = 0, rxErrors = 0, txErrors = 0;
|
|
1739
1774
|
for (const line of data.split("\n")) {
|
|
1740
1775
|
const match = line.match(/^\s*(\w+):\s+(.+)$/);
|
|
@@ -1795,7 +1830,7 @@ async function takeNetworkIoSnapshot() {
|
|
|
1795
1830
|
}
|
|
1796
1831
|
async function getCpuTemperatureInternal() {
|
|
1797
1832
|
if (IS_LINUX) for (const p of ["/sys/class/thermal/thermal_zone0/temp", "/sys/class/hwmon/hwmon0/temp1_input"]) try {
|
|
1798
|
-
const raw = fs.readFileSync(p, "utf-8").trim();
|
|
1833
|
+
const raw = fs$1.readFileSync(p, "utf-8").trim();
|
|
1799
1834
|
const millideg = parseInt(raw, 10);
|
|
1800
1835
|
if (!isNaN(millideg)) return Math.round(millideg / 100) / 10;
|
|
1801
1836
|
} catch {
|
|
@@ -1846,10 +1881,10 @@ function getProcessResources() {
|
|
|
1846
1881
|
let threadCount = 0;
|
|
1847
1882
|
if (IS_LINUX) {
|
|
1848
1883
|
try {
|
|
1849
|
-
openFds = fs.readdirSync(`/proc/${process.pid}/fd`).length;
|
|
1884
|
+
openFds = fs$1.readdirSync(`/proc/${process.pid}/fd`).length;
|
|
1850
1885
|
} catch {}
|
|
1851
1886
|
try {
|
|
1852
|
-
const match = fs.readFileSync(`/proc/${process.pid}/status`, "utf-8").match(/Threads:\s+(\d+)/);
|
|
1887
|
+
const match = fs$1.readFileSync(`/proc/${process.pid}/status`, "utf-8").match(/Threads:\s+(\d+)/);
|
|
1853
1888
|
if (match) threadCount = parseInt(match[1], 10);
|
|
1854
1889
|
} catch {}
|
|
1855
1890
|
}
|
|
@@ -1864,7 +1899,7 @@ function getProcessResources() {
|
|
|
1864
1899
|
function getPressure(resource) {
|
|
1865
1900
|
if (!IS_LINUX) return null;
|
|
1866
1901
|
try {
|
|
1867
|
-
const data = fs.readFileSync(`/proc/pressure/${resource}`, "utf-8");
|
|
1902
|
+
const data = fs$1.readFileSync(`/proc/pressure/${resource}`, "utf-8");
|
|
1868
1903
|
const parseLine = (prefix) => {
|
|
1869
1904
|
const match = data.match(new RegExp(`${prefix} avg10=(\\d+\\.\\d+) avg60=(\\d+\\.\\d+) avg300=(\\d+\\.\\d+)`));
|
|
1870
1905
|
if (!match) return null;
|
|
@@ -45,6 +45,19 @@ export declare const NODE_PROCESS_RSS_KEY: MetricsKey<"process-rss-mib">;
|
|
|
45
45
|
* point closer than 10 s to the previous one of its series (`rate`).
|
|
46
46
|
*/
|
|
47
47
|
export declare const NODE_TOTALS_MIN_INTERVAL_MS = 15e3;
|
|
48
|
+
/**
|
|
49
|
+
* The per-runner series are downsampled to device-history's point cadence:
|
|
50
|
+
* one point per series per this many ms, sustained. Process snapshots arrive
|
|
51
|
+
* at the load-series cadence (5–60 s, `load-series-config.ts`), and at 5 s
|
|
52
|
+
* writing each one has every other batch refused whole for `rate`.
|
|
53
|
+
*
|
|
54
|
+
* These two numbers MIRROR `RECORD_MIN_INTERVAL_MS` / `RECORD_RATE_SLACK_MS`
|
|
55
|
+
* of the ingest door (`device-history/ingest/producer-ingest.ts`) — a builtin
|
|
56
|
+
* does not import another — and `node-metrics-history-cadence.spec.ts` pins
|
|
57
|
+
* them equal, so the door moving fails a spec instead of a day of history.
|
|
58
|
+
*/
|
|
59
|
+
export declare const RUNNER_SAMPLE_MIN_INTERVAL_MS = 1e4;
|
|
60
|
+
export declare const RUNNER_SAMPLE_RATE_SLACK_MS = 1e3;
|
|
48
61
|
export interface NodeHistoryPoint {
|
|
49
62
|
readonly key: string;
|
|
50
63
|
readonly subject: {
|
|
@@ -107,6 +120,8 @@ export declare class NodeMetricsHistoryRecorder {
|
|
|
107
120
|
private readonly deps;
|
|
108
121
|
private declared;
|
|
109
122
|
private readonly lastTotalsAt;
|
|
123
|
+
/** Per node: the door's slot for the per-runner batch (see {@link sampleIsDue}). */
|
|
124
|
+
private readonly sampleSlots;
|
|
110
125
|
/** A not-ready skip was logged and device-history has not been ready since. */
|
|
111
126
|
private waitLogged;
|
|
112
127
|
constructor(deps: NodeMetricsHistoryRecorderDeps);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CoralInfo } from "@camstack/types";
|
|
2
|
+
import { type EdgetpuDelegateLookup } from "@camstack/types/node";
|
|
2
3
|
/**
|
|
3
4
|
* Filesystem seam for Coral Edge TPU detection (USB and PCIe/M.2) — mirrors
|
|
4
5
|
* the `AcceleratorFs` pattern in `intel-accelerators.ts` so the classifier
|
|
@@ -21,6 +22,14 @@ export interface CoralFs {
|
|
|
21
22
|
exists(path: string): boolean;
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
25
|
+
* Where this node would find the libedgetpu delegate — the same lookup the
|
|
26
|
+
* Python pool runs (`edgetpu_device.edgetpu_library_path`): the
|
|
27
|
+
* `CAMSTACK_EDGETPU_LIB` override, the copy the deps downloader staged under
|
|
28
|
+
* `<CAMSTACK_DATA>/deps/edgetpu/lib/`, the hub's historical
|
|
29
|
+
* `/data/deps/edgetpu/lib/libedgetpu.so.1`.
|
|
30
|
+
*/
|
|
31
|
+
export type EdgetpuDelegateHost = Omit<EdgetpuDelegateLookup, "exists">;
|
|
32
|
+
/**
|
|
24
33
|
* Detect Coral Edge TPUs on USB and PCIe/M.2.
|
|
25
34
|
*
|
|
26
35
|
* - USB: every matching USB device counts (multiple Corals run concurrently).
|
|
@@ -34,6 +43,6 @@ export interface CoralFs {
|
|
|
34
43
|
* Returns `null` only when no Coral was found at all; a present-but-unusable
|
|
35
44
|
* Coral is reported with its typed reason, never as absent (D393/D315).
|
|
36
45
|
*/
|
|
37
|
-
export declare function classifyCoralAccelerator(fsx: CoralFs): CoralInfo | null;
|
|
46
|
+
export declare function classifyCoralAccelerator(fsx: CoralFs, delegateHost?: EdgetpuDelegateHost): CoralInfo | null;
|
|
38
47
|
/** The real filesystem view: `/sys` for enumeration, `/dev` for access. */
|
|
39
48
|
export declare const nodeCoralFs: CoralFs;
|
|
@@ -4,7 +4,7 @@ Object.defineProperties(exports, {
|
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
6
|
const require_dist = require("../../dist-Bn-RNanh.js");
|
|
7
|
-
const require_coral_accelerators = require("../../coral-accelerators-
|
|
7
|
+
const require_coral_accelerators = require("../../coral-accelerators-oUXmmbc2.js");
|
|
8
8
|
let node_util = require("node:util");
|
|
9
9
|
let node_os = require("node:os");
|
|
10
10
|
node_os = require_chunk.__toESM(node_os);
|
|
@@ -329,9 +329,12 @@ var PlatformScorer = class {
|
|
|
329
329
|
* lookup (dev / agent environments where Python is on PATH).
|
|
330
330
|
*/
|
|
331
331
|
embeddedPythonPath;
|
|
332
|
-
|
|
332
|
+
/** Where the Coral scan reads `/sys` and `/dev` (the host's, unless a spec fakes one). */
|
|
333
|
+
coralFs;
|
|
334
|
+
constructor(logger = noopLogger, embeddedPythonPath = null, coralFs = require_coral_accelerators.nodeCoralFs) {
|
|
333
335
|
this.logger = logger;
|
|
334
336
|
this.embeddedPythonPath = embeddedPythonPath;
|
|
337
|
+
this.coralFs = coralFs;
|
|
335
338
|
}
|
|
336
339
|
/**
|
|
337
340
|
* Probe hardware + derive scores from pure rules and score all backend combos.
|
|
@@ -414,7 +417,7 @@ var PlatformScorer = class {
|
|
|
414
417
|
} });
|
|
415
418
|
let gpu = null;
|
|
416
419
|
let npu = null;
|
|
417
|
-
const coral = require_coral_accelerators.classifyCoralAccelerator(
|
|
420
|
+
const coral = require_coral_accelerators.classifyCoralAccelerator(this.coralFs);
|
|
418
421
|
if (coral) {
|
|
419
422
|
if ((coral.units ?? []).length > 0) this.logger.info("Coral Edge TPU detected", { meta: { units: coral.units } });
|
|
420
423
|
for (const unavailable of coral.unavailable ?? []) this.logger.warn("Coral Edge TPU present but unusable", { meta: {
|