@camstack/addon-terminal 0.1.27 → 0.1.29
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 +310 -173
- package/dist/addon.mjs +310 -173
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -31,7 +31,7 @@ let node_module = require("node:module");
|
|
|
31
31
|
let sharp = require("sharp");
|
|
32
32
|
sharp = __toESM(sharp);
|
|
33
33
|
let node_http = require("node:http");
|
|
34
|
-
//#region ../types/dist/event-category-
|
|
34
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
35
35
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
36
36
|
EventCategory["SystemBoot"] = "system.boot";
|
|
37
37
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -47,6 +47,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
47
47
|
*/
|
|
48
48
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
49
49
|
/**
|
|
50
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
51
|
+
* Emitted only when the material on disk actually changed, so an
|
|
52
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
53
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
54
|
+
*
|
|
55
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
56
|
+
*/
|
|
57
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
58
|
+
/**
|
|
50
59
|
* A newer addon or server-root package version was found by the
|
|
51
60
|
* authoritative registry check. Emitted once when any observed
|
|
52
61
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -19025,6 +19034,12 @@ var CameraStatusSchema = object({
|
|
|
19025
19034
|
/** Unix timestamp (ms) when this snapshot was composed server-side. */
|
|
19026
19035
|
fetchedAt: number()
|
|
19027
19036
|
});
|
|
19037
|
+
var InferenceDeviceExclusionReasonSchema = _enum([
|
|
19038
|
+
"disabled",
|
|
19039
|
+
"unavailable",
|
|
19040
|
+
"cannot-host-camera-root",
|
|
19041
|
+
"accelerator-preferred"
|
|
19042
|
+
]);
|
|
19028
19043
|
var NodeInferenceDeviceSchema = object({
|
|
19029
19044
|
/** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
|
|
19030
19045
|
key: string(),
|
|
@@ -19055,7 +19070,17 @@ var NodeInferenceDeviceSchema = object({
|
|
|
19055
19070
|
* available per format; this is the stored selection that becomes the
|
|
19056
19071
|
* default for EVERY camera landing on this accelerator.
|
|
19057
19072
|
*/
|
|
19058
|
-
steps: record(string(), DeviceStepConfigSchema).optional()
|
|
19073
|
+
steps: record(string(), DeviceStepConfigSchema).optional(),
|
|
19074
|
+
/**
|
|
19075
|
+
* `null` when the device IS a camera-root candidate on this node; otherwise
|
|
19076
|
+
* the reason the dispatcher drops it. Computed by the SAME
|
|
19077
|
+
* `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
|
|
19078
|
+
* never disagree with the election — deriving it in the UI from
|
|
19079
|
+
* `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
|
|
19080
|
+
* the node's model catalog) and `accelerator-preferred` (needs the node-wide
|
|
19081
|
+
* "an accelerator is serving" predicate).
|
|
19082
|
+
*/
|
|
19083
|
+
exclusion: InferenceDeviceExclusionReasonSchema.nullable()
|
|
19059
19084
|
});
|
|
19060
19085
|
var NodeInferenceDevicesSchema = object({
|
|
19061
19086
|
nodeId: string(),
|
|
@@ -24053,7 +24078,12 @@ var ListResultSchema = object({
|
|
|
24053
24078
|
probedAt: number()
|
|
24054
24079
|
});
|
|
24055
24080
|
var PreferredSchema = LocalInterfaceSchema.nullable();
|
|
24056
|
-
|
|
24081
|
+
/**
|
|
24082
|
+
* Candidate base URL for the SDK to race on connect. Order matters —
|
|
24083
|
+
* the SDK should attempt these top-to-bottom with a short per-candidate
|
|
24084
|
+
* timeout (e.g. 1500ms) and cache the winner for the session.
|
|
24085
|
+
*/
|
|
24086
|
+
var ConnectionEndpointSchema = object({
|
|
24057
24087
|
/** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
|
|
24058
24088
|
label: string(),
|
|
24059
24089
|
/** Fully-formed base URL with scheme + host + port. */
|
|
@@ -24096,7 +24126,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
|
|
|
24096
24126
|
* ordering between polls.
|
|
24097
24127
|
*/
|
|
24098
24128
|
priority: number()
|
|
24099
|
-
})
|
|
24129
|
+
});
|
|
24130
|
+
/**
|
|
24131
|
+
* Where the advertised local port came from. Ordered most → least
|
|
24132
|
+
* authoritative, and the whole point of returning it: a client must be able to
|
|
24133
|
+
* tell a FACT about the hub's socket from an echo of its own guess.
|
|
24134
|
+
*/
|
|
24135
|
+
var LocalPortSourceEnum = _enum([
|
|
24136
|
+
"server-config",
|
|
24137
|
+
"server-env",
|
|
24138
|
+
"caller-hint",
|
|
24139
|
+
"default"
|
|
24140
|
+
]);
|
|
24141
|
+
/** The port every LAN/loopback `baseUrl` in the same result was built with. */
|
|
24142
|
+
var AdvertisedLocalPortSchema = object({
|
|
24143
|
+
port: number().int().min(1).max(65535),
|
|
24144
|
+
source: LocalPortSourceEnum
|
|
24145
|
+
});
|
|
24146
|
+
var GetConnectionEndpointsResultSchema = object({
|
|
24147
|
+
endpoints: array(ConnectionEndpointSchema).readonly(),
|
|
24148
|
+
/**
|
|
24149
|
+
* The port the hub built the LAN/loopback URLs with, and where that number
|
|
24150
|
+
* came from.
|
|
24151
|
+
*
|
|
24152
|
+
* Returned rather than merely applied, because "the URL is right" and "the
|
|
24153
|
+
* client can KNOW the URL is right" are different properties. A client that
|
|
24154
|
+
* only sees a corrected URL cannot distinguish a hub that fixed the port from
|
|
24155
|
+
* a hub that echoed the port the client sent, so it cannot decide whether to
|
|
24156
|
+
* race the candidate or discard it. With `source` it can: anything but
|
|
24157
|
+
* `caller-hint` is the hub's own socket.
|
|
24158
|
+
*
|
|
24159
|
+
* Absent on hubs predating this field — a client that finds it missing is
|
|
24160
|
+
* talking to an echoing hub and must degrade exactly as it does for
|
|
24161
|
+
* `caller-hint`.
|
|
24162
|
+
*/
|
|
24163
|
+
localPort: AdvertisedLocalPortSchema
|
|
24164
|
+
});
|
|
24100
24165
|
/**
|
|
24101
24166
|
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
24102
24167
|
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
@@ -24117,8 +24182,13 @@ var AllowedAddressesSchema = object({
|
|
|
24117
24182
|
*/
|
|
24118
24183
|
addresses: array(string()).readonly() });
|
|
24119
24184
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
24120
|
-
/**
|
|
24121
|
-
|
|
24185
|
+
/**
|
|
24186
|
+
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
24187
|
+
* written against the echoing contract keep working; the hub uses it
|
|
24188
|
+
* only when it cannot read its own port, and says so via
|
|
24189
|
+
* `localPort.source === 'caller-hint'`.
|
|
24190
|
+
*/
|
|
24191
|
+
port: number().int().min(1).max(65535).optional(),
|
|
24122
24192
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
24123
24193
|
* candidate. Default `true`. */
|
|
24124
24194
|
includeLoopback: boolean().optional(),
|
|
@@ -44216,6 +44286,38 @@ var TerminalSessionManager = class {
|
|
|
44216
44286
|
* (`node-pty`) and should update via `camstack deploy` independently of the
|
|
44217
44287
|
* framework, exactly like the node-av decoder addon.
|
|
44218
44288
|
*/
|
|
44289
|
+
/**
|
|
44290
|
+
* Default argv for the Glances profile — deliberately EMPTY.
|
|
44291
|
+
*
|
|
44292
|
+
* Measured on the hub (2026-08-21, glances 4.5.6, embedded Python, a real pty
|
|
44293
|
+
* at the terminal camera's own 120x40 grid, CPU sampled from
|
|
44294
|
+
* /proc/<pid>/{utime,stime} so the number is the process's own and not the
|
|
44295
|
+
* box's contention):
|
|
44296
|
+
*
|
|
44297
|
+
* argv CPU (of one core)
|
|
44298
|
+
* (none — this default) 0.8 %
|
|
44299
|
+
* -t 3 0.7 %
|
|
44300
|
+
* -t 5 0.6 %
|
|
44301
|
+
* --disable-plugin processlist 0.7 %
|
|
44302
|
+
* --disable-plugin containers 0.9 %
|
|
44303
|
+
* --disable-plugin sensors 0.8 %
|
|
44304
|
+
* --disable-process 0.8 %
|
|
44305
|
+
* -t 3 --disable-plugin processlist,containers,sensors 0.5 %
|
|
44306
|
+
* -t 5 --disable-plugin processlist,containers,sensors 0.4 %
|
|
44307
|
+
*
|
|
44308
|
+
* Startup costs 0.19 core-seconds; steady state is 1.0 % of one core at 36 MB
|
|
44309
|
+
* RSS. The whole tuning range is worth ~0.4 % of ONE core out of 20 — below the
|
|
44310
|
+
* noise floor of a box that idles at 2.6 cores — while every entry that buys
|
|
44311
|
+
* something removes a panel the operator opened the camera to read. `-t` is
|
|
44312
|
+
* additionally counter-productive here: the terminal camera renders at 2 FPS
|
|
44313
|
+
* and glances already repaints every 2 s, so slowing glances only makes the
|
|
44314
|
+
* camera show stale numbers.
|
|
44315
|
+
*
|
|
44316
|
+
* So the default ships empty and the knob stays in front of the operator.
|
|
44317
|
+
* Anyone who does want to trade panels for CPU has the numbers above.
|
|
44318
|
+
*/
|
|
44319
|
+
var DEFAULT_GLANCES_ARGS = [];
|
|
44320
|
+
var GLANCES_ARGS_DESCRIPTION = "Exact arguments passed to Glances. One tag per argv entry. Empty is the measured-best default: at the camera grid Glances costs ~1% of one core, and the cheapest tuning found (`-t 5 --disable-plugin processlist,containers,sensors`) saves only ~0.4% of one core while removing the panels most people open it for. `-t` also makes the camera show stale numbers — it renders at 2 FPS and Glances already repaints every 2s.";
|
|
44219
44321
|
var DEFAULTS = {
|
|
44220
44322
|
btmPath: "",
|
|
44221
44323
|
btmEnabled: true,
|
|
@@ -44225,7 +44327,7 @@ var DEFAULTS = {
|
|
|
44225
44327
|
topArgs: [],
|
|
44226
44328
|
glancesEnabled: true,
|
|
44227
44329
|
glancesPath: "",
|
|
44228
|
-
glancesArgs:
|
|
44330
|
+
glancesArgs: DEFAULT_GLANCES_ARGS,
|
|
44229
44331
|
allowShell: false,
|
|
44230
44332
|
shellPath: "",
|
|
44231
44333
|
maxSessions: 4,
|
|
@@ -44612,85 +44714,13 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44612
44714
|
return this.instanceInfo(instance);
|
|
44613
44715
|
}
|
|
44614
44716
|
globalSettingsSchema() {
|
|
44615
|
-
return this.schema({ sections: [
|
|
44616
|
-
|
|
44617
|
-
|
|
44618
|
-
|
|
44619
|
-
|
|
44620
|
-
|
|
44621
|
-
this.field({
|
|
44622
|
-
type: "boolean",
|
|
44623
|
-
key: "btmEnabled",
|
|
44624
|
-
label: "Enable BTM camera",
|
|
44625
|
-
default: true,
|
|
44626
|
-
perNode: true
|
|
44627
|
-
}),
|
|
44628
|
-
this.field({
|
|
44629
|
-
type: "text",
|
|
44630
|
-
key: "btmPath",
|
|
44631
|
-
label: "BTM binary",
|
|
44632
|
-
description: "Path to the `btm` (bottom) executable. Leave empty to resolve from PATH.",
|
|
44633
|
-
placeholder: "btm",
|
|
44634
|
-
default: "",
|
|
44635
|
-
perNode: true
|
|
44636
|
-
}),
|
|
44637
|
-
this.field({
|
|
44638
|
-
type: "tags",
|
|
44639
|
-
key: "btmArgs",
|
|
44640
|
-
label: "BTM arguments",
|
|
44641
|
-
description: "Exact arguments passed to btm.",
|
|
44642
|
-
default: [],
|
|
44643
|
-
perNode: true
|
|
44644
|
-
}),
|
|
44645
|
-
this.field({
|
|
44646
|
-
type: "boolean",
|
|
44647
|
-
key: "topEnabled",
|
|
44648
|
-
label: "Enable Top camera",
|
|
44649
|
-
default: true,
|
|
44650
|
-
perNode: true
|
|
44651
|
-
}),
|
|
44652
|
-
this.field({
|
|
44653
|
-
type: "text",
|
|
44654
|
-
key: "topPath",
|
|
44655
|
-
label: "Top binary",
|
|
44656
|
-
placeholder: "top",
|
|
44657
|
-
default: "",
|
|
44658
|
-
perNode: true
|
|
44659
|
-
}),
|
|
44660
|
-
this.field({
|
|
44661
|
-
type: "tags",
|
|
44662
|
-
key: "topArgs",
|
|
44663
|
-
label: "Top arguments",
|
|
44664
|
-
description: "Exact arguments passed to top.",
|
|
44665
|
-
default: [],
|
|
44666
|
-
perNode: true
|
|
44667
|
-
}),
|
|
44668
|
-
this.field({
|
|
44669
|
-
type: "boolean",
|
|
44670
|
-
key: "glancesEnabled",
|
|
44671
|
-
label: "Enable Glances camera",
|
|
44672
|
-
description: "Glances is installed automatically into CamStack embedded Python.",
|
|
44673
|
-
default: true,
|
|
44674
|
-
perNode: true
|
|
44675
|
-
}),
|
|
44676
|
-
this.field({
|
|
44677
|
-
type: "text",
|
|
44678
|
-
key: "glancesPath",
|
|
44679
|
-
label: "Glances binary override",
|
|
44680
|
-
description: "Optional executable override. Empty uses the automatically managed Python package.",
|
|
44681
|
-
placeholder: "glances",
|
|
44682
|
-
default: "",
|
|
44683
|
-
perNode: true
|
|
44684
|
-
}),
|
|
44685
|
-
this.field({
|
|
44686
|
-
type: "tags",
|
|
44687
|
-
key: "glancesArgs",
|
|
44688
|
-
label: "Glances arguments",
|
|
44689
|
-
description: "Exact arguments passed to Glances.",
|
|
44690
|
-
default: [],
|
|
44691
|
-
perNode: true
|
|
44692
|
-
}),
|
|
44693
|
-
this.field({
|
|
44717
|
+
return this.schema({ sections: [
|
|
44718
|
+
{
|
|
44719
|
+
id: "terminal",
|
|
44720
|
+
title: "Terminal",
|
|
44721
|
+
description: "Interactive terminal sessions in the Admin UI. Only pre-declared profiles can be opened; a free-form command is never accepted. Every setting below is per node — the values you see belong to the node selected above.",
|
|
44722
|
+
columns: 2,
|
|
44723
|
+
fields: [this.field({
|
|
44694
44724
|
type: "number",
|
|
44695
44725
|
key: "maxSessions",
|
|
44696
44726
|
label: "Max concurrent sessions",
|
|
@@ -44699,16 +44729,122 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44699
44729
|
step: 1,
|
|
44700
44730
|
default: 4,
|
|
44701
44731
|
perNode: true
|
|
44702
|
-
})
|
|
44703
|
-
|
|
44732
|
+
})]
|
|
44733
|
+
},
|
|
44734
|
+
{
|
|
44735
|
+
id: "terminal-btm",
|
|
44736
|
+
title: "BTM camera",
|
|
44737
|
+
description: "bottom (btm) — CPU, memory, network and process monitor.",
|
|
44738
|
+
columns: 2,
|
|
44739
|
+
fields: [
|
|
44740
|
+
this.field({
|
|
44741
|
+
type: "boolean",
|
|
44742
|
+
key: "btmEnabled",
|
|
44743
|
+
label: "Enabled",
|
|
44744
|
+
description: "Offer the BTM profile on this node.",
|
|
44745
|
+
default: true,
|
|
44746
|
+
perNode: true
|
|
44747
|
+
}),
|
|
44748
|
+
this.field({
|
|
44749
|
+
type: "text",
|
|
44750
|
+
key: "btmPath",
|
|
44751
|
+
label: "Binary",
|
|
44752
|
+
description: "Path to the `btm` (bottom) executable. Leave empty to resolve from PATH.",
|
|
44753
|
+
placeholder: "btm",
|
|
44754
|
+
default: "",
|
|
44755
|
+
perNode: true
|
|
44756
|
+
}),
|
|
44757
|
+
this.field({
|
|
44758
|
+
type: "tags",
|
|
44759
|
+
key: "btmArgs",
|
|
44760
|
+
label: "Arguments",
|
|
44761
|
+
description: "Exact arguments passed to btm. One tag per argv entry.",
|
|
44762
|
+
default: [],
|
|
44763
|
+
perNode: true,
|
|
44764
|
+
span: 2
|
|
44765
|
+
})
|
|
44766
|
+
]
|
|
44767
|
+
},
|
|
44768
|
+
{
|
|
44769
|
+
id: "terminal-top",
|
|
44770
|
+
title: "Top camera",
|
|
44771
|
+
description: "The operating system process and resource monitor.",
|
|
44772
|
+
columns: 2,
|
|
44773
|
+
fields: [
|
|
44774
|
+
this.field({
|
|
44775
|
+
type: "boolean",
|
|
44776
|
+
key: "topEnabled",
|
|
44777
|
+
label: "Enabled",
|
|
44778
|
+
description: "Offer the Top profile on this node.",
|
|
44779
|
+
default: true,
|
|
44780
|
+
perNode: true
|
|
44781
|
+
}),
|
|
44782
|
+
this.field({
|
|
44783
|
+
type: "text",
|
|
44784
|
+
key: "topPath",
|
|
44785
|
+
label: "Binary",
|
|
44786
|
+
placeholder: "top",
|
|
44787
|
+
default: "",
|
|
44788
|
+
perNode: true
|
|
44789
|
+
}),
|
|
44790
|
+
this.field({
|
|
44791
|
+
type: "tags",
|
|
44792
|
+
key: "topArgs",
|
|
44793
|
+
label: "Arguments",
|
|
44794
|
+
description: "Exact arguments passed to top. One tag per argv entry.",
|
|
44795
|
+
default: [],
|
|
44796
|
+
perNode: true,
|
|
44797
|
+
span: 2
|
|
44798
|
+
})
|
|
44799
|
+
]
|
|
44800
|
+
},
|
|
44801
|
+
{
|
|
44802
|
+
id: "terminal-glances",
|
|
44803
|
+
title: "Glances camera",
|
|
44804
|
+
description: "Cross-platform curses monitor, installed automatically into CamStack embedded Python. Glances is the most expensive built-in profile — it only runs while somebody is watching, but while it runs it costs real CPU. See the Arguments help below before widening it.",
|
|
44805
|
+
columns: 2,
|
|
44806
|
+
fields: [
|
|
44807
|
+
this.field({
|
|
44808
|
+
type: "boolean",
|
|
44809
|
+
key: "glancesEnabled",
|
|
44810
|
+
label: "Enabled",
|
|
44811
|
+
description: "Offer the Glances profile on this node.",
|
|
44812
|
+
default: true,
|
|
44813
|
+
perNode: true
|
|
44814
|
+
}),
|
|
44815
|
+
this.field({
|
|
44816
|
+
type: "text",
|
|
44817
|
+
key: "glancesPath",
|
|
44818
|
+
label: "Binary override",
|
|
44819
|
+
description: "Optional executable override. Empty uses the automatically managed Python package.",
|
|
44820
|
+
placeholder: "glances",
|
|
44821
|
+
default: "",
|
|
44822
|
+
perNode: true
|
|
44823
|
+
}),
|
|
44824
|
+
this.field({
|
|
44825
|
+
type: "tags",
|
|
44826
|
+
key: "glancesArgs",
|
|
44827
|
+
label: "Arguments",
|
|
44828
|
+
description: GLANCES_ARGS_DESCRIPTION,
|
|
44829
|
+
default: [...DEFAULT_GLANCES_ARGS],
|
|
44830
|
+
perNode: true,
|
|
44831
|
+
span: 2
|
|
44832
|
+
})
|
|
44833
|
+
]
|
|
44834
|
+
},
|
|
44835
|
+
{
|
|
44836
|
+
id: "terminal-shell",
|
|
44837
|
+
title: "Interactive shell",
|
|
44838
|
+
description: "The one profile that is genuinely a command surface. Off by default; turning it on grants command execution as the server user to every admin.",
|
|
44839
|
+
columns: 2,
|
|
44840
|
+
fields: [this.field({
|
|
44704
44841
|
type: "boolean",
|
|
44705
44842
|
key: "allowShell",
|
|
44706
44843
|
label: "Allow interactive shell",
|
|
44707
|
-
description: "Adds a \"Shell\" profile
|
|
44844
|
+
description: "Adds a \"Shell\" profile on this node.",
|
|
44708
44845
|
default: false,
|
|
44709
44846
|
perNode: true
|
|
44710
|
-
}),
|
|
44711
|
-
this.field({
|
|
44847
|
+
}), this.field({
|
|
44712
44848
|
type: "text",
|
|
44713
44849
|
key: "shellPath",
|
|
44714
44850
|
label: "Shell binary",
|
|
@@ -44716,89 +44852,90 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44716
44852
|
placeholder: "/bin/bash",
|
|
44717
44853
|
default: "",
|
|
44718
44854
|
perNode: true
|
|
44719
|
-
})
|
|
44720
|
-
|
|
44721
|
-
|
|
44722
|
-
|
|
44723
|
-
|
|
44724
|
-
|
|
44725
|
-
|
|
44726
|
-
|
|
44727
|
-
|
|
44728
|
-
|
|
44729
|
-
|
|
44730
|
-
|
|
44731
|
-
|
|
44732
|
-
|
|
44733
|
-
|
|
44734
|
-
|
|
44735
|
-
|
|
44736
|
-
|
|
44737
|
-
|
|
44738
|
-
|
|
44739
|
-
|
|
44740
|
-
|
|
44741
|
-
|
|
44742
|
-
|
|
44743
|
-
|
|
44744
|
-
|
|
44745
|
-
},
|
|
44746
|
-
itemFields: [
|
|
44747
|
-
{
|
|
44748
|
-
type: "boolean",
|
|
44749
|
-
key: "enabled",
|
|
44750
|
-
label: "Enabled",
|
|
44751
|
-
default: true
|
|
44752
|
-
},
|
|
44753
|
-
{
|
|
44754
|
-
type: "text",
|
|
44755
|
-
key: "profileId",
|
|
44756
|
-
label: "Profile ID",
|
|
44757
|
-
description: "Stable lowercase slug, for example gpu-monitor.",
|
|
44758
|
-
required: true
|
|
44759
|
-
},
|
|
44760
|
-
{
|
|
44761
|
-
type: "text",
|
|
44762
|
-
key: "label",
|
|
44763
|
-
label: "Display name",
|
|
44764
|
-
required: true
|
|
44765
|
-
},
|
|
44766
|
-
{
|
|
44767
|
-
type: "textarea",
|
|
44768
|
-
key: "description",
|
|
44769
|
-
label: "Description",
|
|
44770
|
-
rows: 2
|
|
44771
|
-
},
|
|
44772
|
-
{
|
|
44773
|
-
type: "text",
|
|
44774
|
-
key: "executable",
|
|
44775
|
-
label: "Executable",
|
|
44776
|
-
description: "Absolute path or a binary resolved from PATH.",
|
|
44777
|
-
required: true
|
|
44778
|
-
},
|
|
44779
|
-
{
|
|
44780
|
-
type: "tags",
|
|
44781
|
-
key: "args",
|
|
44782
|
-
label: "Arguments",
|
|
44783
|
-
description: "One exact process argument per tag.",
|
|
44784
|
-
maxTags: 64
|
|
44785
|
-
},
|
|
44786
|
-
{
|
|
44787
|
-
type: "text",
|
|
44788
|
-
key: "cwd",
|
|
44789
|
-
label: "Working directory",
|
|
44790
|
-
description: "Optional working directory for this profile."
|
|
44855
|
+
})]
|
|
44856
|
+
},
|
|
44857
|
+
{
|
|
44858
|
+
id: "terminal-profiles",
|
|
44859
|
+
title: "Custom profiles",
|
|
44860
|
+
description: "Enabled profiles are available templates on this node. Create a Terminal instance on the Terminal page to declare a camera; session requests only carry the profile ID and commands cannot be overridden by clients.",
|
|
44861
|
+
columns: 1,
|
|
44862
|
+
fields: [this.field({
|
|
44863
|
+
type: "editable-array",
|
|
44864
|
+
key: "customProfiles",
|
|
44865
|
+
label: "Profiles",
|
|
44866
|
+
perNode: true,
|
|
44867
|
+
default: [],
|
|
44868
|
+
maxRows: 32,
|
|
44869
|
+
addLabel: "Add profile",
|
|
44870
|
+
emptyMessage: "No custom profiles configured.",
|
|
44871
|
+
rowTitleTemplate: "{label} — {executable}",
|
|
44872
|
+
defaultItem: {
|
|
44873
|
+
enabled: true,
|
|
44874
|
+
profileId: "",
|
|
44875
|
+
label: "",
|
|
44876
|
+
description: "",
|
|
44877
|
+
executable: "",
|
|
44878
|
+
args: [],
|
|
44879
|
+
cwd: "",
|
|
44880
|
+
environment: []
|
|
44791
44881
|
},
|
|
44792
|
-
|
|
44793
|
-
|
|
44794
|
-
|
|
44795
|
-
|
|
44796
|
-
|
|
44797
|
-
|
|
44798
|
-
|
|
44799
|
-
|
|
44800
|
-
|
|
44801
|
-
|
|
44882
|
+
itemFields: [
|
|
44883
|
+
{
|
|
44884
|
+
type: "boolean",
|
|
44885
|
+
key: "enabled",
|
|
44886
|
+
label: "Enabled",
|
|
44887
|
+
default: true
|
|
44888
|
+
},
|
|
44889
|
+
{
|
|
44890
|
+
type: "text",
|
|
44891
|
+
key: "profileId",
|
|
44892
|
+
label: "Profile ID",
|
|
44893
|
+
description: "Stable lowercase slug, for example gpu-monitor.",
|
|
44894
|
+
required: true
|
|
44895
|
+
},
|
|
44896
|
+
{
|
|
44897
|
+
type: "text",
|
|
44898
|
+
key: "label",
|
|
44899
|
+
label: "Display name",
|
|
44900
|
+
required: true
|
|
44901
|
+
},
|
|
44902
|
+
{
|
|
44903
|
+
type: "textarea",
|
|
44904
|
+
key: "description",
|
|
44905
|
+
label: "Description",
|
|
44906
|
+
rows: 2
|
|
44907
|
+
},
|
|
44908
|
+
{
|
|
44909
|
+
type: "text",
|
|
44910
|
+
key: "executable",
|
|
44911
|
+
label: "Executable",
|
|
44912
|
+
description: "Absolute path or a binary resolved from PATH.",
|
|
44913
|
+
required: true
|
|
44914
|
+
},
|
|
44915
|
+
{
|
|
44916
|
+
type: "tags",
|
|
44917
|
+
key: "args",
|
|
44918
|
+
label: "Arguments",
|
|
44919
|
+
description: "One exact process argument per tag.",
|
|
44920
|
+
maxTags: 64
|
|
44921
|
+
},
|
|
44922
|
+
{
|
|
44923
|
+
type: "text",
|
|
44924
|
+
key: "cwd",
|
|
44925
|
+
label: "Working directory",
|
|
44926
|
+
description: "Optional working directory for this profile."
|
|
44927
|
+
},
|
|
44928
|
+
{
|
|
44929
|
+
type: "tags",
|
|
44930
|
+
key: "environment",
|
|
44931
|
+
label: "Environment",
|
|
44932
|
+
description: "Optional NAME=value entries merged into the process environment.",
|
|
44933
|
+
maxTags: 64
|
|
44934
|
+
}
|
|
44935
|
+
]
|
|
44936
|
+
})]
|
|
44937
|
+
}
|
|
44938
|
+
] });
|
|
44802
44939
|
}
|
|
44803
44940
|
};
|
|
44804
44941
|
//#endregion
|
package/dist/addon.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { createServer } from "node:http";
|
|
|
8
8
|
//#region \0rolldown/runtime.js
|
|
9
9
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region ../types/dist/event-category-
|
|
11
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
12
12
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
13
13
|
EventCategory["SystemBoot"] = "system.boot";
|
|
14
14
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -24,6 +24,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
24
24
|
*/
|
|
25
25
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
26
26
|
/**
|
|
27
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
28
|
+
* Emitted only when the material on disk actually changed, so an
|
|
29
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
30
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
31
|
+
*
|
|
32
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
33
|
+
*/
|
|
34
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
35
|
+
/**
|
|
27
36
|
* A newer addon or server-root package version was found by the
|
|
28
37
|
* authoritative registry check. Emitted once when any observed
|
|
29
38
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -19002,6 +19011,12 @@ var CameraStatusSchema = object({
|
|
|
19002
19011
|
/** Unix timestamp (ms) when this snapshot was composed server-side. */
|
|
19003
19012
|
fetchedAt: number()
|
|
19004
19013
|
});
|
|
19014
|
+
var InferenceDeviceExclusionReasonSchema = _enum([
|
|
19015
|
+
"disabled",
|
|
19016
|
+
"unavailable",
|
|
19017
|
+
"cannot-host-camera-root",
|
|
19018
|
+
"accelerator-preferred"
|
|
19019
|
+
]);
|
|
19005
19020
|
var NodeInferenceDeviceSchema = object({
|
|
19006
19021
|
/** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
|
|
19007
19022
|
key: string(),
|
|
@@ -19032,7 +19047,17 @@ var NodeInferenceDeviceSchema = object({
|
|
|
19032
19047
|
* available per format; this is the stored selection that becomes the
|
|
19033
19048
|
* default for EVERY camera landing on this accelerator.
|
|
19034
19049
|
*/
|
|
19035
|
-
steps: record(string(), DeviceStepConfigSchema).optional()
|
|
19050
|
+
steps: record(string(), DeviceStepConfigSchema).optional(),
|
|
19051
|
+
/**
|
|
19052
|
+
* `null` when the device IS a camera-root candidate on this node; otherwise
|
|
19053
|
+
* the reason the dispatcher drops it. Computed by the SAME
|
|
19054
|
+
* `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
|
|
19055
|
+
* never disagree with the election — deriving it in the UI from
|
|
19056
|
+
* `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
|
|
19057
|
+
* the node's model catalog) and `accelerator-preferred` (needs the node-wide
|
|
19058
|
+
* "an accelerator is serving" predicate).
|
|
19059
|
+
*/
|
|
19060
|
+
exclusion: InferenceDeviceExclusionReasonSchema.nullable()
|
|
19036
19061
|
});
|
|
19037
19062
|
var NodeInferenceDevicesSchema = object({
|
|
19038
19063
|
nodeId: string(),
|
|
@@ -24030,7 +24055,12 @@ var ListResultSchema = object({
|
|
|
24030
24055
|
probedAt: number()
|
|
24031
24056
|
});
|
|
24032
24057
|
var PreferredSchema = LocalInterfaceSchema.nullable();
|
|
24033
|
-
|
|
24058
|
+
/**
|
|
24059
|
+
* Candidate base URL for the SDK to race on connect. Order matters —
|
|
24060
|
+
* the SDK should attempt these top-to-bottom with a short per-candidate
|
|
24061
|
+
* timeout (e.g. 1500ms) and cache the winner for the session.
|
|
24062
|
+
*/
|
|
24063
|
+
var ConnectionEndpointSchema = object({
|
|
24034
24064
|
/** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
|
|
24035
24065
|
label: string(),
|
|
24036
24066
|
/** Fully-formed base URL with scheme + host + port. */
|
|
@@ -24073,7 +24103,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
|
|
|
24073
24103
|
* ordering between polls.
|
|
24074
24104
|
*/
|
|
24075
24105
|
priority: number()
|
|
24076
|
-
})
|
|
24106
|
+
});
|
|
24107
|
+
/**
|
|
24108
|
+
* Where the advertised local port came from. Ordered most → least
|
|
24109
|
+
* authoritative, and the whole point of returning it: a client must be able to
|
|
24110
|
+
* tell a FACT about the hub's socket from an echo of its own guess.
|
|
24111
|
+
*/
|
|
24112
|
+
var LocalPortSourceEnum = _enum([
|
|
24113
|
+
"server-config",
|
|
24114
|
+
"server-env",
|
|
24115
|
+
"caller-hint",
|
|
24116
|
+
"default"
|
|
24117
|
+
]);
|
|
24118
|
+
/** The port every LAN/loopback `baseUrl` in the same result was built with. */
|
|
24119
|
+
var AdvertisedLocalPortSchema = object({
|
|
24120
|
+
port: number().int().min(1).max(65535),
|
|
24121
|
+
source: LocalPortSourceEnum
|
|
24122
|
+
});
|
|
24123
|
+
var GetConnectionEndpointsResultSchema = object({
|
|
24124
|
+
endpoints: array(ConnectionEndpointSchema).readonly(),
|
|
24125
|
+
/**
|
|
24126
|
+
* The port the hub built the LAN/loopback URLs with, and where that number
|
|
24127
|
+
* came from.
|
|
24128
|
+
*
|
|
24129
|
+
* Returned rather than merely applied, because "the URL is right" and "the
|
|
24130
|
+
* client can KNOW the URL is right" are different properties. A client that
|
|
24131
|
+
* only sees a corrected URL cannot distinguish a hub that fixed the port from
|
|
24132
|
+
* a hub that echoed the port the client sent, so it cannot decide whether to
|
|
24133
|
+
* race the candidate or discard it. With `source` it can: anything but
|
|
24134
|
+
* `caller-hint` is the hub's own socket.
|
|
24135
|
+
*
|
|
24136
|
+
* Absent on hubs predating this field — a client that finds it missing is
|
|
24137
|
+
* talking to an echoing hub and must degrade exactly as it does for
|
|
24138
|
+
* `caller-hint`.
|
|
24139
|
+
*/
|
|
24140
|
+
localPort: AdvertisedLocalPortSchema
|
|
24141
|
+
});
|
|
24077
24142
|
/**
|
|
24078
24143
|
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
24079
24144
|
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
@@ -24094,8 +24159,13 @@ var AllowedAddressesSchema = object({
|
|
|
24094
24159
|
*/
|
|
24095
24160
|
addresses: array(string()).readonly() });
|
|
24096
24161
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
24097
|
-
/**
|
|
24098
|
-
|
|
24162
|
+
/**
|
|
24163
|
+
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
24164
|
+
* written against the echoing contract keep working; the hub uses it
|
|
24165
|
+
* only when it cannot read its own port, and says so via
|
|
24166
|
+
* `localPort.source === 'caller-hint'`.
|
|
24167
|
+
*/
|
|
24168
|
+
port: number().int().min(1).max(65535).optional(),
|
|
24099
24169
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
24100
24170
|
* candidate. Default `true`. */
|
|
24101
24171
|
includeLoopback: boolean().optional(),
|
|
@@ -44193,6 +44263,38 @@ var TerminalSessionManager = class {
|
|
|
44193
44263
|
* (`node-pty`) and should update via `camstack deploy` independently of the
|
|
44194
44264
|
* framework, exactly like the node-av decoder addon.
|
|
44195
44265
|
*/
|
|
44266
|
+
/**
|
|
44267
|
+
* Default argv for the Glances profile — deliberately EMPTY.
|
|
44268
|
+
*
|
|
44269
|
+
* Measured on the hub (2026-08-21, glances 4.5.6, embedded Python, a real pty
|
|
44270
|
+
* at the terminal camera's own 120x40 grid, CPU sampled from
|
|
44271
|
+
* /proc/<pid>/{utime,stime} so the number is the process's own and not the
|
|
44272
|
+
* box's contention):
|
|
44273
|
+
*
|
|
44274
|
+
* argv CPU (of one core)
|
|
44275
|
+
* (none — this default) 0.8 %
|
|
44276
|
+
* -t 3 0.7 %
|
|
44277
|
+
* -t 5 0.6 %
|
|
44278
|
+
* --disable-plugin processlist 0.7 %
|
|
44279
|
+
* --disable-plugin containers 0.9 %
|
|
44280
|
+
* --disable-plugin sensors 0.8 %
|
|
44281
|
+
* --disable-process 0.8 %
|
|
44282
|
+
* -t 3 --disable-plugin processlist,containers,sensors 0.5 %
|
|
44283
|
+
* -t 5 --disable-plugin processlist,containers,sensors 0.4 %
|
|
44284
|
+
*
|
|
44285
|
+
* Startup costs 0.19 core-seconds; steady state is 1.0 % of one core at 36 MB
|
|
44286
|
+
* RSS. The whole tuning range is worth ~0.4 % of ONE core out of 20 — below the
|
|
44287
|
+
* noise floor of a box that idles at 2.6 cores — while every entry that buys
|
|
44288
|
+
* something removes a panel the operator opened the camera to read. `-t` is
|
|
44289
|
+
* additionally counter-productive here: the terminal camera renders at 2 FPS
|
|
44290
|
+
* and glances already repaints every 2 s, so slowing glances only makes the
|
|
44291
|
+
* camera show stale numbers.
|
|
44292
|
+
*
|
|
44293
|
+
* So the default ships empty and the knob stays in front of the operator.
|
|
44294
|
+
* Anyone who does want to trade panels for CPU has the numbers above.
|
|
44295
|
+
*/
|
|
44296
|
+
var DEFAULT_GLANCES_ARGS = [];
|
|
44297
|
+
var GLANCES_ARGS_DESCRIPTION = "Exact arguments passed to Glances. One tag per argv entry. Empty is the measured-best default: at the camera grid Glances costs ~1% of one core, and the cheapest tuning found (`-t 5 --disable-plugin processlist,containers,sensors`) saves only ~0.4% of one core while removing the panels most people open it for. `-t` also makes the camera show stale numbers — it renders at 2 FPS and Glances already repaints every 2s.";
|
|
44196
44298
|
var DEFAULTS = {
|
|
44197
44299
|
btmPath: "",
|
|
44198
44300
|
btmEnabled: true,
|
|
@@ -44202,7 +44304,7 @@ var DEFAULTS = {
|
|
|
44202
44304
|
topArgs: [],
|
|
44203
44305
|
glancesEnabled: true,
|
|
44204
44306
|
glancesPath: "",
|
|
44205
|
-
glancesArgs:
|
|
44307
|
+
glancesArgs: DEFAULT_GLANCES_ARGS,
|
|
44206
44308
|
allowShell: false,
|
|
44207
44309
|
shellPath: "",
|
|
44208
44310
|
maxSessions: 4,
|
|
@@ -44589,85 +44691,13 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44589
44691
|
return this.instanceInfo(instance);
|
|
44590
44692
|
}
|
|
44591
44693
|
globalSettingsSchema() {
|
|
44592
|
-
return this.schema({ sections: [
|
|
44593
|
-
|
|
44594
|
-
|
|
44595
|
-
|
|
44596
|
-
|
|
44597
|
-
|
|
44598
|
-
this.field({
|
|
44599
|
-
type: "boolean",
|
|
44600
|
-
key: "btmEnabled",
|
|
44601
|
-
label: "Enable BTM camera",
|
|
44602
|
-
default: true,
|
|
44603
|
-
perNode: true
|
|
44604
|
-
}),
|
|
44605
|
-
this.field({
|
|
44606
|
-
type: "text",
|
|
44607
|
-
key: "btmPath",
|
|
44608
|
-
label: "BTM binary",
|
|
44609
|
-
description: "Path to the `btm` (bottom) executable. Leave empty to resolve from PATH.",
|
|
44610
|
-
placeholder: "btm",
|
|
44611
|
-
default: "",
|
|
44612
|
-
perNode: true
|
|
44613
|
-
}),
|
|
44614
|
-
this.field({
|
|
44615
|
-
type: "tags",
|
|
44616
|
-
key: "btmArgs",
|
|
44617
|
-
label: "BTM arguments",
|
|
44618
|
-
description: "Exact arguments passed to btm.",
|
|
44619
|
-
default: [],
|
|
44620
|
-
perNode: true
|
|
44621
|
-
}),
|
|
44622
|
-
this.field({
|
|
44623
|
-
type: "boolean",
|
|
44624
|
-
key: "topEnabled",
|
|
44625
|
-
label: "Enable Top camera",
|
|
44626
|
-
default: true,
|
|
44627
|
-
perNode: true
|
|
44628
|
-
}),
|
|
44629
|
-
this.field({
|
|
44630
|
-
type: "text",
|
|
44631
|
-
key: "topPath",
|
|
44632
|
-
label: "Top binary",
|
|
44633
|
-
placeholder: "top",
|
|
44634
|
-
default: "",
|
|
44635
|
-
perNode: true
|
|
44636
|
-
}),
|
|
44637
|
-
this.field({
|
|
44638
|
-
type: "tags",
|
|
44639
|
-
key: "topArgs",
|
|
44640
|
-
label: "Top arguments",
|
|
44641
|
-
description: "Exact arguments passed to top.",
|
|
44642
|
-
default: [],
|
|
44643
|
-
perNode: true
|
|
44644
|
-
}),
|
|
44645
|
-
this.field({
|
|
44646
|
-
type: "boolean",
|
|
44647
|
-
key: "glancesEnabled",
|
|
44648
|
-
label: "Enable Glances camera",
|
|
44649
|
-
description: "Glances is installed automatically into CamStack embedded Python.",
|
|
44650
|
-
default: true,
|
|
44651
|
-
perNode: true
|
|
44652
|
-
}),
|
|
44653
|
-
this.field({
|
|
44654
|
-
type: "text",
|
|
44655
|
-
key: "glancesPath",
|
|
44656
|
-
label: "Glances binary override",
|
|
44657
|
-
description: "Optional executable override. Empty uses the automatically managed Python package.",
|
|
44658
|
-
placeholder: "glances",
|
|
44659
|
-
default: "",
|
|
44660
|
-
perNode: true
|
|
44661
|
-
}),
|
|
44662
|
-
this.field({
|
|
44663
|
-
type: "tags",
|
|
44664
|
-
key: "glancesArgs",
|
|
44665
|
-
label: "Glances arguments",
|
|
44666
|
-
description: "Exact arguments passed to Glances.",
|
|
44667
|
-
default: [],
|
|
44668
|
-
perNode: true
|
|
44669
|
-
}),
|
|
44670
|
-
this.field({
|
|
44694
|
+
return this.schema({ sections: [
|
|
44695
|
+
{
|
|
44696
|
+
id: "terminal",
|
|
44697
|
+
title: "Terminal",
|
|
44698
|
+
description: "Interactive terminal sessions in the Admin UI. Only pre-declared profiles can be opened; a free-form command is never accepted. Every setting below is per node — the values you see belong to the node selected above.",
|
|
44699
|
+
columns: 2,
|
|
44700
|
+
fields: [this.field({
|
|
44671
44701
|
type: "number",
|
|
44672
44702
|
key: "maxSessions",
|
|
44673
44703
|
label: "Max concurrent sessions",
|
|
@@ -44676,16 +44706,122 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44676
44706
|
step: 1,
|
|
44677
44707
|
default: 4,
|
|
44678
44708
|
perNode: true
|
|
44679
|
-
})
|
|
44680
|
-
|
|
44709
|
+
})]
|
|
44710
|
+
},
|
|
44711
|
+
{
|
|
44712
|
+
id: "terminal-btm",
|
|
44713
|
+
title: "BTM camera",
|
|
44714
|
+
description: "bottom (btm) — CPU, memory, network and process monitor.",
|
|
44715
|
+
columns: 2,
|
|
44716
|
+
fields: [
|
|
44717
|
+
this.field({
|
|
44718
|
+
type: "boolean",
|
|
44719
|
+
key: "btmEnabled",
|
|
44720
|
+
label: "Enabled",
|
|
44721
|
+
description: "Offer the BTM profile on this node.",
|
|
44722
|
+
default: true,
|
|
44723
|
+
perNode: true
|
|
44724
|
+
}),
|
|
44725
|
+
this.field({
|
|
44726
|
+
type: "text",
|
|
44727
|
+
key: "btmPath",
|
|
44728
|
+
label: "Binary",
|
|
44729
|
+
description: "Path to the `btm` (bottom) executable. Leave empty to resolve from PATH.",
|
|
44730
|
+
placeholder: "btm",
|
|
44731
|
+
default: "",
|
|
44732
|
+
perNode: true
|
|
44733
|
+
}),
|
|
44734
|
+
this.field({
|
|
44735
|
+
type: "tags",
|
|
44736
|
+
key: "btmArgs",
|
|
44737
|
+
label: "Arguments",
|
|
44738
|
+
description: "Exact arguments passed to btm. One tag per argv entry.",
|
|
44739
|
+
default: [],
|
|
44740
|
+
perNode: true,
|
|
44741
|
+
span: 2
|
|
44742
|
+
})
|
|
44743
|
+
]
|
|
44744
|
+
},
|
|
44745
|
+
{
|
|
44746
|
+
id: "terminal-top",
|
|
44747
|
+
title: "Top camera",
|
|
44748
|
+
description: "The operating system process and resource monitor.",
|
|
44749
|
+
columns: 2,
|
|
44750
|
+
fields: [
|
|
44751
|
+
this.field({
|
|
44752
|
+
type: "boolean",
|
|
44753
|
+
key: "topEnabled",
|
|
44754
|
+
label: "Enabled",
|
|
44755
|
+
description: "Offer the Top profile on this node.",
|
|
44756
|
+
default: true,
|
|
44757
|
+
perNode: true
|
|
44758
|
+
}),
|
|
44759
|
+
this.field({
|
|
44760
|
+
type: "text",
|
|
44761
|
+
key: "topPath",
|
|
44762
|
+
label: "Binary",
|
|
44763
|
+
placeholder: "top",
|
|
44764
|
+
default: "",
|
|
44765
|
+
perNode: true
|
|
44766
|
+
}),
|
|
44767
|
+
this.field({
|
|
44768
|
+
type: "tags",
|
|
44769
|
+
key: "topArgs",
|
|
44770
|
+
label: "Arguments",
|
|
44771
|
+
description: "Exact arguments passed to top. One tag per argv entry.",
|
|
44772
|
+
default: [],
|
|
44773
|
+
perNode: true,
|
|
44774
|
+
span: 2
|
|
44775
|
+
})
|
|
44776
|
+
]
|
|
44777
|
+
},
|
|
44778
|
+
{
|
|
44779
|
+
id: "terminal-glances",
|
|
44780
|
+
title: "Glances camera",
|
|
44781
|
+
description: "Cross-platform curses monitor, installed automatically into CamStack embedded Python. Glances is the most expensive built-in profile — it only runs while somebody is watching, but while it runs it costs real CPU. See the Arguments help below before widening it.",
|
|
44782
|
+
columns: 2,
|
|
44783
|
+
fields: [
|
|
44784
|
+
this.field({
|
|
44785
|
+
type: "boolean",
|
|
44786
|
+
key: "glancesEnabled",
|
|
44787
|
+
label: "Enabled",
|
|
44788
|
+
description: "Offer the Glances profile on this node.",
|
|
44789
|
+
default: true,
|
|
44790
|
+
perNode: true
|
|
44791
|
+
}),
|
|
44792
|
+
this.field({
|
|
44793
|
+
type: "text",
|
|
44794
|
+
key: "glancesPath",
|
|
44795
|
+
label: "Binary override",
|
|
44796
|
+
description: "Optional executable override. Empty uses the automatically managed Python package.",
|
|
44797
|
+
placeholder: "glances",
|
|
44798
|
+
default: "",
|
|
44799
|
+
perNode: true
|
|
44800
|
+
}),
|
|
44801
|
+
this.field({
|
|
44802
|
+
type: "tags",
|
|
44803
|
+
key: "glancesArgs",
|
|
44804
|
+
label: "Arguments",
|
|
44805
|
+
description: GLANCES_ARGS_DESCRIPTION,
|
|
44806
|
+
default: [...DEFAULT_GLANCES_ARGS],
|
|
44807
|
+
perNode: true,
|
|
44808
|
+
span: 2
|
|
44809
|
+
})
|
|
44810
|
+
]
|
|
44811
|
+
},
|
|
44812
|
+
{
|
|
44813
|
+
id: "terminal-shell",
|
|
44814
|
+
title: "Interactive shell",
|
|
44815
|
+
description: "The one profile that is genuinely a command surface. Off by default; turning it on grants command execution as the server user to every admin.",
|
|
44816
|
+
columns: 2,
|
|
44817
|
+
fields: [this.field({
|
|
44681
44818
|
type: "boolean",
|
|
44682
44819
|
key: "allowShell",
|
|
44683
44820
|
label: "Allow interactive shell",
|
|
44684
|
-
description: "Adds a \"Shell\" profile
|
|
44821
|
+
description: "Adds a \"Shell\" profile on this node.",
|
|
44685
44822
|
default: false,
|
|
44686
44823
|
perNode: true
|
|
44687
|
-
}),
|
|
44688
|
-
this.field({
|
|
44824
|
+
}), this.field({
|
|
44689
44825
|
type: "text",
|
|
44690
44826
|
key: "shellPath",
|
|
44691
44827
|
label: "Shell binary",
|
|
@@ -44693,89 +44829,90 @@ var TerminalAddon = class extends BaseAddon {
|
|
|
44693
44829
|
placeholder: "/bin/bash",
|
|
44694
44830
|
default: "",
|
|
44695
44831
|
perNode: true
|
|
44696
|
-
})
|
|
44697
|
-
|
|
44698
|
-
|
|
44699
|
-
|
|
44700
|
-
|
|
44701
|
-
|
|
44702
|
-
|
|
44703
|
-
|
|
44704
|
-
|
|
44705
|
-
|
|
44706
|
-
|
|
44707
|
-
|
|
44708
|
-
|
|
44709
|
-
|
|
44710
|
-
|
|
44711
|
-
|
|
44712
|
-
|
|
44713
|
-
|
|
44714
|
-
|
|
44715
|
-
|
|
44716
|
-
|
|
44717
|
-
|
|
44718
|
-
|
|
44719
|
-
|
|
44720
|
-
|
|
44721
|
-
|
|
44722
|
-
},
|
|
44723
|
-
itemFields: [
|
|
44724
|
-
{
|
|
44725
|
-
type: "boolean",
|
|
44726
|
-
key: "enabled",
|
|
44727
|
-
label: "Enabled",
|
|
44728
|
-
default: true
|
|
44729
|
-
},
|
|
44730
|
-
{
|
|
44731
|
-
type: "text",
|
|
44732
|
-
key: "profileId",
|
|
44733
|
-
label: "Profile ID",
|
|
44734
|
-
description: "Stable lowercase slug, for example gpu-monitor.",
|
|
44735
|
-
required: true
|
|
44736
|
-
},
|
|
44737
|
-
{
|
|
44738
|
-
type: "text",
|
|
44739
|
-
key: "label",
|
|
44740
|
-
label: "Display name",
|
|
44741
|
-
required: true
|
|
44742
|
-
},
|
|
44743
|
-
{
|
|
44744
|
-
type: "textarea",
|
|
44745
|
-
key: "description",
|
|
44746
|
-
label: "Description",
|
|
44747
|
-
rows: 2
|
|
44748
|
-
},
|
|
44749
|
-
{
|
|
44750
|
-
type: "text",
|
|
44751
|
-
key: "executable",
|
|
44752
|
-
label: "Executable",
|
|
44753
|
-
description: "Absolute path or a binary resolved from PATH.",
|
|
44754
|
-
required: true
|
|
44755
|
-
},
|
|
44756
|
-
{
|
|
44757
|
-
type: "tags",
|
|
44758
|
-
key: "args",
|
|
44759
|
-
label: "Arguments",
|
|
44760
|
-
description: "One exact process argument per tag.",
|
|
44761
|
-
maxTags: 64
|
|
44762
|
-
},
|
|
44763
|
-
{
|
|
44764
|
-
type: "text",
|
|
44765
|
-
key: "cwd",
|
|
44766
|
-
label: "Working directory",
|
|
44767
|
-
description: "Optional working directory for this profile."
|
|
44832
|
+
})]
|
|
44833
|
+
},
|
|
44834
|
+
{
|
|
44835
|
+
id: "terminal-profiles",
|
|
44836
|
+
title: "Custom profiles",
|
|
44837
|
+
description: "Enabled profiles are available templates on this node. Create a Terminal instance on the Terminal page to declare a camera; session requests only carry the profile ID and commands cannot be overridden by clients.",
|
|
44838
|
+
columns: 1,
|
|
44839
|
+
fields: [this.field({
|
|
44840
|
+
type: "editable-array",
|
|
44841
|
+
key: "customProfiles",
|
|
44842
|
+
label: "Profiles",
|
|
44843
|
+
perNode: true,
|
|
44844
|
+
default: [],
|
|
44845
|
+
maxRows: 32,
|
|
44846
|
+
addLabel: "Add profile",
|
|
44847
|
+
emptyMessage: "No custom profiles configured.",
|
|
44848
|
+
rowTitleTemplate: "{label} — {executable}",
|
|
44849
|
+
defaultItem: {
|
|
44850
|
+
enabled: true,
|
|
44851
|
+
profileId: "",
|
|
44852
|
+
label: "",
|
|
44853
|
+
description: "",
|
|
44854
|
+
executable: "",
|
|
44855
|
+
args: [],
|
|
44856
|
+
cwd: "",
|
|
44857
|
+
environment: []
|
|
44768
44858
|
},
|
|
44769
|
-
|
|
44770
|
-
|
|
44771
|
-
|
|
44772
|
-
|
|
44773
|
-
|
|
44774
|
-
|
|
44775
|
-
|
|
44776
|
-
|
|
44777
|
-
|
|
44778
|
-
|
|
44859
|
+
itemFields: [
|
|
44860
|
+
{
|
|
44861
|
+
type: "boolean",
|
|
44862
|
+
key: "enabled",
|
|
44863
|
+
label: "Enabled",
|
|
44864
|
+
default: true
|
|
44865
|
+
},
|
|
44866
|
+
{
|
|
44867
|
+
type: "text",
|
|
44868
|
+
key: "profileId",
|
|
44869
|
+
label: "Profile ID",
|
|
44870
|
+
description: "Stable lowercase slug, for example gpu-monitor.",
|
|
44871
|
+
required: true
|
|
44872
|
+
},
|
|
44873
|
+
{
|
|
44874
|
+
type: "text",
|
|
44875
|
+
key: "label",
|
|
44876
|
+
label: "Display name",
|
|
44877
|
+
required: true
|
|
44878
|
+
},
|
|
44879
|
+
{
|
|
44880
|
+
type: "textarea",
|
|
44881
|
+
key: "description",
|
|
44882
|
+
label: "Description",
|
|
44883
|
+
rows: 2
|
|
44884
|
+
},
|
|
44885
|
+
{
|
|
44886
|
+
type: "text",
|
|
44887
|
+
key: "executable",
|
|
44888
|
+
label: "Executable",
|
|
44889
|
+
description: "Absolute path or a binary resolved from PATH.",
|
|
44890
|
+
required: true
|
|
44891
|
+
},
|
|
44892
|
+
{
|
|
44893
|
+
type: "tags",
|
|
44894
|
+
key: "args",
|
|
44895
|
+
label: "Arguments",
|
|
44896
|
+
description: "One exact process argument per tag.",
|
|
44897
|
+
maxTags: 64
|
|
44898
|
+
},
|
|
44899
|
+
{
|
|
44900
|
+
type: "text",
|
|
44901
|
+
key: "cwd",
|
|
44902
|
+
label: "Working directory",
|
|
44903
|
+
description: "Optional working directory for this profile."
|
|
44904
|
+
},
|
|
44905
|
+
{
|
|
44906
|
+
type: "tags",
|
|
44907
|
+
key: "environment",
|
|
44908
|
+
label: "Environment",
|
|
44909
|
+
description: "Optional NAME=value entries merged into the process environment.",
|
|
44910
|
+
maxTags: 64
|
|
44911
|
+
}
|
|
44912
|
+
]
|
|
44913
|
+
})]
|
|
44914
|
+
}
|
|
44915
|
+
] });
|
|
44779
44916
|
}
|
|
44780
44917
|
};
|
|
44781
44918
|
//#endregion
|