@camstack/addon-ai 0.4.28 → 0.4.30

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 +270 -184
  2. package/dist/addon.mjs +282 -195
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -4,18 +4,15 @@ Object.defineProperties(exports, {
4
4
  });
5
5
  const require_chunk = require("./chunk-CVvi-lCc.js");
6
6
  let node_path = require("node:path");
7
- let node_path$1 = require_chunk.__toESM(node_path, 1);
8
7
  node_path = require_chunk.__toESM(node_path);
9
8
  let node_crypto = require("node:crypto");
10
9
  let node_net = require("node:net");
11
10
  let node_fs = require("node:fs");
12
- node_fs = require_chunk.__toESM(node_fs, 1);
13
- let node_util = require("node:util");
14
- let node_zlib = require("node:zlib");
11
+ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
15
12
  let node_fs_promises = require("node:fs/promises");
16
13
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
17
14
  let node_child_process = require("node:child_process");
18
- //#region ../types/dist/event-category-CIa_iT6b.mjs
15
+ //#region ../types/dist/event-category-BZL-fdNj.mjs
19
16
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
20
17
  EventCategory["SystemBoot"] = "system.boot";
21
18
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -452,7 +449,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
452
449
  EventCategory["MetricsNodeResourcesSnapshot"] = "metrics.node-resources-snapshot";
453
450
  /**
454
451
  * Periodic per-node process-tree snapshot (camstack-related pids
455
- * with ghost / managed / root classification). Emitted ~0.2 Hz by
452
+ * with root / managed / system classification). Emitted ~0.2 Hz by
456
453
  * the metrics-provider addon. Drives the Cluster → Processes tab
457
454
  * without polling `metricsProvider.listNodeProcesses`.
458
455
  */
@@ -11332,6 +11329,19 @@ var SettingsRecordSchema = object({
11332
11329
  data: record(string(), unknown())
11333
11330
  });
