@camstack/system 1.2.146 → 1.2.147

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.
Files changed (63) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/load-series-config.d.ts +74 -0
  30. package/dist/builtins/native-metrics/load-series-reader.d.ts +37 -0
  31. package/dist/builtins/native-metrics/load-series-store.d.ts +232 -0
  32. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +118 -35
  33. package/dist/builtins/native-metrics/native-metrics.addon.js +1463 -199
  34. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1463 -199
  35. package/dist/builtins/native-metrics/node-load-ring.d.ts +214 -0
  36. package/dist/builtins/native-metrics/process-classification.d.ts +51 -0
  37. package/dist/builtins/native-metrics/thread-cpu-sampler.d.ts +116 -0
  38. package/dist/builtins/platform-probe/index.js +1 -1
  39. package/dist/builtins/platform-probe/index.mjs +1 -1
  40. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  41. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  42. package/dist/builtins/snapshot/index.js +1 -1
  43. package/dist/builtins/snapshot/index.mjs +1 -1
  44. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  45. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  46. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +25 -1
  47. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  48. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  49. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -1
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -1
  51. package/dist/builtins/system-config/system-config.addon.js +1 -1
  52. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  53. package/dist/builtins/winston-logging/index.js +1 -1
  54. package/dist/builtins/winston-logging/index.mjs +1 -1
  55. package/dist/{dist-BVU5JADq.js → dist-Dl6MFXPr.js} +496 -35
  56. package/dist/{dist-CG7kwIZp.mjs → dist-DrBc-7Y3.mjs} +479 -36
  57. package/dist/index.js +2 -2
  58. package/dist/index.mjs +2 -2
  59. package/dist/{manifest-python-deps-CVeckyXx.mjs → manifest-python-deps-DhT0oFOZ.mjs} +1 -1
  60. package/dist/{manifest-python-deps-CktMcXzS.js → manifest-python-deps-FYZBHc3v.js} +1 -1
  61. package/dist/{retired-settings-keys-_PLI9w0k.js → retired-settings-keys-6w_JOqBg.js} +1 -1
  62. package/dist/{retired-settings-keys-Dm1z4mO4.mjs → retired-settings-keys-CF5r4YKq.mjs} +1 -1
  63. package/package.json +1 -1
@@ -1,6 +1,14 @@
1
1
  import { ProviderRegistration, BaseAddon } from '@camstack/types';
2
2
  interface NativeMetricsConfig {
3
3
  readonly samplingIntervalMs: number;
4
+ /**
5
+ * Fixed cadence of the process-tree snapshot, in SECONDS. 5-60, refused
6
+ * outside — `load-series-config.ts` explains why refused and not clamped.
7
+ */
8
+ readonly loadSeriesCadenceSec: number;
9
+ /** How long the durable series is KEPT, in hours. The intention; the row
10
+ * cap in `load-series-store.ts` is the guarantee. */
11
+ readonly loadSeriesRetentionHours: number;
4
12
  }
5
13
  /**
6
14
  * Native metrics — CPU, memory, disk usage sampling.
@@ -18,9 +26,88 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
18
26
  * elapsed) is skipped.
19
27
  */
20
28
  private lastResourcesEmit;
21
- private lastProcessesEmit;
29
+ /**
30
+ * Holds the previous `/proc/<pid>/task/*` tick counts so each process scan
31
+ * can turn them into an instantaneous CPU rate split between the process's
32
+ * own threads and V8's helper pool. Self-bounding — see `ThreadCpuTracker`.
33
+ */
34
+ private readonly threadCpu;
35
+ /**
36
+ * Retention for the snapshots this addon emits. Fed by SUBSCRIBING to
37
+ * `metrics.node-processes-snapshot`, never by a second sampler — on the hub
38
+ * that bus carries every node, so the hub's ring is the cluster's. Bounds and
39
+ * measured cost live in `node-load-ring.ts`.
40
+ */
41
+ private readonly loadRing;
42
+ /**
43
+ * The COLD tier, and it exists only on the HUB.
44
+ *
45
+ * The table is hub-resident and the hub already hears every node's snapshot
46
+ * on its bus, so the hub's writer is the cluster's. An agent writing through
47
+ * the `settings-store` singleton would ship its rows over Moleculer, once
48
+ * per sample, to reach that very same table.
49
+ */
50
+ private loadStore;
51
+ /** The resolved knobs. Re-resolved on every settings write. */
52
+ private loadConfig;
53
+ /**
54
+ * Process rows seen in each node's most recent snapshot — the OBSERVED
55
+ * numbers the settings form projects its cost from. A constant here would be
56
+ * a projection that stops being true the first time the fleet changes.
57
+ */
58
+ private readonly observedRowsByNode;
22
59
  constructor();
