@upbeat-works/fisgon 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 (155) hide show
  1. package/LICENSE.md +10 -0
  2. package/README.md +150 -0
  3. package/dist/adapters/drizzle.d.ts +17 -0
  4. package/dist/adapters/drizzle.d.ts.map +1 -0
  5. package/dist/adapters/drizzle.js +83 -0
  6. package/dist/adapters/drizzle.js.map +1 -0
  7. package/dist/adapters/prisma.d.ts +16 -0
  8. package/dist/adapters/prisma.d.ts.map +1 -0
  9. package/dist/adapters/prisma.js +69 -0
  10. package/dist/adapters/prisma.js.map +1 -0
  11. package/dist/agent/ai.d.ts +3 -0
  12. package/dist/agent/ai.d.ts.map +1 -0
  13. package/dist/agent/ai.js +19 -0
  14. package/dist/agent/ai.js.map +1 -0
  15. package/dist/agent/browser-bridge.d.ts +42 -0
  16. package/dist/agent/browser-bridge.d.ts.map +1 -0
  17. package/dist/agent/browser-bridge.js +2 -0
  18. package/dist/agent/browser-bridge.js.map +1 -0
  19. package/dist/agent/index.d.ts +66 -0
  20. package/dist/agent/index.d.ts.map +1 -0
  21. package/dist/agent/index.js +572 -0
  22. package/dist/agent/index.js.map +1 -0
  23. package/dist/agent/llm-driver.d.ts +30 -0
  24. package/dist/agent/llm-driver.d.ts.map +1 -0
  25. package/dist/agent/llm-driver.js +239 -0
  26. package/dist/agent/llm-driver.js.map +1 -0
  27. package/dist/agent/session-state.d.ts +28 -0
  28. package/dist/agent/session-state.d.ts.map +1 -0
  29. package/dist/agent/session-state.js +6 -0
  30. package/dist/agent/session-state.js.map +1 -0
  31. package/dist/agent/worker.d.ts +6 -0
  32. package/dist/agent/worker.d.ts.map +1 -0
  33. package/dist/agent/worker.js +12 -0
  34. package/dist/agent/worker.js.map +1 -0
  35. package/dist/cli/browser-handler.d.ts +30 -0
  36. package/dist/cli/browser-handler.d.ts.map +1 -0
  37. package/dist/cli/browser-handler.js +89 -0
  38. package/dist/cli/browser-handler.js.map +1 -0
  39. package/dist/cli/browser-setup.d.ts +11 -0
  40. package/dist/cli/browser-setup.d.ts.map +1 -0
  41. package/dist/cli/browser-setup.js +25 -0
  42. package/dist/cli/browser-setup.js.map +1 -0
  43. package/dist/cli/commands/actions.d.ts +3 -0
  44. package/dist/cli/commands/actions.d.ts.map +1 -0
  45. package/dist/cli/commands/actions.js +28 -0
  46. package/dist/cli/commands/actions.js.map +1 -0
  47. package/dist/cli/commands/do.d.ts +3 -0
  48. package/dist/cli/commands/do.d.ts.map +1 -0
  49. package/dist/cli/commands/do.js +138 -0
  50. package/dist/cli/commands/do.js.map +1 -0
  51. package/dist/cli/commands/events.d.ts +3 -0
  52. package/dist/cli/commands/events.d.ts.map +1 -0
  53. package/dist/cli/commands/events.js +36 -0
  54. package/dist/cli/commands/events.js.map +1 -0
  55. package/dist/cli/commands/interact.d.ts +3 -0
  56. package/dist/cli/commands/interact.d.ts.map +1 -0
  57. package/dist/cli/commands/interact.js +54 -0
  58. package/dist/cli/commands/interact.js.map +1 -0
  59. package/dist/cli/commands/navigate.d.ts +3 -0
  60. package/dist/cli/commands/navigate.d.ts.map +1 -0
  61. package/dist/cli/commands/navigate.js +34 -0
  62. package/dist/cli/commands/navigate.js.map +1 -0
  63. package/dist/cli/commands/open.d.ts +3 -0
  64. package/dist/cli/commands/open.d.ts.map +1 -0
  65. package/dist/cli/commands/open.js +29 -0
  66. package/dist/cli/commands/open.js.map +1 -0
  67. package/dist/cli/commands/run.d.ts +3 -0
  68. package/dist/cli/commands/run.d.ts.map +1 -0
  69. package/dist/cli/commands/run.js +209 -0
  70. package/dist/cli/commands/run.js.map +1 -0
  71. package/dist/cli/commands/start.d.ts +3 -0
  72. package/dist/cli/commands/start.d.ts.map +1 -0
  73. package/dist/cli/commands/start.js +169 -0
  74. package/dist/cli/commands/start.js.map +1 -0
  75. package/dist/cli/commands/stop.d.ts +3 -0
  76. package/dist/cli/commands/stop.d.ts.map +1 -0
  77. package/dist/cli/commands/stop.js +37 -0
  78. package/dist/cli/commands/stop.js.map +1 -0
  79. package/dist/cli/commands/tick.d.ts +3 -0
  80. package/dist/cli/commands/tick.d.ts.map +1 -0
  81. package/dist/cli/commands/tick.js +34 -0
  82. package/dist/cli/commands/tick.js.map +1 -0
  83. package/dist/cli/config.d.ts +3 -0
  84. package/dist/cli/config.d.ts.map +1 -0
  85. package/dist/cli/config.js +20 -0
  86. package/dist/cli/config.js.map +1 -0
  87. package/dist/cli/connection.d.ts +18 -0
  88. package/dist/cli/connection.d.ts.map +1 -0
  89. package/dist/cli/connection.js +79 -0
  90. package/dist/cli/connection.js.map +1 -0
  91. package/dist/cli/index.d.ts +3 -0
  92. package/dist/cli/index.d.ts.map +1 -0
  93. package/dist/cli/index.js +29 -0
  94. package/dist/cli/index.js.map +1 -0
  95. package/dist/cli/session-file.d.ts +9 -0
  96. package/dist/cli/session-file.d.ts.map +1 -0
  97. package/dist/cli/session-file.js +23 -0
  98. package/dist/cli/session-file.js.map +1 -0
  99. package/dist/cli/task-runner.d.ts +20 -0
  100. package/dist/cli/task-runner.d.ts.map +1 -0
  101. package/dist/cli/task-runner.js +318 -0
  102. package/dist/cli/task-runner.js.map +1 -0
  103. package/dist/core/task-file.d.ts +32 -0
  104. package/dist/core/task-file.d.ts.map +1 -0
  105. package/dist/core/task-file.js +51 -0
  106. package/dist/core/task-file.js.map +1 -0
  107. package/dist/core/tick-detector.d.ts +24 -0
  108. package/dist/core/tick-detector.d.ts.map +1 -0
  109. package/dist/core/tick-detector.js +71 -0
  110. package/dist/core/tick-detector.js.map +1 -0
  111. package/dist/core/types.d.ts +74 -0
  112. package/dist/core/types.d.ts.map +1 -0
  113. package/dist/core/types.js +4 -0
  114. package/dist/core/types.js.map +1 -0
  115. package/dist/index.d.ts +4 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +4 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/probes/action-scanner.d.ts +2 -0
  120. package/dist/probes/action-scanner.d.ts.map +1 -0
  121. package/dist/probes/action-scanner.js +9 -0
  122. package/dist/probes/action-scanner.js.map +1 -0
  123. package/dist/probes/fetch-probe.d.ts +2 -0
  124. package/dist/probes/fetch-probe.d.ts.map +1 -0
  125. package/dist/probes/fetch-probe.js +9 -0
  126. package/dist/probes/fetch-probe.js.map +1 -0
  127. package/dist/probes/inject.d.ts +3 -0
  128. package/dist/probes/inject.d.ts.map +1 -0
  129. package/dist/probes/inject.js +24 -0
  130. package/dist/probes/inject.js.map +1 -0
  131. package/dist/probes/navigation-probe.d.ts +2 -0
  132. package/dist/probes/navigation-probe.d.ts.map +1 -0
  133. package/dist/probes/navigation-probe.js +9 -0
  134. package/dist/probes/navigation-probe.js.map +1 -0
  135. package/dist/probes/scripts/action-scanner.js +62 -0
  136. package/dist/probes/scripts/fetch.js +61 -0
  137. package/dist/probes/scripts/navigation.js +55 -0
  138. package/dist/probes/scripts/scripts/action-scanner.js +62 -0
  139. package/dist/probes/scripts/scripts/fetch.js +61 -0
  140. package/dist/probes/scripts/scripts/navigation.js +55 -0
  141. package/dist/probes/scripts/scripts/ws-bootstrap.js +35 -0
  142. package/dist/probes/scripts/ws-bootstrap.js +35 -0
  143. package/dist/server/create-probe.d.ts +8 -0
  144. package/dist/server/create-probe.d.ts.map +1 -0
  145. package/dist/server/create-probe.js +73 -0
  146. package/dist/server/create-probe.js.map +1 -0
  147. package/dist/server/sql-parser.d.ts +6 -0
  148. package/dist/server/sql-parser.d.ts.map +1 -0
  149. package/dist/server/sql-parser.js +40 -0
  150. package/dist/server/sql-parser.js.map +1 -0
  151. package/dist/server.d.ts +3 -0
  152. package/dist/server.d.ts.map +1 -0
  153. package/dist/server.js +2 -0
  154. package/dist/server.js.map +1 -0
  155. package/package.json +64 -0