11334
11331
  /**
11332
+ * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
11333
+ * optional.
11334
+ *
11335
+ * A separate schema rather than loosening the shared one: every other method
11336
+ * on this cap addresses a row BY its id, and making that field optional
11337
+ * everywhere would turn a forgotten key into a silently generated one on
11338
+ * `update` and `delete` as well.
11339
+ */
11340
+ var BulkRecordSchema = object({
11341
+ id: string().optional(),
11342
+ data: record(string(), unknown())
11343
+ });
11344
+ /**
11335
11345
  * Column declaration for a structured (SQL-backed) collection.
11336
11346
  *
11337
11347
  * Logical types — the backend translates each to the matching SQLite
@@ -11388,6 +11398,10 @@ method(object({
11388
11398
  collection: string(),
11389
11399
  record: SettingsRecordSchema
11390
11400
  }), _void(), { kind: "mutation" }), method(object({
11401
+ namespace: string().optional(),
11402
+ collection: string(),
11403
+ records: array(BulkRecordSchema).readonly()
11404
+ }), object({ inserted: number$1().int() }), { kind: "mutation" }), method(object({
11391
11405
  namespace: string().optional(),
11392
11406
  collection: string(),
11393
11407
  id: string(),
@@ -11496,6 +11510,13 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11496
11510
  }), _void(), {
11497
11511
  kind: "mutation",
11498
11512
  auth: "admin"
11513
+ }), method(object({
11514
+ namespace: string().optional(),
11515
+ collection: string(),
11516
+ records: array(BulkRecordSchema).readonly()
11517
+ }), object({ inserted: number$1().int() }), {
11518
+ kind: "mutation",
11519
+ auth: "admin"
11499
11520
  }), method(object({
11500
11521
  namespace: string().optional(),
11501
11522
  collection: string(),
@@ -13358,6 +13379,68 @@ method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
13358
13379
  limit: number$1().optional(),
13359
13380
  tags: record(string(), string()).optional()
13360
13381
  }), array(LogEntrySchema).readonly());
13382
+ var LoadContributionSchema = object({
13383
+ role: _enum([
13384
+ "decode",
13385
+ "transcode",
13386
+ "recording",
13387
+ "streaming",
13388
+ "detection"
13389
+ ]),
13390
+ /**
13391
+ * The NUMERIC device id — the same value every log line carries as
13392
+ * `tags.deviceId`. `null` means this cost genuinely belongs to no single
13393
+ * camera (a shared pool), NOT that the contributor forgot to look it up: a
13394
+ * contributor that cannot name its camera must not emit the entry at all,
13395
+ * because an unnamed per-camera entry is indistinguishable from a shared one
13396
+ * and would quietly turn one camera's cost into everybody's.
13397
+ */
13398
+ deviceId: number$1().int().positive().nullable(),
13399
+ attribution: _enum([
13400
+ "measured",
13401
+ "accounted",
13402
+ "unattributable"
13403
+ ]),
13404
+ /**
13405
+ * What ONE entry is, in the contributor's own words — `615/high`,
13406
+ * `617/native`, `cuda:0 shared pool`. Free text because the unit differs per
13407
+ * family and inventing a common one would lose the only information that
13408
+ * makes two entries for the same camera distinguishable.
13409
+ */
13410
+ unit: string(),
13411
+ /**
13412
+ * The OS process this cost lives in, when there is one. Present so a
13413
+ * consumer can (a) tell two generations of the same unit apart across a
13414
+ * restart, and (b) subtract claimed processes from the node's process
13415
+ * snapshot to see what NOBODY claimed. Absent for an entry that owns no
13416
+ * process of its own.
13417
+ */
13418
+ pid: number$1().int().positive().optional(),
13419
+ /**
13420
+ * When this generation started. The pid's incarnation marker: a consumer
13421
+ * differencing {@link LoadContributionSchema.shape.cpuSeconds} must drop the
13422
+ * window when this changes, because the counter restarted from zero in a new
13423
+ * process.
13424
+ */
13425
+ startedAtMs: number$1().optional(),
13426
+ /**
13427
+ * CUMULATIVE CPU seconds this unit has consumed since it started — user +
13428
+ * system, read from the child's own `/proc/<pid>/stat` at the moment the
13429
+ * contribution is asked for.
13430
+ *
13431
+ * Cumulative and not a rate on purpose: a rate needs a window, a window
13432
+ * needs a sampler, and a new per-node sampler is the defect half of
13433
+ * `docs/architecture/load-ledger.md` documents. A counter can be differenced
13434
+ * by whoever already keeps a history; a rate cannot be un-averaged.
13435
+ *
13436
+ * Absent — never zero — on a node with no `/proc`, on a read failure, and on
13437
+ * an entry with no process.
13438
+ */
13439
+ cpuSeconds: number$1().optional(),
13440
+ /** Resident bytes of this unit's process, same source and same rules. */
13441
+ rssBytes: number$1().optional()
13442
+ });
13443
+ method(_void(), array(LoadContributionSchema).readonly());
13361
13444
  /**
13362
13445
  * `login-method` — collection cap through which auth addons contribute
13363
13446
  * their pre-auth login surfaces to the login page. This is the SINGLE,
@@ -13561,8 +13644,7 @@ var NodeProcessSchema = object({
13561
13644
  classification: _enum([
13562
13645
  "root",
13563
13646
  "managed",
13564
- "system",
13565
- "ghost"
13647
+ "system"
13566
13648
  ]),
13567
13649
  /** `$process` addon binding when `managed`, else null. */
13568
13650
  addonId: string().nullable(),