60
+ /** Is this the hub? The same test every other addon uses (`addon-ai`). */
61
+ private get isHub();
62
+ /** Process rows observed across the whole fleet, for the cost projection. */
63
+ private observedFleetRows;
64
+ /**
65
+ * Project a `NodeProcess` onto the series' own row.
66
+ *
67
+ * `command`, `ppid`, `pgid`, `nodeId`, `threadCount` and `uptimeSec` are
68
+ * dropped here, at the single point both tiers pass through, so the hot ring
69
+ * and the cold table carry the SAME shape and the merged read cannot tell
70
+ * them apart. `command` in particular is the fattest field in a snapshot and
71
+ * the same identical string on every runner — the runner id travels in the
72
+ * environment, not in argv — and nothing that draws this series reads it.
73
+ */
74
+ private static toRetained;
23
75
  protected onInitialize(): Promise<ProviderRegistration[]>;
76
+ /**
77
+ * Retain one arriving snapshot in BOTH tiers.
78
+ *
79
+ * The ring is written FIRST and it is the gate: `record` refuses a timestamp
80
+ * this node has already delivered, and only an accepted sample reaches the
81
+ * table. That is what makes the append idempotent without a unique index
82
+ * over two million rows — the composite key it replaces was measured at ~40
83
+ * bytes per row (`load-series-store.ts`).
84
+ *
85
+ * The durable append is fire-and-forget: a storage stall must cost a gap in
86
+ * the cold window, never a blocked event-bus handler. Every failure logs.
87
+ */
88
+ private retainSnapshot;
89
+ /**
90
+ * The ONE reader, over both tiers.
91
+ *
92
+ * Cold first, hot second, merged and deduped on `atMs` — see
93
+ * `load-series-reader.ts`. The cold read is bounded in ROWS, because rows
94
+ * are what a query costs, and the fold + reduction happen HERE rather than
95
+ * in the browser: six hours at the 10 s cadence is 2 160 snapshots, and
96
+ * shipping them to a page that will discard most of them is precisely the
97
+ * cost this subsystem exists to avoid.
98
+ */
99
+ private readLoadSeries;
100
+ /**
101
+ * Re-resolve the knobs and restate the fixed cadence.
102
+ *
103
+ * A REFUSED value (out of 5-60 s, or out of 1-72 h) leaves the previous
104
+ * configuration in force and says so. Refused, never clamped: storing 10
105
+ * when the operator typed 2 and reading 10 back is a knob and a readback
106
+ * agreeing on a value nobody chose.
107
+ */
108
+ private applyLoadSeriesConfig;
109
+ /** (Re)arm the fixed-cadence process-tree timer at the configured interval. */
110
+ private startProcessSnapshotTimer;
24
111
  protected onShutdown(): Promise<void>;
25
112
  /**
26
113
  * Resolve this node's short id (strips any `nodeId/addonId` suffix).
@@ -34,10 +121,14 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
34
121
  */
35
122
  private emitResourcesSnapshot;
36
123
  /**
37
- * Emit one `metrics.node-processes-snapshot` for this node. Heavy —
38
- * runs a full OS `ps -eo` scan (`runPs`) plus a `$process.list` broker
39
- * call. Fires on the coarser PROCESS_SNAPSHOT_INTERVAL_MS so an idle
40
- * node isn't paying a process-table walk every 5s. Skip on failure.
124
+ * Emit one `metrics.node-processes-snapshot` for this node.
125
+ *
126
+ * Heavy a full OS `ps -eo` scan plus a `$process.list` broker call — and
127
+ * UNCONDITIONAL. The change-detection that used to guard it is gone: with a
128
+ * fixed cadence a missing interval means exactly one thing, and that is the
129
+ * property an operator investigating a spike is actually looking for.
130
+ *
131
+ * A failed scan emits nothing, which is the same signal: nobody reported.
41
132
  */