@@ -0,0 +1,9 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const SCRIPT = readFileSync(resolve(__dirname, 'scripts/action-scanner.js'), 'utf-8');
6
+ export function createActionScannerScript() {
7
+ return SCRIPT;
8
+ }
9
+ //# sourceMappingURL=action-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-scanner.js","sourceRoot":"","sources":["../../src/probes/action-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,2BAA2B,CAAC,EAAE,OAAO,CAAC,CAAA;AAErF,MAAM,UAAU,yBAAyB;IACxC,OAAO,MAAM,CAAA;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function createFetchProbeScript(patterns: string[]): string;
2
+ //# sourceMappingURL=fetch-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-probe.d.ts","sourceRoot":"","sources":["../../src/probes/fetch-probe.ts"],"names":[],"mappings":"AAOA,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,9 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const SCRIPT = readFileSync(resolve(__dirname, 'scripts/fetch.js'), 'utf-8');
6
+ export function createFetchProbeScript(patterns) {
7
+ return SCRIPT.replaceAll('__FISGON_FETCH_PATTERNS__', JSON.stringify(patterns));
8
+ }
9
+ //# sourceMappingURL=fetch-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-probe.js","sourceRoot":"","sources":["../../src/probes/fetch-probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAA;AAE5E,MAAM,UAAU,sBAAsB,CAAC,QAAkB;IACxD,OAAO,MAAM,CAAC,UAAU,CAAC,2BAA2B,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;AAChF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type FisgonConfig } from '../core/types.js';
2
+ export declare function createInjectableScript(config: FisgonConfig, sessionId: string): string;
3
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../../src/probes/inject.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAWpD,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,GACf,MAAM,CAyBR"}
@@ -0,0 +1,24 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { createFetchProbeScript } from './fetch-probe.js';
5
+ import { createNavigationProbeScript } from './navigation-probe.js';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const WS_BOOTSTRAP = readFileSync(resolve(__dirname, 'scripts/ws-bootstrap.js'), 'utf-8');
8
+ export function createInjectableScript(config, sessionId) {
9
+ const port = config.port ?? 9876;
10
+ const wsUrl = `ws://localhost:${port}/agents/fisgon/default?role=browser-probe`;
11
+ const parts = [];
12
+ // WebSocket connection + __FISGON_EMIT__ function
13
+ parts.push(WS_BOOTSTRAP.replaceAll('__FISGON_WS_URL__', JSON.stringify(wsUrl)).replaceAll('__FISGON_SESSION_ID__', JSON.stringify(sessionId)));
14
+ // Navigation probe (always on unless explicitly disabled)
15
+ if (config.probes?.navigation !== false) {
16
+ parts.push(createNavigationProbeScript());
17
+ }
18
+ // Fetch probe (pattern-matched)
19
+ if (config.probes?.fetch?.match) {
20
+ parts.push(createFetchProbeScript(config.probes.fetch.match));
21
+ }
22
+ return parts.join('\n');
23
+ }
24
+ //# sourceMappingURL=inject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/probes/inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAA;AAEnE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,YAAY,GAAG,YAAY,CAChC,OAAO,CAAC,SAAS,EAAE,yBAAyB,CAAC,EAC7C,OAAO,CACP,CAAA;AAED,MAAM,UAAU,sBAAsB,CACrC,MAAoB,EACpB,SAAiB;IAEjB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,CAAA;IAChC,MAAM,KAAK,GAAG,kBAAkB,IAAI,2CAA2C,CAAA;IAE/E,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,kDAAkD;IAClD,KAAK,CAAC,IAAI,CACT,YAAY,CAAC,UAAU,CAAC,mBAAmB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAC7E,uBAAuB,EACvB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CACzB,CACD,CAAA;IAED,0DAA0D;IAC1D,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,KAAK,KAAK,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,2BAA2B,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED,gCAAgC;IAChC,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function createNavigationProbeScript(): string;
2
+ //# sourceMappingURL=navigation-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-probe.d.ts","sourceRoot":"","sources":["../../src/probes/navigation-probe.ts"],"names":[],"mappings":"AAOA,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD"}
@@ -0,0 +1,9 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const SCRIPT = readFileSync(resolve(__dirname, 'scripts/navigation.js'), 'utf-8');
6
+ export function createNavigationProbeScript() {
7
+ return SCRIPT;
8
+ }
9
+ //# sourceMappingURL=navigation-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-probe.js","sourceRoot":"","sources":["../../src/probes/navigation-probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,uBAAuB,CAAC,EAAE,OAAO,CAAC,CAAA;AAEjF,MAAM,UAAU,2BAA2B;IAC1C,OAAO,MAAM,CAAA;AACd,CAAC"}
@@ -0,0 +1,62 @@
1
+ // Action scanner — runs on-demand in the browser when `fisgon actions` is called.
2
+ // Not a continuous probe — scans once, injects data-fisgon attrs, returns Action[].
3
+ ;(function () {
4
+ const actions = []
5
+ let counter = 0
6
+
7
+ // Clear previous data-fisgon attributes
8
+ document
9
+ .querySelectorAll('[data-fisgon]')
10
+ .forEach((el) => el.removeAttribute('data-fisgon'))
11
+
12
+ const elements = document.querySelectorAll([
13
+ // Standard interactive elements
14
+ 'form', 'a[href]', 'button', 'select', 'textarea', 'summary',
15
+ 'input:not([type="hidden"])',
16
+ // Non-standard but common
17
+ '[type="button"]', '[contenteditable]:not([contenteditable="false"])',
18
+ // ARIA roles
19
+ '[role="button"]', '[role="link"]', '[role="menuitem"]', '[role="tab"]',
20
+ '[role="option"]', '[role="switch"]', '[role="checkbox"]', '[role="radio"]',
21
+ '[role="combobox"]', '[role="slider"]', '[role="spinbutton"]', '[role="treeitem"]',
22
+ '[role="textbox"]', '[role="listbox"]', '[role="searchbox"]',
23
+ // ARIA state attributes (imply interactivity)
24
+ '[aria-haspopup]', '[aria-expanded]', '[aria-pressed]', '[aria-checked]', '[aria-selected]',
25
+ // Keyboard-focusable
26
+ '[tabindex]:not([tabindex="-1"])',
27
+ ].join(', '))
28
+
29
+ const seen = new Set()
30
+
31
+ for (const el of elements) {
32
+ // Deduplicate — an element might match multiple selectors
33
+ if (seen.has(el)) continue
34
+ seen.add(el)
35
+
36
+ // Skip truly hidden elements (except forms which may be invisible wrappers).
37
+ // offsetParent is null for display:none BUT ALSO for position:fixed/sticky
38
+ // ancestors (navbars, modals, headers), so check computed style instead.
39
+ if (el.tagName !== 'FORM') {
40
+ const style = getComputedStyle(el)
41
+ if (style.display === 'none' || style.visibility === 'hidden') continue
42
+ }
43
+
44
+ const id = 'f' + (++counter).toString(36)
45
+ el.setAttribute('data-fisgon', id)
46
+
47
+ const tag = el.tagName.toLowerCase()
48
+ let elementType = tag
49
+ if (tag === 'input') elementType = 'button'
50
+ const role = el.getAttribute('role')
51
+ if (role) elementType = role
52
+
53
+ const textContent = (el.textContent || '')
54
+ .trim()
55
+ .replace(/\s+/g, ' ')
56
+ .slice(0, 200)
57
+
58
+ actions.push({ id, elementType, textContent })
59
+ }
60
+
61
+ return actions
62
+ })()
@@ -0,0 +1,61 @@
1
+ // Fetch probe — injected into the browser by Fisgon.
2
+ // __FISGON_EMIT__ is defined by the WebSocket bootstrap (see ws-bootstrap.js).
3
+ ;(function () {
4
+ const patterns = __FISGON_FETCH_PATTERNS__
5
+
6
+ function matchesAny(pathname, pats) {
7
+ for (let i = 0; i < pats.length; i++) {
8
+ if (matchGlob(pathname, pats[i])) return true
9
+ }
10
+ return false
11
+ }
12
+
13
+ function matchGlob(str, pattern) {
14
+ const regex = pattern
15
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
16
+ .replace(/\*\*/g, '__DOUBLESTAR__')
17
+ .replace(/\*/g, '[^/]*')
18
+ .replace(/__DOUBLESTAR__/g, '.*')
19
+ .replace(/\?/g, '.')
20
+ return new RegExp('^' + regex + '$').test(str)
21
+ }
22
+
23
+ const originalFetch = window.fetch
24
+ window.fetch = async function (input, init) {
25
+ const url = new URL(
26
+ typeof input === 'string'
27
+ ? input
28
+ : input instanceof Request
29
+ ? input.url
30
+ : String(input),
31
+ location.origin,
32
+ )
33
+
34
+ if (!matchesAny(url.pathname + url.search, patterns)) {
35
+ return originalFetch.call(this, input, init)
36
+ }
37
+
38
+ const method =
39
+ (init && init.method) ||
40
+ (input instanceof Request ? input.method : 'GET')
41
+ const timestamp = Date.now()
42
+
43
+ __FISGON_EMIT__({
44
+ source: 'fetch',
45
+ type: 'request',
46
+ timestamp: timestamp,
47
+ data: { url: url.pathname + url.search, method: method },
48
+ })
49
+
50
+ const response = await originalFetch.call(this, input, init)
51
+
52
+ __FISGON_EMIT__({
53
+ source: 'fetch',
54
+ type: 'response',
55
+ timestamp: Date.now(),
56
+ data: { url: url.pathname + url.search, status: response.status },
57
+ })
58
+
59
+ return response
60
+ }
61
+ })()
@@ -0,0 +1,55 @@
1
+ // Navigation probe — injected into the browser by Fisgon.
2
+ // Listens to History API pushState/replaceState and popstate events.
3
+ // __FISGON_EMIT__ is defined by the WebSocket bootstrap (see ws-bootstrap.js).
4
+ ;(function () {
5
+ const originalPushState = history.pushState
6
+ const originalReplaceState = history.replaceState
7
+
8
+ history.pushState = function (...args) {
9
+ const result = originalPushState.apply(this, args)
10
+ __FISGON_EMIT__({
11
+ source: 'nav',
12
+ type: 'navigate',
13
+ timestamp: Date.now(),
14
+ data: {
15
+ url: location.pathname + location.search,
16
+ method: 'pushState',
17
+ },
18
+ })
19
+ return result
20
+ }
21
+
22
+ history.replaceState = function (...args) {
23
+ const result = originalReplaceState.apply(this, args)
24
+ __FISGON_EMIT__({
25
+ source: 'nav',
26
+ type: 'navigate',
27
+ timestamp: Date.now(),
28
+ data: {
29
+ url: location.pathname + location.search,
30
+ method: 'replaceState',
31
+ },
32
+ })
33
+ return result
34
+ }
35
+
36
+ window.addEventListener('popstate', function () {
37
+ __FISGON_EMIT__({
38
+ source: 'nav',
39
+ type: 'navigate',
40
+ timestamp: Date.now(),
41
+ data: {
42
+ url: location.pathname + location.search,
43
+ method: 'popstate',
44
+ },
45
+ })
46
+ })
47
+
48
+ // Emit initial page load
49
+ __FISGON_EMIT__({
50
+ source: 'nav',
51
+ type: 'load',
52
+ timestamp: Date.now(),
53
+ data: { url: location.pathname + location.search },
54
+ })
55
+ })()
@@ -0,0 +1,62 @@
1
+ // Action scanner — runs on-demand in the browser when `fisgon actions` is called.
2
+ // Not a continuous probe — scans once, injects data-fisgon attrs, returns Action[].
3
+ ;(function () {
4
+ const actions = []
5
+ let counter = 0
6
+
7
+ // Clear previous data-fisgon attributes
8
+ document
9
+ .querySelectorAll('[data-fisgon]')
10
+ .forEach((el) => el.removeAttribute('data-fisgon'))
11
+
12
+ const elements = document.querySelectorAll([
13
+ // Standard interactive elements
14
+ 'form', 'a[href]', 'button', 'select', 'textarea', 'summary',
15
+ 'input:not([type="hidden"])',
16
+ // Non-standard but common
17
+ '[type="button"]', '[contenteditable]:not([contenteditable="false"])',
18
+ // ARIA roles
19
+ '[role="button"]', '[role="link"]', '[role="menuitem"]', '[role="tab"]',
20
+ '[role="option"]', '[role="switch"]', '[role="checkbox"]', '[role="radio"]',
21
+ '[role="combobox"]', '[role="slider"]', '[role="spinbutton"]', '[role="treeitem"]',
22
+ '[role="textbox"]', '[role="listbox"]', '[role="searchbox"]',
23
+ // ARIA state attributes (imply interactivity)
24
+ '[aria-haspopup]', '[aria-expanded]', '[aria-pressed]', '[aria-checked]', '[aria-selected]',
25
+ // Keyboard-focusable
26
+ '[tabindex]:not([tabindex="-1"])',
27
+ ].join(', '))
28
+
29
+ const seen = new Set()
30
+
31
+ for (const el of elements) {
32
+ // Deduplicate — an element might match multiple selectors
33
+ if (seen.has(el)) continue
34
+ seen.add(el)
35
+
36
+ // Skip truly hidden elements (except forms which may be invisible wrappers).
37
+ // offsetParent is null for display:none BUT ALSO for position:fixed/sticky
38
+ // ancestors (navbars, modals, headers), so check computed style instead.
39
+ if (el.tagName !== 'FORM') {
40
+ const style = getComputedStyle(el)
41
+ if (style.display === 'none' || style.visibility === 'hidden') continue
42
+ }
43
+
44
+ const id = 'f' + (++counter).toString(36)
45
+ el.setAttribute('data-fisgon', id)
46
+
47
+ const tag = el.tagName.toLowerCase()
48
+ let elementType = tag
49
+ if (tag === 'input') elementType = 'button'
50
+ const role = el.getAttribute('role')
51
+ if (role) elementType = role
52
+
53
+ const textContent = (el.textContent || '')
54
+ .trim()
55
+ .replace(/\s+/g, ' ')
56
+ .slice(0, 200)
57
+
58
+ actions.push({ id, elementType, textContent })
59
+ }
60
+
61
+ return actions
62
+ })()
@@ -0,0 +1,61 @@
1
+ // Fetch probe — injected into the browser by Fisgon.
2
+ // __FISGON_EMIT__ is defined by the WebSocket bootstrap (see ws-bootstrap.js).
3
+ ;(function () {
4
+ const patterns = __FISGON_FETCH_PATTERNS__
5
+
6
+ function matchesAny(pathname, pats) {
7
+ for (let i = 0; i < pats.length; i++) {
8
+ if (matchGlob(pathname, pats[i])) return true
9
+ }
10
+ return false
11
+ }
12
+
13
+ function matchGlob(str, pattern) {
14
+ const regex = pattern
15
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
16
+ .replace(/\*\*/g, '__DOUBLESTAR__')
17
+ .replace(/\*/g, '[^/]*')
18
+ .replace(/__DOUBLESTAR__/g, '.*')
19
+ .replace(/\?/g, '.')
20
+ return new RegExp('^' + regex + '$').test(str)
21
+ }
22
+
23
+ const originalFetch = window.fetch
24
+ window.fetch = async function (input, init) {
25
+ const url = new URL(
26
+ typeof input === 'string'
27
+ ? input
28
+ : input instanceof Request
29
+ ? input.url
30
+ : String(input),
31
+ location.origin,
32
+ )
33
+
34
+ if (!matchesAny(url.pathname + url.search, patterns)) {
35
+ return originalFetch.call(this, input, init)
36
+ }
37
+
38
+ const method =
39
+ (init && init.method) ||
40
+ (input instanceof Request ? input.method : 'GET')
41
+ const timestamp = Date.now()
42
+
43
+ __FISGON_EMIT__({
44
+ source: 'fetch',
45
+ type: 'request',
46
+ timestamp: timestamp,
47
+ data: { url: url.pathname + url.search, method: method },
48
+ })
49
+
50
+ const response = await originalFetch.call(this, input, init)
51
+
52
+ __FISGON_EMIT__({
53
+ source: 'fetch',
54
+ type: 'response',
55
+ timestamp: Date.now(),
56
+ data: { url: url.pathname + url.search, status: response.status },
57
+ })
58
+
59
+ return response
60
+ }
61
+ })()
@@ -0,0 +1,55 @@
1
+ // Navigation probe — injected into the browser by Fisgon.
2
+ // Listens to History API pushState/replaceState and popstate events.
3
+ // __FISGON_EMIT__ is defined by the WebSocket bootstrap (see ws-bootstrap.js).
4
+ ;(function () {
5
+ const originalPushState = history.pushState
6
+ const originalReplaceState = history.replaceState
7
+
8
+ history.pushState = function (...args) {
9
+ const result = originalPushState.apply(this, args)
10
+ __FISGON_EMIT__({
11
+ source: 'nav',
12
+ type: 'navigate',
13
+ timestamp: Date.now(),
14
+ data: {
15
+ url: location.pathname + location.search,
16
+ method: 'pushState',
17
+ },
18
+ })
19
+ return result
20
+ }
21
+
22
+ history.replaceState = function (...args) {
23
+ const result = originalReplaceState.apply(this, args)
24
+ __FISGON_EMIT__({
25
+ source: 'nav',
26
+ type: 'navigate',
27
+ timestamp: Date.now(),
28
+ data: {
29
+ url: location.pathname + location.search,
30
+ method: 'replaceState',
31
+ },
32
+ })
33
+ return result
34
+ }
35
+
36
+ window.addEventListener('popstate', function () {
37
+ __FISGON_EMIT__({
38
+ source: 'nav',
39
+ type: 'navigate',
40
+ timestamp: Date.now(),
41
+ data: {
42
+ url: location.pathname + location.search,
43
+ method: 'popstate',
44
+ },
45
+ })
46
+ })
47
+
48
+ // Emit initial page load
49
+ __FISGON_EMIT__({
50
+ source: 'nav',
51
+ type: 'load',
52
+ timestamp: Date.now(),
53
+ data: { url: location.pathname + location.search },
54
+ })
55
+ })()
@@ -0,0 +1,35 @@
1
+ // WebSocket bootstrap — injected first, defines __FISGON_EMIT__.
2
+ ;(function () {
3
+ let ws = null
4
+ const buffer = []
5
+ let connected = false
6
+
7
+ function connect() {
8
+ ws = new WebSocket(__FISGON_WS_URL__)
9
+ ws.onopen = function () {
10
+ connected = true
11
+ for (const event of buffer) {
12
+ ws.send(JSON.stringify({ type: 'event', event: event }))
13
+ }
14
+ buffer.length = 0
15
+ }
16
+ ws.onclose = function () {
17
+ connected = false
18
+ setTimeout(connect, 1000)
19
+ }
20
+ ws.onerror = function () {
21
+ connected = false
22
+ }
23
+ }
24
+
25
+ window.__FISGON_EMIT__ = function (event) {
26
+ event.sessionId = __FISGON_SESSION_ID__
27
+ if (connected && ws && ws.readyState === 1) {
28
+ ws.send(JSON.stringify({ type: 'event', event: event }))
29
+ } else {
30
+ buffer.push(event)
31
+ }
32
+ }
33
+
34
+ connect()
35
+ })()
@@ -0,0 +1,35 @@
1
+ // WebSocket bootstrap — injected first, defines __FISGON_EMIT__.
2
+ ;(function () {
3
+ let ws = null
4
+ const buffer = []
5
+ let connected = false
6
+
7
+ function connect() {
8
+ ws = new WebSocket(__FISGON_WS_URL__)
9
+ ws.onopen = function () {
10
+ connected = true
11
+ for (const event of buffer) {
12
+ ws.send(JSON.stringify({ type: 'event', event: event }))
13
+ }
14
+ buffer.length = 0
15
+ }
16
+ ws.onclose = function () {
17
+ connected = false
18
+ setTimeout(connect, 1000)
19
+ }
20
+ ws.onerror = function () {
21
+ connected = false
22
+ }
23
+ }
24
+
25
+ window.__FISGON_EMIT__ = function (event) {
26
+ event.sessionId = __FISGON_SESSION_ID__
27
+ if (connected && ws && ws.readyState === 1) {
28
+ ws.send(JSON.stringify({ type: 'event', event: event }))
29
+ } else {
30
+ buffer.push(event)
31
+ }
32
+ }
33
+
34
+ connect()
35
+ })()
@@ -0,0 +1,8 @@
1
+ import { type Probe } from '../core/types.js';
2
+ type CreateProbeOptions = {
3
+ url: string;
4
+ env?: string;
5
+ };
6
+ export declare function createProbe(options: CreateProbeOptions): Probe;
7
+ export {};
8
+ //# sourceMappingURL=create-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-probe.d.ts","sourceRoot":"","sources":["../../src/server/create-probe.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAqC,MAAM,kBAAkB,CAAA;AAGhF,KAAK,kBAAkB,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ,CAAA;AASD,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,KAAK,CAkE9D"}
@@ -0,0 +1,73 @@
1
+ import { agentFetch } from 'agents/client';
2
+ import { parseSQL } from './sql-parser.js';
3
+ const NOOP_SCOPED = {
4
+ active: false,
5
+ sessionId: null,
6
+ emit() { },
7
+ fromSQL() { },
8
+ };
9
+ export function createProbe(options) {
10
+ const parsedUrl = new URL(options.url);
11
+ const host = parsedUrl.host;
12
+ const envName = options.env ?? 'default';
13
+ function sendEvent(event) {
14
+ agentFetch({ agent: 'fisgon', name: envName, host }, {
15
+ method: 'POST',
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ type: 'ingest-event', event }),
18
+ }).catch(() => { });
19
+ }
20
+ return {
21
+ get active() {
22
+ // With fetch-based probe, we're always "active" — the agent will
23
+ // discard events for unknown sessions on its end.
24
+ return true;
25
+ },
26
+ fromRequest(request) {
27
+ // Read the fisgon cookie from the request
28
+ let cookieHeader = null;
29
+ if (request instanceof Request) {
30
+ cookieHeader = request.headers.get('cookie');
31
+ }
32
+ else if (request.headers) {
33
+ if (typeof request.headers.get === 'function') {
34
+ cookieHeader = request.headers.get('cookie');
35
+ }
36
+ else {
37
+ cookieHeader =
38
+ request.headers.cookie ?? null;
39
+ }
40
+ }
41
+ if (!cookieHeader)
42
+ return NOOP_SCOPED;
43
+ const sessionId = parseCookie(cookieHeader, 'fisgon');
44
+ if (!sessionId)
45
+ return NOOP_SCOPED;
46
+ return {
47
+ active: true,
48
+ sessionId,
49
+ emit(event) {
50
+ sendEvent({ ...event, sessionId });
51
+ },
52
+ fromSQL(query, _params) {
53
+ const parsed = parseSQL(query);
54
+ sendEvent({
55
+ sessionId,
56
+ source: 'sql',
57
+ type: parsed.operation,
58
+ timestamp: Date.now(),
59
+ data: { table: parsed.table },
60
+ });
61
+ },
62
+ };
63
+ },
64
+ disconnect() {
65
+ // Nothing to close with fetch-based approach
66
+ },
67
+ };
68
+ }
69
+ function parseCookie(header, name) {
70
+ const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]+)`));
71
+ return match ? match[1] : null;
72
+ }
73
+ //# sourceMappingURL=create-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-probe.js","sourceRoot":"","sources":["../../src/server/create-probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type ParsedSQL = {
2
+ operation: string;
3
+ table: string;
4
+ };
5
+ export declare function parseSQL(query: string): ParsedSQL;
6
+ //# sourceMappingURL=sql-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-parser.d.ts","sourceRoot":"","sources":["../../src/server/sql-parser.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACb,CAAA;AAyCD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAajD"}