opensentinel 2.1.1 → 3.1.1

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 (268) hide show
  1. package/README.md +354 -283
  2. package/dist/archiver-AVNBYCKQ.js +15340 -0
  3. package/dist/archiver-AVNBYCKQ.js.map +1 -0
  4. package/dist/audit-logger-OBPR7CRO.js +22 -0
  5. package/dist/auth-UOX5K2BE.js +18 -0
  6. package/dist/autonomy-ZXDBDQUJ.js +86 -0
  7. package/dist/autonomy-ZXDBDQUJ.js.map +1 -0
  8. package/dist/aws-s3-Q4LLZZPD.js +146 -0
  9. package/dist/aws-s3-Q4LLZZPD.js.map +1 -0
  10. package/dist/backup-restore-PZ7CYYB7.js +16 -0
  11. package/dist/blocks-R3PODY47.js +23 -0
  12. package/dist/bot-QRARP4UN.js +36 -0
  13. package/dist/brain-7XLLM3KC.js +56 -0
  14. package/dist/camera-monitor-M5CYKUU4.js +335 -0
  15. package/dist/camera-monitor-M5CYKUU4.js.map +1 -0
  16. package/dist/{charts-MMXM6BWW.js → charts-V7ARZNKF.js} +2 -2
  17. package/dist/chunk-22VGGA7S.js +330 -0
  18. package/dist/chunk-22VGGA7S.js.map +1 -0
  19. package/dist/chunk-35WYTA3C.js +382 -0
  20. package/dist/chunk-35WYTA3C.js.map +1 -0
  21. package/dist/chunk-3E2PSU2C.js +146 -0
  22. package/dist/chunk-3E2PSU2C.js.map +1 -0
  23. package/dist/{chunk-L3F43VPB.js → chunk-4GLYY4NN.js} +2 -2
  24. package/dist/{chunk-L3F43VPB.js.map → chunk-4GLYY4NN.js.map} +1 -1
  25. package/dist/{chunk-L3PDU3XN.js → chunk-4UOE5TUZ.js} +4 -4
  26. package/dist/{chunk-6SNHU3CY.js → chunk-66OJ3WB4.js} +2 -2
  27. package/dist/chunk-6KONMXQ6.js +297 -0
  28. package/dist/chunk-6KONMXQ6.js.map +1 -0
  29. package/dist/chunk-6PMVAAA7.js +196 -0
  30. package/dist/chunk-6PMVAAA7.js.map +1 -0
  31. package/dist/chunk-766ASQWE.js +32620 -0
  32. package/dist/chunk-766ASQWE.js.map +1 -0
  33. package/dist/chunk-7WQO5J2M.js +29 -0
  34. package/dist/chunk-7WQO5J2M.js.map +1 -0
  35. package/dist/chunk-APHSRMBS.js +148 -0
  36. package/dist/chunk-APHSRMBS.js.map +1 -0
  37. package/dist/{chunk-4LVWXUNC.js → chunk-AYUKPTSM.js} +57 -39
  38. package/dist/chunk-AYUKPTSM.js.map +1 -0
  39. package/dist/chunk-BIPYADGB.js +84 -0
  40. package/dist/chunk-BIPYADGB.js.map +1 -0
  41. package/dist/chunk-BRBWNV65.js +457 -0
  42. package/dist/chunk-BRBWNV65.js.map +1 -0
  43. package/dist/chunk-BXZ6EA52.js +382 -0
  44. package/dist/chunk-BXZ6EA52.js.map +1 -0
  45. package/dist/chunk-EVE7MIIY.js +290 -0
  46. package/dist/chunk-EVE7MIIY.js.map +1 -0
  47. package/dist/chunk-F3TTNID2.js +138 -0
  48. package/dist/chunk-F3TTNID2.js.map +1 -0
  49. package/dist/chunk-H5RQOFO2.js +190 -0
  50. package/dist/chunk-H5RQOFO2.js.map +1 -0
  51. package/dist/chunk-HN3F4WSW.js +145 -0
  52. package/dist/chunk-HN3F4WSW.js.map +1 -0
  53. package/dist/{chunk-6DRDKB45.js → chunk-I6BDYQIG.js} +20 -9
  54. package/dist/chunk-I6BDYQIG.js.map +1 -0
  55. package/dist/chunk-IZJMVV7O.js +347 -0
  56. package/dist/chunk-IZJMVV7O.js.map +1 -0
  57. package/dist/chunk-KM22GV7G.js +211 -0
  58. package/dist/chunk-KM22GV7G.js.map +1 -0
  59. package/dist/chunk-MGFBLVR7.js +103 -0
  60. package/dist/chunk-MGFBLVR7.js.map +1 -0
  61. package/dist/chunk-MQJ2ECQT.js +228 -0
  62. package/dist/chunk-MQJ2ECQT.js.map +1 -0
  63. package/dist/{chunk-F6QUZQGI.js → chunk-MXAPLSJ5.js} +2 -2
  64. package/dist/{chunk-GK3E2I7A.js → chunk-NHMBTUMW.js} +2 -2
  65. package/dist/chunk-NPRTSZIF.js +131 -0
  66. package/dist/chunk-NPRTSZIF.js.map +1 -0
  67. package/dist/chunk-O7IH7JTI.js +1898 -0
  68. package/dist/chunk-O7IH7JTI.js.map +1 -0
  69. package/dist/chunk-OCVQGBJK.js +293 -0
  70. package/dist/chunk-OCVQGBJK.js.map +1 -0
  71. package/dist/chunk-P6QINGFL.js +332 -0
  72. package/dist/chunk-P6QINGFL.js.map +1 -0
  73. package/dist/chunk-PHDZKPNE.js +91 -0
  74. package/dist/chunk-PHDZKPNE.js.map +1 -0
  75. package/dist/chunk-PLDDJCW6.js +49 -0
  76. package/dist/chunk-PTGTGXV2.js +164 -0
  77. package/dist/chunk-PTGTGXV2.js.map +1 -0
  78. package/dist/chunk-REMIY4U2.js +171 -0
  79. package/dist/chunk-REMIY4U2.js.map +1 -0
  80. package/dist/chunk-RZ4YESBG.js +141 -0
  81. package/dist/chunk-RZ4YESBG.js.map +1 -0
  82. package/dist/chunk-SAX5MHK4.js +111 -0
  83. package/dist/chunk-SAX5MHK4.js.map +1 -0
  84. package/dist/{chunk-GVJVEWHI.js → chunk-SJSUSJ47.js} +2 -2
  85. package/dist/chunk-SPPMCAKG.js +777 -0
  86. package/dist/chunk-SPPMCAKG.js.map +1 -0
  87. package/dist/chunk-SVAPX2XN.js +2441 -0
  88. package/dist/chunk-SVAPX2XN.js.map +1 -0
  89. package/dist/chunk-TVEWKIK3.js +452 -0
  90. package/dist/chunk-TVEWKIK3.js.map +1 -0
  91. package/dist/{chunk-HH2HBTQM.js → chunk-TYAGMJNV.js} +5 -5
  92. package/dist/{chunk-JXUP2X7V.js → chunk-VEHFVBLI.js} +2 -2
  93. package/dist/chunk-VNX5GMTN.js +128 -0
  94. package/dist/chunk-VNX5GMTN.js.map +1 -0
  95. package/dist/chunk-VRD5CYRL.js +1568 -0
  96. package/dist/chunk-VRD5CYRL.js.map +1 -0
  97. package/dist/chunk-WLUHNG6X.js +122 -0
  98. package/dist/chunk-WLUHNG6X.js.map +1 -0
  99. package/dist/chunk-WRAKK6K6.js +265 -0
  100. package/dist/chunk-WRAKK6K6.js.map +1 -0
  101. package/dist/chunk-XKYRH4FM.js +681 -0
  102. package/dist/chunk-XKYRH4FM.js.map +1 -0
  103. package/dist/{chunk-GUBEEYDW.js → chunk-XMCVRVTF.js} +2 -2
  104. package/dist/{chunk-GUBEEYDW.js.map → chunk-XMCVRVTF.js.map} +1 -1
  105. package/dist/chunk-ZLZKF2PM.js +310 -0
  106. package/dist/chunk-ZLZKF2PM.js.map +1 -0
  107. package/dist/cli.js +5 -1
  108. package/dist/cli.js.map +1 -1
  109. package/dist/client-ZQSFPMOB.js +21 -0
  110. package/dist/clipboard-manager-TEO2GEDN.js +24 -0
  111. package/dist/commands/setup.js +3 -3
  112. package/dist/commands/setup.js.map +1 -1
  113. package/dist/commands/start.js +3 -3
  114. package/dist/commands/status.js +2 -2
  115. package/dist/commands/stop.js +2 -2
  116. package/dist/commands/utils.js +2 -2
  117. package/dist/cron-explain-HHQKPD3M.js +16 -0
  118. package/dist/crypto-4AP47IKC.js +14 -0
  119. package/dist/crypto-4AP47IKC.js.map +1 -0
  120. package/dist/databases-37X4CI2Y.js +21 -0
  121. package/dist/databases-37X4CI2Y.js.map +1 -0
  122. package/dist/discord-B3HUPGQ6.js +70 -0
  123. package/dist/discord-B3HUPGQ6.js.map +1 -0
  124. package/dist/dist-UISMLMFN.js +21847 -0
  125. package/dist/dist-UISMLMFN.js.map +1 -0
  126. package/dist/email-K7LO2IPB.js +268 -0
  127. package/dist/email-K7LO2IPB.js.map +1 -0
  128. package/dist/enhanced-retrieval-DNLLEM4Z.js +753 -0
  129. package/dist/enhanced-retrieval-DNLLEM4Z.js.map +1 -0
  130. package/dist/enrichment-pipeline-MNHNW65K.js +13 -0
  131. package/dist/enrichment-pipeline-MNHNW65K.js.map +1 -0
  132. package/dist/entity-resolution-Y3IUWEAT.js +24 -0
  133. package/dist/entity-resolution-Y3IUWEAT.js.map +1 -0
  134. package/dist/env-IWXUVTCB.js +12 -0
  135. package/dist/env-IWXUVTCB.js.map +1 -0
  136. package/dist/google-workspace-DKWUVNGC.js +169 -0
  137. package/dist/google-workspace-DKWUVNGC.js.map +1 -0
  138. package/dist/hash-tool-ULQYD7B5.js +22 -0
  139. package/dist/hash-tool-ULQYD7B5.js.map +1 -0
  140. package/dist/heartbeat-monitor-GCISLXI3.js +22 -0
  141. package/dist/heartbeat-monitor-GCISLXI3.js.map +1 -0
  142. package/dist/image-generation-OSU7FP6F.js +486 -0
  143. package/dist/image-generation-OSU7FP6F.js.map +1 -0
  144. package/dist/imessage-NGA2XF2V.js +35 -0
  145. package/dist/imessage-NGA2XF2V.js.map +1 -0
  146. package/dist/inbox-summarizer-NRI4S7IF.js +47 -0
  147. package/dist/inbox-summarizer-NRI4S7IF.js.map +1 -0
  148. package/dist/incident-response-C5J7Q6DT.js +244 -0
  149. package/dist/incident-response-C5J7Q6DT.js.map +1 -0
  150. package/dist/inventory-manager-352OHXWD.js +24 -0
  151. package/dist/inventory-manager-352OHXWD.js.map +1 -0
  152. package/dist/jira-GSGDBMIG.js +199 -0
  153. package/dist/jira-GSGDBMIG.js.map +1 -0
  154. package/dist/json-tool-QE2SYHEG.js +26 -0
  155. package/dist/json-tool-QE2SYHEG.js.map +1 -0
  156. package/dist/key-rotation-DPHU4ZTB.js +18 -0
  157. package/dist/key-rotation-DPHU4ZTB.js.map +1 -0
  158. package/dist/lib.d.ts +603 -11
  159. package/dist/lib.js +161 -35
  160. package/dist/lib.js.map +1 -1
  161. package/dist/mailchimp-KKNF6QJ7.js +152 -0
  162. package/dist/mailchimp-KKNF6QJ7.js.map +1 -0
  163. package/dist/matrix-QVHG76I7.js +279 -0
  164. package/dist/matrix-QVHG76I7.js.map +1 -0
  165. package/dist/{mcp-LS7Q3Z5W.js → mcp-3JI6W7ZE.js} +3 -3
  166. package/dist/mcp-3JI6W7ZE.js.map +1 -0
  167. package/dist/microsoft365-UCBKJHNX.js +164 -0
  168. package/dist/microsoft365-UCBKJHNX.js.map +1 -0
  169. package/dist/ocr-AC7NPX33.js +22 -0
  170. package/dist/ocr-AC7NPX33.js.map +1 -0
  171. package/dist/ollama-BOAMSPLJ.js +8 -0
  172. package/dist/ollama-BOAMSPLJ.js.map +1 -0
  173. package/dist/pages-MI523RB7.js +26 -0
  174. package/dist/pages-MI523RB7.js.map +1 -0
  175. package/dist/pair-JDFTERIK.js +24 -0
  176. package/dist/pair-JDFTERIK.js.map +1 -0
  177. package/dist/pairing-IFQYCPNS.js +10 -0
  178. package/dist/pairing-IFQYCPNS.js.map +1 -0
  179. package/dist/pdf-ALQVOEJR.js +17 -0
  180. package/dist/pdf-ALQVOEJR.js.map +1 -0
  181. package/dist/presentations-DSV5IHG5.js +1002 -0
  182. package/dist/presentations-DSV5IHG5.js.map +1 -0
  183. package/dist/prometheus-JNT2BD4L.js +10 -0
  184. package/dist/prometheus-JNT2BD4L.js.map +1 -0
  185. package/dist/providers-J4LYPHDR.js +19 -0
  186. package/dist/providers-J4LYPHDR.js.map +1 -0
  187. package/dist/qr-code-WIX4PB4U.js +16 -0
  188. package/dist/qr-code-WIX4PB4U.js.map +1 -0
  189. package/dist/quickbooks-XB4NII2S.js +190 -0
  190. package/dist/quickbooks-XB4NII2S.js.map +1 -0
  191. package/dist/regex-tool-W4ABRKGK.js +24 -0
  192. package/dist/regex-tool-W4ABRKGK.js.map +1 -0
  193. package/dist/scheduler-VK4WFERV.js +63 -0
  194. package/dist/scheduler-VK4WFERV.js.map +1 -0
  195. package/dist/search-BCLBO5E3.js +25 -0
  196. package/dist/search-BCLBO5E3.js.map +1 -0
  197. package/dist/sendgrid-RNXCAFKM.js +152 -0
  198. package/dist/sendgrid-RNXCAFKM.js.map +1 -0
  199. package/dist/shopify-NCXYJB4R.js +171 -0
  200. package/dist/shopify-NCXYJB4R.js.map +1 -0
  201. package/dist/signal-6CGDFYL2.js +35 -0
  202. package/dist/signal-6CGDFYL2.js.map +1 -0
  203. package/dist/slack-IZQWIKOH.js +75 -0
  204. package/dist/slack-IZQWIKOH.js.map +1 -0
  205. package/dist/sms-M3JIOTCW.js +23 -0
  206. package/dist/sms-M3JIOTCW.js.map +1 -0
  207. package/dist/{src-K7GASHRH.js → src-VYUE6LRA.js} +138 -32
  208. package/dist/src-VYUE6LRA.js.map +1 -0
  209. package/dist/stocks-XXWBPOCU.js +14 -0
  210. package/dist/stocks-XXWBPOCU.js.map +1 -0
  211. package/dist/text-transform-6SGUA5Z4.js +22 -0
  212. package/dist/text-transform-6SGUA5Z4.js.map +1 -0
  213. package/dist/tools-2RLEI2N6.js +38 -0
  214. package/dist/tools-2RLEI2N6.js.map +1 -0
  215. package/dist/tunnel-IWMXUML4.js +301 -0
  216. package/dist/tunnel-IWMXUML4.js.map +1 -0
  217. package/dist/twilio-53GEW5JT.js +139 -0
  218. package/dist/twilio-53GEW5JT.js.map +1 -0
  219. package/dist/unit-converter-ZYXMEZOE.js +14 -0
  220. package/dist/unit-converter-ZYXMEZOE.js.map +1 -0
  221. package/dist/whatsapp-LFX6YKCM.js +35 -0
  222. package/dist/whatsapp-LFX6YKCM.js.map +1 -0
  223. package/dist/word-document-7B6SJMAY.js +902 -0
  224. package/dist/word-document-7B6SJMAY.js.map +1 -0
  225. package/dist/xero-QYO66D45.js +162 -0
  226. package/dist/xero-QYO66D45.js.map +1 -0
  227. package/dist/zapier-webhook-TBZ5YF2A.js +106 -0
  228. package/dist/zapier-webhook-TBZ5YF2A.js.map +1 -0
  229. package/drizzle/0002_mushy_master_mold.sql +140 -0
  230. package/drizzle/meta/0002_snapshot.json +3637 -0
  231. package/drizzle/meta/_journal.json +7 -0
  232. package/package.json +100 -98
  233. package/dist/bot-KJ26BG56.js +0 -15
  234. package/dist/chunk-4LVWXUNC.js.map +0 -1
  235. package/dist/chunk-4TG2IG5K.js +0 -5249
  236. package/dist/chunk-4TG2IG5K.js.map +0 -1
  237. package/dist/chunk-6DRDKB45.js.map +0 -1
  238. package/dist/chunk-CI6Q63MM.js +0 -1613
  239. package/dist/chunk-CI6Q63MM.js.map +0 -1
  240. package/dist/chunk-KHNYJY2Z.js +0 -178
  241. package/dist/chunk-KHNYJY2Z.js.map +0 -1
  242. package/dist/chunk-NSBPE2FW.js +0 -17
  243. package/dist/discord-ZOJFTVTB.js +0 -49
  244. package/dist/imessage-JFRB6EJ7.js +0 -14
  245. package/dist/scheduler-EZ7CZMCS.js +0 -42
  246. package/dist/signal-T3MCSULM.js +0 -14
  247. package/dist/slack-N2M4FHAJ.js +0 -54
  248. package/dist/src-K7GASHRH.js.map +0 -1
  249. package/dist/tools-24GZHYRF.js +0 -16
  250. package/dist/whatsapp-VCRUPAO5.js +0 -14
  251. /package/dist/{bot-KJ26BG56.js.map → audit-logger-OBPR7CRO.js.map} +0 -0
  252. /package/dist/{chunk-NSBPE2FW.js.map → auth-UOX5K2BE.js.map} +0 -0
  253. /package/dist/{discord-ZOJFTVTB.js.map → backup-restore-PZ7CYYB7.js.map} +0 -0
  254. /package/dist/{imessage-JFRB6EJ7.js.map → blocks-R3PODY47.js.map} +0 -0
  255. /package/dist/{mcp-LS7Q3Z5W.js.map → bot-QRARP4UN.js.map} +0 -0
  256. /package/dist/{scheduler-EZ7CZMCS.js.map → brain-7XLLM3KC.js.map} +0 -0
  257. /package/dist/{charts-MMXM6BWW.js.map → charts-V7ARZNKF.js.map} +0 -0
  258. /package/dist/{chunk-L3PDU3XN.js.map → chunk-4UOE5TUZ.js.map} +0 -0
  259. /package/dist/{chunk-6SNHU3CY.js.map → chunk-66OJ3WB4.js.map} +0 -0
  260. /package/dist/{chunk-F6QUZQGI.js.map → chunk-MXAPLSJ5.js.map} +0 -0
  261. /package/dist/{chunk-GK3E2I7A.js.map → chunk-NHMBTUMW.js.map} +0 -0
  262. /package/dist/{signal-T3MCSULM.js.map → chunk-PLDDJCW6.js.map} +0 -0
  263. /package/dist/{chunk-GVJVEWHI.js.map → chunk-SJSUSJ47.js.map} +0 -0
  264. /package/dist/{chunk-HH2HBTQM.js.map → chunk-TYAGMJNV.js.map} +0 -0
  265. /package/dist/{chunk-JXUP2X7V.js.map → chunk-VEHFVBLI.js.map} +0 -0
  266. /package/dist/{slack-N2M4FHAJ.js.map → client-ZQSFPMOB.js.map} +0 -0
  267. /package/dist/{tools-24GZHYRF.js.map → clipboard-manager-TEO2GEDN.js.map} +0 -0
  268. /package/dist/{whatsapp-VCRUPAO5.js.map → cron-explain-HHQKPD3M.js.map} +0 -0
