@camstack/addon-ai 0.4.27 → 0.4.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.
Files changed (3) hide show
  1. package/dist/addon.js +255 -25
  2. package/dist/addon.mjs +255 -25
  3. 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-CIa_iT6b.mjs
18
+ //#region ../types/dist/event-category-BZL-fdNj.mjs
19
19
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
20
20
  EventCategory["SystemBoot"] = "system.boot";
21
21
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -452,7 +452,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
452
452
  EventCategory["MetricsNodeResourcesSnapshot"] = "metrics.node-resources-snapshot";
453
453
  /**
454
454
  * Periodic per-node process-tree snapshot (camstack-related pids
455
- * with ghost / managed / root classification). Emitted ~0.2 Hz by
455
+ * with root / managed / system classification). Emitted ~0.2 Hz by
456
456
  * the metrics-provider addon. Drives the Cluster → Processes tab
457
457
  * without polling `metricsProvider.listNodeProcesses`.
458
458
  */
@@ -11332,6 +11332,19 @@ var SettingsRecordSchema = object({
11332
11332
  data: record(string(), unknown())
11333
11333
  });
11334
11334
  /**
11335
+ * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
11336
+ * optional.
11337
+ *
11338
+ * A separate schema rather than loosening the shared one: every other method
11339
+ * on this cap addresses a row BY its id, and making that field optional
11340
+ * everywhere would turn a forgotten key into a silently generated one on
11341
+ * `update` and `delete` as well.
11342
+ */
11343
+ var BulkRecordSchema = object({
11344
+ id: string().optional(),
11345
+ data: record(string(), unknown())
11346
+ });
11347
+ /**
11335
11348
  * Column declaration for a structured (SQL-backed) collection.
11336
11349
  *
11337
11350
  * Logical types — the backend translates each to the matching SQLite
@@ -11388,6 +11401,10 @@ method(object({
11388
11401
  collection: string(),
11389
11402
  record: SettingsRecordSchema
11390
11403
  }), _void(), { kind: "mutation" }), method(object({
11404
+ namespace: string().optional(),
11405
+ collection: string(),
11406
+ records: array(BulkRecordSchema).readonly()
11407
+ }), object({ inserted: number$1().int() }), { kind: "mutation" }), method(object({
11391
11408
  namespace: string().optional(),
11392
11409
  collection: string(),
11393
11410
  id: string(),
@@ -11496,6 +11513,13 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11496
11513
  }), _void(), {
11497
11514
  kind: "mutation",
11498
11515
  auth: "admin"
11516
+ }), method(object({
11517
+ namespace: string().optional(),
11518
+ collection: string(),
11519
+ records: array(BulkRecordSchema).readonly()
11520
+ }), object({ inserted: number$1().int() }), {
11521
+ kind: "mutation",
11522
+ auth: "admin"
11499
11523
  }), method(object({
11500
11524
  namespace: string().optional(),
11501
11525
  collection: string(),
@@ -13358,6 +13382,68 @@ method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
13358
13382
  limit: number$1().optional(),
13359
13383
  tags: record(string(), string()).optional()
13360
13384
  }), array(LogEntrySchema).readonly());
13385
+ var LoadContributionSchema = object({
13386
+ role: _enum([
13387
+ "decode",
13388
+ "transcode",
13389
+ "recording",
13390
+ "streaming",
13391
+ "detection"
13392
+ ]),
13393
+ /**
13394
+ * The NUMERIC device id — the same value every log line carries as
13395
+ * `tags.deviceId`. `null` means this cost genuinely belongs to no single
13396
+ * camera (a shared pool), NOT that the contributor forgot to look it up: a
13397
+ * contributor that cannot name its camera must not emit the entry at all,
13398
+ * because an unnamed per-camera entry is indistinguishable from a shared one
13399
+ * and would quietly turn one camera's cost into everybody's.
13400
+ */
13401
+ deviceId: number$1().int().positive().nullable(),
13402
+ attribution: _enum([
13403
+ "measured",
13404
+ "accounted",
13405
+ "unattributable"
13406
+ ]),
13407
+ /**
13408
+ * What ONE entry is, in the contributor's own words — `615/high`,
13409
+ * `617/native`, `cuda:0 shared pool`. Free text because the unit differs per
13410
+ * family and inventing a common one would lose the only information that
13411
+ * makes two entries for the same camera distinguishable.
13412
+ */
13413
+ unit: string(),
13414
+ /**
13415
+ * The OS process this cost lives in, when there is one. Present so a
13416
+ * consumer can (a) tell two generations of the same unit apart across a
13417
+ * restart, and (b) subtract claimed processes from the node's process
13418
+ * snapshot to see what NOBODY claimed. Absent for an entry that owns no
13419
+ * process of its own.
13420
+ */
13421
+ pid: number$1().int().positive().optional(),
13422
+ /**
13423
+ * When this generation started. The pid's incarnation marker: a consumer
13424
+ * differencing {@link LoadContributionSchema.shape.cpuSeconds} must drop the
13425
+ * window when this changes, because the counter restarted from zero in a new
13426
+ * process.
13427
+ */
13428
+ startedAtMs: number$1().optional(),
13429
+ /**
13430
+ * CUMULATIVE CPU seconds this unit has consumed since it started — user +
13431
+ * system, read from the child's own `/proc/<pid>/stat` at the moment the
13432
+ * contribution is asked for.
13433
+ *
13434
+ * Cumulative and not a rate on purpose: a rate needs a window, a window
13435
+ * needs a sampler, and a new per-node sampler is the defect half of
13436
+ * `docs/architecture/load-ledger.md` documents. A counter can be differenced
13437
+ * by whoever already keeps a history; a rate cannot be un-averaged.
13438
+ *
13439
+ * Absent — never zero — on a node with no `/proc`, on a read failure, and on
13440
+ * an entry with no process.
13441
+ */
13442
+ cpuSeconds: number$1().optional(),
13443
+ /** Resident bytes of this unit's process, same source and same rules. */
13444
+ rssBytes: number$1().optional()
13445
+ });
13446
+ method(_void(), array(LoadContributionSchema).readonly());
13361
13447
  /**
13362
13448
  * `login-method` — collection cap through which auth addons contribute
13363
13449
  * their pre-auth login surfaces to the login page. This is the SINGLE,
@@ -13561,8 +13647,7 @@ var NodeProcessSchema = object({
13561
13647
  classification: _enum([
13562
13648
  "root",
13563
13649
  "managed",
13564
- "system",
13565
- "ghost"
13650
+ "system"
13566
13651
  ]),
13567
13652
  /** `$process` addon binding when `managed`, else null. */
