@timmeck/brain-core 2.36.11 → 2.36.14

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 (127) hide show
  1. package/dist/cross-brain/__tests__/borg-sync-engine.test.d.ts +1 -0
  2. package/dist/cross-brain/__tests__/borg-sync-engine.test.js +240 -0
  3. package/dist/cross-brain/__tests__/borg-sync-engine.test.js.map +1 -0
  4. package/dist/cross-brain/borg-sync-engine.d.ts +62 -0
  5. package/dist/cross-brain/borg-sync-engine.js +215 -0
  6. package/dist/cross-brain/borg-sync-engine.js.map +1 -0
  7. package/dist/cross-brain/borg-types.d.ts +37 -0
  8. package/dist/cross-brain/borg-types.js +9 -0
  9. package/dist/cross-brain/borg-types.js.map +1 -0
  10. package/dist/embeddings/engine.js +2 -1
  11. package/dist/embeddings/engine.js.map +1 -1
  12. package/dist/index.d.ts +18 -1
  13. package/dist/index.js +14 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/llm/__tests__/anthropic-provider.test.d.ts +1 -0
  16. package/dist/llm/__tests__/anthropic-provider.test.js +121 -0
  17. package/dist/llm/__tests__/anthropic-provider.test.js.map +1 -0
  18. package/dist/llm/__tests__/llm-service.test.js +181 -40
  19. package/dist/llm/__tests__/llm-service.test.js.map +1 -1
  20. package/dist/llm/__tests__/ollama-embedding.test.d.ts +1 -0
  21. package/dist/llm/__tests__/ollama-embedding.test.js +128 -0
  22. package/dist/llm/__tests__/ollama-embedding.test.js.map +1 -0
  23. package/dist/llm/__tests__/ollama-provider.test.d.ts +1 -0
  24. package/dist/llm/__tests__/ollama-provider.test.js +213 -0
  25. package/dist/llm/__tests__/ollama-provider.test.js.map +1 -0
  26. package/dist/llm/__tests__/provider.test.d.ts +1 -0
  27. package/dist/llm/__tests__/provider.test.js +126 -0
  28. package/dist/llm/__tests__/provider.test.js.map +1 -0
  29. package/dist/llm/anthropic-provider.d.ts +41 -0
  30. package/dist/llm/anthropic-provider.js +86 -0
  31. package/dist/llm/anthropic-provider.js.map +1 -0
  32. package/dist/llm/index.d.ts +9 -1
  33. package/dist/llm/index.js +4 -0
  34. package/dist/llm/index.js.map +1 -1
  35. package/dist/llm/llm-service.d.ts +55 -7
  36. package/dist/llm/llm-service.js +184 -82
  37. package/dist/llm/llm-service.js.map +1 -1
  38. package/dist/llm/ollama-embedding.d.ts +46 -0
  39. package/dist/llm/ollama-embedding.js +93 -0
  40. package/dist/llm/ollama-embedding.js.map +1 -0
  41. package/dist/llm/ollama-provider.d.ts +80 -0
  42. package/dist/llm/ollama-provider.js +178 -0
  43. package/dist/llm/ollama-provider.js.map +1 -0
  44. package/dist/llm/provider.d.ts +120 -0
  45. package/dist/llm/provider.js +104 -0
  46. package/dist/llm/provider.js.map +1 -0
  47. package/dist/missions/mission-engine.d.ts +4 -0
  48. package/dist/missions/mission-engine.js +30 -8
  49. package/dist/missions/mission-engine.js.map +1 -1
  50. package/dist/notifications/__tests__/notification-service.test.d.ts +1 -0
  51. package/dist/notifications/__tests__/notification-service.test.js +176 -0
  52. package/dist/notifications/__tests__/notification-service.test.js.map +1 -0
  53. package/dist/notifications/discord-provider.d.ts +30 -0
  54. package/dist/notifications/discord-provider.js +89 -0
  55. package/dist/notifications/discord-provider.js.map +1 -0
  56. package/dist/notifications/email-provider.d.ts +41 -0
  57. package/dist/notifications/email-provider.js +101 -0
  58. package/dist/notifications/email-provider.js.map +1 -0
  59. package/dist/notifications/index.d.ts +8 -0
  60. package/dist/notifications/index.js +5 -0
  61. package/dist/notifications/index.js.map +1 -0
  62. package/dist/notifications/notification-provider.d.ts +75 -0
  63. package/dist/notifications/notification-provider.js +47 -0
  64. package/dist/notifications/notification-provider.js.map +1 -0
  65. package/dist/notifications/notification-service.d.ts +85 -0
  66. package/dist/notifications/notification-service.js +184 -0
  67. package/dist/notifications/notification-service.js.map +1 -0
  68. package/dist/notifications/telegram-provider.d.ts +30 -0
  69. package/dist/notifications/telegram-provider.js +78 -0
  70. package/dist/notifications/telegram-provider.js.map +1 -0
  71. package/dist/plugin/__tests__/plugin-registry.test.d.ts +1 -0
  72. package/dist/plugin/__tests__/plugin-registry.test.js +166 -0
  73. package/dist/plugin/__tests__/plugin-registry.test.js.map +1 -0
  74. package/dist/plugin/plugin-registry.d.ts +38 -0
  75. package/dist/plugin/plugin-registry.js +185 -0
  76. package/dist/plugin/plugin-registry.js.map +1 -0
  77. package/dist/plugin/types.d.ts +59 -0
  78. package/dist/plugin/types.js +2 -0
  79. package/dist/plugin/types.js.map +1 -0
  80. package/dist/research/adapters/__tests__/web-adapters.test.d.ts +1 -0
  81. package/dist/research/adapters/__tests__/web-adapters.test.js +106 -0
  82. package/dist/research/adapters/__tests__/web-adapters.test.js.map +1 -0
  83. package/dist/research/adapters/firecrawl-adapter.d.ts +57 -0
  84. package/dist/research/adapters/firecrawl-adapter.js +137 -0
  85. package/dist/research/adapters/firecrawl-adapter.js.map +1 -0
  86. package/dist/research/adapters/index.d.ts +3 -0
  87. package/dist/research/adapters/index.js +2 -0
  88. package/dist/research/adapters/index.js.map +1 -1
  89. package/dist/research/adapters/playwright-adapter.d.ts +54 -0
  90. package/dist/research/adapters/playwright-adapter.js +130 -0
  91. package/dist/research/adapters/playwright-adapter.js.map +1 -0
  92. package/dist/research/research-orchestrator.d.ts +3 -0
  93. package/dist/research/research-orchestrator.js +19 -1
  94. package/dist/research/research-orchestrator.js.map +1 -1
  95. package/dist/self-modification/self-modification-engine.js +28 -4
  96. package/dist/self-modification/self-modification-engine.js.map +1 -1
  97. package/dist/techradar/__tests__/techradar-engine.test.d.ts +1 -0
  98. package/dist/techradar/__tests__/techradar-engine.test.js +246 -0
  99. package/dist/techradar/__tests__/techradar-engine.test.js.map +1 -0
  100. package/dist/techradar/daily-digest.d.ts +18 -0
  101. package/dist/techradar/daily-digest.js +100 -0
  102. package/dist/techradar/daily-digest.js.map +1 -0
  103. package/dist/techradar/index.d.ts +5 -0
  104. package/dist/techradar/index.js +5 -0
  105. package/dist/techradar/index.js.map +1 -0
  106. package/dist/techradar/relevance-scorer.d.ts +29 -0
  107. package/dist/techradar/relevance-scorer.js +139 -0
  108. package/dist/techradar/relevance-scorer.js.map +1 -0
  109. package/dist/techradar/repo-watcher.d.ts +24 -0
  110. package/dist/techradar/repo-watcher.js +87 -0
  111. package/dist/techradar/repo-watcher.js.map +1 -0
  112. package/dist/techradar/techradar-engine.d.ts +69 -0
  113. package/dist/techradar/techradar-engine.js +382 -0
  114. package/dist/techradar/techradar-engine.js.map +1 -0
  115. package/dist/techradar/types.d.ts +87 -0
  116. package/dist/techradar/types.js +5 -0
  117. package/dist/techradar/types.js.map +1 -0
  118. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +1 -0
  119. package/dist/watchdog/__tests__/watchdog-service.test.js +113 -0
  120. package/dist/watchdog/__tests__/watchdog-service.test.js.map +1 -0
  121. package/dist/watchdog/watchdog-service.d.ts +60 -0
  122. package/dist/watchdog/watchdog-service.js +275 -0
  123. package/dist/watchdog/watchdog-service.js.map +1 -0
  124. package/dist/watchdog/windows-service.d.ts +39 -0
  125. package/dist/watchdog/windows-service.js +179 -0
  126. package/dist/watchdog/windows-service.js.map +1 -0
  127. package/package.json +20 -2
