@panguard-ai/core 0.1.0

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 (233) hide show
  1. package/dist/adapters/adapter-registry.d.ts +150 -0
  2. package/dist/adapters/adapter-registry.d.ts.map +1 -0
  3. package/dist/adapters/adapter-registry.js +271 -0
  4. package/dist/adapters/adapter-registry.js.map +1 -0
  5. package/dist/adapters/base-adapter.d.ts +101 -0
  6. package/dist/adapters/base-adapter.d.ts.map +1 -0
  7. package/dist/adapters/base-adapter.js +160 -0
  8. package/dist/adapters/base-adapter.js.map +1 -0
  9. package/dist/adapters/defender-adapter.d.ts +90 -0
  10. package/dist/adapters/defender-adapter.d.ts.map +1 -0
  11. package/dist/adapters/defender-adapter.js +227 -0
  12. package/dist/adapters/defender-adapter.js.map +1 -0
  13. package/dist/adapters/index.d.ts +22 -0
  14. package/dist/adapters/index.d.ts.map +1 -0
  15. package/dist/adapters/index.js +23 -0
  16. package/dist/adapters/index.js.map +1 -0
  17. package/dist/adapters/syslog-adapter.d.ts +207 -0
  18. package/dist/adapters/syslog-adapter.d.ts.map +1 -0
  19. package/dist/adapters/syslog-adapter.js +432 -0
  20. package/dist/adapters/syslog-adapter.js.map +1 -0
  21. package/dist/adapters/types.d.ts +135 -0
  22. package/dist/adapters/types.d.ts.map +1 -0
  23. package/dist/adapters/types.js +13 -0
  24. package/dist/adapters/types.js.map +1 -0
  25. package/dist/adapters/wazuh-adapter.d.ts +120 -0
  26. package/dist/adapters/wazuh-adapter.d.ts.map +1 -0
  27. package/dist/adapters/wazuh-adapter.js +266 -0
  28. package/dist/adapters/wazuh-adapter.js.map +1 -0
  29. package/dist/ai/claude-provider.d.ts +66 -0
  30. package/dist/ai/claude-provider.d.ts.map +1 -0
  31. package/dist/ai/claude-provider.js +166 -0
  32. package/dist/ai/claude-provider.js.map +1 -0
  33. package/dist/ai/funnel-router.d.ts +75 -0
  34. package/dist/ai/funnel-router.d.ts.map +1 -0
  35. package/dist/ai/funnel-router.js +173 -0
  36. package/dist/ai/funnel-router.js.map +1 -0
  37. package/dist/ai/index.d.ts +77 -0
  38. package/dist/ai/index.d.ts.map +1 -0
  39. package/dist/ai/index.js +95 -0
  40. package/dist/ai/index.js.map +1 -0
  41. package/dist/ai/ollama-provider.d.ts +73 -0
  42. package/dist/ai/ollama-provider.d.ts.map +1 -0
  43. package/dist/ai/ollama-provider.js +200 -0
  44. package/dist/ai/ollama-provider.js.map +1 -0
  45. package/dist/ai/openai-provider.d.ts +70 -0
  46. package/dist/ai/openai-provider.d.ts.map +1 -0
  47. package/dist/ai/openai-provider.js +175 -0
  48. package/dist/ai/openai-provider.js.map +1 -0
  49. package/dist/ai/prompts/event-classifier.d.ts +25 -0
  50. package/dist/ai/prompts/event-classifier.d.ts.map +1 -0
  51. package/dist/ai/prompts/event-classifier.js +94 -0
  52. package/dist/ai/prompts/event-classifier.js.map +1 -0
  53. package/dist/ai/prompts/index.d.ts +13 -0
  54. package/dist/ai/prompts/index.d.ts.map +1 -0
  55. package/dist/ai/prompts/index.js +13 -0
  56. package/dist/ai/prompts/index.js.map +1 -0
  57. package/dist/ai/prompts/report-generator.d.ts +25 -0
  58. package/dist/ai/prompts/report-generator.d.ts.map +1 -0
  59. package/dist/ai/prompts/report-generator.js +131 -0
  60. package/dist/ai/prompts/report-generator.js.map +1 -0
  61. package/dist/ai/prompts/threat-analyzer.d.ts +26 -0
  62. package/dist/ai/prompts/threat-analyzer.d.ts.map +1 -0
  63. package/dist/ai/prompts/threat-analyzer.js +75 -0
  64. package/dist/ai/prompts/threat-analyzer.js.map +1 -0
  65. package/dist/ai/provider-base.d.ts +100 -0
  66. package/dist/ai/provider-base.d.ts.map +1 -0
  67. package/dist/ai/provider-base.js +166 -0
  68. package/dist/ai/provider-base.js.map +1 -0
  69. package/dist/ai/response-parser.d.ts +36 -0
  70. package/dist/ai/response-parser.d.ts.map +1 -0
  71. package/dist/ai/response-parser.js +195 -0
  72. package/dist/ai/response-parser.js.map +1 -0
  73. package/dist/ai/token-tracker.d.ts +72 -0
  74. package/dist/ai/token-tracker.d.ts.map +1 -0
  75. package/dist/ai/token-tracker.js +145 -0
  76. package/dist/ai/token-tracker.js.map +1 -0
  77. package/dist/ai/types.d.ts +138 -0
  78. package/dist/ai/types.d.ts.map +1 -0
  79. package/dist/ai/types.js +12 -0
  80. package/dist/ai/types.js.map +1 -0
  81. package/dist/cli/index.d.ts +146 -0
  82. package/dist/cli/index.d.ts.map +1 -0
  83. package/dist/cli/index.js +515 -0
  84. package/dist/cli/index.js.map +1 -0
  85. package/dist/cli/prompts.d.ts +58 -0
  86. package/dist/cli/prompts.d.ts.map +1 -0
  87. package/dist/cli/prompts.js +327 -0
  88. package/dist/cli/prompts.js.map +1 -0
  89. package/dist/cli/wizard.d.ts +58 -0
  90. package/dist/cli/wizard.d.ts.map +1 -0
  91. package/dist/cli/wizard.js +200 -0
  92. package/dist/cli/wizard.js.map +1 -0
  93. package/dist/discovery/firewall-checker.d.ts +28 -0
  94. package/dist/discovery/firewall-checker.d.ts.map +1 -0
  95. package/dist/discovery/firewall-checker.js +379 -0
  96. package/dist/discovery/firewall-checker.js.map +1 -0
  97. package/dist/discovery/index.d.ts +23 -0
  98. package/dist/discovery/index.d.ts.map +1 -0
  99. package/dist/discovery/index.js +29 -0
  100. package/dist/discovery/index.js.map +1 -0
  101. package/dist/discovery/network-scanner.d.ts +60 -0
  102. package/dist/discovery/network-scanner.d.ts.map +1 -0
  103. package/dist/discovery/network-scanner.js +640 -0
  104. package/dist/discovery/network-scanner.js.map +1 -0
  105. package/dist/discovery/os-detector.d.ts +24 -0
  106. package/dist/discovery/os-detector.d.ts.map +1 -0
  107. package/dist/discovery/os-detector.js +253 -0
  108. package/dist/discovery/os-detector.js.map +1 -0
  109. package/dist/discovery/osquery-provider.d.ts +127 -0
  110. package/dist/discovery/osquery-provider.d.ts.map +1 -0
  111. package/dist/discovery/osquery-provider.js +214 -0
  112. package/dist/discovery/osquery-provider.js.map +1 -0
  113. package/dist/discovery/risk-scorer.d.ts +66 -0
  114. package/dist/discovery/risk-scorer.d.ts.map +1 -0
  115. package/dist/discovery/risk-scorer.js +294 -0
  116. package/dist/discovery/risk-scorer.js.map +1 -0
  117. package/dist/discovery/security-tools.d.ts +31 -0
  118. package/dist/discovery/security-tools.d.ts.map +1 -0
  119. package/dist/discovery/security-tools.js +346 -0
  120. package/dist/discovery/security-tools.js.map +1 -0
  121. package/dist/discovery/service-detector.d.ts +28 -0
  122. package/dist/discovery/service-detector.d.ts.map +1 -0
  123. package/dist/discovery/service-detector.js +300 -0
  124. package/dist/discovery/service-detector.js.map +1 -0
  125. package/dist/discovery/types.d.ts +502 -0
  126. package/dist/discovery/types.d.ts.map +1 -0
  127. package/dist/discovery/types.js +12 -0
  128. package/dist/discovery/types.js.map +1 -0
  129. package/dist/discovery/user-auditor.d.ts +28 -0
  130. package/dist/discovery/user-auditor.d.ts.map +1 -0
  131. package/dist/discovery/user-auditor.js +385 -0
  132. package/dist/discovery/user-auditor.js.map +1 -0
  133. package/dist/i18n/config.d.ts +45 -0
  134. package/dist/i18n/config.d.ts.map +1 -0
  135. package/dist/i18n/config.js +135 -0
  136. package/dist/i18n/config.js.map +1 -0
  137. package/dist/i18n/index.d.ts +8 -0
  138. package/dist/i18n/index.d.ts.map +1 -0
  139. package/dist/i18n/index.js +8 -0
  140. package/dist/i18n/index.js.map +1 -0
  141. package/dist/index.d.ts +31 -0
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +31 -0
  144. package/dist/index.js.map +1 -0
  145. package/dist/monitor/event-normalizer.d.ts +102 -0
  146. package/dist/monitor/event-normalizer.d.ts.map +1 -0
  147. package/dist/monitor/event-normalizer.js +195 -0
  148. package/dist/monitor/event-normalizer.js.map +1 -0
  149. package/dist/monitor/file-monitor.d.ts +90 -0
  150. package/dist/monitor/file-monitor.d.ts.map +1 -0
  151. package/dist/monitor/file-monitor.js +222 -0
  152. package/dist/monitor/file-monitor.js.map +1 -0
  153. package/dist/monitor/index.d.ts +147 -0
  154. package/dist/monitor/index.d.ts.map +1 -0
  155. package/dist/monitor/index.js +293 -0
  156. package/dist/monitor/index.js.map +1 -0
  157. package/dist/monitor/log-monitor.d.ts +102 -0
  158. package/dist/monitor/log-monitor.d.ts.map +1 -0
  159. package/dist/monitor/log-monitor.js +245 -0
  160. package/dist/monitor/log-monitor.js.map +1 -0
  161. package/dist/monitor/network-monitor.d.ts +103 -0
  162. package/dist/monitor/network-monitor.d.ts.map +1 -0
  163. package/dist/monitor/network-monitor.js +336 -0
  164. package/dist/monitor/network-monitor.js.map +1 -0
  165. package/dist/monitor/process-monitor.d.ts +108 -0
  166. package/dist/monitor/process-monitor.d.ts.map +1 -0
  167. package/dist/monitor/process-monitor.js +245 -0
  168. package/dist/monitor/process-monitor.js.map +1 -0
  169. package/dist/monitor/threat-intel-feeds.d.ts +141 -0
  170. package/dist/monitor/threat-intel-feeds.d.ts.map +1 -0
  171. package/dist/monitor/threat-intel-feeds.js +430 -0
  172. package/dist/monitor/threat-intel-feeds.js.map +1 -0
  173. package/dist/monitor/threat-intel.d.ts +83 -0
  174. package/dist/monitor/threat-intel.d.ts.map +1 -0
  175. package/dist/monitor/threat-intel.js +215 -0
  176. package/dist/monitor/threat-intel.js.map +1 -0
  177. package/dist/monitor/types.d.ts +65 -0
  178. package/dist/monitor/types.d.ts.map +1 -0
  179. package/dist/monitor/types.js +20 -0
  180. package/dist/monitor/types.js.map +1 -0
  181. package/dist/rules/index.d.ts +115 -0
  182. package/dist/rules/index.d.ts.map +1 -0
  183. package/dist/rules/index.js +244 -0
  184. package/dist/rules/index.js.map +1 -0
  185. package/dist/rules/rule-loader.d.ts +54 -0
  186. package/dist/rules/rule-loader.d.ts.map +1 -0
  187. package/dist/rules/rule-loader.js +167 -0
  188. package/dist/rules/rule-loader.js.map +1 -0
  189. package/dist/rules/sigma-matcher.d.ts +40 -0
  190. package/dist/rules/sigma-matcher.d.ts.map +1 -0
  191. package/dist/rules/sigma-matcher.js +447 -0
  192. package/dist/rules/sigma-matcher.js.map +1 -0
  193. package/dist/rules/sigma-parser.d.ts +36 -0
  194. package/dist/rules/sigma-parser.d.ts.map +1 -0
  195. package/dist/rules/sigma-parser.js +180 -0
  196. package/dist/rules/sigma-parser.js.map +1 -0
  197. package/dist/rules/types.d.ts +112 -0
  198. package/dist/rules/types.d.ts.map +1 -0
  199. package/dist/rules/types.js +11 -0
  200. package/dist/rules/types.js.map +1 -0
  201. package/dist/rules/yara-scanner.d.ts +103 -0
  202. package/dist/rules/yara-scanner.d.ts.map +1 -0
  203. package/dist/rules/yara-scanner.js +421 -0
  204. package/dist/rules/yara-scanner.js.map +1 -0
  205. package/dist/scoring/achievements.d.ts +76 -0
  206. package/dist/scoring/achievements.d.ts.map +1 -0
  207. package/dist/scoring/achievements.js +211 -0
  208. package/dist/scoring/achievements.js.map +1 -0
  209. package/dist/scoring/index.d.ts +3 -0
  210. package/dist/scoring/index.d.ts.map +1 -0
  211. package/dist/scoring/index.js +3 -0
  212. package/dist/scoring/index.js.map +1 -0
  213. package/dist/scoring/security-score.d.ts +60 -0
  214. package/dist/scoring/security-score.d.ts.map +1 -0
  215. package/dist/scoring/security-score.js +211 -0
  216. package/dist/scoring/security-score.js.map +1 -0
  217. package/dist/types.d.ts +71 -0
  218. package/dist/types.d.ts.map +1 -0
  219. package/dist/types.js +8 -0
  220. package/dist/types.js.map +1 -0
  221. package/dist/utils/index.d.ts +10 -0
  222. package/dist/utils/index.d.ts.map +1 -0
  223. package/dist/utils/index.js +9 -0
  224. package/dist/utils/index.js.map +1 -0
  225. package/dist/utils/logger.d.ts +38 -0
  226. package/dist/utils/logger.d.ts.map +1 -0
  227. package/dist/utils/logger.js +71 -0
  228. package/dist/utils/logger.js.map +1 -0
  229. package/dist/utils/validation.d.ts +35 -0
  230. package/dist/utils/validation.d.ts.map +1 -0
  231. package/dist/utils/validation.js +56 -0
  232. package/dist/utils/validation.js.map +1 -0
  233. package/package.json +60 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Ollama LLM provider implementation