13568
13653
  addonId: string().nullable(),
@@ -13570,22 +13655,39 @@ var NodeProcessSchema = object({
13570
13655
  nodeId: string().nullable(),
13571
13656
  /** Truncated command line. */
13572
13657
  command: string(),
13658
+ /**
13659
+ * `ps pcpu` — CPU averaged over the process's WHOLE LIFETIME, not a rate.
13660
+ * On a runner up for days it barely moves. Fine as a column, useless as a
13661
+ * series: use `cpuMainPercent + cpuGcPercent` for anything time-varying.
13662
+ */
13573
13663
  cpuPercent: number$1(),
13574
13664
  memoryRssBytes: number$1(),
13665
+ /**
13666
+ * Instantaneous CPU% of the process's own threads over the last
13667
+ * process-snapshot window, from a `/proc/<pid>/task/*` tick delta.
13668
+ *
13669
+ * `null` = UNKNOWN, never zero: no previous sample yet (first tick after
13670
+ * boot), the pid was recycled, or this node is not Linux.
13671
+ */
13672
+ cpuMainPercent: number$1().nullable(),
13673
+ /**
13674
+ * Instantaneous CPU% of V8's `V8Worker` platform pool over the same window.
13675
+ *
13676
+ * This is the number that rewrote the 2026-08-27 diagnosis — hub-main 73%,
13677
+ * `stream-broker` 61% (`docs/architecture/load-ledger.md`). A CPU chart that
13678
+ * does not separate it from `cpuMainPercent` shows "busy" where the truth is
13679
+ * "allocating too much".
13680
+ *
13681
+ * Concurrent GC is the dominant tenant of that pool but not the only one
13682
+ * (background compilation runs there too), so it is reported as
13683
+ * "GC / V8 helpers" rather than as pure collection time. `null` has the same
13684
+ * meaning as on `cpuMainPercent`.
13685
+ */
13686
+ cpuGcPercent: number$1().nullable(),
13687
+ /** Threads seen in the tick scan. `null` under the same conditions. */
13688
+ threadCount: number$1().nullable(),
13575
13689
  /** Wall-clock uptime (seconds). Parsed from `ps etime`. */
13576
- uptimeSec: number$1(),
13577
- /** True when ancestor walk reaches `ppid=1` (reparented to init/launchd). */
13578
- orphaned: boolean()
13579
- });
13580
- var KillProcessInputSchema = object({
13581
- pid: number$1(),
13582
- /** Force = SIGKILL. Default is SIGTERM. */
13583
- force: boolean().optional()
13584
- });
13585
- var KillProcessResultSchema = object({
13586
- success: boolean(),
13587
- reason: string().optional(),
13588
- signal: _enum(["SIGTERM", "SIGKILL"]).optional()
13690
+ uptimeSec: number$1()
13589
13691
  });