@@ -0,0 +1,106 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ vi.mock('../../../utils/logger.js', () => ({
3
+ getLogger: () => ({
4
+ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(),
5
+ }),
6
+ }));
7
+ import { PlaywrightAdapter } from '../playwright-adapter.js';
8
+ import { FirecrawlAdapter } from '../firecrawl-adapter.js';
9
+ describe('PlaywrightAdapter', () => {
10
+ it('has correct name', () => {
11
+ const adapter = new PlaywrightAdapter();
12
+ expect(adapter.name).toBe('playwright');
13
+ });
14
+ it('isEnabled returns true (optimistic)', () => {
15
+ const adapter = new PlaywrightAdapter();
16
+ expect(adapter.isEnabled()).toBe(true);
17
+ });
18
+ it('scout returns empty array', async () => {
19
+ const adapter = new PlaywrightAdapter();
20
+ const discoveries = await adapter.scout();
21
+ expect(discoveries).toEqual([]);
22
+ });
23
+ it('checkAvailable returns false when playwright not installed', async () => {
24
+ const adapter = new PlaywrightAdapter();
25
+ // In test environment, playwright chromium is likely not installed
26
+ const available = await adapter.checkAvailable();
27
+ expect(typeof available).toBe('boolean');
28
+ });
29
+ it('extract returns null when playwright unavailable', async () => {
30
+ const adapter = new PlaywrightAdapter();
31
+ // Force unavailable
32
+ adapter.available = false;
33
+ const result = await adapter.extract('https://example.com');
34
+ expect(result).toBeNull();
35
+ });
36
+ it('shutdown is safe when no browser', async () => {
37
+ const adapter = new PlaywrightAdapter();
38
+ await expect(adapter.shutdown()).resolves.not.toThrow();
39
+ });
40
+ });
41
+ describe('FirecrawlAdapter', () => {
42
+ it('has correct name', () => {
43
+ const adapter = new FirecrawlAdapter();
44
+ expect(adapter.name).toBe('firecrawl');
45
+ });
46
+ it('isEnabled returns false without API key', () => {
47
+ const adapter = new FirecrawlAdapter({ apiKey: undefined });
48
+ expect(adapter.isEnabled()).toBe(false);
49
+ });
50
+ it('isEnabled returns true with API key', () => {
51
+ const adapter = new FirecrawlAdapter({ apiKey: 'fc-test' });
52
+ expect(adapter.isEnabled()).toBe(true);
53
+ });
54
+ it('scout returns empty array', async () => {
55
+ const adapter = new FirecrawlAdapter();
56
+ const discoveries = await adapter.scout();
57
+ expect(discoveries).toEqual([]);
58
+ });
59
+ it('scrape returns null when not enabled', async () => {
60
+ const adapter = new FirecrawlAdapter({ apiKey: undefined });
61
+ const result = await adapter.scrape('https://example.com');
62
+ expect(result).toBeNull();
63
+ });
64
+ it('crawl returns empty when not enabled', async () => {
65
+ const adapter = new FirecrawlAdapter({ apiKey: undefined });
66
+ const result = await adapter.crawl('https://example.com');
67
+ expect(result).toEqual([]);
68
+ });
69
+ it('scrape calls API with correct URL', async () => {
70
+ const mockFetch = vi.fn().mockResolvedValue({
71
+ ok: true,
72
+ json: async () => ({
73
+ success: true,
74
+ data: {
75
+ markdown: '# Test\n\nContent here',
76
+ metadata: { title: 'Test Page', description: 'A test page' },
77
+ },
78
+ }),
79
+ });
80
+ vi.stubGlobal('fetch', mockFetch);
81
+ const adapter = new FirecrawlAdapter({ apiKey: 'fc-test' });
82
+ const result = await adapter.scrape('https://example.com');
83
+ expect(mockFetch).toHaveBeenCalledWith('https://api.firecrawl.dev/v1/scrape', expect.objectContaining({
84
+ method: 'POST',
85
+ headers: expect.objectContaining({
86
+ 'Authorization': 'Bearer fc-test',
87
+ }),
88
+ }));
89
+ expect(result).not.toBeNull();
90
+ expect(result.title).toBe('Test Page');
91
+ expect(result.markdown).toContain('# Test');
92
+ vi.unstubAllGlobals();
93
+ });
94
+ it('scrape handles API errors gracefully', async () => {
95
+ const mockFetch = vi.fn().mockResolvedValue({
96
+ ok: false,
97
+ status: 500,
98
+ });
99
+ vi.stubGlobal('fetch', mockFetch);
100
+ const adapter = new FirecrawlAdapter({ apiKey: 'fc-test' });
101
+ const result = await adapter.scrape('https://example.com');
102
+ expect(result).toBeNull();
103
+ vi.unstubAllGlobals();
104
+ });
105
+ });
106
+ //# sourceMappingURL=web-adapters.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-adapters.test.js","sourceRoot":"","sources":["../../../../src/research/adapters/__tests__/web-adapters.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Firecrawl Adapter — Cloud-based LLM-optimized web scraping
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * 1. Account erstellen: https://firecrawl.dev
9
+ * 2. API Key holen
10
+ * 3. In .env:
11
+ * FIRECRAWL_API_KEY=fc-...
12
+ *
13
+ * Wann nutzen?
14
+ * → Bulk Crawling (ganze Websites)
15
+ * → Wenn LLM-ready Markdown gebraucht wird
16
+ * → Wenn lokaler Playwright zu langsam ist
17
+ *
18
+ * Fallback-Strategie:
19
+ * 1. JinaReader (schnell, kostenlos, kein JS)
20
+ * 2. PlaywrightAdapter (lokal, JS-Rendering)
21
+ * 3. FirecrawlAdapter (Cloud, bezahlt, beste Qualität)
22
+ * ═══════════════════════════════════════════════════════════════
23
+ */
24
+ import type { ScoutAdapter, ScoutDiscovery } from '../data-scout.js';
25
+ export interface FirecrawlConfig {
26
+ apiKey?: string;
27
+ baseUrl?: string;
28
+ }
29
+ export declare class FirecrawlAdapter implements ScoutAdapter {
30
+ readonly name = "firecrawl";
31
+ private readonly apiKey;
32
+ private readonly baseUrl;
33
+ constructor(config?: FirecrawlConfig);
34
+ isEnabled(): boolean;
35
+ scout(): Promise<ScoutDiscovery[]>;
36
+ /**
37
+ * Scrape a single URL and return LLM-ready markdown content.
38
+ */
39
+ scrape(url: string): Promise<{
40
+ title: string;
41
+ content: string;
42
+ description: string;
43
+ markdown: string;
44
+ } | null>;
45
+ /**
46
+ * Crawl a website starting from a URL.
47
+ * Returns markdown for multiple pages.
48
+ */
49
+ crawl(url: string, options?: {
50
+ limit?: number;
51
+ maxDepth?: number;
52
+ }): Promise<Array<{
53
+ url: string;
54
+ title: string;
55
+ markdown: string;
56
+ }>>;
57
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Firecrawl Adapter — Cloud-based LLM-optimized web scraping
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * 1. Account erstellen: https://firecrawl.dev
9
+ * 2. API Key holen
10
+ * 3. In .env:
11
+ * FIRECRAWL_API_KEY=fc-...
12
+ *
13
+ * Wann nutzen?
14
+ * → Bulk Crawling (ganze Websites)
15
+ * → Wenn LLM-ready Markdown gebraucht wird
16
+ * → Wenn lokaler Playwright zu langsam ist
17
+ *
18
+ * Fallback-Strategie:
19
+ * 1. JinaReader (schnell, kostenlos, kein JS)
20
+ * 2. PlaywrightAdapter (lokal, JS-Rendering)
21
+ * 3. FirecrawlAdapter (Cloud, bezahlt, beste Qualität)
22
+ * ═══════════════════════════════════════════════════════════════
23
+ */
24
+ import { getLogger } from '../../utils/logger.js';
25
+ const log = getLogger();
26
+ export class FirecrawlAdapter {
27
+ name = 'firecrawl';
28
+ apiKey;
29
+ baseUrl;
30
+ constructor(config = {}) {
31
+ this.apiKey = config.apiKey ?? process.env.FIRECRAWL_API_KEY ?? null;
32
+ this.baseUrl = config.baseUrl ?? 'https://api.firecrawl.dev/v1';
33
+ }
34
+ isEnabled() {
35
+ return this.apiKey !== null && this.apiKey.length > 0;
36
+ }
37
+ async scout() {
38
+ // Firecrawl doesn't search — it scrapes URLs.
39
+ return [];
40
+ }
41
+ /**
42
+ * Scrape a single URL and return LLM-ready markdown content.
43
+ */
44
+ async scrape(url) {
45
+ if (!this.isEnabled())
46
+ return null;
47
+ try {
48
+ const response = await fetch(`${this.baseUrl}/scrape`, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ 'Authorization': `Bearer ${this.apiKey}`,
53
+ },
54
+ body: JSON.stringify({
55
+ url,
56
+ formats: ['markdown'],
57
+ }),
58
+ });
59
+ if (!response.ok) {
60
+ log.warn(`[firecrawl] API error (${response.status})`);
61
+ return null;
62
+ }
63
+ const data = await response.json();
64
+ if (!data.success || !data.data?.markdown)
65
+ return null;
66
+ const markdown = data.data.markdown;
67
+ const title = data.data.metadata?.title ?? url;
68
+ const description = data.data.metadata?.description ?? markdown.substring(0, 300);
69
+ return { title, content: markdown, description, markdown };
70
+ }
71
+ catch (err) {
72
+ log.warn(`[firecrawl] Error scraping ${url}: ${err.message}`);
73
+ return null;
74
+ }
75
+ }
76
+ /**
77
+ * Crawl a website starting from a URL.
78
+ * Returns markdown for multiple pages.
79
+ */
80
+ async crawl(url, options = {}) {
81
+ if (!this.isEnabled())
82
+ return [];
83
+ try {
84
+ // Start crawl job
85
+ const startResponse = await fetch(`${this.baseUrl}/crawl`, {
86
+ method: 'POST',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ 'Authorization': `Bearer ${this.apiKey}`,
90
+ },
91
+ body: JSON.stringify({
92
+ url,
93
+ limit: options.limit ?? 10,
94
+ maxDepth: options.maxDepth ?? 2,
95
+ formats: ['markdown'],
96
+ }),
97
+ });
98
+ if (!startResponse.ok) {
99
+ log.warn(`[firecrawl] Crawl start error (${startResponse.status})`);
100
+ return [];
101
+ }
102
+ const startData = await startResponse.json();
103
+ if (!startData.success || !startData.id)
104
+ return [];
105
+ // Poll for results (max 60s)
106
+ for (let i = 0; i < 30; i++) {
107
+ await new Promise(r => setTimeout(r, 2000));
108
+ const statusResponse = await fetch(`${this.baseUrl}/crawl/${startData.id}`, {
109
+ headers: { 'Authorization': `Bearer ${this.apiKey}` },
110
+ });
111
+ if (!statusResponse.ok)
112
+ continue;
113
+ const statusData = await statusResponse.json();
114
+ if (statusData.status === 'completed' && statusData.data) {
115
+ return statusData.data
116
+ .filter(d => d.markdown)
117
+ .map(d => ({
118
+ url: d.metadata?.sourceURL ?? url,
119
+ title: d.metadata?.title ?? 'Untitled',
120
+ markdown: d.markdown,
121
+ }));
122
+ }
123
+ if (statusData.status === 'failed') {
124
+ log.warn('[firecrawl] Crawl job failed');
125
+ return [];
126
+ }
127
+ }
128
+ log.warn('[firecrawl] Crawl job timed out');
129
+ return [];
130
+ }
131
+ catch (err) {
132
+ log.warn(`[firecrawl] Error crawling ${url}: ${err.message}`);
133
+ return [];
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=firecrawl-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firecrawl-adapter.js","sourceRoot":"","sources":["../../../src/research/adapters/firecrawl-adapter.ts"],"names":[],"mappings":"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"}
@@ -3,3 +3,6 @@ export { TradingDataMinerAdapter } from './trading-adapter.js';
3
3
  export { MarketingDataMinerAdapter } from './marketing-adapter.js';
4
4
  export { ScannerDataMinerAdapter } from './scanner-adapter.js';
5
5
  export { BraveSearchAdapter, JinaReaderAdapter } from './web-research-adapter.js';
6
+ export { PlaywrightAdapter } from './playwright-adapter.js';
7
+ export { FirecrawlAdapter } from './firecrawl-adapter.js';
8
+ export type { FirecrawlConfig } from './firecrawl-adapter.js';
@@ -3,4 +3,6 @@ export { TradingDataMinerAdapter } from './trading-adapter.js';
3
3
  export { MarketingDataMinerAdapter } from './marketing-adapter.js';
4
4
  export { ScannerDataMinerAdapter } from './scanner-adapter.js';
5
5
  export { BraveSearchAdapter, JinaReaderAdapter } from './web-research-adapter.js';
6
+ export { PlaywrightAdapter } from './playwright-adapter.js';
7
+ export { FirecrawlAdapter } from './firecrawl-adapter.js';
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/research/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/research/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Playwright Adapter — Headless Browser for JS-rendered pages
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * 1. Playwright ist als optionale peerDependency installiert.
9
+ * Falls nötig: npm install playwright
10
+ * 2. Browser installieren:
11
+ * npx playwright install chromium
12
+ * 3. Keine Config nötig — funktioniert automatisch.
13
+ *
14
+ * Wann nutzen?
15
+ * → SPAs (React, Vue, Angular) — Inhalt wird per JS gerendert
16
+ * → Seiten die ohne JS leer oder unvollständig sind
17
+ * → Wenn Jina Reader kein brauchbares Ergebnis liefert
18
+ *
19
+ * Fallback-Strategie:
20
+ * 1. JinaReader (schnell, kostenlos, kein JS)
21
+ * 2. PlaywrightAdapter (langsamer, lokal, JS-Rendering)
22
+ * 3. FirecrawlAdapter (Cloud, optional)
23
+ * ═══════════════════════════════════════════════════════════════
24
+ */
25
+ import type { ScoutAdapter, ScoutDiscovery } from '../data-scout.js';
26
+ export declare class PlaywrightAdapter implements ScoutAdapter {
27
+ readonly name = "playwright";
28
+ private browser;
29
+ private available;
30
+ isEnabled(): boolean;
31
+ scout(): Promise<ScoutDiscovery[]>;
32
+ /**
33
+ * Check if Playwright + Chromium are available.
34
+ * Caches the result.
35
+ */
36
+ checkAvailable(): Promise<boolean>;
37
+ /**
38
+ * Extract content from a URL using a headless browser.
39
+ * Renders JavaScript, waits for content, then extracts text.
40
+ */
41
+ extract(url: string, options?: {
42
+ waitForSelector?: string;
43
+ timeout?: number;
44
+ screenshot?: boolean;
45
+ }): Promise<{
46
+ title: string;
47
+ content: string;
48
+ description: string;
49
+ screenshot?: Buffer;
50
+ } | null>;
51
+ private getBrowser;
52
+ /** Graceful shutdown — close the browser */
53
+ shutdown(): Promise<void>;
54
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Playwright Adapter — Headless Browser for JS-rendered pages
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * 1. Playwright ist als optionale peerDependency installiert.
9
+ * Falls nötig: npm install playwright
10
+ * 2. Browser installieren:
11
+ * npx playwright install chromium
12
+ * 3. Keine Config nötig — funktioniert automatisch.
13
+ *
14
+ * Wann nutzen?
15
+ * → SPAs (React, Vue, Angular) — Inhalt wird per JS gerendert
16
+ * → Seiten die ohne JS leer oder unvollständig sind
17
+ * → Wenn Jina Reader kein brauchbares Ergebnis liefert
18
+ *
19
+ * Fallback-Strategie:
20
+ * 1. JinaReader (schnell, kostenlos, kein JS)
21
+ * 2. PlaywrightAdapter (langsamer, lokal, JS-Rendering)
22
+ * 3. FirecrawlAdapter (Cloud, optional)
23
+ * ═══════════════════════════════════════════════════════════════
24
+ */
25
+ import { getLogger } from '../../utils/logger.js';
26
+ const log = getLogger();
27
+ export class PlaywrightAdapter {
28
+ name = 'playwright';
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ browser = null;
31
+ available = null;
32
+ isEnabled() {
33
+ // Optimistic — actual check happens on first use
34
+ return true;
35
+ }
36
+ async scout() {
37
+ // Playwright doesn't search — it extracts content from URLs.
38
+ return [];
39
+ }
40
+ /**
41
+ * Check if Playwright + Chromium are available.
42
+ * Caches the result.
43
+ */
44
+ async checkAvailable() {
45
+ if (this.available !== null)
46
+ return this.available;
47
+ try {
48
+ const pwPath = 'playwright';
49
+ const { chromium } = await import(/* webpackIgnore: true */ pwPath);
50
+ const browser = await chromium.launch({ headless: true });
51
+ await browser.close();
52
+ this.available = true;
53
+ }
54
+ catch {
55
+ this.available = false;
56
+ log.debug('[playwright] Not available (install with: npx playwright install chromium)');
57
+ }
58
+ return this.available;
59
+ }
60
+ /**
61
+ * Extract content from a URL using a headless browser.
62
+ * Renders JavaScript, waits for content, then extracts text.
63
+ */
64
+ async extract(url, options = {}) {
65
+ try {
66
+ if (!(await this.checkAvailable()))
67
+ return null;
68
+ const browser = await this.getBrowser();
69
+ const context = await browser.newContext({
70
+ userAgent: 'BrainEcosystem/1.0 (Research Bot)',
71
+ });
72
+ const page = await context.newPage();
73
+ try {
74
+ await page.goto(url, {
75
+ waitUntil: 'networkidle',
76
+ timeout: options.timeout ?? 30_000,
77
+ });
78
+ if (options.waitForSelector) {
79
+ await page.waitForSelector(options.waitForSelector, { timeout: 10_000 }).catch(() => { });
80
+ }
81
+ // Auto-scroll for lazy loading
82
+ await page.evaluate(() => {
83
+ window.scrollTo(0, document.body.scrollHeight);
84
+ });
85
+ await page.waitForTimeout(1000);
86
+ const title = await page.title();
87
+ const content = await page.evaluate(() => {
88
+ // Remove scripts, styles, navigation
89
+ const clone = document.body.cloneNode(true);
90
+ clone.querySelectorAll('script, style, nav, footer, header, aside, [role="navigation"]')
91
+ .forEach(el => el.remove());
92
+ return clone.innerText || clone.textContent || '';
93
+ });
94
+ const description = content.trim().substring(0, 300);
95
+ let screenshot;
96
+ if (options.screenshot) {
97
+ screenshot = await page.screenshot({ fullPage: false });
98
+ }
99
+ return { title, content: content.trim(), description, screenshot };
100
+ }
101
+ finally {
102
+ await context.close();
103
+ }
104
+ }
105
+ catch (err) {
106
+ log.warn(`[playwright] Error extracting ${url}: ${err.message}`);
107
+ return null;
108
+ }
109
+ }
110
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
+ async getBrowser() {
112
+ if (this.browser)
113
+ return this.browser;
114
+ const pwPath = 'playwright';
115
+ const { chromium } = await import(/* webpackIgnore: true */ pwPath);
116
+ this.browser = await chromium.launch({ headless: true });
117
+ return this.browser;
118
+ }
119
+ /** Graceful shutdown — close the browser */
120
+ async shutdown() {
121
+ if (this.browser) {
122
+ try {
123
+ await this.browser.close();
124
+ }
125
+ catch { /* best effort */ }
126
+ this.browser = null;
127
+ }
128
+ }
129
+ }
130
+ //# sourceMappingURL=playwright-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-adapter.js","sourceRoot":"","sources":["../../../src/research/adapters/playwright-adapter.ts"],"names":[],"mappings":"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"}
@@ -96,6 +96,7 @@ export declare class ResearchOrchestrator {
96
96
  private bootstrapService;
97
97
  private conceptAbstraction;
98
98
  private llmService;
99
+ private onSuggestionCallback;
99
100
  private db;
100
101
  private brainName;
101
102
  private feedbackTimer;
@@ -113,6 +114,8 @@ export declare class ResearchOrchestrator {
113
114
  /** Cycle number of last written suggestions — write at most once per cycle. */
114
115
  private lastSuggestionsCycle;
115
116
  constructor(db: Database.Database, config: ResearchOrchestratorConfig, causalGraph?: CausalGraph);
117
+ /** Set callback for self-improvement suggestions (e.g. to create notifications). */
118
+ setOnSuggestion(callback: (suggestions: string[]) => void): void;
116
119
  /** Set the DataMiner instance for DB-driven engine feeding. */
117
120
  setDataMiner(miner: DataMiner): void;
118
121
  /** Set the DreamEngine — wires journal + knowledgeDistiller into it. */
@@ -57,6 +57,7 @@ export class ResearchOrchestrator {
57
57
  bootstrapService = null;
58
58
  conceptAbstraction = null;
59
59
  llmService = null;
60
+ onSuggestionCallback = null;
60
61
  db;
61
62
  brainName;
62
63
  feedbackTimer = null;
@@ -92,7 +93,11 @@ export class ResearchOrchestrator {
92
93
  this.autoResponder = new AutoResponder(db, { brainName: config.brainName });
93
94
  this.autoResponder.setAdaptiveStrategy(this.adaptiveStrategy);
94
95
  this.autoResponder.setJournal(this.journal);
95
- this.hypothesisEngine = new HypothesisEngine(db, { minEvidence: 3, confirmThreshold: 0.05, rejectThreshold: 0.5 });
96
+ this.hypothesisEngine = new HypothesisEngine(db, { minEvidence: 3, confirmThreshold: 0.10, rejectThreshold: 0.5 });
97
+ }
98
+ /** Set callback for self-improvement suggestions (e.g. to create notifications). */
99
+ setOnSuggestion(callback) {
100
+ this.onSuggestionCallback = callback;
96
101
  }
97
102
  /** Set the DataMiner instance for DB-driven engine feeding. */
98
103
  setDataMiner(miner) {
@@ -366,6 +371,10 @@ export class ResearchOrchestrator {
366
371
  const now = Date.now();
367
372
  this.hypothesisEngine.observe({ source: this.brainName, type: 'anomaly_count', value: anomalies.length, timestamp: now });
368
373
  this.hypothesisEngine.observe({ source: this.brainName, type: 'insight_count', value: insights.length, timestamp: now });
374
+ // Feed journal significance for richer hypothesis generation
375
+ for (const insight of insights) {
376
+ this.hypothesisEngine.observe({ source: this.brainName, type: 'journal', value: insight.confidence, timestamp: now, metadata: { title: insight.title } });
377
+ }
369
378
  if (anomalies.length > 0) {
370
379
  for (const a of anomalies) {
371
380
  this.hypothesisEngine.observe({ source: this.brainName, type: `anomaly:${a.metric}`, value: a.deviation, timestamp: now, metadata: { severity: a.severity } });
@@ -497,6 +506,8 @@ export class ResearchOrchestrator {
497
506
  const sig = result.conclusion.significant;
498
507
  ts?.emit('experiment', 'discovering', `Experiment "${exp.name}": ${sig ? result.conclusion.direction : 'inconclusive'} (p=${result.conclusion.p_value.toFixed(4)})`, sig ? 'notable' : 'routine');
499
508
  this.journal.recordExperiment(exp.name, sig ? (result.conclusion.direction === 'positive' ? 'confirmed' : 'rejected') : 'inconclusive', { conclusion: result.conclusion, hypothesis: exp.hypothesis }, sig);
509
+ // Feed experiment effect size into HypothesisEngine
510
+ this.hypothesisEngine.observe({ source: this.brainName, type: 'experiment', value: result.conclusion.effect_size, timestamp: now, metadata: { name: exp.name, direction: result.conclusion.direction, significant: sig } });
500
511
  this.log.info(`[orchestrator] Experiment "${exp.name}": ${sig ? result.conclusion.direction : 'inconclusive'} (p=${result.conclusion.p_value.toFixed(4)}, d=${result.conclusion.effect_size.toFixed(2)})`);
501
512
  }
502
513
  }
@@ -2359,6 +2370,13 @@ export class ResearchOrchestrator {
2359
2370
  else {
2360
2371
  fs.appendFileSync(filePath, `---\n${header}${body}`, 'utf-8');
2361
2372
  }
2373
+ // Notify via callback (e.g. to create NotificationService entries)
2374
+ if (this.onSuggestionCallback) {
2375
+ try {
2376
+ this.onSuggestionCallback(suggestions);
2377
+ }
2378
+ catch { /* best effort */ }
2379
+ }
2362
2380
  }
2363
2381
  catch {
2364
2382
  // Don't let file writing break the feedback cycle