3
+ * Ollama LLM 供應商實作
4
+ *
5
+ * Communicates with a local Ollama instance via its HTTP API.
6
+ * Uses native fetch (Node 18+) with no external dependencies.
7
+ * 透過 HTTP API 與本地 Ollama 實例通訊。
8
+ * 使用原生 fetch(Node 18+),無需外部相依。
9
+ *
10
+ * @module @panguard-ai/core/ai/ollama-provider
11
+ */
12
+ import type { LLMConfig } from './types.js';
13
+ import { LLMProviderBase } from './provider-base.js';
14
+ /**
15
+ * Ollama LLM provider using the local HTTP API
16
+ * 使用本地 HTTP API 的 Ollama LLM 供應商
17
+ *
18
+ * Connects to a running Ollama instance (default: localhost:11434)
19
+ * and uses the /api/generate endpoint for text generation.
20
+ * 連接到正在執行的 Ollama 實例(預設:localhost:11434),
21
+ * 並使用 /api/generate 端點進行文字生成。
22
+ */
23
+ export declare class OllamaProvider extends LLMProviderBase {
24
+ /** Resolved API endpoint / 解析後的 API 端點 */
25
+ private readonly endpoint;
26
+ /**
27
+ * Create a new OllamaProvider instance
28
+ * 建立新的 OllamaProvider 實例
29
+ *
30
+ * @param config - LLM configuration / LLM 配置
31
+ */
32
+ constructor(config: LLMConfig);
33
+ /**
34
+ * Check if the Ollama instance is reachable and running
35
+ * 檢查 Ollama 實例是否可連接且正在執行
36
+ *
37
+ * Sends a GET request to /api/tags to verify connectivity.
38
+ * 發送 GET 請求到 /api/tags 以驗證連接性。
39
+ *
40
+ * @returns True if Ollama is reachable / Ollama 可連接時回傳 true
41
+ */
42
+ isAvailable(): Promise<boolean>;
43
+ /**
44
+ * Check if the configured model has been pulled in Ollama
45
+ * 檢查配置的模型是否已在 Ollama 中下載
46
+ *
47
+ * @returns True if model is available locally / 模型在本地可用時回傳 true
48
+ */
49
+ isModelPulled(): Promise<boolean>;
50
+ /**
51
+ * Send a prompt to the Ollama /api/generate endpoint
52
+ * 向 Ollama /api/generate 端點發送提示詞
53
+ *
54
+ * @param prompt - The prompt to send / 要發送的提示詞
55
+ * @returns Raw response text / 原始回應文字
56
+ * @throws Error if the request fails or times out / 請求失敗或逾時時拋出錯誤
57
+ */
58
+ protected sendRequest(prompt: string): Promise<string>;
59
+ /**
60
+ * Rough token count estimation (for when Ollama doesn't report counts)
61
+ * 粗略的 Token 計數估算(當 Ollama 不報告計數時使用)
62
+ *
63
+ * Uses a simple heuristic: ~4 characters per token for English,
64
+ * ~2 characters per token for CJK text.
65
+ * 使用簡單啟發式方法:英文約每 4 個字元一個 Token,CJK 文字約每 2 個字元一個 Token。
66
+ *
67
+ * @param text - Text to estimate / 要估算的文字
68
+ * @returns Estimated token count / 估算的 Token 數量
69
+ * @internal
70
+ */
71
+ private estimateTokens;
72
+ }
73
+ //# sourceMappingURL=ollama-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-provider.d.ts","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAgCrD;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD,0CAA0C;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC;;;;;OAKG;gBACS,MAAM,EAAE,SAAS;IAS7B;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA8CrC;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAqBvC;;;;;;;OAOG;cACa,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqE5D;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;CAOvB"}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Ollama LLM provider implementation
3
+ * Ollama LLM 供應商實作
4
+ *
5
+ * Communicates with a local Ollama instance via its HTTP API.
6
+ * Uses native fetch (Node 18+) with no external dependencies.
7
+ * 透過 HTTP API 與本地 Ollama 實例通訊。
8
+ * 使用原生 fetch(Node 18+),無需外部相依。
9
+ *
10
+ * @module @panguard-ai/core/ai/ollama-provider
11
+ */
12
+ import { LLMProviderBase } from './provider-base.js';
13
+ /**
14
+ * Default Ollama API endpoint
15
+ * 預設 Ollama API 端點
16
+ * @internal
17
+ */
18
+ const DEFAULT_ENDPOINT = 'http://localhost:11434';
19
+ /**
20
+ * Ollama LLM provider using the local HTTP API
21
+ * 使用本地 HTTP API 的 Ollama LLM 供應商
22
+ *
23
+ * Connects to a running Ollama instance (default: localhost:11434)
24
+ * and uses the /api/generate endpoint for text generation.
25
+ * 連接到正在執行的 Ollama 實例(預設:localhost:11434),
26
+ * 並使用 /api/generate 端點進行文字生成。
27
+ */
28
+ export class OllamaProvider extends LLMProviderBase {
29
+ /** Resolved API endpoint / 解析後的 API 端點 */
30
+ endpoint;
31
+ /**
32
+ * Create a new OllamaProvider instance
33
+ * 建立新的 OllamaProvider 實例
34
+ *
35
+ * @param config - LLM configuration / LLM 配置
36
+ */
37
+ constructor(config) {
38
+ super(config);
39
+ this.endpoint = (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, '');
40
+ this.logger.info('Ollama provider initialized', {
41
+ endpoint: this.endpoint,
42
+ model: this.model,
43
+ });
44
+ }
45
+ /**
46
+ * Check if the Ollama instance is reachable and running
47
+ * 檢查 Ollama 實例是否可連接且正在執行
48
+ *
49
+ * Sends a GET request to /api/tags to verify connectivity.
50
+ * 發送 GET 請求到 /api/tags 以驗證連接性。
51
+ *
52
+ * @returns True if Ollama is reachable / Ollama 可連接時回傳 true
53
+ */
54
+ async isAvailable() {
55
+ try {
56
+ const controller = new AbortController();
57
+ const timeoutId = setTimeout(() => controller.abort(), 5_000);
58
+ const response = await fetch(`${this.endpoint}/api/tags`, {
59
+ method: 'GET',
60
+ signal: controller.signal,
61
+ });
62
+ clearTimeout(timeoutId);
63
+ if (!response.ok) {
64
+ this.logger.warn('Ollama returned non-OK status', {
65
+ status: response.status,
66
+ });
67
+ return false;
68
+ }
69
+ const data = (await response.json());
70
+ const models = data.models?.map((m) => m.name) ?? [];
71
+ // Check if the configured model is pulled
72
+ // 檢查配置的模型是否已下載
73
+ const modelPulled = models.some((m) => m === this.model || m.startsWith(`${this.model}:`));
74
+ if (!modelPulled && models.length > 0) {
75
+ this.logger.warn('Configured model not found in Ollama', {
76
+ requestedModel: this.model,
77
+ availableModels: models,
78
+ hint: `Run: ollama pull ${this.model}`,
79
+ });
80
+ }
81
+ this.logger.debug('Ollama available', {
82
+ availableModels: models.length,
83
+ modelPulled,
84
+ });
85
+ return true;
86
+ }
87
+ catch (error) {
88
+ this.logger.debug('Ollama not available', {
89
+ error: error instanceof Error ? error.message : String(error),
90
+ });
91
+ return false;
92
+ }
93
+ }
94
+ /**
95
+ * Check if the configured model has been pulled in Ollama
96
+ * 檢查配置的模型是否已在 Ollama 中下載
97
+ *
98
+ * @returns True if model is available locally / 模型在本地可用時回傳 true
99
+ */
100
+ async isModelPulled() {
101
+ try {
102
+ const controller = new AbortController();
103
+ const timeoutId = setTimeout(() => controller.abort(), 5_000);
104
+ const response = await fetch(`${this.endpoint}/api/tags`, {
105
+ method: 'GET',
106
+ signal: controller.signal,
107
+ });
108
+ clearTimeout(timeoutId);
109
+ if (!response.ok)
110
+ return false;
111
+ const data = (await response.json());
112
+ const models = data.models?.map((m) => m.name) ?? [];
113
+ return models.some((m) => m === this.model || m.startsWith(`${this.model}:`));
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ /**
120
+ * Send a prompt to the Ollama /api/generate endpoint
121
+ * 向 Ollama /api/generate 端點發送提示詞
122
+ *
123
+ * @param prompt - The prompt to send / 要發送的提示詞
124
+ * @returns Raw response text / 原始回應文字
125
+ * @throws Error if the request fails or times out / 請求失敗或逾時時拋出錯誤
126
+ */
127
+ async sendRequest(prompt) {
128
+ const controller = new AbortController();
129
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
130
+ try {
131
+ const response = await fetch(`${this.endpoint}/api/generate`, {
132
+ method: 'POST',
133
+ headers: { 'Content-Type': 'application/json' },
134
+ body: JSON.stringify({
135
+ model: this.model,
136
+ prompt,
137
+ stream: false,
138
+ options: {
139
+ temperature: this.config.temperature,
140
+ num_predict: this.config.maxTokens,
141
+ },
142
+ }),
143
+ signal: controller.signal,
144
+ });
145
+ clearTimeout(timeoutId);
146
+ if (!response.ok) {
147
+ const errorText = await response.text().catch(() => 'Unknown error');
148
+ throw new Error(`Ollama API error (${response.status}): ${errorText}`);
149
+ }
150
+ const data = (await response.json());
151
+ // Track token usage from Ollama response metrics
152
+ // 從 Ollama 回應指標追蹤 Token 使用量
153
+ const promptTokens = data.prompt_eval_count ?? this.estimateTokens(prompt);
154
+ const completionTokens = data.eval_count ?? this.estimateTokens(data.response);
155
+ this.tokenTracker.track(promptTokens, completionTokens);
156
+ this.logger.debug('Ollama request completed', {
157
+ model: data.model,
158
+ done: data.done,
159
+ promptTokens,
160
+ completionTokens,
161
+ });
162
+ return data.response;
163
+ }
164
+ catch (error) {
165
+ clearTimeout(timeoutId);
166
+ if (error instanceof Error && error.name === 'AbortError') {
167
+ throw new Error(`Ollama request timed out after ${this.config.timeout}ms. ` +
168
+ `Ensure Ollama is running at ${this.endpoint} and the model "${this.model}" is available.`);
169
+ }
170
+ // Handle connection refused specifically
171
+ // 特別處理連線被拒絕的情況
172
+ if (error instanceof TypeError &&
173
+ (error.message.includes('fetch failed') || error.message.includes('ECONNREFUSED'))) {
174
+ throw new Error(`Cannot connect to Ollama at ${this.endpoint}. ` +
175
+ `Ensure Ollama is installed and running: https://ollama.ai`);
176
+ }
177
+ throw error;
178
+ }
179
+ }
180
+ /**
181
+ * Rough token count estimation (for when Ollama doesn't report counts)
182
+ * 粗略的 Token 計數估算(當 Ollama 不報告計數時使用)
183
+ *
184
+ * Uses a simple heuristic: ~4 characters per token for English,
185
+ * ~2 characters per token for CJK text.
186
+ * 使用簡單啟發式方法:英文約每 4 個字元一個 Token,CJK 文字約每 2 個字元一個 Token。
187
+ *
188
+ * @param text - Text to estimate / 要估算的文字
189
+ * @returns Estimated token count / 估算的 Token 數量
190
+ * @internal
191
+ */
192
+ estimateTokens(text) {
193
+ // Count CJK characters
194
+ // 計算 CJK 字元數
195
+ const cjkCount = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) ?? []).length;
196
+ const nonCjkLength = text.length - cjkCount;
197
+ return Math.ceil(nonCjkLength / 4) + Math.ceil(cjkCount / 1.5);
198
+ }
199
+ }
200
+ //# sourceMappingURL=ollama-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-provider.js","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * OpenAI LLM provider implementation
3
+ * OpenAI LLM 供應商實作
4
+ *
5
+ * Uses the openai package via dynamic import to avoid hard dependencies.
6
+ * Users must install the SDK separately.
7
+ * 透過動態匯入使用 openai 套件以避免硬性相依。
8
+ * 使用者必須另外安裝 SDK。
9
+ *
10
+ * @module @panguard-ai/core/ai/openai-provider
11
+ */
12
+ import type { LLMConfig } from './types.js';
13
+ import { LLMProviderBase } from './provider-base.js';
14
+ /**
15
+ * OpenAI LLM provider
16
+ * OpenAI LLM 供應商
17
+ *
18
+ * Requires the openai package to be installed separately.
19
+ * The SDK is loaded via dynamic import() on first use.
20
+ * 需要另外安裝 openai 套件。
21
+ * SDK 在首次使用時透過動態 import() 載入。
22
+ */
23
+ export declare class OpenAIProvider extends LLMProviderBase {
24
+ /**
25
+ * Cached OpenAI client instance / 快取的 OpenAI 客戶端實例
26
+ * @internal
27
+ */
28
+ private client;
29
+ /**
30
+ * Create a new OpenAIProvider instance
31
+ * 建立新的 OpenAIProvider 實例
32
+ *
33
+ * @param config - LLM configuration (apiKey required) / LLM 配置(需要 apiKey)
34
+ */
35
+ constructor(config: LLMConfig);
36
+ /**
37
+ * Lazily initialize the OpenAI SDK client via dynamic import
38
+ * 透過動態匯入延遲初始化 OpenAI SDK 客戶端
39
+ *
40
+ * @returns Initialized OpenAI client / 初始化的 OpenAI 客戶端
41
+ * @throws Error if the SDK is not installed or API key is missing
42
+ * 如果 SDK 未安裝或 API 金鑰遺失則拋出錯誤
43
+ * @internal
44
+ */
45
+ private getClient;
46
+ /**
47
+ * Check if the OpenAI API is available and the API key is valid
48
+ * 檢查 OpenAI API 是否可用且 API 金鑰有效
49
+ *
50
+ * Attempts to create a minimal chat completion to verify connectivity.
51
+ * 嘗試建立最小聊天完成以驗證連接性。
52
+ *
53
+ * @returns True if OpenAI API is reachable / OpenAI API 可連接時回傳 true
54
+ */
55
+ isAvailable(): Promise<boolean>;
56
+ /**
57
+ * Send a prompt to the OpenAI Chat Completions API
58
+ * 向 OpenAI Chat Completions API 發送提示詞
59
+ *
60
+ * Uses a system message to establish the security analyst role,
61
+ * followed by the user prompt.
62
+ * 使用系統訊息建立安全分析師角色,接著是使用者提示詞。
63
+ *
64
+ * @param prompt - The prompt to send / 要發送的提示詞
65
+ * @returns Raw response text / 原始回應文字
66
+ * @throws Error if the API call fails / API 呼叫失敗時拋出錯誤
67
+ */
68
+ protected sendRequest(prompt: string): Promise<string>;
69
+ }
70
+ //# sourceMappingURL=openai-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAyCrD;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAA6B;IAE3C;;;;;OAKG;gBACS,MAAM,EAAE,SAAS;IAK7B;;;;;;;;OAQG;YACW,SAAS;IAiCvB;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA4BrC;;;;;;;;;;;OAWG;cACa,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA+D7D"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * OpenAI LLM provider implementation
3
+ * OpenAI LLM 供應商實作
4
+ *
5
+ * Uses the openai package via dynamic import to avoid hard dependencies.
6
+ * Users must install the SDK separately.
7
+ * 透過動態匯入使用 openai 套件以避免硬性相依。
8
+ * 使用者必須另外安裝 SDK。
9
+ *
10
+ * @module @panguard-ai/core/ai/openai-provider
11
+ */
12
+ import { LLMProviderBase } from './provider-base.js';
13
+ /**
14
+ * OpenAI LLM provider
15
+ * OpenAI LLM 供應商
16
+ *
17
+ * Requires the openai package to be installed separately.
18
+ * The SDK is loaded via dynamic import() on first use.
19
+ * 需要另外安裝 openai 套件。
20
+ * SDK 在首次使用時透過動態 import() 載入。
21
+ */
22
+ export class OpenAIProvider extends LLMProviderBase {
23
+ /**
24
+ * Cached OpenAI client instance / 快取的 OpenAI 客戶端實例
25
+ * @internal
26
+ */
27
+ client = null;
28
+ /**
29
+ * Create a new OpenAIProvider instance
30
+ * 建立新的 OpenAIProvider 實例
31
+ *
32
+ * @param config - LLM configuration (apiKey required) / LLM 配置(需要 apiKey)
33
+ */
34
+ constructor(config) {
35
+ super(config);
36
+ this.logger.info('OpenAI provider initialized', { model: this.model });
37
+ }
38
+ /**
39
+ * Lazily initialize the OpenAI SDK client via dynamic import
40
+ * 透過動態匯入延遲初始化 OpenAI SDK 客戶端
41
+ *
42
+ * @returns Initialized OpenAI client / 初始化的 OpenAI 客戶端
43
+ * @throws Error if the SDK is not installed or API key is missing
44
+ * 如果 SDK 未安裝或 API 金鑰遺失則拋出錯誤
45
+ * @internal
46
+ */
47
+ async getClient() {
48
+ if (this.client) {
49
+ return this.client;
50
+ }
51
+ if (!this.config.apiKey) {
52
+ throw new Error('OpenAI API key is required. Set the apiKey field in LLMConfig or the OPENAI_API_KEY environment variable.');
53
+ }
54
+ let OpenAI;
55
+ try {
56
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
57
+ const module = await import('openai');
58
+ OpenAI = (module['default'] ?? module);
59
+ }
60
+ catch (error) {
61
+ const message = error instanceof Error && error.message.includes('Cannot find')
62
+ ? 'Install openai package to use OpenAI provider: npm install openai'
63
+ : `Failed to load openai package: ${error instanceof Error ? error.message : String(error)}. ` +
64
+ 'Install it with: npm install openai';
65
+ throw new Error(message);
66
+ }
67
+ this.client = new OpenAI({
68
+ apiKey: this.config.apiKey,
69
+ timeout: this.config.timeout,
70
+ });
71
+ return this.client;
72
+ }
73
+ /**
74
+ * Check if the OpenAI API is available and the API key is valid
75
+ * 檢查 OpenAI API 是否可用且 API 金鑰有效
76
+ *
77
+ * Attempts to create a minimal chat completion to verify connectivity.
78
+ * 嘗試建立最小聊天完成以驗證連接性。
79
+ *
80
+ * @returns True if OpenAI API is reachable / OpenAI API 可連接時回傳 true
81
+ */
82
+ async isAvailable() {
83
+ try {
84
+ if (!this.config.apiKey) {
85
+ this.logger.debug('OpenAI provider: no API key configured');
86
+ return false;
87
+ }
88
+ const client = await this.getClient();
89
+ // Send a minimal test request
90
+ // 發送最小測試請求
91
+ const response = await client.chat.completions.create({
92
+ model: this.model,
93
+ messages: [{ role: 'user', content: 'Reply with "ok".' }],
94
+ max_tokens: 10,
95
+ });
96
+ const isOk = response.choices.length > 0;
97
+ this.logger.debug('OpenAI availability check', { available: isOk });
98
+ return isOk;
99
+ }
100
+ catch (error) {
101
+ this.logger.debug('OpenAI not available', {
102
+ error: error instanceof Error ? error.message : String(error),
103
+ });
104
+ return false;
105
+ }
106
+ }
107
+ /**
108
+ * Send a prompt to the OpenAI Chat Completions API
109
+ * 向 OpenAI Chat Completions API 發送提示詞
110
+ *
111
+ * Uses a system message to establish the security analyst role,
112
+ * followed by the user prompt.
113
+ * 使用系統訊息建立安全分析師角色,接著是使用者提示詞。
114
+ *
115
+ * @param prompt - The prompt to send / 要發送的提示詞
116
+ * @returns Raw response text / 原始回應文字
117
+ * @throws Error if the API call fails / API 呼叫失敗時拋出錯誤
118
+ */
119
+ async sendRequest(prompt) {
120
+ const client = await this.getClient();
121
+ const systemMessage = this.config.lang === 'zh-TW'
122
+ ? '你是一位專業的資安分析師,專精於威脅偵測、事件分析和安全報告撰寫。請以繁體中文回應。'
123
+ : 'You are a professional cybersecurity analyst specializing in threat detection, incident analysis, and security report writing.';
124
+ try {
125
+ const response = await client.chat.completions.create({
126
+ model: this.model,
127
+ messages: [
128
+ { role: 'system', content: systemMessage },
129
+ { role: 'user', content: prompt },
130
+ ],
131
+ temperature: this.config.temperature,
132
+ max_tokens: this.config.maxTokens,
133
+ });
134
+ // Track token usage from API response
135
+ // 從 API 回應追蹤 Token 使用量
136
+ if (response.usage) {
137
+ this.tokenTracker.track(response.usage.prompt_tokens, response.usage.completion_tokens);
138
+ }
139
+ // Extract the assistant's message content
140
+ // 提取助手的訊息內容
141
+ const choice = response.choices[0];
142
+ const content = choice?.message?.content ?? '';
143
+ this.logger.debug('OpenAI request completed', {
144
+ model: this.model,
145
+ finishReason: choice?.finish_reason,
146
+ promptTokens: response.usage?.prompt_tokens,
147
+ completionTokens: response.usage?.completion_tokens,
148
+ });
149
+ if (!content) {
150
+ throw new Error('OpenAI returned an empty response');
151
+ }
152
+ return content;
153
+ }
154
+ catch (error) {
155
+ // Provide more specific error messages for common failures
156
+ // 為常見失敗提供更具體的錯誤訊息
157
+ if (error instanceof Error) {
158
+ if (error.message.includes('401') || error.message.includes('Incorrect API key')) {
159
+ throw new Error('OpenAI API authentication failed. Check your API key.');
160
+ }
161
+ if (error.message.includes('429') || error.message.includes('Rate limit')) {
162
+ throw new Error('OpenAI API rate limit exceeded. Please wait and try again.');
163
+ }
164
+ if (error.message.includes('timeout') || error.message.includes('ETIMEDOUT')) {
165
+ throw new Error(`OpenAI API request timed out after ${this.config.timeout}ms.`);
166
+ }
167
+ if (error.message.includes('model_not_found') || error.message.includes('does not exist')) {
168
+ throw new Error(`OpenAI model "${this.model}" not found. Check the model name.`);
169
+ }
170
+ }
171
+ throw error;
172
+ }
173
+ }
174
+ }
175
+ //# sourceMappingURL=openai-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Event classification prompt templates
3
+ * 事件分類提示詞範本
4
+ *
5
+ * Generates prompts for classifying security events using
6
+ * the MITRE ATT&CK framework. Supports bilingual output.
7
+ * 產生使用 MITRE ATT&CK 框架分類安全事件的提示詞。支援雙語輸出。
8
+ *
9
+ * @module @panguard-ai/core/ai/prompts/event-classifier
10
+ */
11
+ import type { Language, SecurityEvent } from '../../types.js';
12
+ /**
13
+ * Generate an event classification prompt for the given security event
14
+ * 為指定的安全事件產生事件分類提示詞
15
+ *
16
+ * The prompt instructs the LLM to classify the event according to
17
+ * MITRE ATT&CK framework and return structured JSON output.
18
+ * 提示詞指示 LLM 根據 MITRE ATT&CK 框架分類事件並回傳結構化 JSON 輸出。
19
+ *
20
+ * @param event - The security event to classify / 要分類的安全事件
21
+ * @param lang - Output language / 輸出語言
22
+ * @returns Formatted prompt string / 格式化的提示詞字串
23
+ */
24
+ export declare function getEventClassifierPrompt(event: SecurityEvent, lang: Language): string;
25
+ //# sourceMappingURL=event-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-classifier.d.ts","sourceRoot":"","sources":["../../../src/ai/prompts/event-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAwB9D;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAuDrF"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Event classification prompt templates
3
+ * 事件分類提示詞範本
4
+ *
5
+ * Generates prompts for classifying security events using
6
+ * the MITRE ATT&CK framework. Supports bilingual output.
7
+ * 產生使用 MITRE ATT&CK 框架分類安全事件的提示詞。支援雙語輸出。
8
+ *
9
+ * @module @panguard-ai/core/ai/prompts/event-classifier
10
+ */
11
+ /**
12
+ * MITRE ATT&CK tactic categories for reference in prompts
13
+ * MITRE ATT&CK 戰術分類(供提示詞參考)
14
+ * @internal
15
+ */
16
+ const MITRE_TACTICS = [
17
+ 'Reconnaissance',
18
+ 'Resource Development',
19
+ 'Initial Access',
20
+ 'Execution',
21
+ 'Persistence',
22
+ 'Privilege Escalation',
23
+ 'Defense Evasion',
24
+ 'Credential Access',
25
+ 'Discovery',
26
+ 'Lateral Movement',
27
+ 'Collection',
28
+ 'Command and Control',
29
+ 'Exfiltration',
30
+ 'Impact',
31
+ ];
32
+ /**
33
+ * Generate an event classification prompt for the given security event
34
+ * 為指定的安全事件產生事件分類提示詞
35
+ *
36
+ * The prompt instructs the LLM to classify the event according to
37
+ * MITRE ATT&CK framework and return structured JSON output.
38
+ * 提示詞指示 LLM 根據 MITRE ATT&CK 框架分類事件並回傳結構化 JSON 輸出。
39
+ *
40
+ * @param event - The security event to classify / 要分類的安全事件
41
+ * @param lang - Output language / 輸出語言
42
+ * @returns Formatted prompt string / 格式化的提示詞字串
43
+ */
44
+ export function getEventClassifierPrompt(event, lang) {
45
+ const eventData = JSON.stringify({
46
+ id: event.id,
47
+ timestamp: event.timestamp instanceof Date ? event.timestamp.toISOString() : event.timestamp,
48
+ source: event.source,
49
+ severity: event.severity,
50
+ category: event.category,
51
+ description: event.description,
52
+ host: event.host,
53
+ metadata: event.metadata,
54
+ }, null, 2);
55
+ if (lang === 'zh-TW') {
56
+ return `你是一位專業的資安分析師。請根據 MITRE ATT&CK 框架分析以下安全事件。
57
+
58
+ 安全事件資料:
59
+ ${eventData}
60
+
61
+ 可用的 MITRE ATT&CK 戰術分類:
62
+ ${MITRE_TACTICS.join(', ')}
63
+
64
+ 請以 JSON 格式回應,包含以下欄位:
65
+ {
66
+ "category": "MITRE ATT&CK 戰術分類(從上方清單中選擇)",
67
+ "technique": "MITRE ATT&CK 技術 ID(例如 T1059、T1548)",
68
+ "severity": "嚴重等級:info、low、medium、high 或 critical",
69
+ "confidence": "信心分數,0 到 1 之間的數字",
70
+ "description": "此分類的簡短說明"
71
+ }
72
+
73
+ 只回傳 JSON,不要包含其他文字。`;
74
+ }
75
+ return `You are a professional cybersecurity analyst. Analyze the following security event according to the MITRE ATT&CK framework.
76
+
77
+ Security Event Data:
78
+ ${eventData}
79
+
80
+ Available MITRE ATT&CK Tactic Categories:
81
+ ${MITRE_TACTICS.join(', ')}
82
+
83
+ Respond in JSON format with the following fields:
84
+ {
85
+ "category": "MITRE ATT&CK tactic category (choose from the list above)",
86
+ "technique": "MITRE ATT&CK technique ID (e.g., T1059, T1548)",
87
+ "severity": "severity level: info, low, medium, high, or critical",
88
+ "confidence": "confidence score, a number between 0 and 1",
89
+ "description": "brief explanation of this classification"
90
+ }
91
+
92
+ Return only JSON, no additional text.`;
93
+ }
94
+ //# sourceMappingURL=event-classifier.js.map