13590
13692
  var DumpHeapSnapshotInputSchema = object({
13591
13693
  /** The addon whose runner should dump a heap snapshot. */
@@ -13598,6 +13700,104 @@ var DumpHeapSnapshotResultSchema = object({
13598
13700
  pid: number$1().optional(),
13599
13701
  reason: string().optional()
13600
13702
  });
13703
+ /**
13704
+ * One point of one function's series.
13705
+ *
13706
+ * The unsuffixed fields are the bucket's **MAXIMUM**, and that choice is the
13707
+ * point of the whole surface. The two obvious reductions both lie: a mean per
13708
+ * bucket smears a spike away, and taking every Nth sample skips it outright.
13709
+ * Either would give us a tool built to find peaks that does not show peaks.
13710
+ * `...Min` carries the other end, `samples` says how many raw snapshots folded
13711
+ * into the bucket, and a mean stays derivable where it is wanted.
13712
+ *
13713
+ * An UNREDUCED point is a one-sample bucket: `samples === 1` and each `...Min`
13714
+ * equals its unsuffixed twin. Reduced and unreduced are the same shape, so a
13715
+ * caller cannot tell which it received — which is what "one reader" means.
13716
+ */
13717
+ var LoadPointSchema = object({
13718
+ /** Bucket START, or the snapshot's own timestamp when unreduced. */
13719
+ atMs: number$1(),
13720
+ /** Raw snapshots in this bucket. Never 0 — AN EMPTY BUCKET IS ABSENT. */
13721
+ samples: number$1().int(),
13722
+ /**
13723
+ * `null` = UNKNOWN and it PROPAGATES: a bucket is null unless every process
13724
+ * of every snapshot in it reported a thread split. A partial sum is a
13725
+ * smaller number that looks exactly as real as a complete one.
13726
+ */
13727
+ cpuMainPercent: number$1().nullable(),
13728
+ cpuMainPercentMin: number$1().nullable(),
13729
+ cpuGcPercent: number$1().nullable(),
13730
+ cpuGcPercentMin: number$1().nullable(),
13731
+ /** Lifetime-average CPU%, summed. Always known — and never a rate. */
13732
+ cpuLifetimePercent: number$1(),
13733
+ cpuLifetimePercentMin: number$1(),
13734
+ memoryRssBytes: number$1(),
13735
+ memoryRssBytesMin: number$1(),
13736
+ processCount: number$1().int(),
13737
+ processCountMin: number$1().int()
13738
+ });
13739
+ /** One function's series. `key` is an addonId, `__root__` or `__unattributed__`. */
13740
+ var LoadFunctionSeriesSchema = object({
13741
+ key: string(),
13742
+ kind: _enum([
13743
+ "addon",
13744
+ "root",
13745
+ "unattributed"
13746
+ ]),
13747
+ /** Oldest-first. A missing interval is MISSING — never zero-filled. */
13748
+ points: array(LoadPointSchema).readonly()
13749
+ });
13750
+ var NodeLoadSeriesSchema = object({
13751
+ nodeId: string(),
13752
+ /** One entry per function seen in the window, heaviest-first. */
13753
+ series: array(LoadFunctionSeriesSchema).readonly(),
13754
+ /**
13755
+ * Width of one returned bucket, in ms. Equals the sampling cadence when no
13756
+ * reduction was needed — so a caller can always say what one point covers
13757
+ * without having to know whether it was reduced.
13758
+ */
13759
+ bucketMs: number$1(),
13760
+ /** Raw snapshots that went into this answer, across both tiers. */
13761
+ retainedSamples: number$1(),
13762
+ /** Oldest snapshot represented, or `null` when nothing is retained. */
13763
+ oldestAtMs: number$1().nullable(),
13764
+ /** The fixed sampling cadence in force on the cluster, in ms. */
13765
+ cadenceMs: number$1(),
13766
+ /**
13767
+ * Did the DURABLE tier contribute? `false` means the answer is the hot ring
13768
+ * alone — an agent (which holds no table), or a store that refused.
13769
+ * Reported because "the last hour" and "the last six hours" are different
13770
+ * questions and an operator must not have to guess which was answered.
13771
+ */
13772
+ durable: boolean()
13773
+ });
13774
+ var GetLoadSeriesInputSchema = object({
13775
+ /**
13776
+ * The node whose series is wanted.
13777
+ *
13778
+ * NOT named `nodeId`: the generated cap router strips a top-level
13779
+ * `nodeId` from every method input and uses it to ROUTE the call to
13780
+ * that node's provider (`generated-cap-routers.ts`). A series target
13781
+ * called `nodeId` would silently become a routing pin and never reach
13782
+ * the provider. The hub holds every node it hears from, so the
13783
+ * ordinary call is unpinned — answered by the hub, for any node.
13784
+ */
13785
+ forNodeId: string(),
13786
+ /**
13787
+ * EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
13788
+ * holds and receives only what it is missing, so seeding a live chart
13789
+ * from this method cannot double a point already drawn.
13790
+ */
13791
+ sinceMs: number$1().optional(),
13792
+ /**
13793
+ * Most points the caller wants PER FUNCTION. The window is reduced to fit,
13794
+ * preserving min and max per bucket.
13795
+ *
13796
+ * Absent means NO reduction — legitimate for a short window and a trap for a
13797
+ * long one, which is why a chart passes its own pixel width.
13798
+ */
13799
+ maxPoints: number$1().int().positive().optional()
13800
+ });
13601
13801
  var SystemMetricsSchema = object({
13602
13802
  cpuPercent: number$1(),
13603
13803
  memoryPercent: number$1(),
@@ -13608,10 +13808,7 @@ var SystemMetricsSchema = object({
13608
13808
  gpuPercent: number$1().optional(),
13609
13809
  gpuMemoryPercent: number$1().optional()
13610
13810
  });
13611
- method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number$1().nullable()), method(object({ pids: array(number$1()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(KillProcessInputSchema, KillProcessResultSchema, {
13612
- kind: "mutation",
13613
- auth: "admin"
13614
- }), method(DumpHeapSnapshotInputSchema, DumpHeapSnapshotResultSchema, {
13811
+ method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number$1().nullable()), method(object({ pids: array(number$1()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(GetLoadSeriesInputSchema, NodeLoadSeriesSchema), method(DumpHeapSnapshotInputSchema, DumpHeapSnapshotResultSchema, {
13615
13812
  kind: "mutation",
13616
13813
  auth: "admin"
13617
13814
  });
@@ -26914,6 +27111,15 @@ var LoggingSettingsPatchSchema = object({
26914
27111
  * authority over the whole hierarchy and answers for every layer, so the
26915
27112
  * layer selector needs a name the transport does not already own.
26916
27113
  */
27114
+ /**
27115
+ * One contribution, plus WHO reported it.
27116
+ *
27117
+ * The addon and node are added by the hub as it enumerates providers, never by
27118
+ * the contributor: an addon reporting its own identity could report somebody
27119
+ * else's, and the whole point of this surface is that no claim is made by
27120
+ * anyone but its owner.
27121
+ */
27122
+ var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: string() });
26917
27123
  var GetLoggingSettingsInputSchema = object({
26918
27124
  scopeNodeId: string().optional(),
26919
27125
  /**
@@ -26972,7 +27178,7 @@ method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), met
26972
27178
  }), method(_void(), SiteLocationStatusSchema, {
26973
27179
  kind: "mutation",
26974
27180
  auth: "admin"
26975
- }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
27181
+ }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
26976
27182
  kind: "mutation",
26977
27183
  auth: "admin"
26978
27184
  });
@@ -28588,6 +28794,12 @@ Object.freeze({
28588
28794
  addonId: null,
28589
28795
  access: "create"
28590
28796
  },
28797
+ "dataStoreProvider.insertMany": {
28798
+ capName: "data-store-provider",
28799
+ capScope: "system",
28800
+ addonId: null,
28801
+ access: "create"
28802
+ },
28591
28803
  "dataStoreProvider.isEmpty": {
28592
28804
  capName: "data-store-provider",
28593
28805
  capScope: "system",
@@ -29902,6 +30114,12 @@ Object.freeze({
29902
30114
  addonId: null,
29903
30115
  access: "create"
29904
30116
  },
30117
+ "loadContribution.list": {
30118
+ capName: "load-contribution",
30119
+ capScope: "system",
30120
+ addonId: null,
30121
+ access: "view"
30122
+ },
29905
30123
  "localNetwork.downloadCa": {
29906
30124
  capName: "local-network",
29907
30125
  capScope: "system",
@@ -30202,17 +30420,17 @@ Object.freeze({
30202
30420
  addonId: null,
30203
30421
  access: "view"
30204
30422
  },
30205
- "metricsProvider.getProcessStats": {
30423
+ "metricsProvider.getLoadSeries": {
30206
30424
  capName: "metrics-provider",
30207
30425
  capScope: "system",
30208
30426
  addonId: null,
30209
30427
  access: "view"
30210
30428
  },
30211
- "metricsProvider.killProcess": {
30429
+ "metricsProvider.getProcessStats": {
30212
30430
  capName: "metrics-provider",
30213
30431
  capScope: "system",
30214
30432
  addonId: null,
30215
- access: "create"
30433
+ access: "view"
30216
30434
  },
30217
30435
  "metricsProvider.listAddonInstances": {
30218
30436
  capName: "metrics-provider",
@@ -32224,6 +32442,12 @@ Object.freeze({
32224
32442
  addonId: null,
32225
32443
  access: "create"
32226
32444
  },
32445
+ "settingsStore.insertMany": {
32446
+ capName: "settings-store",
32447
+ capScope: "system",
32448
+ addonId: null,
32449
+ access: "create"
32450
+ },
32227
32451
  "settingsStore.isEmpty": {
32228
32452
  capName: "settings-store",
32229
32453
  capScope: "system",
@@ -32836,6 +33060,12 @@ Object.freeze({
32836
33060
  addonId: null,
32837
33061
  access: "create"
32838
33062
  },
33063
+ "system.getLoadContributions": {
33064
+ capName: "system",
33065
+ capScope: "system",
33066
+ addonId: null,
33067
+ access: "view"
33068
+ },
32839
33069
  "system.getLoggingSettings": {
32840
33070
  capName: "system",
32841
33071
  capScope: "system",
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-CIa_iT6b.mjs
44
+ //#region ../types/dist/event-category-BZL-fdNj.mjs
45
45
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
46
46
  EventCategory["SystemBoot"] = "system.boot";
47
47
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -478,7 +478,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
478
478
  EventCategory["MetricsNodeResourcesSnapshot"] = "metrics.node-resources-snapshot";
479
479
  /**
480
480
  * Periodic per-node process-tree snapshot (camstack-related pids
481
- * with ghost / managed / root classification). Emitted ~0.2 Hz by
481
+ * with root / managed / system classification). Emitted ~0.2 Hz by
482
482
  * the metrics-provider addon. Drives the Cluster → Processes tab
483
483
  * without polling `metricsProvider.listNodeProcesses`.
484
484
  */
@@ -11358,6 +11358,19 @@ var SettingsRecordSchema = object({
11358
11358
  data: record(string(), unknown())
11359
11359
  });
11360
11360
  /**
11361
+ * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
11362
+ * optional.
11363
+ *
11364
+ * A separate schema rather than loosening the shared one: every other method
11365
+ * on this cap addresses a row BY its id, and making that field optional
11366
+ * everywhere would turn a forgotten key into a silently generated one on
11367
+ * `update` and `delete` as well.
11368
+ */
11369
+ var BulkRecordSchema = object({
11370
+ id: string().optional(),
11371
+ data: record(string(), unknown())
11372
+ });
11373
+ /**
11361
11374
  * Column declaration for a structured (SQL-backed) collection.
11362
11375
  *
11363
11376
  * Logical types — the backend translates each to the matching SQLite
@@ -11414,6 +11427,10 @@ method(object({
11414
11427
  collection: string(),
11415
11428
  record: SettingsRecordSchema
11416
11429
  }), _void(), { kind: "mutation" }), method(object({
11430
+ namespace: string().optional(),
11431
+ collection: string(),
11432
+ records: array(BulkRecordSchema).readonly()
11433
+ }), object({ inserted: number$1().int() }), { kind: "mutation" }), method(object({
11417
11434
  namespace: string().optional(),
11418
11435
  collection: string(),
11419
11436
  id: string(),
@@ -11522,6 +11539,13 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11522
11539
  }), _void(), {
11523
11540
  kind: "mutation",
11524
11541
  auth: "admin"
11542
+ }), method(object({
11543
+ namespace: string().optional(),
11544
+ collection: string(),
11545
+ records: array(BulkRecordSchema).readonly()
11546
+ }), object({ inserted: number$1().int() }), {
11547
+ kind: "mutation",
11548
+ auth: "admin"
11525
11549
  }), method(object({
11526
11550
  namespace: string().optional(),
11527
11551
  collection: string(),
@@ -13384,6 +13408,68 @@ method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
13384
13408
  limit: number$1().optional(),
13385
13409
  tags: record(string(), string()).optional()
13386
13410
  }), array(LogEntrySchema).readonly());
13411
+ var LoadContributionSchema = object({
13412
+ role: _enum([
13413
+ "decode",
13414
+ "transcode",
13415
+ "recording",
13416
+ "streaming",
13417
+ "detection"
13418
+ ]),
13419
+ /**
13420
+ * The NUMERIC device id — the same value every log line carries as
13421
+ * `tags.deviceId`. `null` means this cost genuinely belongs to no single
13422
+ * camera (a shared pool), NOT that the contributor forgot to look it up: a
13423
+ * contributor that cannot name its camera must not emit the entry at all,
13424
+ * because an unnamed per-camera entry is indistinguishable from a shared one
13425
+ * and would quietly turn one camera's cost into everybody's.
13426
+ */
13427
+ deviceId: number$1().int().positive().nullable(),
13428
+ attribution: _enum([
13429
+ "measured",
13430
+ "accounted",
13431
+ "unattributable"
13432
+ ]),
13433
+ /**
13434
+ * What ONE entry is, in the contributor's own words — `615/high`,
13435
+ * `617/native`, `cuda:0 shared pool`. Free text because the unit differs per
13436
+ * family and inventing a common one would lose the only information that
13437
+ * makes two entries for the same camera distinguishable.
13438
+ */
13439
+ unit: string(),
13440
+ /**
13441
+ * The OS process this cost lives in, when there is one. Present so a
13442
+ * consumer can (a) tell two generations of the same unit apart across a
13443
+ * restart, and (b) subtract claimed processes from the node's process
13444
+ * snapshot to see what NOBODY claimed. Absent for an entry that owns no
13445
+ * process of its own.
13446
+ */
13447
+ pid: number$1().int().positive().optional(),
13448
+ /**
13449
+ * When this generation started. The pid's incarnation marker: a consumer
13450
+ * differencing {@link LoadContributionSchema.shape.cpuSeconds} must drop the
13451
+ * window when this changes, because the counter restarted from zero in a new
13452
+ * process.
13453
+ */
13454
+ startedAtMs: number$1().optional(),
13455
+ /**
13456
+ * CUMULATIVE CPU seconds this unit has consumed since it started — user +
13457
+ * system, read from the child's own `/proc/<pid>/stat` at the moment the
13458
+ * contribution is asked for.
13459
+ *
13460
+ * Cumulative and not a rate on purpose: a rate needs a window, a window
13461
+ * needs a sampler, and a new per-node sampler is the defect half of
13462
+ * `docs/architecture/load-ledger.md` documents. A counter can be differenced
13463
+ * by whoever already keeps a history; a rate cannot be un-averaged.
13464
+ *
13465
+ * Absent — never zero — on a node with no `/proc`, on a read failure, and on
13466
+ * an entry with no process.
13467
+ */
13468
+ cpuSeconds: number$1().optional(),
13469
+ /** Resident bytes of this unit's process, same source and same rules. */
13470
+ rssBytes: number$1().optional()
13471
+ });
13472
+ method(_void(), array(LoadContributionSchema).readonly());
13387
13473
  /**
13388
13474
  * `login-method` — collection cap through which auth addons contribute
13389
13475
  * their pre-auth login surfaces to the login page. This is the SINGLE,
@@ -13587,8 +13673,7 @@ var NodeProcessSchema = object({
13587
13673
  classification: _enum([
13588
13674
  "root",
13589
13675
  "managed",
13590
- "system",
13591
- "ghost"
13676
+ "system"
13592
13677
  ]),
13593
13678
  /** `$process` addon binding when `managed`, else null. */
13594
13679
  addonId: string().nullable(),
@@ -13596,22 +13681,39 @@ var NodeProcessSchema = object({
13596
13681
  nodeId: string().nullable(),
13597
13682
  /** Truncated command line. */
13598
13683
  command: string(),
13684
+ /**
13685
+ * `ps pcpu` — CPU averaged over the process's WHOLE LIFETIME, not a rate.
13686
+ * On a runner up for days it barely moves. Fine as a column, useless as a
13687
+ * series: use `cpuMainPercent + cpuGcPercent` for anything time-varying.
13688
+ */
13599
13689
  cpuPercent: number$1(),
13600
13690
  memoryRssBytes: number$1(),
13691
+ /**
13692
+ * Instantaneous CPU% of the process's own threads over the last
13693
+ * process-snapshot window, from a `/proc/<pid>/task/*` tick delta.
13694
+ *
13695
+ * `null` = UNKNOWN, never zero: no previous sample yet (first tick after
13696
+ * boot), the pid was recycled, or this node is not Linux.
13697
+ */
13698
+ cpuMainPercent: number$1().nullable(),
13699
+ /**
13700
+ * Instantaneous CPU% of V8's `V8Worker` platform pool over the same window.
13701
+ *
13702
+ * This is the number that rewrote the 2026-08-27 diagnosis — hub-main 73%,
13703
+ * `stream-broker` 61% (`docs/architecture/load-ledger.md`). A CPU chart that
13704
+ * does not separate it from `cpuMainPercent` shows "busy" where the truth is
13705
+ * "allocating too much".
13706
+ *
13707
+ * Concurrent GC is the dominant tenant of that pool but not the only one
13708
+ * (background compilation runs there too), so it is reported as
13709
+ * "GC / V8 helpers" rather than as pure collection time. `null` has the same
13710
+ * meaning as on `cpuMainPercent`.
13711
+ */
13712
+ cpuGcPercent: number$1().nullable(),
13713
+ /** Threads seen in the tick scan. `null` under the same conditions. */
13714
+ threadCount: number$1().nullable(),
13601
13715
  /** Wall-clock uptime (seconds). Parsed from `ps etime`. */
13602
- uptimeSec: number$1(),
13603
- /** True when ancestor walk reaches `ppid=1` (reparented to init/launchd). */
13604
- orphaned: boolean()
13605
- });
13606
- var KillProcessInputSchema = object({
13607
- pid: number$1(),
13608
- /** Force = SIGKILL. Default is SIGTERM. */
13609
- force: boolean().optional()
13610
- });
13611
- var KillProcessResultSchema = object({
13612
- success: boolean(),
13613
- reason: string().optional(),
13614
- signal: _enum(["SIGTERM", "SIGKILL"]).optional()
13716
+ uptimeSec: number$1()
13615
13717
  });
13616
13718
  var DumpHeapSnapshotInputSchema = object({
13617
13719
  /** The addon whose runner should dump a heap snapshot. */
@@ -13624,6 +13726,104 @@ var DumpHeapSnapshotResultSchema = object({
13624
13726
  pid: number$1().optional(),
13625
13727
  reason: string().optional()
13626
13728
  });
13729
+ /**
13730
+ * One point of one function's series.
13731
+ *
13732
+ * The unsuffixed fields are the bucket's **MAXIMUM**, and that choice is the
13733
+ * point of the whole surface. The two obvious reductions both lie: a mean per
13734
+ * bucket smears a spike away, and taking every Nth sample skips it outright.
13735
+ * Either would give us a tool built to find peaks that does not show peaks.
13736
+ * `...Min` carries the other end, `samples` says how many raw snapshots folded
13737
+ * into the bucket, and a mean stays derivable where it is wanted.
13738
+ *
13739
+ * An UNREDUCED point is a one-sample bucket: `samples === 1` and each `...Min`
13740
+ * equals its unsuffixed twin. Reduced and unreduced are the same shape, so a
13741
+ * caller cannot tell which it received — which is what "one reader" means.
13742
+ */
13743
+ var LoadPointSchema = object({
13744
+ /** Bucket START, or the snapshot's own timestamp when unreduced. */
13745
+ atMs: number$1(),
13746
+ /** Raw snapshots in this bucket. Never 0 — AN EMPTY BUCKET IS ABSENT. */
13747
+ samples: number$1().int(),
13748
+ /**
13749
+ * `null` = UNKNOWN and it PROPAGATES: a bucket is null unless every process
13750
+ * of every snapshot in it reported a thread split. A partial sum is a
13751
+ * smaller number that looks exactly as real as a complete one.
13752
+ */
13753
+ cpuMainPercent: number$1().nullable(),
13754
+ cpuMainPercentMin: number$1().nullable(),
13755
+ cpuGcPercent: number$1().nullable(),
13756
+ cpuGcPercentMin: number$1().nullable(),
13757
+ /** Lifetime-average CPU%, summed. Always known — and never a rate. */
13758
+ cpuLifetimePercent: number$1(),
13759
+ cpuLifetimePercentMin: number$1(),
13760
+ memoryRssBytes: number$1(),
13761
+ memoryRssBytesMin: number$1(),
13762
+ processCount: number$1().int(),
13763
+ processCountMin: number$1().int()
13764
+ });
13765
+ /** One function's series. `key` is an addonId, `__root__` or `__unattributed__`. */
13766
+ var LoadFunctionSeriesSchema = object({
13767
+ key: string(),
13768
+ kind: _enum([
13769
+ "addon",
13770
+ "root",
13771
+ "unattributed"
13772
+ ]),
13773
+ /** Oldest-first. A missing interval is MISSING — never zero-filled. */
13774
+ points: array(LoadPointSchema).readonly()
13775
+ });
13776
+ var NodeLoadSeriesSchema = object({
13777
+ nodeId: string(),
13778
+ /** One entry per function seen in the window, heaviest-first. */
13779
+ series: array(LoadFunctionSeriesSchema).readonly(),
13780
+ /**
13781
+ * Width of one returned bucket, in ms. Equals the sampling cadence when no
13782
+ * reduction was needed — so a caller can always say what one point covers
13783
+ * without having to know whether it was reduced.
13784
+ */
13785
+ bucketMs: number$1(),
13786
+ /** Raw snapshots that went into this answer, across both tiers. */
13787
+ retainedSamples: number$1(),
13788
+ /** Oldest snapshot represented, or `null` when nothing is retained. */
13789
+ oldestAtMs: number$1().nullable(),
13790
+ /** The fixed sampling cadence in force on the cluster, in ms. */
13791
+ cadenceMs: number$1(),
13792
+ /**
13793
+ * Did the DURABLE tier contribute? `false` means the answer is the hot ring
13794
+ * alone — an agent (which holds no table), or a store that refused.
13795
+ * Reported because "the last hour" and "the last six hours" are different
13796
+ * questions and an operator must not have to guess which was answered.
13797
+ */
13798
+ durable: boolean()
13799
+ });
13800
+ var GetLoadSeriesInputSchema = object({
13801
+ /**
13802
+ * The node whose series is wanted.
13803
+ *
13804
+ * NOT named `nodeId`: the generated cap router strips a top-level
13805
+ * `nodeId` from every method input and uses it to ROUTE the call to
13806
+ * that node's provider (`generated-cap-routers.ts`). A series target
13807
+ * called `nodeId` would silently become a routing pin and never reach
13808
+ * the provider. The hub holds every node it hears from, so the
13809
+ * ordinary call is unpinned — answered by the hub, for any node.
13810
+ */
13811
+ forNodeId: string(),
13812
+ /**
13813
+ * EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
13814
+ * holds and receives only what it is missing, so seeding a live chart
13815
+ * from this method cannot double a point already drawn.
13816
+ */
13817
+ sinceMs: number$1().optional(),
13818
+ /**
13819
+ * Most points the caller wants PER FUNCTION. The window is reduced to fit,
13820
+ * preserving min and max per bucket.
13821
+ *
13822
+ * Absent means NO reduction — legitimate for a short window and a trap for a
13823
+ * long one, which is why a chart passes its own pixel width.
13824
+ */
13825
+ maxPoints: number$1().int().positive().optional()
13826
+ });
13627
13827
  var SystemMetricsSchema = object({
13628
13828
  cpuPercent: number$1(),
13629
13829
  memoryPercent: number$1(),
@@ -13634,10 +13834,7 @@ var SystemMetricsSchema = object({
13634
13834
  gpuPercent: number$1().optional(),
13635
13835
  gpuMemoryPercent: number$1().optional()
13636
13836
  });
13637
- method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number$1().nullable()), method(object({ pids: array(number$1()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(KillProcessInputSchema, KillProcessResultSchema, {
13638
- kind: "mutation",
13639
- auth: "admin"
13640
- }), method(DumpHeapSnapshotInputSchema, DumpHeapSnapshotResultSchema, {
13837
+ method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number$1().nullable()), method(object({ pids: array(number$1()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(GetLoadSeriesInputSchema, NodeLoadSeriesSchema), method(DumpHeapSnapshotInputSchema, DumpHeapSnapshotResultSchema, {
13641
13838
  kind: "mutation",
13642
13839
  auth: "admin"
13643
13840
  });
@@ -26940,6 +27137,15 @@ var LoggingSettingsPatchSchema = object({
26940
27137
  * authority over the whole hierarchy and answers for every layer, so the
26941
27138
  * layer selector needs a name the transport does not already own.
26942
27139
  */
27140
+ /**
27141
+ * One contribution, plus WHO reported it.
27142
+ *
27143
+ * The addon and node are added by the hub as it enumerates providers, never by
27144
+ * the contributor: an addon reporting its own identity could report somebody
27145
+ * else's, and the whole point of this surface is that no claim is made by
27146
+ * anyone but its owner.
27147
+ */
27148
+ var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: string() });
26943
27149
  var GetLoggingSettingsInputSchema = object({
26944
27150
  scopeNodeId: string().optional(),
26945
27151
  /**
@@ -26998,7 +27204,7 @@ method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), met
26998
27204
  }), method(_void(), SiteLocationStatusSchema, {
26999
27205
  kind: "mutation",
27000
27206
  auth: "admin"
27001
- }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
27207
+ }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
27002
27208
  kind: "mutation",
27003
27209
  auth: "admin"
27004
27210
  });
@@ -28614,6 +28820,12 @@ Object.freeze({
28614
28820
  addonId: null,
28615
28821
  access: "create"
28616
28822
  },
28823
+ "dataStoreProvider.insertMany": {
28824
+ capName: "data-store-provider",
28825
+ capScope: "system",
28826
+ addonId: null,
28827
+ access: "create"
28828
+ },
28617
28829
  "dataStoreProvider.isEmpty": {
28618
28830
  capName: "data-store-provider",
28619
28831
  capScope: "system",
@@ -29928,6 +30140,12 @@ Object.freeze({
29928
30140
  addonId: null,
29929
30141
  access: "create"
29930
30142
  },
30143
+ "loadContribution.list": {
30144
+ capName: "load-contribution",
30145
+ capScope: "system",
30146
+ addonId: null,
30147
+ access: "view"
30148
+ },
29931
30149
  "localNetwork.downloadCa": {
29932
30150
  capName: "local-network",
29933
30151
  capScope: "system",
@@ -30228,17 +30446,17 @@ Object.freeze({
30228
30446
  addonId: null,
30229
30447
  access: "view"
30230
30448
  },
30231
- "metricsProvider.getProcessStats": {
30449
+ "metricsProvider.getLoadSeries": {
30232
30450
  capName: "metrics-provider",
30233
30451
  capScope: "system",
30234
30452
  addonId: null,
30235
30453
  access: "view"
30236
30454
  },
30237
- "metricsProvider.killProcess": {
30455
+ "metricsProvider.getProcessStats": {
30238
30456
  capName: "metrics-provider",
30239
30457
  capScope: "system",
30240
30458
  addonId: null,
30241
- access: "create"
30459
+ access: "view"
30242
30460
  },
30243
30461
  "metricsProvider.listAddonInstances": {
30244
30462
  capName: "metrics-provider",
@@ -32250,6 +32468,12 @@ Object.freeze({
32250
32468
  addonId: null,
32251
32469
  access: "create"
32252
32470
  },
32471
+ "settingsStore.insertMany": {
32472
+ capName: "settings-store",
32473
+ capScope: "system",
32474
+ addonId: null,
32475
+ access: "create"
32476
+ },
32253
32477
  "settingsStore.isEmpty": {
32254
32478
  capName: "settings-store",
32255
32479
  capScope: "system",
@@ -32862,6 +33086,12 @@ Object.freeze({
32862
33086
  addonId: null,
32863
33087
  access: "create"
32864
33088
  },
33089
+ "system.getLoadContributions": {
33090
+ capName: "system",
33091
+ capScope: "system",
33092
+ addonId: null,
33093
+ access: "view"
33094
+ },
32865
33095
  "system.getLoggingSettings": {
32866
33096
  capName: "system",
32867
33097
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-ai",
3
- "version": "0.4.27",
3
+ "version": "0.4.29",
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",