@@ -0,0 +1,335 @@
1
+ import {
2
+ __require
3
+ } from "./chunk-PLDDJCW6.js";
4
+
5
+ // src/tools/camera-monitor.ts
6
+ import { spawn, execSync } from "child_process";
7
+ import { promises as fs } from "fs";
8
+ import { tmpdir, homedir } from "os";
9
+ import { join } from "path";
10
+ import { randomUUID } from "crypto";
11
+ var _ffmpegPath = null;
12
+ function getFFmpegPath() {
13
+ if (_ffmpegPath) return _ffmpegPath;
14
+ try {
15
+ execSync("ffmpeg -version", { stdio: "pipe", timeout: 5e3 });
16
+ _ffmpegPath = "ffmpeg";
17
+ return _ffmpegPath;
18
+ } catch {
19
+ }
20
+ if (process.platform === "win32") {
21
+ const wingetBase = join(
22
+ homedir(),
23
+ "AppData",
24
+ "Local",
25
+ "Microsoft",
26
+ "WinGet",
27
+ "Packages"
28
+ );
29
+ try {
30
+ const entries = __require("fs").readdirSync(wingetBase);
31
+ const gyanDir = entries.find((e) => e.startsWith("Gyan.FFmpeg"));
32
+ if (gyanDir) {
33
+ const pkgPath = join(wingetBase, gyanDir);
34
+ const subDirs = __require("fs").readdirSync(pkgPath);
35
+ const buildDir = subDirs.find((d) => d.startsWith("ffmpeg-") && d.includes("build"));
36
+ if (buildDir) {
37
+ const candidate = join(pkgPath, buildDir, "bin", "ffmpeg.exe");
38
+ try {
39
+ __require("fs").accessSync(candidate);
40
+ _ffmpegPath = candidate;
41
+ return _ffmpegPath;
42
+ } catch {
43
+ }
44
+ }
45
+ }
46
+ } catch {
47
+ }
48
+ }
49
+ _ffmpegPath = "ffmpeg";
50
+ return _ffmpegPath;
51
+ }
52
+ function parseResolution(res) {
53
+ if (!res) return void 0;
54
+ const match = res.match(/^(\d+)x(\d+)$/i);
55
+ if (!match) return void 0;
56
+ return { width: parseInt(match[1], 10), height: parseInt(match[2], 10) };
57
+ }
58
+ async function isFFmpegAvailable() {
59
+ const ffmpeg = getFFmpegPath();
60
+ return new Promise((resolve) => {
61
+ const proc = spawn(ffmpeg, ["-version"], { stdio: "pipe" });
62
+ proc.on("error", () => resolve(false));
63
+ proc.on("close", (code) => resolve(code === 0));
64
+ });
65
+ }
66
+ async function captureFromWebcam(options = {}) {
67
+ const available = await isFFmpegAvailable();
68
+ if (!available) {
69
+ return { success: false, error: "ffmpeg not installed or not in PATH" };
70
+ }
71
+ const format = options.format || "jpg";
72
+ const outPath = join(tmpdir(), `opensentinel-capture-${randomUUID()}.${format}`);
73
+ const resolution = parseResolution(options.resolution);
74
+ const isWindows = process.platform === "win32";
75
+ const isLinux = process.platform === "linux";
76
+ const args = [];
77
+ if (isWindows) {
78
+ args.push("-f", "dshow");
79
+ args.push("-i", options.device || "video=Integrated Camera");
80
+ } else if (isLinux) {
81
+ args.push("-f", "v4l2");
82
+ args.push("-i", options.device || "/dev/video0");
83
+ } else {
84
+ args.push("-f", "avfoundation");
85
+ args.push("-i", options.device || "0");
86
+ }
87
+ if (resolution) {
88
+ args.push("-s", `${resolution.width}x${resolution.height}`);
89
+ }
90
+ args.push("-frames:v", "1", "-y", outPath);
91
+ const ffmpeg = getFFmpegPath();
92
+ return new Promise((resolve) => {
93
+ const proc = spawn(ffmpeg, args, { stdio: "pipe" });
94
+ let stderr = "";
95
+ proc.stderr?.on("data", (d) => stderr += d.toString());
96
+ const timer = setTimeout(() => {
97
+ proc.kill("SIGKILL");
98
+ resolve({ success: false, error: "Capture timeout (10s)" });
99
+ }, 1e4);
100
+ proc.on("close", async (code) => {
101
+ clearTimeout(timer);
102
+ if (code !== 0) {
103
+ resolve({ success: false, error: `ffmpeg exited with code ${code}: ${stderr.slice(0, 200)}` });
104
+ return;
105
+ }
106
+ try {
107
+ const stat = await fs.stat(outPath);
108
+ resolve({
109
+ success: true,
110
+ filePath: outPath,
111
+ fileSize: stat.size,
112
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
113
+ dimensions: resolution
114
+ });
115
+ } catch {
116
+ resolve({ success: false, error: "Capture file not created" });
117
+ }
118
+ });
119
+ proc.on("error", (err) => {
120
+ clearTimeout(timer);
121
+ resolve({ success: false, error: err.message });
122
+ });
123
+ });
124
+ }
125
+ async function burstCapture(frameCount = 5, options = {}) {
126
+ const frames = [];
127
+ const count = Math.min(Math.max(1, frameCount), 30);
128
+ for (let i = 0; i < count; i++) {
129
+ const result = await captureFromWebcam(options);
130
+ frames.push(result);
131
+ if (!result.success) break;
132
+ await new Promise((r) => setTimeout(r, 200));
133
+ }
134
+ return {
135
+ success: frames.some((f) => f.success),
136
+ frames,
137
+ totalFrames: frames.length
138
+ };
139
+ }
140
+ async function snapshotRTSP(rtspUrl, format = "jpg") {
141
+ if (!rtspUrl) {
142
+ return { success: false, error: "RTSP URL is required" };
143
+ }
144
+ const available = await isFFmpegAvailable();
145
+ if (!available) {
146
+ return { success: false, error: "ffmpeg not installed or not in PATH" };
147
+ }
148
+ const outPath = join(tmpdir(), `opensentinel-rtsp-${randomUUID()}.${format}`);
149
+ const args = [
150
+ "-rtsp_transport",
151
+ "tcp",
152
+ "-i",
153
+ rtspUrl,
154
+ "-frames:v",
155
+ "1",
156
+ "-y",
157
+ outPath
158
+ ];
159
+ const ffmpeg = getFFmpegPath();
160
+ return new Promise((resolve) => {
161
+ const proc = spawn(ffmpeg, args, { stdio: "pipe" });
162
+ let stderr = "";
163
+ proc.stderr?.on("data", (d) => stderr += d.toString());
164
+ const timer = setTimeout(() => {
165
+ proc.kill("SIGKILL");
166
+ resolve({ success: false, error: "RTSP capture timeout (15s)" });
167
+ }, 15e3);
168
+ proc.on("close", async (code) => {
169
+ clearTimeout(timer);
170
+ if (code !== 0) {
171
+ resolve({ success: false, error: `ffmpeg RTSP error (code ${code}): ${stderr.slice(0, 200)}` });
172
+ return;
173
+ }
174
+ try {
175
+ const stat = await fs.stat(outPath);
176
+ resolve({
177
+ success: true,
178
+ filePath: outPath,
179
+ fileSize: stat.size,
180
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
181
+ });
182
+ } catch {
183
+ resolve({ success: false, error: "RTSP snapshot file not created" });
184
+ }
185
+ });
186
+ proc.on("error", (err) => {
187
+ clearTimeout(timer);
188
+ resolve({ success: false, error: err.message });
189
+ });
190
+ });
191
+ }
192
+ async function snapshotHA(entityId, haUrl, haToken) {
193
+ if (!entityId) {
194
+ return { success: false, error: "entity_id is required" };
195
+ }
196
+ if (!haUrl || !haToken) {
197
+ return { success: false, error: "Home Assistant URL and token are required. Set HOME_ASSISTANT_URL and HOME_ASSISTANT_TOKEN in .env" };
198
+ }
199
+ try {
200
+ const url = `${haUrl.replace(/\/$/, "")}/api/camera_proxy/${entityId}`;
201
+ const response = await fetch(url, {
202
+ headers: { Authorization: `Bearer ${haToken}` }
203
+ });
204
+ if (!response.ok) {
205
+ return { success: false, error: `HA camera error: ${response.status} ${response.statusText}` };
206
+ }
207
+ const buffer = Buffer.from(await response.arrayBuffer());
208
+ const outPath = join(tmpdir(), `opensentinel-ha-${randomUUID()}.jpg`);
209
+ await fs.writeFile(outPath, buffer);
210
+ return {
211
+ success: true,
212
+ filePath: outPath,
213
+ fileSize: buffer.length,
214
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
215
+ };
216
+ } catch (error) {
217
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
218
+ }
219
+ }
220
+ async function listCameraDevices(haUrl, haToken) {
221
+ const devices = [];
222
+ const isLinux = process.platform === "linux";
223
+ if (isLinux) {
224
+ try {
225
+ const files = await fs.readdir("/dev");
226
+ const videoDevices = files.filter((f) => f.startsWith("video"));
227
+ for (const dev of videoDevices) {
228
+ devices.push({
229
+ id: `/dev/${dev}`,
230
+ name: dev,
231
+ source: "webcam"
232
+ });
233
+ }
234
+ } catch {
235
+ }
236
+ } else {
237
+ devices.push({
238
+ id: process.platform === "win32" ? "video=Integrated Camera" : "0",
239
+ name: "Default Camera",
240
+ source: "webcam"
241
+ });
242
+ }
243
+ if (haUrl && haToken) {
244
+ try {
245
+ const response = await fetch(`${haUrl.replace(/\/$/, "")}/api/states`, {
246
+ headers: { Authorization: `Bearer ${haToken}` }
247
+ });
248
+ if (response.ok) {
249
+ const states = await response.json();
250
+ for (const state of states) {
251
+ if (state.entity_id.startsWith("camera.")) {
252
+ devices.push({
253
+ id: state.entity_id,
254
+ name: state.attributes?.friendly_name || state.entity_id,
255
+ source: "home_assistant",
256
+ entityId: state.entity_id
257
+ });
258
+ }
259
+ }
260
+ }
261
+ } catch {
262
+ }
263
+ }
264
+ return devices;
265
+ }
266
+ async function detectMotion(duration = 10, threshold = 0.1, options = {}) {
267
+ const available = await isFFmpegAvailable();
268
+ if (!available) {
269
+ return {
270
+ success: false,
271
+ events: [],
272
+ totalFramesAnalyzed: 0,
273
+ motionDetected: false,
274
+ error: "ffmpeg not installed"
275
+ };
276
+ }
277
+ const events = [];
278
+ const intervalMs = 1e3;
279
+ const maxFrames = Math.min(Math.ceil(duration), 60);
280
+ let previousBuffer = null;
281
+ let framesAnalyzed = 0;
282
+ for (let i = 0; i < maxFrames; i++) {
283
+ const result = await captureFromWebcam({ ...options, format: "jpg" });
284
+ if (!result.success || !result.filePath) continue;
285
+ framesAnalyzed++;
286
+ try {
287
+ const currentBuffer = await fs.readFile(result.filePath);
288
+ if (previousBuffer) {
289
+ const change = compareBuffers(previousBuffer, currentBuffer);
290
+ if (change > threshold) {
291
+ events.push({
292
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
293
+ frameIndex: i,
294
+ filePath: result.filePath,
295
+ changePercent: Math.round(change * 100) / 100
296
+ });
297
+ }
298
+ }
299
+ previousBuffer = currentBuffer;
300
+ } catch {
301
+ }
302
+ if (i < maxFrames - 1) {
303
+ await new Promise((r) => setTimeout(r, intervalMs));
304
+ }
305
+ }
306
+ return {
307
+ success: true,
308
+ events,
309
+ totalFramesAnalyzed: framesAnalyzed,
310
+ motionDetected: events.length > 0
311
+ };
312
+ }
313
+ function compareBuffers(a, b) {
314
+ const len = Math.min(a.length, b.length);
315
+ if (len === 0) return 0;
316
+ let diff = 0;
317
+ let samples = 0;
318
+ for (let i = 0; i < len; i += 100) {
319
+ diff += Math.abs(a[i] - b[i]);
320
+ samples++;
321
+ }
322
+ return samples > 0 ? diff / (samples * 255) : 0;
323
+ }
324
+ export {
325
+ burstCapture,
326
+ captureFromWebcam,
327
+ detectMotion,
328
+ getFFmpegPath,
329
+ isFFmpegAvailable,
330
+ listCameraDevices,
331
+ parseResolution,
332
+ snapshotHA,
333
+ snapshotRTSP
334
+ };
335
+ //# sourceMappingURL=camera-monitor-M5CYKUU4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/camera-monitor.ts"],"sourcesContent":["/**\r\n * Camera/RTSP Monitor Tool\r\n *\r\n * Captures images from webcams, RTSP streams, or Home Assistant camera entities.\r\n * Supports single capture, burst mode, motion detection, and device listing.\r\n */\r\n\r\nimport { spawn, execSync } from \"child_process\";\r\nimport { promises as fs } from \"fs\";\r\nimport { tmpdir, homedir } from \"os\";\r\nimport { join } from \"path\";\r\nimport { randomUUID } from \"crypto\";\r\n\r\n/**\r\n * Resolve the ffmpeg binary path. Tries PATH first, then known install locations.\r\n */\r\nlet _ffmpegPath: string | null = null;\r\nexport function getFFmpegPath(): string {\r\n if (_ffmpegPath) return _ffmpegPath;\r\n\r\n // Try \"ffmpeg\" directly (relies on PATH)\r\n try {\r\n execSync(\"ffmpeg -version\", { stdio: \"pipe\", timeout: 5000 });\r\n _ffmpegPath = \"ffmpeg\";\r\n return _ffmpegPath;\r\n } catch {\r\n // Not in PATH\r\n }\r\n\r\n // Windows: check winget Gyan.FFmpeg install location\r\n if (process.platform === \"win32\") {\r\n const wingetBase = join(\r\n homedir(),\r\n \"AppData\", \"Local\", \"Microsoft\", \"WinGet\", \"Packages\"\r\n );\r\n try {\r\n const entries = require(\"fs\").readdirSync(wingetBase);\r\n const gyanDir = entries.find((e: string) => e.startsWith(\"Gyan.FFmpeg\"));\r\n if (gyanDir) {\r\n const pkgPath = join(wingetBase, gyanDir);\r\n const subDirs = require(\"fs\").readdirSync(pkgPath);\r\n const buildDir = subDirs.find((d: string) => d.startsWith(\"ffmpeg-\") && d.includes(\"build\"));\r\n if (buildDir) {\r\n const candidate = join(pkgPath, buildDir, \"bin\", \"ffmpeg.exe\");\r\n try {\r\n require(\"fs\").accessSync(candidate);\r\n _ffmpegPath = candidate;\r\n return _ffmpegPath;\r\n } catch { /* not accessible */ }\r\n }\r\n }\r\n } catch { /* winget dir not found */ }\r\n }\r\n\r\n // Fallback: just use \"ffmpeg\" and let it fail with a clear error\r\n _ffmpegPath = \"ffmpeg\";\r\n return _ffmpegPath;\r\n}\r\n\r\nexport interface CaptureResult {\r\n success: boolean;\r\n filePath?: string;\r\n fileSize?: number;\r\n capturedAt?: string;\r\n dimensions?: { width: number; height: number };\r\n error?: string;\r\n}\r\n\r\nexport interface BurstResult {\r\n success: boolean;\r\n frames: CaptureResult[];\r\n totalFrames: number;\r\n error?: string;\r\n}\r\n\r\nexport interface CameraDevice {\r\n id: string;\r\n name: string;\r\n source: \"webcam\" | \"home_assistant\";\r\n entityId?: string;\r\n}\r\n\r\nexport interface MotionEvent {\r\n timestamp: string;\r\n frameIndex: number;\r\n filePath: string;\r\n changePercent: number;\r\n}\r\n\r\nexport interface MotionResult {\r\n success: boolean;\r\n events: MotionEvent[];\r\n totalFramesAnalyzed: number;\r\n motionDetected: boolean;\r\n error?: string;\r\n}\r\n\r\ninterface CaptureOptions {\r\n device?: string;\r\n resolution?: string;\r\n format?: string;\r\n}\r\n\r\n/**\r\n * Parse resolution string \"WxH\" into width/height\r\n */\r\nexport function parseResolution(res?: string): { width: number; height: number } | undefined {\r\n if (!res) return undefined;\r\n const match = res.match(/^(\\d+)x(\\d+)$/i);\r\n if (!match) return undefined;\r\n return { width: parseInt(match[1], 10), height: parseInt(match[2], 10) };\r\n}\r\n\r\n/**\r\n * Check if ffmpeg is available\r\n */\r\nexport async function isFFmpegAvailable(): Promise<boolean> {\r\n const ffmpeg = getFFmpegPath();\r\n return new Promise((resolve) => {\r\n const proc = spawn(ffmpeg, [\"-version\"], { stdio: \"pipe\" });\r\n proc.on(\"error\", () => resolve(false));\r\n proc.on(\"close\", (code) => resolve(code === 0));\r\n });\r\n}\r\n\r\n/**\r\n * Capture a single frame from a webcam using ffmpeg\r\n */\r\nexport async function captureFromWebcam(options: CaptureOptions = {}): Promise<CaptureResult> {\r\n const available = await isFFmpegAvailable();\r\n if (!available) {\r\n return { success: false, error: \"ffmpeg not installed or not in PATH\" };\r\n }\r\n\r\n const format = options.format || \"jpg\";\r\n const outPath = join(tmpdir(), `opensentinel-capture-${randomUUID()}.${format}`);\r\n const resolution = parseResolution(options.resolution);\r\n\r\n const isWindows = process.platform === \"win32\";\r\n const isLinux = process.platform === \"linux\";\r\n\r\n const args: string[] = [];\r\n\r\n if (isWindows) {\r\n args.push(\"-f\", \"dshow\");\r\n args.push(\"-i\", options.device || \"video=Integrated Camera\");\r\n } else if (isLinux) {\r\n args.push(\"-f\", \"v4l2\");\r\n args.push(\"-i\", options.device || \"/dev/video0\");\r\n } else {\r\n args.push(\"-f\", \"avfoundation\");\r\n args.push(\"-i\", options.device || \"0\");\r\n }\r\n\r\n if (resolution) {\r\n args.push(\"-s\", `${resolution.width}x${resolution.height}`);\r\n }\r\n\r\n args.push(\"-frames:v\", \"1\", \"-y\", outPath);\r\n\r\n const ffmpeg = getFFmpegPath();\r\n return new Promise((resolve) => {\r\n const proc = spawn(ffmpeg, args, { stdio: \"pipe\" });\r\n let stderr = \"\";\r\n proc.stderr?.on(\"data\", (d) => (stderr += d.toString()));\r\n\r\n const timer = setTimeout(() => {\r\n proc.kill(\"SIGKILL\");\r\n resolve({ success: false, error: \"Capture timeout (10s)\" });\r\n }, 10000);\r\n\r\n proc.on(\"close\", async (code) => {\r\n clearTimeout(timer);\r\n if (code !== 0) {\r\n resolve({ success: false, error: `ffmpeg exited with code ${code}: ${stderr.slice(0, 200)}` });\r\n return;\r\n }\r\n\r\n try {\r\n const stat = await fs.stat(outPath);\r\n resolve({\r\n success: true,\r\n filePath: outPath,\r\n fileSize: stat.size,\r\n capturedAt: new Date().toISOString(),\r\n dimensions: resolution,\r\n });\r\n } catch {\r\n resolve({ success: false, error: \"Capture file not created\" });\r\n }\r\n });\r\n\r\n proc.on(\"error\", (err) => {\r\n clearTimeout(timer);\r\n resolve({ success: false, error: err.message });\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Capture multiple frames in burst mode\r\n */\r\nexport async function burstCapture(\r\n frameCount = 5,\r\n options: CaptureOptions = {}\r\n): Promise<BurstResult> {\r\n const frames: CaptureResult[] = [];\r\n const count = Math.min(Math.max(1, frameCount), 30);\r\n\r\n for (let i = 0; i < count; i++) {\r\n const result = await captureFromWebcam(options);\r\n frames.push(result);\r\n if (!result.success) break;\r\n // Small delay between captures\r\n await new Promise((r) => setTimeout(r, 200));\r\n }\r\n\r\n return {\r\n success: frames.some((f) => f.success),\r\n frames,\r\n totalFrames: frames.length,\r\n };\r\n}\r\n\r\n/**\r\n * Capture a single frame from an RTSP stream\r\n */\r\nexport async function snapshotRTSP(rtspUrl: string, format = \"jpg\"): Promise<CaptureResult> {\r\n if (!rtspUrl) {\r\n return { success: false, error: \"RTSP URL is required\" };\r\n }\r\n\r\n const available = await isFFmpegAvailable();\r\n if (!available) {\r\n return { success: false, error: \"ffmpeg not installed or not in PATH\" };\r\n }\r\n\r\n const outPath = join(tmpdir(), `opensentinel-rtsp-${randomUUID()}.${format}`);\r\n const args = [\r\n \"-rtsp_transport\", \"tcp\",\r\n \"-i\", rtspUrl,\r\n \"-frames:v\", \"1\",\r\n \"-y\", outPath,\r\n ];\r\n\r\n const ffmpeg = getFFmpegPath();\r\n return new Promise((resolve) => {\r\n const proc = spawn(ffmpeg, args, { stdio: \"pipe\" });\r\n let stderr = \"\";\r\n proc.stderr?.on(\"data\", (d) => (stderr += d.toString()));\r\n\r\n const timer = setTimeout(() => {\r\n proc.kill(\"SIGKILL\");\r\n resolve({ success: false, error: \"RTSP capture timeout (15s)\" });\r\n }, 15000);\r\n\r\n proc.on(\"close\", async (code) => {\r\n clearTimeout(timer);\r\n if (code !== 0) {\r\n resolve({ success: false, error: `ffmpeg RTSP error (code ${code}): ${stderr.slice(0, 200)}` });\r\n return;\r\n }\r\n\r\n try {\r\n const stat = await fs.stat(outPath);\r\n resolve({\r\n success: true,\r\n filePath: outPath,\r\n fileSize: stat.size,\r\n capturedAt: new Date().toISOString(),\r\n });\r\n } catch {\r\n resolve({ success: false, error: \"RTSP snapshot file not created\" });\r\n }\r\n });\r\n\r\n proc.on(\"error\", (err) => {\r\n clearTimeout(timer);\r\n resolve({ success: false, error: err.message });\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Capture a snapshot from a Home Assistant camera entity\r\n */\r\nexport async function snapshotHA(\r\n entityId: string,\r\n haUrl: string,\r\n haToken: string\r\n): Promise<CaptureResult> {\r\n if (!entityId) {\r\n return { success: false, error: \"entity_id is required\" };\r\n }\r\n if (!haUrl || !haToken) {\r\n return { success: false, error: \"Home Assistant URL and token are required. Set HOME_ASSISTANT_URL and HOME_ASSISTANT_TOKEN in .env\" };\r\n }\r\n\r\n try {\r\n const url = `${haUrl.replace(/\\/$/, \"\")}/api/camera_proxy/${entityId}`;\r\n const response = await fetch(url, {\r\n headers: { Authorization: `Bearer ${haToken}` },\r\n });\r\n\r\n if (!response.ok) {\r\n return { success: false, error: `HA camera error: ${response.status} ${response.statusText}` };\r\n }\r\n\r\n const buffer = Buffer.from(await response.arrayBuffer());\r\n const outPath = join(tmpdir(), `opensentinel-ha-${randomUUID()}.jpg`);\r\n await fs.writeFile(outPath, buffer);\r\n\r\n return {\r\n success: true,\r\n filePath: outPath,\r\n fileSize: buffer.length,\r\n capturedAt: new Date().toISOString(),\r\n };\r\n } catch (error) {\r\n return { success: false, error: error instanceof Error ? error.message : String(error) };\r\n }\r\n}\r\n\r\n/**\r\n * List available camera devices (webcams + HA cameras)\r\n */\r\nexport async function listCameraDevices(\r\n haUrl?: string,\r\n haToken?: string\r\n): Promise<CameraDevice[]> {\r\n const devices: CameraDevice[] = [];\r\n\r\n // Check for local webcam devices\r\n const isLinux = process.platform === \"linux\";\r\n if (isLinux) {\r\n try {\r\n const files = await fs.readdir(\"/dev\");\r\n const videoDevices = files.filter((f) => f.startsWith(\"video\"));\r\n for (const dev of videoDevices) {\r\n devices.push({\r\n id: `/dev/${dev}`,\r\n name: dev,\r\n source: \"webcam\",\r\n });\r\n }\r\n } catch {\r\n // No video devices accessible\r\n }\r\n } else {\r\n // On Windows/macOS, add a generic device entry\r\n devices.push({\r\n id: process.platform === \"win32\" ? \"video=Integrated Camera\" : \"0\",\r\n name: \"Default Camera\",\r\n source: \"webcam\",\r\n });\r\n }\r\n\r\n // Check Home Assistant for camera entities\r\n if (haUrl && haToken) {\r\n try {\r\n const response = await fetch(`${haUrl.replace(/\\/$/, \"\")}/api/states`, {\r\n headers: { Authorization: `Bearer ${haToken}` },\r\n });\r\n\r\n if (response.ok) {\r\n const states = (await response.json()) as Array<{ entity_id: string; attributes?: { friendly_name?: string } }>;\r\n for (const state of states) {\r\n if (state.entity_id.startsWith(\"camera.\")) {\r\n devices.push({\r\n id: state.entity_id,\r\n name: state.attributes?.friendly_name || state.entity_id,\r\n source: \"home_assistant\",\r\n entityId: state.entity_id,\r\n });\r\n }\r\n }\r\n }\r\n } catch {\r\n // HA not reachable\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\n/**\r\n * Simple motion detection by comparing consecutive frames\r\n */\r\nexport async function detectMotion(\r\n duration = 10,\r\n threshold = 0.1,\r\n options: CaptureOptions = {}\r\n): Promise<MotionResult> {\r\n const available = await isFFmpegAvailable();\r\n if (!available) {\r\n return {\r\n success: false,\r\n events: [],\r\n totalFramesAnalyzed: 0,\r\n motionDetected: false,\r\n error: \"ffmpeg not installed\",\r\n };\r\n }\r\n\r\n const events: MotionEvent[] = [];\r\n const intervalMs = 1000;\r\n const maxFrames = Math.min(Math.ceil(duration), 60);\r\n let previousBuffer: Buffer | null = null;\r\n let framesAnalyzed = 0;\r\n\r\n for (let i = 0; i < maxFrames; i++) {\r\n const result = await captureFromWebcam({ ...options, format: \"jpg\" });\r\n if (!result.success || !result.filePath) continue;\r\n\r\n framesAnalyzed++;\r\n\r\n try {\r\n const currentBuffer = await fs.readFile(result.filePath);\r\n\r\n if (previousBuffer) {\r\n const change = compareBuffers(previousBuffer, currentBuffer);\r\n if (change > threshold) {\r\n events.push({\r\n timestamp: new Date().toISOString(),\r\n frameIndex: i,\r\n filePath: result.filePath,\r\n changePercent: Math.round(change * 100) / 100,\r\n });\r\n }\r\n }\r\n\r\n previousBuffer = currentBuffer;\r\n } catch {\r\n // Skip frame comparison error\r\n }\r\n\r\n if (i < maxFrames - 1) {\r\n await new Promise((r) => setTimeout(r, intervalMs));\r\n }\r\n }\r\n\r\n return {\r\n success: true,\r\n events,\r\n totalFramesAnalyzed: framesAnalyzed,\r\n motionDetected: events.length > 0,\r\n };\r\n}\r\n\r\n/**\r\n * Simple buffer comparison (normalized byte difference)\r\n */\r\nfunction compareBuffers(a: Buffer, b: Buffer): number {\r\n const len = Math.min(a.length, b.length);\r\n if (len === 0) return 0;\r\n\r\n // Sample every 100th byte for speed\r\n let diff = 0;\r\n let samples = 0;\r\n for (let i = 0; i < len; i += 100) {\r\n diff += Math.abs(a[i] - b[i]);\r\n samples++;\r\n }\r\n\r\n return samples > 0 ? diff / (samples * 255) : 0;\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isPathAllowed
3
3
  } from "./chunk-CQ4JURG7.js";
4
- import "./chunk-NSBPE2FW.js";
4
+ import "./chunk-PLDDJCW6.js";
5
5
 
6
6
  // src/tools/file-generation/charts.ts
7
7
  import { join } from "path";
@@ -238,4 +238,4 @@ export {
238
238
  generateChart,
239
239
  quickChart
240
240
  };
241
- //# sourceMappingURL=charts-MMXM6BWW.js.map
241
+ //# sourceMappingURL=charts-V7ARZNKF.js.map