42
133
  private emitProcessesSnapshot;
43
134
  protected onConfigChanged(): Promise<void>;
@@ -47,38 +138,12 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
47
138
  /**
48
139
  * Walk the OS process table and classify each camstack-shaped process.
49
140
  *
50
- * Classification (ancestry-driven, NOT pattern-driven):
51
- * - root — the current node's own pid (`process.pid`).
52
- * - managedpid is registered in the kernel's `$process.list`
53
- * (forked addon worker spawned by this hub).
54
- * - system — ancestry walk crosses a SUPERVISOR_BOUNDARY_RE match
55
- * (tsx-watch launcher, agent CLI, concurrently, vite,
56
- * npm exec wrapper). The process belongs to the dev
57
- * tree even if not in `$process.list`. NEVER killable.
58
- * - ghost — ancestry walk reaches `ppid=1` without crossing any
59
- * supervisor boundary AND the parent isn't visible in
60
- * `ps`. A truly orphaned camstack-shaped process. The
61
- * ONLY classification that's eligible for kill.
62
- *
63
- * Old pattern-only ghost detection produced false positives: every
64
- * monorepo-path process matched CAMSTACK_CMD_RE, ancestry walk
65
- * stopping at ppid=hub returned false-positive ghosts whenever a
66
- * concurrently sibling sat above hub. Ancestry-driven classification
67
- * fixes that.
141
+ * Classification is IDENTITY-driven: `root` is this pid, `managed` is a pid
142
+ * the kernel's `$process.list` names, and every other camstack-shaped
143
+ * process is `system`. The rules and why there is no longer an ancestry
144
+ * walk behind them live in `process-classification.ts`.
68
145
  */
69
146
  private listNodeProcesses;
70
- /**
71
- * Send SIGTERM / SIGKILL to a pid. Refuses pids that don't appear in
72
- * `listNodeProcesses()` to prevent arbitrary system kills — a dedicated
73
- * admin-path for resurrected zombies, not a generic shell replacement.
74
- *
75
- * `root`-classified pids (the running launcher / agent CLI / hub itself)
76
- * are also refused: killing them tears down the whole node and the
77
- * operator's intent is almost always to nuke a leaked child, not the
78
- * supervisor that keeps the rest alive. Process restart goes through
79
- * the dedicated `$process.restart` action, not this kill API.
80
- */
81
- private killProcess;
82
147
  /**
83
148
  * Ask the addon's forked runner to write a V8 heap snapshot (SIGUSR2 → the
84
149
  * runner's diagnostic handler in addon-runner.ts), for deep per-addon memory
@@ -89,6 +154,24 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
89
154
  private dumpHeapSnapshot;
90
155
  /** Raw `ps` scan returning every pid + command + resource stats. */
91
156
  private runPs;
157
+ /**
158
+ * The knobs live HERE, on the document this addon already owns.
159
+ *
160
+ * Fields on an existing document, never a method per knob —
161
+ * `system.getLoggingSettings` / `setLoggingSettings` set that precedent.
162
+ * They are deliberately NOT in the logging document: that one is about
163
+ * levels and diagnostic windows, and two documents both claiming a knob is
164
+ * how this repo has already shipped a switch nobody read.
165
+ *
166
+ * Cluster-wide, not per-node: every node must emit on the same cadence or
167
+ * the fleet's series cannot be laid over each other, and the table is single
168
+ * and hub-resident, so a per-node retention would be a promise nothing could
169
+ * keep.
170
+ *
171
+ * The cost line is computed from OBSERVED numbers — the nodes and process
172
+ * counts the cluster is actually reporting — so an operator raising the
173
+ * retention sees what it costs BEFORE applying it, not afterwards.
174
+ */
92
175
  protected globalSettingsSchema(): import('@camstack/types').ConfigUISchema;
93
176
  }
94
177
  export {};