@camstack/addon-ai 0.4.15 → 0.4.17
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.js +308 -31
- package/dist/addon.mjs +308 -31
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -15,7 +15,7 @@ let node_zlib = require("node:zlib");
|
|
|
15
15
|
let node_fs_promises = require("node:fs/promises");
|
|
16
16
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
17
17
|
let node_child_process = require("node:child_process");
|
|
18
|
-
//#region ../types/dist/event-category-
|
|
18
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
19
19
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
20
20
|
EventCategory["SystemBoot"] = "system.boot";
|
|
21
21
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -31,6 +31,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
31
31
|
*/
|
|
32
32
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
33
33
|
/**
|
|
34
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
35
|
+
* Emitted only when the material on disk actually changed, so an
|
|
36
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
37
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
38
|
+
*
|
|
39
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
40
|
+
*/
|
|
41
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
42
|
+
/**
|
|
34
43
|
* A newer addon or server-root package version was found by the
|
|
35
44
|
* authoritative registry check. Emitted once when any observed
|
|
36
45
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -8217,6 +8226,15 @@ var LabelDefinitionSchema = object({
|
|
|
8217
8226
|
description: string().optional(),
|
|
8218
8227
|
icon: string().optional()
|
|
8219
8228
|
});
|
|
8229
|
+
var ClassMapDefinitionSchema = object({
|
|
8230
|
+
mapping: record(string(), _enum([
|
|
8231
|
+
"person",
|
|
8232
|
+
"vehicle",
|
|
8233
|
+
"animal",
|
|
8234
|
+
"package"
|
|
8235
|
+
])),
|
|
8236
|
+
preserveOriginal: boolean()
|
|
8237
|
+
});
|
|
8220
8238
|
var MODEL_FORMATS = [
|
|
8221
8239
|
"onnx",
|
|
8222
8240
|
"coreml",
|
|
@@ -8395,7 +8413,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8395
8413
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8396
8414
|
* is a presentation overlay resolved back to an `id`.
|
|
8397
8415
|
*/
|
|
8398
|
-
group: ModelVariantGroupSchema.optional()
|
|
8416
|
+
group: ModelVariantGroupSchema.optional(),
|
|
8417
|
+
/**
|
|
8418
|
+
* Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
|
|
8419
|
+
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8420
|
+
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8421
|
+
*/
|
|
8422
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8399
8423
|
});
|
|
8400
8424
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8401
8425
|
format: literal("openvino"),
|
|
@@ -8424,7 +8448,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8424
8448
|
"ocr",
|
|
8425
8449
|
"segmentation"
|
|
8426
8450
|
]),
|
|
8427
|
-
faceAlignment: boolean().optional()
|
|
8451
|
+
faceAlignment: boolean().optional(),
|
|
8452
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8428
8453
|
});
|
|
8429
8454
|
var ConvertResultSchema = object({
|
|
8430
8455
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17496,6 +17521,33 @@ var NativeCropRefSchema = object({
|
|
|
17496
17521
|
h: number$1()
|
|
17497
17522
|
})
|
|
17498
17523
|
});
|
|
17524
|
+
object({
|
|
17525
|
+
crop: object({
|
|
17526
|
+
left: number$1(),
|
|
17527
|
+
top: number$1(),
|
|
17528
|
+
width: number$1().positive(),
|
|
17529
|
+
height: number$1().positive()
|
|
17530
|
+
}).optional(),
|
|
17531
|
+
content: object({
|
|
17532
|
+
width: number$1().int().positive(),
|
|
17533
|
+
height: number$1().int().positive()
|
|
17534
|
+
}),
|
|
17535
|
+
fit: _enum(["stretch", "contain"]),
|
|
17536
|
+
format: _enum([
|
|
17537
|
+
"rgb",
|
|
17538
|
+
"gray",
|
|
17539
|
+
"jpeg"
|
|
17540
|
+
])
|
|
17541
|
+
});
|
|
17542
|
+
var FrameRefSchema = object({
|
|
17543
|
+
registryId: string().min(1),
|
|
17544
|
+
id: string().min(1),
|
|
17545
|
+
width: number$1().int().positive(),
|
|
17546
|
+
height: number$1().int().positive(),
|
|
17547
|
+
format: _enum(["rgb", "gray"]),
|
|
17548
|
+
timestamp: number$1(),
|
|
17549
|
+
capturedAt: number$1().optional()
|
|
17550
|
+
});
|
|
17499
17551
|
var ModelFormatSchema$1 = _enum([
|
|
17500
17552
|
"onnx",
|
|
17501
17553
|
"coreml",
|
|
@@ -17740,6 +17792,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17740
17792
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17741
17793
|
frame: FrameInputSchema.optional(),
|
|
17742
17794
|
/**
|
|
17795
|
+
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
17796
|
+
* in the same execution-group process; split/cross-node callers use
|
|
17797
|
+
* `frame`/`image` inline compatibility instead.
|
|
17798
|
+
*/
|
|
17799
|
+
frameRef: FrameRefSchema.optional(),
|
|
17800
|
+
/**
|
|
17743
17801
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17744
17802
|
* the decoded pixels live in. One more member of the one-of
|
|
17745
17803
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -17995,7 +18053,10 @@ var NativeCropResultSchema = object({
|
|
|
17995
18053
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
17996
18054
|
* `keyFrame`) can reject a degraded fallback:
|
|
17997
18055
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
17998
|
-
* quality path).
|
|
18056
|
+
* quality path). A subject-tile serve is also native-resolution and stays
|
|
18057
|
+
* `native` here: the public enum cannot name `tile` without a breaking cap
|
|
18058
|
+
* change. Runner telemetry distinguishes lease vs tile via `source` on the
|
|
18059
|
+
* internal crop result (`nativeHits` vs `tileHits`).
|
|
17999
18060
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
18000
18061
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
18001
18062
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18486,12 +18547,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18486
18547
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18487
18548
|
* working unchanged when they switch to reading from the runner cap.
|
|
18488
18549
|
*/
|
|
18550
|
+
var FrameLazyCountersSchema = object({
|
|
18551
|
+
framesDecoded: number$1(),
|
|
18552
|
+
framesAdmitted: number$1(),
|
|
18553
|
+
framesDroppedPixelFree: number$1(),
|
|
18554
|
+
viewsMaterialized: number$1(),
|
|
18555
|
+
viewsSkipped: number$1(),
|
|
18556
|
+
workerToRunnerBytes: number$1(),
|
|
18557
|
+
runnerToPoolRawBytes: number$1(),
|
|
18558
|
+
runnerToPoolJpegBytes: number$1(),
|
|
18559
|
+
onDemandFullFrameRequests: number$1(),
|
|
18560
|
+
onDemandCropRequests: number$1(),
|
|
18561
|
+
nativeHits: number$1(),
|
|
18562
|
+
nativeMisses: number$1(),
|
|
18563
|
+
tileHits: number$1(),
|
|
18564
|
+
tileMisses: number$1(),
|
|
18565
|
+
fallbackHits: number$1(),
|
|
18566
|
+
fallbackMisses: number$1(),
|
|
18567
|
+
retainedWritesAvoided: number$1(),
|
|
18568
|
+
residentRefs: number$1(),
|
|
18569
|
+
residentBytes: number$1(),
|
|
18570
|
+
releases: number$1(),
|
|
18571
|
+
evictions: number$1(),
|
|
18572
|
+
staleMisses: number$1()
|
|
18573
|
+
});
|
|
18574
|
+
var FrameLazyMetricsSchema = object({
|
|
18575
|
+
node: FrameLazyCountersSchema,
|
|
18576
|
+
cameras: array(FrameLazyCountersSchema.extend({ deviceId: number$1() }))
|
|
18577
|
+
});
|
|
18489
18578
|
var RunnerLocalMetricsSchema = object({
|
|
18490
18579
|
nodeId: string(),
|
|
18491
18580
|
activeCameras: number$1(),
|
|
18492
18581
|
throttledCameras: number$1(),
|
|
18493
18582
|
avgInferenceTimeMs: number$1(),
|
|
18494
|
-
queueDepth: number$1()
|
|
18583
|
+
queueDepth: number$1(),
|
|
18584
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18495
18585
|
});
|
|
18496
18586
|
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number$1() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number$1() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number$1()).readonly()), method(object({
|
|
18497
18587
|
handle: FrameHandleSchema,
|
|
@@ -19791,6 +19881,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19791
19881
|
location: StorageLocationSchema,
|
|
19792
19882
|
relativePath: string()
|
|
19793
19883
|
}), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number$1().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
|
|
19884
|
+
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
19885
|
+
var ProfileSettingsSchemaBridge = unknown().nullable();
|
|
19886
|
+
var ProfileSettingsBagSchema = record(string(), unknown());
|
|
19794
19887
|
/**
|
|
19795
19888
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19796
19889
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19820,7 +19913,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19820
19913
|
var TerminalProfileInfoSchema = object({
|
|
19821
19914
|
profileId: string(),
|
|
19822
19915
|
label: string(),
|
|
19823
|
-
description: string().optional()
|
|
19916
|
+
description: string().optional(),
|
|
19917
|
+
/** Spawn defaults the instance form copies on create. */
|
|
19918
|
+
executable: string().optional(),
|
|
19919
|
+
args: array(string()).readonly().optional(),
|
|
19920
|
+
cwd: string().optional(),
|
|
19921
|
+
environment: array(string()).readonly().optional(),
|
|
19922
|
+
/** ConfigUISchema for instance knobs, or null when the profile has none. */
|
|
19923
|
+
settingsSchema: ProfileSettingsSchemaBridge.optional()
|
|
19824
19924
|
});
|
|
19825
19925
|
/**
|
|
19826
19926
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19833,7 +19933,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19833
19933
|
profileId: string(),
|
|
19834
19934
|
profileLabel: string(),
|
|
19835
19935
|
name: string(),
|
|
19836
|
-
enabled: boolean()
|
|
19936
|
+
enabled: boolean(),
|
|
19937
|
+
executable: string(),
|
|
19938
|
+
args: array(string()).readonly(),
|
|
19939
|
+
cwd: string(),
|
|
19940
|
+
environment: array(string()).readonly(),
|
|
19941
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19837
19942
|
});
|
|
19838
19943
|
var TerminalLegacyCameraSchema = object({
|
|
19839
19944
|
stableId: string(),
|
|
@@ -19863,7 +19968,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19863
19968
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19864
19969
|
targetNodeId: string().min(1),
|
|
19865
19970
|
profileId: string().min(1),
|
|
19866
|
-
name: string().trim().min(1).max(160).optional()
|
|
19971
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19972
|
+
executable: string().max(1024).optional(),
|
|
19973
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19974
|
+
cwd: string().max(1024).optional(),
|
|
19975
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19976
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19977
|
+
}), TerminalInstanceInfoSchema, {
|
|
19978
|
+
kind: "mutation",
|
|
19979
|
+
auth: "admin"
|
|
19980
|
+
}), method(object({
|
|
19981
|
+
instanceId: string().min(1),
|
|
19982
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19983
|
+
executable: string().max(1024).optional(),
|
|
19984
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19985
|
+
cwd: string().max(1024).optional(),
|
|
19986
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19987
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19867
19988
|
}), TerminalInstanceInfoSchema, {
|
|
19868
19989
|
kind: "mutation",
|
|
19869
19990
|
auth: "admin"
|
|
@@ -19885,7 +20006,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19885
20006
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19886
20007
|
profileId: string(),
|
|
19887
20008
|
cols: number$1().int().positive(),
|
|
19888
|
-
rows: number$1().int().positive()
|
|
20009
|
+
rows: number$1().int().positive(),
|
|
20010
|
+
executable: string().max(1024).optional(),
|
|
20011
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
20012
|
+
cwd: string().max(1024).optional(),
|
|
20013
|
+
environment: array(string().max(4096)).max(64).optional()
|
|
19889
20014
|
}), TerminalSessionInfoSchema, {
|
|
19890
20015
|
kind: "mutation",
|
|
19891
20016
|
auth: "admin"
|
|
@@ -22667,10 +22792,10 @@ DeviceType.LawnMower, method(object({ deviceId: number$1().int().nonnegative() }
|
|
|
22667
22792
|
*
|
|
22668
22793
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22669
22794
|
* to receive an ordered list of candidate base URLs it should race
|
|
22670
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22671
|
-
* then public hostname (if a tunnel is
|
|
22672
|
-
* race them with short timeouts and stick with the
|
|
22673
|
-
* session.
|
|
22795
|
+
* on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
|
|
22796
|
+
* when on the same network), then public hostname (if a tunnel is
|
|
22797
|
+
* up). The SDK can race them with short timeouts and stick with the
|
|
22798
|
+
* winner for the session.
|
|
22674
22799
|
*
|
|
22675
22800
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22676
22801
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22825,6 +22950,17 @@ var NotificationEndpointSchema = object({
|
|
|
22825
22950
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22826
22951
|
resolved: string().nullable()
|
|
22827
22952
|
});
|
|
22953
|
+
/**
|
|
22954
|
+
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
22955
|
+
* AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
|
|
22956
|
+
* currently expands to, so the UI can show the effective set either way.
|
|
22957
|
+
*/
|
|
22958
|
+
var ViewerEndpointsSchema = object({
|
|
22959
|
+
/** The operator's explicit race set, or empty for AUTO. */
|
|
22960
|
+
baseUrls: array(string()).readonly(),
|
|
22961
|
+
/** What the ranking currently resolves to (may be empty if nothing is up). */
|
|
22962
|
+
resolved: array(string()).readonly()
|
|
22963
|
+
});
|
|
22828
22964
|
var AllowedAddressesSchema = object({
|
|
22829
22965
|
/**
|
|
22830
22966
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22833,6 +22969,20 @@ var AllowedAddressesSchema = object({
|
|
|
22833
22969
|
* Network Addresses admin page and persisted by the addon.
|
|
22834
22970
|
*/
|
|
22835
22971
|
addresses: array(string()).readonly() });
|
|
22972
|
+
var TlsStatusSchema = object({
|
|
22973
|
+
mode: _enum([
|
|
22974
|
+
"generated",
|
|
22975
|
+
"uploaded",
|
|
22976
|
+
"disabled"
|
|
22977
|
+
]),
|
|
22978
|
+
leafFingerprintSha256: string().nullable(),
|
|
22979
|
+
caFingerprintSha256: string().nullable(),
|
|
22980
|
+
validTo: string().nullable(),
|
|
22981
|
+
sans: array(string()),
|
|
22982
|
+
caCertPem: string().nullable(),
|
|
22983
|
+
reissueError: string().nullable(),
|
|
22984
|
+
restartRequired: boolean()
|
|
22985
|
+
});
|
|
22836
22986
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22837
22987
|
/**
|
|
22838
22988
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22842,17 +22992,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22842
22992
|
*/
|
|
22843
22993
|
port: number$1().int().min(1).max(65535).optional(),
|
|
22844
22994
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22845
|
-
* candidate. Default `
|
|
22995
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22846
22996
|
includeLoopback: boolean().optional(),
|
|
22847
|
-
/** Skip IPv6 entries.
|
|
22848
|
-
*
|
|
22997
|
+
/** Skip IPv6 entries. Default `false` — the palette includes stable
|
|
22998
|
+
* LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
|
|
22999
|
+
* hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
|
|
22849
23000
|
ipv4Only: boolean().optional(),
|
|
22850
23001
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22851
23002
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22852
23003
|
* to avoid mixed-content blocks in the browser. The public
|
|
22853
23004
|
* tunnel always emits `https://` regardless. */
|
|
22854
23005
|
scheme: _enum(["http", "https"]).optional()
|
|
22855
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" })
|
|
23006
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
23007
|
+
kind: "mutation",
|
|
23008
|
+
auth: "admin"
|
|
23009
|
+
}), method(object({
|
|
23010
|
+
certPem: string().min(1),
|
|
23011
|
+
keyPem: string().min(1),
|
|
23012
|
+
caPem: string().optional()
|
|
23013
|
+
}), TlsStatusSchema, {
|
|
23014
|
+
kind: "mutation",
|
|
23015
|
+
auth: "admin"
|
|
23016
|
+
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
23017
|
+
kind: "mutation",
|
|
23018
|
+
auth: "admin"
|
|
23019
|
+
});
|
|
22856
23020
|
object({
|
|
22857
23021
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22858
23022
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28615,6 +28779,12 @@ Object.freeze({
|
|
|
28615
28779
|
addonId: null,
|
|
28616
28780
|
access: "create"
|
|
28617
28781
|
},
|
|
28782
|
+
"localNetwork.downloadCa": {
|
|
28783
|
+
capName: "local-network",
|
|
28784
|
+
capScope: "system",
|
|
28785
|
+
addonId: null,
|
|
28786
|
+
access: "view"
|
|
28787
|
+
},
|
|
28618
28788
|
"localNetwork.getAllowedAddresses": {
|
|
28619
28789
|
capName: "local-network",
|
|
28620
28790
|
capScope: "system",
|
|
@@ -28639,18 +28809,42 @@ Object.freeze({
|
|
|
28639
28809
|
addonId: null,
|
|
28640
28810
|
access: "view"
|
|
28641
28811
|
},
|
|
28812
|
+
"localNetwork.getTlsStatus": {
|
|
28813
|
+
capName: "local-network",
|
|
28814
|
+
capScope: "system",
|
|
28815
|
+
addonId: null,
|
|
28816
|
+
access: "view"
|
|
28817
|
+
},
|
|
28818
|
+
"localNetwork.getViewerEndpoints": {
|
|
28819
|
+
capName: "local-network",
|
|
28820
|
+
capScope: "system",
|
|
28821
|
+
addonId: null,
|
|
28822
|
+
access: "view"
|
|
28823
|
+
},
|
|
28642
28824
|
"localNetwork.list": {
|
|
28643
28825
|
capName: "local-network",
|
|
28644
28826
|
capScope: "system",
|
|
28645
28827
|
addonId: null,
|
|
28646
28828
|
access: "view"
|
|
28647
28829
|
},
|
|
28830
|
+
"localNetwork.regenerateCertificate": {
|
|
28831
|
+
capName: "local-network",
|
|
28832
|
+
capScope: "system",
|
|
28833
|
+
addonId: null,
|
|
28834
|
+
access: "create"
|
|
28835
|
+
},
|
|
28648
28836
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28649
28837
|
capName: "local-network",
|
|
28650
28838
|
capScope: "system",
|
|
28651
28839
|
addonId: null,
|
|
28652
28840
|
access: "delete"
|
|
28653
28841
|
},
|
|
28842
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28843
|
+
capName: "local-network",
|
|
28844
|
+
capScope: "system",
|
|
28845
|
+
addonId: null,
|
|
28846
|
+
access: "create"
|
|
28847
|
+
},
|
|
28654
28848
|
"localNetwork.setAllowedAddresses": {
|
|
28655
28849
|
capName: "local-network",
|
|
28656
28850
|
capScope: "system",
|
|
@@ -28663,6 +28857,18 @@ Object.freeze({
|
|
|
28663
28857
|
addonId: null,
|
|
28664
28858
|
access: "create"
|
|
28665
28859
|
},
|
|
28860
|
+
"localNetwork.setViewerEndpoints": {
|
|
28861
|
+
capName: "local-network",
|
|
28862
|
+
capScope: "system",
|
|
28863
|
+
addonId: null,
|
|
28864
|
+
access: "create"
|
|
28865
|
+
},
|
|
28866
|
+
"localNetwork.uploadCertificate": {
|
|
28867
|
+
capName: "local-network",
|
|
28868
|
+
capScope: "system",
|
|
28869
|
+
addonId: null,
|
|
28870
|
+
access: "create"
|
|
28871
|
+
},
|
|
28666
28872
|
"lockControl.lock": {
|
|
28667
28873
|
capName: "lock-control",
|
|
28668
28874
|
capScope: "device",
|
|
@@ -31543,6 +31749,12 @@ Object.freeze({
|
|
|
31543
31749
|
addonId: null,
|
|
31544
31750
|
access: "create"
|
|
31545
31751
|
},
|
|
31752
|
+
"terminalSession.updateInstance": {
|
|
31753
|
+
capName: "terminal-session",
|
|
31754
|
+
capScope: "system",
|
|
31755
|
+
addonId: null,
|
|
31756
|
+
access: "create"
|
|
31757
|
+
},
|
|
31546
31758
|
"terminalSession.writeInput": {
|
|
31547
31759
|
capName: "terminal-session",
|
|
31548
31760
|
capScope: "system",
|
|
@@ -34030,6 +34242,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
34030
34242
|
}]
|
|
34031
34243
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
34032
34244
|
string().min(1);
|
|
34245
|
+
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
34246
|
+
stepId: "face-embedding",
|
|
34247
|
+
key: "minLandmarkFaceSize",
|
|
34248
|
+
label: "Min face size for recognition (detection px)",
|
|
34249
|
+
description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
|
|
34250
|
+
type: "slider",
|
|
34251
|
+
min: 0,
|
|
34252
|
+
max: 64,
|
|
34253
|
+
step: 2,
|
|
34254
|
+
default: 24
|
|
34255
|
+
}];
|
|
34256
|
+
function clusterStepSettingKey(stepId, fieldKey) {
|
|
34257
|
+
return `clusterStepSetting:${stepId}:${fieldKey}`;
|
|
34258
|
+
}
|
|
34259
|
+
var ClusterSettingNumberSchema = number$1().finite();
|
|
34260
|
+
function readClusterStepSettings(config) {
|
|
34261
|
+
const out = {};
|
|
34262
|
+
for (const field of CLUSTER_STEP_SETTING_FIELDS) {
|
|
34263
|
+
const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
|
|
34264
|
+
const value = parsed.success ? parsed.data : field.default;
|
|
34265
|
+
const existing = out[field.stepId] ?? {};
|
|
34266
|
+
out[field.stepId] = {
|
|
34267
|
+
...existing,
|
|
34268
|
+
[field.key]: value
|
|
34269
|
+
};
|
|
34270
|
+
}
|
|
34271
|
+
return out;
|
|
34272
|
+
}
|
|
34273
|
+
readClusterStepSettings({});
|
|
34033
34274
|
object({
|
|
34034
34275
|
/**
|
|
34035
34276
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -71706,7 +71947,7 @@ function entryForRef(ref) {
|
|
|
71706
71947
|
};
|
|
71707
71948
|
}
|
|
71708
71949
|
//#endregion
|
|
71709
|
-
//#region ../system/dist/file-data-plane-
|
|
71950
|
+
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
71710
71951
|
function isNonEmptyFile(filePath) {
|
|
71711
71952
|
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
71712
71953
|
}
|
|
@@ -71728,21 +71969,56 @@ function buildHeaders(url) {
|
|
|
71728
71969
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
71729
71970
|
return headers;
|
|
71730
71971
|
}
|
|
71731
|
-
|
|
71732
|
-
|
|
71733
|
-
|
|
71734
|
-
|
|
71735
|
-
|
|
71736
|
-
|
|
71737
|
-
|
|
71972
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
71973
|
+
function normalizeDownloadOptions(third) {
|
|
71974
|
+
if (typeof third === "function") return { onProgress: third };
|
|
71975
|
+
return third ?? {};
|
|
71976
|
+
}
|
|
71977
|
+
function isRedirectStatus(status) {
|
|
71978
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
71979
|
+
}
|
|
71980
|
+
function resolveRedirectUrl(current, location) {
|
|
71981
|
+
return new URL(location, current);
|
|
71982
|
+
}
|
|
71983
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
71738
71984
|
if (node_fs.existsSync(destPath)) return destPath;
|
|
71985
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
71986
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
71987
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
71739
71988
|
node_fs.mkdirSync(node_path$1.dirname(destPath), { recursive: true });
|
|
71740
71989
|
const tmpPath = destPath + ".downloading";
|
|
71741
71990
|
try {
|
|
71742
|
-
|
|
71743
|
-
|
|
71744
|
-
|
|
71745
|
-
|
|
71991
|
+
let current = url;
|
|
71992
|
+
const seen = /* @__PURE__ */ new Set();
|
|
71993
|
+
let response;
|
|
71994
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
71995
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
71996
|
+
const parsed = new URL(current);
|
|
71997
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
71998
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
71999
|
+
seen.add(parsed.href);
|
|
72000
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
72001
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
72002
|
+
try {
|
|
72003
|
+
response = await fetchImpl(current, {
|
|
72004
|
+
redirect: manual ? "manual" : "follow",
|
|
72005
|
+
headers: buildHeaders(current),
|
|
72006
|
+
...controller ? { signal: controller.signal } : {}
|
|
72007
|
+
});
|
|
72008
|
+
} finally {
|
|
72009
|
+
if (timer) clearTimeout(timer);
|
|
72010
|
+
}
|
|
72011
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
72012
|
+
const location = response.headers.get("location");
|
|
72013
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
72014
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
72015
|
+
current = resolveRedirectUrl(current, location).href;
|
|
72016
|
+
continue;
|
|
72017
|
+
}
|
|
72018
|
+
break;
|
|
72019
|
+
}
|
|
72020
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
72021
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
71746
72022
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
71747
72023
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
71748
72024
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -71753,9 +72029,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
71753
72029
|
for (;;) {
|
|
71754
72030
|
const { done, value } = await reader.read();
|
|
71755
72031
|
if (done || !value) break;
|
|
71756
|
-
fileStream.write(value);
|
|
71757
72032
|
downloaded += value.length;
|
|
71758
|
-
|
|
72033
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
72034
|
+
fileStream.write(value);
|
|
72035
|
+
opts.onProgress?.(downloaded, total);
|
|
71759
72036
|
}
|
|
71760
72037
|
} finally {
|
|
71761
72038
|
fileStream.end();
|
package/dist/addon.mjs
CHANGED
|
@@ -41,7 +41,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
41
41
|
}) : target, mod));
|
|
42
42
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
43
43
|
//#endregion
|
|
44
|
-
//#region ../types/dist/event-category-
|
|
44
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
45
45
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
46
46
|
EventCategory["SystemBoot"] = "system.boot";
|
|
47
47
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -57,6 +57,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
57
57
|
*/
|
|
58
58
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
59
59
|
/**
|
|
60
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
61
|
+
* Emitted only when the material on disk actually changed, so an
|
|
62
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
63
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
64
|
+
*
|
|
65
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
66
|
+
*/
|
|
67
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
68
|
+
/**
|
|
60
69
|
* A newer addon or server-root package version was found by the
|
|
61
70
|
* authoritative registry check. Emitted once when any observed
|
|
62
71
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -8243,6 +8252,15 @@ var LabelDefinitionSchema = object({
|
|
|
8243
8252
|
description: string().optional(),
|
|
8244
8253
|
icon: string().optional()
|
|
8245
8254
|
});
|
|
8255
|
+
var ClassMapDefinitionSchema = object({
|
|
8256
|
+
mapping: record(string(), _enum([
|
|
8257
|
+
"person",
|
|
8258
|
+
"vehicle",
|
|
8259
|
+
"animal",
|
|
8260
|
+
"package"
|
|
8261
|
+
])),
|
|
8262
|
+
preserveOriginal: boolean()
|
|
8263
|
+
});
|
|
8246
8264
|
var MODEL_FORMATS = [
|
|
8247
8265
|
"onnx",
|
|
8248
8266
|
"coreml",
|
|
@@ -8421,7 +8439,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8421
8439
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8422
8440
|
* is a presentation overlay resolved back to an `id`.
|
|
8423
8441
|
*/
|
|
8424
|
-
group: ModelVariantGroupSchema.optional()
|
|
8442
|
+
group: ModelVariantGroupSchema.optional(),
|
|
8443
|
+
/**
|
|
8444
|
+
* Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
|
|
8445
|
+
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8446
|
+
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8447
|
+
*/
|
|
8448
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8425
8449
|
});
|
|
8426
8450
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8427
8451
|
format: literal("openvino"),
|
|
@@ -8450,7 +8474,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8450
8474
|
"ocr",
|
|
8451
8475
|
"segmentation"
|
|
8452
8476
|
]),
|
|
8453
|
-
faceAlignment: boolean().optional()
|
|
8477
|
+
faceAlignment: boolean().optional(),
|
|
8478
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8454
8479
|
});
|
|
8455
8480
|
var ConvertResultSchema = object({
|
|
8456
8481
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17522,6 +17547,33 @@ var NativeCropRefSchema = object({
|
|
|
17522
17547
|
h: number$1()
|
|
17523
17548
|
})
|
|
17524
17549
|
});
|
|
17550
|
+
object({
|
|
17551
|
+
crop: object({
|
|
17552
|
+
left: number$1(),
|
|
17553
|
+
top: number$1(),
|
|
17554
|
+
width: number$1().positive(),
|
|
17555
|
+
height: number$1().positive()
|
|
17556
|
+
}).optional(),
|
|
17557
|
+
content: object({
|
|
17558
|
+
width: number$1().int().positive(),
|
|
17559
|
+
height: number$1().int().positive()
|
|
17560
|
+
}),
|
|
17561
|
+
fit: _enum(["stretch", "contain"]),
|
|
17562
|
+
format: _enum([
|
|
17563
|
+
"rgb",
|
|
17564
|
+
"gray",
|
|
17565
|
+
"jpeg"
|
|
17566
|
+
])
|
|
17567
|
+
});
|
|
17568
|
+
var FrameRefSchema = object({
|
|
17569
|
+
registryId: string().min(1),
|
|
17570
|
+
id: string().min(1),
|
|
17571
|
+
width: number$1().int().positive(),
|
|
17572
|
+
height: number$1().int().positive(),
|
|
17573
|
+
format: _enum(["rgb", "gray"]),
|
|
17574
|
+
timestamp: number$1(),
|
|
17575
|
+
capturedAt: number$1().optional()
|
|
17576
|
+
});
|
|
17525
17577
|
var ModelFormatSchema$1 = _enum([
|
|
17526
17578
|
"onnx",
|
|
17527
17579
|
"coreml",
|
|
@@ -17766,6 +17818,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17766
17818
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17767
17819
|
frame: FrameInputSchema.optional(),
|
|
17768
17820
|
/**
|
|
17821
|
+
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
17822
|
+
* in the same execution-group process; split/cross-node callers use
|
|
17823
|
+
* `frame`/`image` inline compatibility instead.
|
|
17824
|
+
*/
|
|
17825
|
+
frameRef: FrameRefSchema.optional(),
|
|
17826
|
+
/**
|
|
17769
17827
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17770
17828
|
* the decoded pixels live in. One more member of the one-of
|
|
17771
17829
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -18021,7 +18079,10 @@ var NativeCropResultSchema = object({
|
|
|
18021
18079
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
18022
18080
|
* `keyFrame`) can reject a degraded fallback:
|
|
18023
18081
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
18024
|
-
* quality path).
|
|
18082
|
+
* quality path). A subject-tile serve is also native-resolution and stays
|
|
18083
|
+
* `native` here: the public enum cannot name `tile` without a breaking cap
|
|
18084
|
+
* change. Runner telemetry distinguishes lease vs tile via `source` on the
|
|
18085
|
+
* internal crop result (`nativeHits` vs `tileHits`).
|
|
18025
18086
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
18026
18087
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
18027
18088
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18512,12 +18573,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18512
18573
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18513
18574
|
* working unchanged when they switch to reading from the runner cap.
|
|
18514
18575
|
*/
|
|
18576
|
+
var FrameLazyCountersSchema = object({
|
|
18577
|
+
framesDecoded: number$1(),
|
|
18578
|
+
framesAdmitted: number$1(),
|
|
18579
|
+
framesDroppedPixelFree: number$1(),
|
|
18580
|
+
viewsMaterialized: number$1(),
|
|
18581
|
+
viewsSkipped: number$1(),
|
|
18582
|
+
workerToRunnerBytes: number$1(),
|
|
18583
|
+
runnerToPoolRawBytes: number$1(),
|
|
18584
|
+
runnerToPoolJpegBytes: number$1(),
|
|
18585
|
+
onDemandFullFrameRequests: number$1(),
|
|
18586
|
+
onDemandCropRequests: number$1(),
|
|
18587
|
+
nativeHits: number$1(),
|
|
18588
|
+
nativeMisses: number$1(),
|
|
18589
|
+
tileHits: number$1(),
|
|
18590
|
+
tileMisses: number$1(),
|
|
18591
|
+
fallbackHits: number$1(),
|
|
18592
|
+
fallbackMisses: number$1(),
|
|
18593
|
+
retainedWritesAvoided: number$1(),
|
|
18594
|
+
residentRefs: number$1(),
|
|
18595
|
+
residentBytes: number$1(),
|
|
18596
|
+
releases: number$1(),
|
|
18597
|
+
evictions: number$1(),
|
|
18598
|
+
staleMisses: number$1()
|
|
18599
|
+
});
|
|
18600
|
+
var FrameLazyMetricsSchema = object({
|
|
18601
|
+
node: FrameLazyCountersSchema,
|
|
18602
|
+
cameras: array(FrameLazyCountersSchema.extend({ deviceId: number$1() }))
|
|
18603
|
+
});
|
|
18515
18604
|
var RunnerLocalMetricsSchema = object({
|
|
18516
18605
|
nodeId: string(),
|
|
18517
18606
|
activeCameras: number$1(),
|
|
18518
18607
|
throttledCameras: number$1(),
|
|
18519
18608
|
avgInferenceTimeMs: number$1(),
|
|
18520
|
-
queueDepth: number$1()
|
|
18609
|
+
queueDepth: number$1(),
|
|
18610
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18521
18611
|
});
|
|
18522
18612
|
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number$1() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number$1() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number$1()).readonly()), method(object({
|
|
18523
18613
|
handle: FrameHandleSchema,
|
|
@@ -19817,6 +19907,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19817
19907
|
location: StorageLocationSchema,
|
|
19818
19908
|
relativePath: string()
|
|
19819
19909
|
}), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number$1().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
|
|
19910
|
+
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
19911
|
+
var ProfileSettingsSchemaBridge = unknown().nullable();
|
|
19912
|
+
var ProfileSettingsBagSchema = record(string(), unknown());
|
|
19820
19913
|
/**
|
|
19821
19914
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19822
19915
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19846,7 +19939,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19846
19939
|
var TerminalProfileInfoSchema = object({
|
|
19847
19940
|
profileId: string(),
|
|
19848
19941
|
label: string(),
|
|
19849
|
-
description: string().optional()
|
|
19942
|
+
description: string().optional(),
|
|
19943
|
+
/** Spawn defaults the instance form copies on create. */
|
|
19944
|
+
executable: string().optional(),
|
|
19945
|
+
args: array(string()).readonly().optional(),
|
|
19946
|
+
cwd: string().optional(),
|
|
19947
|
+
environment: array(string()).readonly().optional(),
|
|
19948
|
+
/** ConfigUISchema for instance knobs, or null when the profile has none. */
|
|
19949
|
+
settingsSchema: ProfileSettingsSchemaBridge.optional()
|
|
19850
19950
|
});
|
|
19851
19951
|
/**
|
|
19852
19952
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19859,7 +19959,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19859
19959
|
profileId: string(),
|
|
19860
19960
|
profileLabel: string(),
|
|
19861
19961
|
name: string(),
|
|
19862
|
-
enabled: boolean()
|
|
19962
|
+
enabled: boolean(),
|
|
19963
|
+
executable: string(),
|
|
19964
|
+
args: array(string()).readonly(),
|
|
19965
|
+
cwd: string(),
|
|
19966
|
+
environment: array(string()).readonly(),
|
|
19967
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19863
19968
|
});
|
|
19864
19969
|
var TerminalLegacyCameraSchema = object({
|
|
19865
19970
|
stableId: string(),
|
|
@@ -19889,7 +19994,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19889
19994
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19890
19995
|
targetNodeId: string().min(1),
|
|
19891
19996
|
profileId: string().min(1),
|
|
19892
|
-
name: string().trim().min(1).max(160).optional()
|
|
19997
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19998
|
+
executable: string().max(1024).optional(),
|
|
19999
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
20000
|
+
cwd: string().max(1024).optional(),
|
|
20001
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
20002
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
20003
|
+
}), TerminalInstanceInfoSchema, {
|
|
20004
|
+
kind: "mutation",
|
|
20005
|
+
auth: "admin"
|
|
20006
|
+
}), method(object({
|
|
20007
|
+
instanceId: string().min(1),
|
|
20008
|
+
name: string().trim().min(1).max(160).optional(),
|
|
20009
|
+
executable: string().max(1024).optional(),
|
|
20010
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
20011
|
+
cwd: string().max(1024).optional(),
|
|
20012
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
20013
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19893
20014
|
}), TerminalInstanceInfoSchema, {
|
|
19894
20015
|
kind: "mutation",
|
|
19895
20016
|
auth: "admin"
|
|
@@ -19911,7 +20032,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19911
20032
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19912
20033
|
profileId: string(),
|
|
19913
20034
|
cols: number$1().int().positive(),
|
|
19914
|
-
rows: number$1().int().positive()
|
|
20035
|
+
rows: number$1().int().positive(),
|
|
20036
|
+
executable: string().max(1024).optional(),
|
|
20037
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
20038
|
+
cwd: string().max(1024).optional(),
|
|
20039
|
+
environment: array(string().max(4096)).max(64).optional()
|
|
19915
20040
|
}), TerminalSessionInfoSchema, {
|
|
19916
20041
|
kind: "mutation",
|
|
19917
20042
|
auth: "admin"
|
|
@@ -22693,10 +22818,10 @@ DeviceType.LawnMower, method(object({ deviceId: number$1().int().nonnegative() }
|
|
|
22693
22818
|
*
|
|
22694
22819
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22695
22820
|
* to receive an ordered list of candidate base URLs it should race
|
|
22696
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22697
|
-
* then public hostname (if a tunnel is
|
|
22698
|
-
* race them with short timeouts and stick with the
|
|
22699
|
-
* session.
|
|
22821
|
+
* on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
|
|
22822
|
+
* when on the same network), then public hostname (if a tunnel is
|
|
22823
|
+
* up). The SDK can race them with short timeouts and stick with the
|
|
22824
|
+
* winner for the session.
|
|
22700
22825
|
*
|
|
22701
22826
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22702
22827
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22851,6 +22976,17 @@ var NotificationEndpointSchema = object({
|
|
|
22851
22976
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22852
22977
|
resolved: string().nullable()
|
|
22853
22978
|
});
|
|
22979
|
+
/**
|
|
22980
|
+
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
22981
|
+
* AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
|
|
22982
|
+
* currently expands to, so the UI can show the effective set either way.
|
|
22983
|
+
*/
|
|
22984
|
+
var ViewerEndpointsSchema = object({
|
|
22985
|
+
/** The operator's explicit race set, or empty for AUTO. */
|
|
22986
|
+
baseUrls: array(string()).readonly(),
|
|
22987
|
+
/** What the ranking currently resolves to (may be empty if nothing is up). */
|
|
22988
|
+
resolved: array(string()).readonly()
|
|
22989
|
+
});
|
|
22854
22990
|
var AllowedAddressesSchema = object({
|
|
22855
22991
|
/**
|
|
22856
22992
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22859,6 +22995,20 @@ var AllowedAddressesSchema = object({
|
|
|
22859
22995
|
* Network Addresses admin page and persisted by the addon.
|
|
22860
22996
|
*/
|
|
22861
22997
|
addresses: array(string()).readonly() });
|
|
22998
|
+
var TlsStatusSchema = object({
|
|
22999
|
+
mode: _enum([
|
|
23000
|
+
"generated",
|
|
23001
|
+
"uploaded",
|
|
23002
|
+
"disabled"
|
|
23003
|
+
]),
|
|
23004
|
+
leafFingerprintSha256: string().nullable(),
|
|
23005
|
+
caFingerprintSha256: string().nullable(),
|
|
23006
|
+
validTo: string().nullable(),
|
|
23007
|
+
sans: array(string()),
|
|
23008
|
+
caCertPem: string().nullable(),
|
|
23009
|
+
reissueError: string().nullable(),
|
|
23010
|
+
restartRequired: boolean()
|
|
23011
|
+
});
|
|
22862
23012
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22863
23013
|
/**
|
|
22864
23014
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22868,17 +23018,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22868
23018
|
*/
|
|
22869
23019
|
port: number$1().int().min(1).max(65535).optional(),
|
|
22870
23020
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22871
|
-
* candidate. Default `
|
|
23021
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22872
23022
|
includeLoopback: boolean().optional(),
|
|
22873
|
-
/** Skip IPv6 entries.
|
|
22874
|
-
*
|
|
23023
|
+
/** Skip IPv6 entries. Default `false` — the palette includes stable
|
|
23024
|
+
* LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
|
|
23025
|
+
* hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
|
|
22875
23026
|
ipv4Only: boolean().optional(),
|
|
22876
23027
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22877
23028
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22878
23029
|
* to avoid mixed-content blocks in the browser. The public
|
|
22879
23030
|
* tunnel always emits `https://` regardless. */
|
|
22880
23031
|
scheme: _enum(["http", "https"]).optional()
|
|
22881
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" })
|
|
23032
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
23033
|
+
kind: "mutation",
|
|
23034
|
+
auth: "admin"
|
|
23035
|
+
}), method(object({
|
|
23036
|
+
certPem: string().min(1),
|
|
23037
|
+
keyPem: string().min(1),
|
|
23038
|
+
caPem: string().optional()
|
|
23039
|
+
}), TlsStatusSchema, {
|
|
23040
|
+
kind: "mutation",
|
|
23041
|
+
auth: "admin"
|
|
23042
|
+
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
23043
|
+
kind: "mutation",
|
|
23044
|
+
auth: "admin"
|
|
23045
|
+
});
|
|
22882
23046
|
object({
|
|
22883
23047
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22884
23048
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28641,6 +28805,12 @@ Object.freeze({
|
|
|
28641
28805
|
addonId: null,
|
|
28642
28806
|
access: "create"
|
|
28643
28807
|
},
|
|
28808
|
+
"localNetwork.downloadCa": {
|
|
28809
|
+
capName: "local-network",
|
|
28810
|
+
capScope: "system",
|
|
28811
|
+
addonId: null,
|
|
28812
|
+
access: "view"
|
|
28813
|
+
},
|
|
28644
28814
|
"localNetwork.getAllowedAddresses": {
|
|
28645
28815
|
capName: "local-network",
|
|
28646
28816
|
capScope: "system",
|
|
@@ -28665,18 +28835,42 @@ Object.freeze({
|
|
|
28665
28835
|
addonId: null,
|
|
28666
28836
|
access: "view"
|
|
28667
28837
|
},
|
|
28838
|
+
"localNetwork.getTlsStatus": {
|
|
28839
|
+
capName: "local-network",
|
|
28840
|
+
capScope: "system",
|
|
28841
|
+
addonId: null,
|
|
28842
|
+
access: "view"
|
|
28843
|
+
},
|
|
28844
|
+
"localNetwork.getViewerEndpoints": {
|
|
28845
|
+
capName: "local-network",
|
|
28846
|
+
capScope: "system",
|
|
28847
|
+
addonId: null,
|
|
28848
|
+
access: "view"
|
|
28849
|
+
},
|
|
28668
28850
|
"localNetwork.list": {
|
|
28669
28851
|
capName: "local-network",
|
|
28670
28852
|
capScope: "system",
|
|
28671
28853
|
addonId: null,
|
|
28672
28854
|
access: "view"
|
|
28673
28855
|
},
|
|
28856
|
+
"localNetwork.regenerateCertificate": {
|
|
28857
|
+
capName: "local-network",
|
|
28858
|
+
capScope: "system",
|
|
28859
|
+
addonId: null,
|
|
28860
|
+
access: "create"
|
|
28861
|
+
},
|
|
28674
28862
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28675
28863
|
capName: "local-network",
|
|
28676
28864
|
capScope: "system",
|
|
28677
28865
|
addonId: null,
|
|
28678
28866
|
access: "delete"
|
|
28679
28867
|
},
|
|
28868
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28869
|
+
capName: "local-network",
|
|
28870
|
+
capScope: "system",
|
|
28871
|
+
addonId: null,
|
|
28872
|
+
access: "create"
|
|
28873
|
+
},
|
|
28680
28874
|
"localNetwork.setAllowedAddresses": {
|
|
28681
28875
|
capName: "local-network",
|
|
28682
28876
|
capScope: "system",
|
|
@@ -28689,6 +28883,18 @@ Object.freeze({
|
|
|
28689
28883
|
addonId: null,
|
|
28690
28884
|
access: "create"
|
|
28691
28885
|
},
|
|
28886
|
+
"localNetwork.setViewerEndpoints": {
|
|
28887
|
+
capName: "local-network",
|
|
28888
|
+
capScope: "system",
|
|
28889
|
+
addonId: null,
|
|
28890
|
+
access: "create"
|
|
28891
|
+
},
|
|
28892
|
+
"localNetwork.uploadCertificate": {
|
|
28893
|
+
capName: "local-network",
|
|
28894
|
+
capScope: "system",
|
|
28895
|
+
addonId: null,
|
|
28896
|
+
access: "create"
|
|
28897
|
+
},
|
|
28692
28898
|
"lockControl.lock": {
|
|
28693
28899
|
capName: "lock-control",
|
|
28694
28900
|
capScope: "device",
|
|
@@ -31569,6 +31775,12 @@ Object.freeze({
|
|
|
31569
31775
|
addonId: null,
|
|
31570
31776
|
access: "create"
|
|
31571
31777
|
},
|
|
31778
|
+
"terminalSession.updateInstance": {
|
|
31779
|
+
capName: "terminal-session",
|
|
31780
|
+
capScope: "system",
|
|
31781
|
+
addonId: null,
|
|
31782
|
+
access: "create"
|
|
31783
|
+
},
|
|
31572
31784
|
"terminalSession.writeInput": {
|
|
31573
31785
|
capName: "terminal-session",
|
|
31574
31786
|
capScope: "system",
|
|
@@ -34056,6 +34268,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
34056
34268
|
}]
|
|
34057
34269
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
34058
34270
|
string().min(1);
|
|
34271
|
+
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
34272
|
+
stepId: "face-embedding",
|
|
34273
|
+
key: "minLandmarkFaceSize",
|
|
34274
|
+
label: "Min face size for recognition (detection px)",
|
|
34275
|
+
description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
|
|
34276
|
+
type: "slider",
|
|
34277
|
+
min: 0,
|
|
34278
|
+
max: 64,
|
|
34279
|
+
step: 2,
|
|
34280
|
+
default: 24
|
|
34281
|
+
}];
|
|
34282
|
+
function clusterStepSettingKey(stepId, fieldKey) {
|
|
34283
|
+
return `clusterStepSetting:${stepId}:${fieldKey}`;
|
|
34284
|
+
}
|
|
34285
|
+
var ClusterSettingNumberSchema = number$1().finite();
|
|
34286
|
+
function readClusterStepSettings(config) {
|
|
34287
|
+
const out = {};
|
|
34288
|
+
for (const field of CLUSTER_STEP_SETTING_FIELDS) {
|
|
34289
|
+
const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
|
|
34290
|
+
const value = parsed.success ? parsed.data : field.default;
|
|
34291
|
+
const existing = out[field.stepId] ?? {};
|
|
34292
|
+
out[field.stepId] = {
|
|
34293
|
+
...existing,
|
|
34294
|
+
[field.key]: value
|
|
34295
|
+
};
|
|
34296
|
+
}
|
|
34297
|
+
return out;
|
|
34298
|
+
}
|
|
34299
|
+
readClusterStepSettings({});
|
|
34059
34300
|
object({
|
|
34060
34301
|
/**
|
|
34061
34302
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -71732,7 +71973,7 @@ function entryForRef(ref) {
|
|
|
71732
71973
|
};
|
|
71733
71974
|
}
|
|
71734
71975
|
//#endregion
|
|
71735
|
-
//#region ../system/dist/file-data-plane-
|
|
71976
|
+
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
71736
71977
|
function isNonEmptyFile(filePath) {
|
|
71737
71978
|
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
71738
71979
|
}
|
|
@@ -71754,21 +71995,56 @@ function buildHeaders(url) {
|
|
|
71754
71995
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
71755
71996
|
return headers;
|
|
71756
71997
|
}
|
|
71757
|
-
|
|
71758
|
-
|
|
71759
|
-
|
|
71760
|
-
|
|
71761
|
-
|
|
71762
|
-
|
|
71763
|
-
|
|
71998
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
71999
|
+
function normalizeDownloadOptions(third) {
|
|
72000
|
+
if (typeof third === "function") return { onProgress: third };
|
|
72001
|
+
return third ?? {};
|
|
72002
|
+
}
|
|
72003
|
+
function isRedirectStatus(status) {
|
|
72004
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
72005
|
+
}
|
|
72006
|
+
function resolveRedirectUrl(current, location) {
|
|
72007
|
+
return new URL(location, current);
|
|
72008
|
+
}
|
|
72009
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
71764
72010
|
if (fs.existsSync(destPath)) return destPath;
|
|
72011
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
72012
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
72013
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
71765
72014
|
fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
|
|
71766
72015
|
const tmpPath = destPath + ".downloading";
|
|
71767
72016
|
try {
|
|
71768
|
-
|
|
71769
|
-
|
|
71770
|
-
|
|
71771
|
-
|
|
72017
|
+
let current = url;
|
|
72018
|
+
const seen = /* @__PURE__ */ new Set();
|
|
72019
|
+
let response;
|
|
72020
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
72021
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
72022
|
+
const parsed = new URL(current);
|
|
72023
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
72024
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
72025
|
+
seen.add(parsed.href);
|
|
72026
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
72027
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
72028
|
+
try {
|
|
72029
|
+
response = await fetchImpl(current, {
|
|
72030
|
+
redirect: manual ? "manual" : "follow",
|
|
72031
|
+
headers: buildHeaders(current),
|
|
72032
|
+
...controller ? { signal: controller.signal } : {}
|
|
72033
|
+
});
|
|
72034
|
+
} finally {
|
|
72035
|
+
if (timer) clearTimeout(timer);
|
|
72036
|
+
}
|
|
72037
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
72038
|
+
const location = response.headers.get("location");
|
|
72039
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
72040
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
72041
|
+
current = resolveRedirectUrl(current, location).href;
|
|
72042
|
+
continue;
|
|
72043
|
+
}
|
|
72044
|
+
break;
|
|
72045
|
+
}
|
|
72046
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
72047
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
71772
72048
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
71773
72049
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
71774
72050
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -71779,9 +72055,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
71779
72055
|
for (;;) {
|
|
71780
72056
|
const { done, value } = await reader.read();
|
|
71781
72057
|
if (done || !value) break;
|
|
71782
|
-
fileStream.write(value);
|
|
71783
72058
|
downloaded += value.length;
|
|
71784
|
-
|
|
72059
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
72060
|
+
fileStream.write(value);
|
|
72061
|
+
opts.onProgress?.(downloaded, total);
|
|
71785
72062
|
}
|
|
71786
72063
|
} finally {
|
|
71787
72064
|
fileStream.end();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.17",
|
|
4
4
|
"description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|