@@ -13570,22 +13652,39 @@ var NodeProcessSchema = object({
13570
13652
  nodeId: string().nullable(),
13571
13653
  /** Truncated command line. */
13572
13654
  command: string(),
13655
+ /**
13656
+ * `ps pcpu` — CPU averaged over the process's WHOLE LIFETIME, not a rate.
13657
+ * On a runner up for days it barely moves. Fine as a column, useless as a
13658
+ * series: use `cpuMainPercent + cpuGcPercent` for anything time-varying.
13659
+ */
13573
13660
  cpuPercent: number$1(),
13574
13661
  memoryRssBytes: number$1(),
13662
+ /**
13663
+ * Instantaneous CPU% of the process's own threads over the last
13664
+ * process-snapshot window, from a `/proc/<pid>/task/*` tick delta.
13665
+ *
13666
+ * `null` = UNKNOWN, never zero: no previous sample yet (first tick after
13667
+ * boot), the pid was recycled, or this node is not Linux.
13668
+ */
13669
+ cpuMainPercent: number$1().nullable(),
13670
+ /**
13671
+ * Instantaneous CPU% of V8's `V8Worker` platform pool over the same window.
13672
+ *
13673
+ * This is the number that rewrote the 2026-08-27 diagnosis — hub-main 73%,
13674
+ * `stream-broker` 61% (`docs/architecture/load-ledger.md`). A CPU chart that
13675
+ * does not separate it from `cpuMainPercent` shows "busy" where the truth is
13676
+ * "allocating too much".
13677
+ *
13678
+ * Concurrent GC is the dominant tenant of that pool but not the only one
13679
+ * (background compilation runs there too), so it is reported as
13680
+ * "GC / V8 helpers" rather than as pure collection time. `null` has the same
13681
+ * meaning as on `cpuMainPercent`.
13682
+ */
13683
+ cpuGcPercent: number$1().nullable(),
13684
+ /** Threads seen in the tick scan. `null` under the same conditions. */
13685
+ threadCount: number$1().nullable(),
13575
13686
  /** 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()
13687
+ uptimeSec: number$1()
13589
13688
  });
13590
13689
  var DumpHeapSnapshotInputSchema = object({
13591
13690
  /** The addon whose runner should dump a heap snapshot. */
@@ -13598,6 +13697,104 @@ var DumpHeapSnapshotResultSchema = object({
13598
13697
  pid: number$1().optional(),
13599
13698
  reason: string().optional()
13600
13699
  });
13700
+ /**
13701
+ * One point of one function's series.
13702
+ *
13703
+ * The unsuffixed fields are the bucket's **MAXIMUM**, and that choice is the
13704
+ * point of the whole surface. The two obvious reductions both lie: a mean per
13705
+ * bucket smears a spike away, and taking every Nth sample skips it outright.
13706
+ * Either would give us a tool built to find peaks that does not show peaks.
13707
+ * `...Min` carries the other end, `samples` says how many raw snapshots folded
13708
+ * into the bucket, and a mean stays derivable where it is wanted.
13709
+ *
13710
+ * An UNREDUCED point is a one-sample bucket: `samples === 1` and each `...Min`
13711
+ * equals its unsuffixed twin. Reduced and unreduced are the same shape, so a
13712
+ * caller cannot tell which it received — which is what "one reader" means.
13713
+ */
13714
+ var LoadPointSchema = object({
13715
+ /** Bucket START, or the snapshot's own timestamp when unreduced. */
13716
+ atMs: number$1(),
13717
+ /** Raw snapshots in this bucket. Never 0 — AN EMPTY BUCKET IS ABSENT. */
13718
+ samples: number$1().int(),
13719
+ /**
13720
+ * `null` = UNKNOWN and it PROPAGATES: a bucket is null unless every process
13721
+ * of every snapshot in it reported a thread split. A partial sum is a
13722
+ * smaller number that looks exactly as real as a complete one.
13723
+ */
13724
+ cpuMainPercent: number$1().nullable(),
13725
+ cpuMainPercentMin: number$1().nullable(),
13726
+ cpuGcPercent: number$1().nullable(),
13727
+ cpuGcPercentMin: number$1().nullable(),
13728
+ /** Lifetime-average CPU%, summed. Always known — and never a rate. */
13729
+ cpuLifetimePercent: number$1(),
13730
+ cpuLifetimePercentMin: number$1(),
13731
+ memoryRssBytes: number$1(),
13732
+ memoryRssBytesMin: number$1(),
13733
+ processCount: number$1().int(),
13734
+ processCountMin: number$1().int()
13735
+ });
13736
+ /** One function's series. `key` is an addonId, `__root__` or `__unattributed__`. */
13737
+ var LoadFunctionSeriesSchema = object({
13738
+ key: string(),
13739
+ kind: _enum([
13740
+ "addon",
13741
+ "root",
13742
+ "unattributed"
13743
+ ]),
13744
+ /** Oldest-first. A missing interval is MISSING — never zero-filled. */
13745
+ points: array(LoadPointSchema).readonly()
13746
+ });
13747
+ var NodeLoadSeriesSchema = object({
13748
+ nodeId: string(),
13749
+ /** One entry per function seen in the window, heaviest-first. */
13750
+ series: array(LoadFunctionSeriesSchema).readonly(),
13751
+ /**
13752
+ * Width of one returned bucket, in ms. Equals the sampling cadence when no
13753
+ * reduction was needed — so a caller can always say what one point covers
13754
+ * without having to know whether it was reduced.
13755
+ */
13756
+ bucketMs: number$1(),
13757
+ /** Raw snapshots that went into this answer, across both tiers. */
13758
+ retainedSamples: number$1(),
13759
+ /** Oldest snapshot represented, or `null` when nothing is retained. */
13760
+ oldestAtMs: number$1().nullable(),
13761
+ /** The fixed sampling cadence in force on the cluster, in ms. */
13762
+ cadenceMs: number$1(),
13763
+ /**
13764
+ * Did the DURABLE tier contribute? `false` means the answer is the hot ring
13765
+ * alone — an agent (which holds no table), or a store that refused.
13766
+ * Reported because "the last hour" and "the last six hours" are different
13767
+ * questions and an operator must not have to guess which was answered.
13768
+ */
13769
+ durable: boolean()
13770
+ });
13771
+ var GetLoadSeriesInputSchema = object({
13772
+ /**
13773
+ * The node whose series is wanted.
13774
+ *
13775
+ * NOT named `nodeId`: the generated cap router strips a top-level
13776
+ * `nodeId` from every method input and uses it to ROUTE the call to
13777
+ * that node's provider (`generated-cap-routers.ts`). A series target
13778
+ * called `nodeId` would silently become a routing pin and never reach
13779
+ * the provider. The hub holds every node it hears from, so the
13780
+ * ordinary call is unpinned — answered by the hub, for any node.
13781
+ */
13782
+ forNodeId: string(),
13783
+ /**
13784
+ * EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
13785
+ * holds and receives only what it is missing, so seeding a live chart
13786
+ * from this method cannot double a point already drawn.
13787
+ */
13788
+ sinceMs: number$1().optional(),
13789
+ /**
13790
+ * Most points the caller wants PER FUNCTION. The window is reduced to fit,
13791
+ * preserving min and max per bucket.
13792
+ *
13793
+ * Absent means NO reduction — legitimate for a short window and a trap for a
13794
+ * long one, which is why a chart passes its own pixel width.
13795
+ */
13796
+ maxPoints: number$1().int().positive().optional()
13797
+ });
13601
13798
  var SystemMetricsSchema = object({
13602
13799
  cpuPercent: number$1(),
13603
13800
  memoryPercent: number$1(),
@@ -13608,10 +13805,7 @@ var SystemMetricsSchema = object({
13608
13805
  gpuPercent: number$1().optional(),
13609
13806
  gpuMemoryPercent: number$1().optional()
13610
13807
  });
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, {
13808
+ 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
13809
  kind: "mutation",
13616
13810
  auth: "admin"
13617
13811
  });
@@ -26914,6 +27108,15 @@ var LoggingSettingsPatchSchema = object({
26914
27108
  * authority over the whole hierarchy and answers for every layer, so the
26915
27109
  * layer selector needs a name the transport does not already own.
26916
27110
  */
27111
+ /**
27112
+ * One contribution, plus WHO reported it.
27113
+ *
27114
+ * The addon and node are added by the hub as it enumerates providers, never by
27115
+ * the contributor: an addon reporting its own identity could report somebody
27116
+ * else's, and the whole point of this surface is that no claim is made by
27117
+ * anyone but its owner.
27118
+ */
27119
+ var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: string() });
26917
27120
  var GetLoggingSettingsInputSchema = object({
26918
27121
  scopeNodeId: string().optional(),
26919
27122
  /**
@@ -26972,7 +27175,7 @@ method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), met
26972
27175
  }), method(_void(), SiteLocationStatusSchema, {
26973
27176
  kind: "mutation",
26974
27177
  auth: "admin"
26975
- }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
27178
+ }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
26976
27179
  kind: "mutation",
26977
27180
  auth: "admin"
26978
27181
  });
@@ -28588,6 +28791,12 @@ Object.freeze({
28588
28791
  addonId: null,
28589
28792
  access: "create"
28590
28793
  },
28794
+ "dataStoreProvider.insertMany": {
28795
+ capName: "data-store-provider",
28796
+ capScope: "system",
28797
+ addonId: null,
28798
+ access: "create"
28799
+ },
28591
28800
  "dataStoreProvider.isEmpty": {
28592
28801
  capName: "data-store-provider",
28593
28802
  capScope: "system",
@@ -29902,6 +30111,12 @@ Object.freeze({
29902
30111
  addonId: null,
29903
30112
  access: "create"
29904
30113
  },
30114
+ "loadContribution.list": {
30115
+ capName: "load-contribution",
30116
+ capScope: "system",
30117
+ addonId: null,
30118
+ access: "view"
30119
+ },
29905
30120
  "localNetwork.downloadCa": {
29906
30121
  capName: "local-network",
29907
30122
  capScope: "system",
@@ -30202,17 +30417,17 @@ Object.freeze({
30202
30417
  addonId: null,
30203
30418
  access: "view"
30204
30419
  },
30205
- "metricsProvider.getProcessStats": {
30420
+ "metricsProvider.getLoadSeries": {
30206
30421
  capName: "metrics-provider",
30207
30422
  capScope: "system",
30208
30423
  addonId: null,
30209
30424
  access: "view"
30210
30425
  },
30211
- "metricsProvider.killProcess": {
30426
+ "metricsProvider.getProcessStats": {
30212
30427
  capName: "metrics-provider",
30213
30428
  capScope: "system",
30214
30429
  addonId: null,
30215
- access: "create"
30430
+ access: "view"
30216
30431
  },
30217
30432
  "metricsProvider.listAddonInstances": {
30218
30433
  capName: "metrics-provider",
@@ -32224,6 +32439,12 @@ Object.freeze({
32224
32439
  addonId: null,
32225
32440
  access: "create"
32226
32441
  },
32442
+ "settingsStore.insertMany": {
32443
+ capName: "settings-store",
32444
+ capScope: "system",
32445
+ addonId: null,
32446
+ access: "create"
32447
+ },
32227
32448
  "settingsStore.isEmpty": {
32228
32449
  capName: "settings-store",
32229
32450
  capScope: "system",
@@ -32836,6 +33057,12 @@ Object.freeze({
32836
33057
  addonId: null,
32837
33058
  access: "create"
32838
33059
  },
33060
+ "system.getLoadContributions": {
33061
+ capName: "system",
33062
+ capScope: "system",
33063
+ addonId: null,
33064
+ access: "view"
33065
+ },
32839
33066
  "system.getLoggingSettings": {
32840
33067
  capName: "system",
32841
33068
  capScope: "system",
@@ -60996,12 +61223,12 @@ var require_auth_config = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
60996
61223
  });
60997
61224
  module.exports = __toCommonJS(auth_config_exports);
60998
61225
  var fs$1 = __toESM(require("fs"));
60999
- var path$2 = __toESM(require("path"));
61226
+ var path$1 = __toESM(require("path"));
61000
61227
  var import_token_util = require_token_util();
61001
61228
  function getAuthConfigPath() {
61002
61229
  const dataDir = (0, import_token_util.getVercelDataDir)();
61003
61230
  if (!dataDir) throw new Error(`Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`);
61004
- return path$2.join(dataDir, "auth.json");
61231
+ return path$1.join(dataDir, "auth.json");
61005
61232
  }
61006
61233
  function readAuthConfig() {
61007
61234
  try {
@@ -61016,7 +61243,7 @@ var require_auth_config = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61016
61243
  }
61017
61244
  function writeAuthConfig(config) {
61018
61245
  const authPath = getAuthConfigPath();
61019
- const authDir = path$2.dirname(authPath);
61246
+ const authDir = path$1.dirname(authPath);
61020
61247
  if (!fs$1.existsSync(authDir)) fs$1.mkdirSync(authDir, {
61021
61248
  mode: 504,
61022
61249
  recursive: true
@@ -61154,7 +61381,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61154
61381
  saveToken: () => saveToken
61155
61382
  });
61156
61383
  module.exports = __toCommonJS(token_util_exports);
61157
- var path$1 = __toESM(require("path"));
61384
+ var path = __toESM(require("path"));
61158
61385
  var fs = __toESM(require("fs"));
61159
61386
  var import_token_error = require_token_error();
61160
61387
  var import_token_io = require_token_io();
@@ -61165,7 +61392,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61165
61392
  const vercelFolder = "com.vercel.cli";
61166
61393
  const dataDir = (0, import_token_io.getUserDataDir)();
61167
61394
  if (!dataDir) return null;
61168
- return path$1.join(dataDir, vercelFolder);
61395
+ return path.join(dataDir, vercelFolder);
61169
61396
  }
61170
61397
  async function getVercelToken(options) {
61171
61398
  const authConfig = (0, import_auth_config.readAuthConfig)();
@@ -61213,7 +61440,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61213
61440
  function findProjectInfo() {
61214
61441
  const dir = (0, import_token_io.findRootDir)();
61215
61442
  if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find project root directory. Have you linked your project with `vc link?`");
61216
- const prjPath = path$1.join(dir, ".vercel", "project.json");
61443
+ const prjPath = path.join(dir, ".vercel", "project.json");
61217
61444
  if (!fs.existsSync(prjPath)) throw new import_token_error.VercelOidcTokenError("project.json not found, have you linked your project with `vc link?`");
61218
61445
  const prj = JSON.parse(fs.readFileSync(prjPath, "utf8"));
61219
61446
  if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") throw new TypeError("Expected a string-valued projectId property. Try running `vc link` to re-link your project.");
@@ -61225,9 +61452,9 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61225
61452
  function saveToken(token, projectId) {
61226
61453
  const dir = (0, import_token_io.getUserDataDir)();
61227
61454
  if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
61228
- const tokenPath = path$1.join(dir, "com.vercel.token", `${projectId}.json`);
61455
+ const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
61229
61456
  const tokenJson = JSON.stringify(token);
61230
- fs.mkdirSync(path$1.dirname(tokenPath), {
61457
+ fs.mkdirSync(path.dirname(tokenPath), {
61231
61458
  mode: 504,
61232
61459
  recursive: true
61233
61460
  });
@@ -61237,7 +61464,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
61237
61464
  function loadToken(projectId) {
61238
61465
  const dir = (0, import_token_io.getUserDataDir)();
61239
61466
  if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
61240
- const tokenPath = path$1.join(dir, "com.vercel.token", `${projectId}.json`);
61467
+ const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
61241
61468
  if (!fs.existsSync(tokenPath)) return null;
61242
61469
  const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
61243
61470
  assertVercelOidcTokenResponse(token);
@@ -73243,147 +73470,6 @@ function entryForRef(ref) {
73243
73470
  };
73244
73471
  }
73245
73472
  //#endregion
73246
- //#region ../system/dist/file-data-plane-BhKdxJgf.mjs
73247
- function isNonEmptyFile(filePath) {
73248
- return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
73249
- }
73250
- /**
73251
- * Sibling files of a single-file (non-directory) format — extra files the
73252
- * format needs, fetched from the same remote directory as `url` and stored
73253
- * flat alongside the main file in `modelsDir`. Catalog-declared via
73254
- * `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
73255
- * `.xml`. The downloader stays format-agnostic; the convention lives in the
73256
- * catalog data (like `MLPACKAGE_FILES` for the directory case).
73257
- */
73258
- function siblingFilesFor(formatEntry) {
73259
- return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
73260
- }
73261
- /** Build fetch headers, including HF auth token for huggingface.co URLs */
73262
- function buildHeaders(url) {
73263
- const headers = { "User-Agent": "CamStack/1.0" };
73264
- const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
73265
- if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
73266
- return headers;
73267
- }
73268
- var DEFAULT_MAX_REDIRECTS = 5;
73269
- function normalizeDownloadOptions(third) {
73270
- if (typeof third === "function") return { onProgress: third };
73271
- return third ?? {};
73272
- }
73273
- function isRedirectStatus(status) {
73274
- return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
73275
- }
73276
- function resolveRedirectUrl(current, location) {
73277
- return new URL(location, current);
73278
- }
73279
- async function downloadFile(url, destPath, onProgressOrOptions) {
73280
- if (node_fs.existsSync(destPath)) return destPath;
73281
- const opts = normalizeDownloadOptions(onProgressOrOptions);
73282
- const fetchImpl = opts.fetchImpl ?? fetch;
73283
- const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
73284
- node_fs.mkdirSync(node_path$1.dirname(destPath), { recursive: true });
73285
- const tmpPath = destPath + ".downloading";
73286
- try {
73287
- let current = url;
73288
- const seen = /* @__PURE__ */ new Set();
73289
- let response;
73290
- const manual = opts.redirectPolicy !== void 0;
73291
- for (let hop = 0; hop <= maxRedirects; hop++) {
73292
- const parsed = new URL(current);
73293
- if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
73294
- if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
73295
- seen.add(parsed.href);
73296
- const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
73297
- const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
73298
- try {
73299
- response = await fetchImpl(current, {
73300
- redirect: manual ? "manual" : "follow",
73301
- headers: buildHeaders(current),
73302
- ...controller ? { signal: controller.signal } : {}
73303
- });
73304
- } finally {
73305
- if (timer) clearTimeout(timer);
73306
- }
73307
- if (manual && isRedirectStatus(response.status)) {
73308
- const location = response.headers.get("location");
73309
- if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
73310
- if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
73311
- current = resolveRedirectUrl(current, location).href;
73312
- continue;
73313
- }
73314
- break;
73315
- }
73316
- if (!response) throw new Error(`No response downloading ${url}`);
73317
- if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
73318
- if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
73319
- if (!response.body) throw new Error(`No response body from ${url}`);
73320
- const total = parseInt(response.headers.get("content-length") ?? "0", 10);
73321
- let downloaded = 0;
73322
- const fileStream = node_fs.createWriteStream(tmpPath);
73323
- const reader = response.body.getReader();
73324
- try {
73325
- for (;;) {
73326
- const { done, value } = await reader.read();
73327
- if (done || !value) break;
73328
- downloaded += value.length;
73329
- if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
73330
- fileStream.write(value);
73331
- opts.onProgress?.(downloaded, total);
73332
- }
73333
- } finally {
73334
- fileStream.end();
73335
- await new Promise((resolve, reject) => {
73336
- fileStream.on("finish", resolve);
73337
- fileStream.on("error", reject);
73338
- });
73339
- }
73340
- node_fs.renameSync(tmpPath, destPath);
73341
- return destPath;
73342
- } catch (err) {
73343
- try {
73344
- node_fs.unlinkSync(tmpPath);
73345
- } catch {}
73346
- throw err;
73347
- }
73348
- }
73349
- /** Compute the on-disk path for a given model + format, even when not yet downloaded. */
73350
- function getModelFilePath(modelsDir, entry, format) {
73351
- const formatEntry = entry.formats[format];
73352
- if (!formatEntry) return null;
73353
- const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
73354
- return node_path$1.join(modelsDir, filename);
73355
- }
73356
- /** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
73357
- function isModelDownloaded(modelsDir, entry, format) {
73358
- const formatEntry = entry.formats[format];
73359
- if (!formatEntry) return false;
73360
- const modelPath = getModelFilePath(modelsDir, entry, format);
73361
- if (!modelPath || !node_fs.existsSync(modelPath)) return false;
73362
- if (formatEntry.isDirectory) return node_fs.existsSync(node_path$1.join(modelPath, "Manifest.json"));
73363
- if (node_fs.statSync(modelPath).size <= 0) return false;
73364
- return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path$1.join(modelsDir, f)));
73365
- }
73366
- /** Remove the on-disk model file/directory. Returns true if something was deleted. */
73367
- function deleteModelFromDisk(modelsDir, entry, format) {
73368
- const modelPath = getModelFilePath(modelsDir, entry, format);
73369
- if (!modelPath || !node_fs.existsSync(modelPath)) return false;
73370
- const formatEntry = entry.formats[format];
73371
- if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
73372
- recursive: true,
73373
- force: true
73374
- });
73375
- else {
73376
- node_fs.unlinkSync(modelPath);
73377
- if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
73378
- const sibPath = node_path$1.join(modelsDir, sibling);
73379
- if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
73380
- }
73381
- }
73382
- return true;
73383
- }
73384
- (0, node_util.promisify)(node_zlib.brotliCompress);
73385
- (0, node_util.promisify)(node_zlib.gzip);
73386
- //#endregion
73387
73473
  //#region src/runtime/model-ops.ts
73388
73474
  /**
73389
73475
  * Default `RuntimeModelOps` — the ONLY place the reused object-detection model
@@ -73447,7 +73533,7 @@ function createDefaultModelOps(modelsDir) {
73447
73533
  downloadedBytes: carried,
73448
73534
  ...totalBytes > 0 ? { totalBytes } : {}
73449
73535
  });
73450
- await downloadFile(file.url, file.destPath, (downloaded) => {
73536
+ await (0, _camstack_system_addon_utils.downloadFile)(file.url, file.destPath, (downloaded) => {
73451
73537
  onProgress({
73452
73538
  file: file.filename,
73453
73539
  fileIndex: index + 1,
@@ -73458,18 +73544,18 @@ function createDefaultModelOps(modelsDir) {
73458
73544
  });
73459
73545
  carried += (0, node_fs.existsSync)(file.destPath) ? (0, node_fs.statSync)(file.destPath).size : file.expectedBytes;
73460
73546
  }
73461
- const main = getModelFilePath(modelsDir, entry, GGUF);
73547
+ const main = (0, _camstack_system_addon_utils.getModelFilePath)(modelsDir, entry, GGUF);
73462
73548
  if (main === null) throw new Error(`no gguf path for model ${entry.id}`);
73463
73549
  return main;
73464
73550
  },
73465
- isDownloaded: (entry) => isModelDownloaded(modelsDir, entry, GGUF),
73551
+ isDownloaded: (entry) => (0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, entry, GGUF),
73466
73552
  pathFor: (entry) => {
73467
- const p = getModelFilePath(modelsDir, entry, GGUF);
73553
+ const p = (0, _camstack_system_addon_utils.getModelFilePath)(modelsDir, entry, GGUF);
73468
73554
  if (p === null) throw new Error(`no gguf path for model ${entry.id}`);
73469
73555
  return p;
73470
73556
  },
73471
73557
  delete: async (entry) => {
73472
- deleteModelFromDisk(modelsDir, entry, GGUF);
73558
+ (0, _camstack_system_addon_utils.deleteModelFromDisk)(modelsDir, entry, GGUF);
73473
73559
  },
73474
73560
  extraFilePath: (_entry, filename) => node_path.join(modelsDir, filename)
73475
73561
  };