web-agent-bridge 3.4.0 → 3.9.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 (315) hide show
  1. package/LICENSE +84 -84
  2. package/README.ar.md +1565 -1304
  3. package/README.md +171 -298
  4. package/bin/agent-runner.js +474 -474
  5. package/bin/cli.js +237 -237
  6. package/bin/wab-init.js +244 -223
  7. package/bin/wab.js +80 -80
  8. package/examples/azure-dns-wab.js +83 -83
  9. package/examples/bidi-agent.js +119 -119
  10. package/examples/cloudflare-wab-dns.js +121 -121
  11. package/examples/cpanel-wab-dns.js +114 -114
  12. package/examples/cross-site-agent.js +91 -91
  13. package/examples/dns-discovery-agent.js +166 -166
  14. package/examples/gcp-dns-wab.js +76 -76
  15. package/examples/governance-agent.js +169 -169
  16. package/examples/mcp-agent.js +94 -94
  17. package/examples/next-app-router/README.md +44 -44
  18. package/examples/plesk-wab-dns.js +103 -103
  19. package/examples/puppeteer-agent.js +108 -108
  20. package/examples/route53-wab-dns.js +144 -144
  21. package/examples/saas-dashboard/README.md +55 -55
  22. package/examples/safe-mode-agent.js +96 -96
  23. package/examples/self-discovery.js +106 -0
  24. package/examples/shopify-hydrogen/README.md +74 -74
  25. package/examples/vision-agent.js +171 -171
  26. package/examples/wab-sign.js +74 -74
  27. package/examples/wab-verify.js +60 -60
  28. package/examples/wordpress-elementor/README.md +77 -77
  29. package/package.json +93 -93
  30. package/public/.well-known/agent-tools.json +180 -180
  31. package/public/.well-known/ai-assets.json +59 -59
  32. package/public/.well-known/security.txt +8 -8
  33. package/public/.well-known/wab.json +28 -28
  34. package/public/activate.html +448 -368
  35. package/public/adopt.html +236 -0
  36. package/public/adoption-metrics.html +188 -188
  37. package/public/agent-workspace.html +359 -349
  38. package/public/ai.html +198 -198
  39. package/public/api.html +397 -413
  40. package/public/atp.html +171 -0
  41. package/public/azure-dns-integration.html +289 -289
  42. package/public/browser.html +486 -486
  43. package/public/cloudflare-integration.html +380 -380
  44. package/public/commander-dashboard.html +243 -243
  45. package/public/cookies.html +210 -210
  46. package/public/cpanel-integration.html +398 -398
  47. package/public/css/agent-workspace.css +1713 -1713
  48. package/public/css/premium.css +317 -317
  49. package/public/css/styles.css +1401 -1263
  50. package/public/dashboard-shieldlink.html +295 -0
  51. package/public/dashboard.html +711 -707
  52. package/public/dns.html +436 -436
  53. package/public/docs.html +588 -588
  54. package/public/enterprise-mesh.ar.html +80 -0
  55. package/public/enterprise-mesh.html +81 -0
  56. package/public/feed.xml +89 -89
  57. package/public/gcp-dns-integration.html +318 -318
  58. package/public/governance.ar.html +70 -0
  59. package/public/governance.html +69 -0
  60. package/public/growth.html +465 -465
  61. package/public/index.html +1372 -1266
  62. package/public/integrations.html +556 -556
  63. package/public/js/activate.js +449 -145
  64. package/public/js/agent-workspace.js +1740 -1740
  65. package/public/js/auth-nav.js +117 -65
  66. package/public/js/auth-redirect.js +12 -12
  67. package/public/js/cookie-consent.js +56 -56
  68. package/public/js/dns.js +438 -438
  69. package/public/js/wab-demo-page.js +721 -721
  70. package/public/js/ws-client.js +74 -74
  71. package/public/l-preview.html +242 -0
  72. package/public/llms-full.txt +360 -360
  73. package/public/llms.txt +125 -125
  74. package/public/login.html +85 -85
  75. package/public/mesh-dashboard.html +328 -328
  76. package/public/milestones.html +346 -0
  77. package/public/one-click.html +779 -0
  78. package/public/openapi.json +669 -669
  79. package/public/partners.ar.html +145 -0
  80. package/public/partners.html +143 -0
  81. package/public/phone-shield.html +281 -281
  82. package/public/plesk-integration.html +375 -375
  83. package/public/premium-dashboard.html +2489 -2489
  84. package/public/premium.html +793 -793
  85. package/public/privacy.html +297 -297
  86. package/public/provider-onboarding.html +172 -172
  87. package/public/provider-sandbox.html +134 -134
  88. package/public/providers.html +359 -359
  89. package/public/refusals.html +172 -0
  90. package/public/register.html +105 -105
  91. package/public/registrar-integrations.html +141 -141
  92. package/public/ring4.html +292 -0
  93. package/public/robots.txt +99 -99
  94. package/public/route53-integration.html +531 -531
  95. package/public/score.html +263 -0
  96. package/public/script/wab-consent.d.ts +36 -36
  97. package/public/script/wab-consent.js +104 -104
  98. package/public/script/wab-schema.js +131 -131
  99. package/public/script/wab.d.ts +108 -108
  100. package/public/script/wab.min.js +580 -580
  101. package/public/security.txt +8 -8
  102. package/public/shieldlink.html +244 -0
  103. package/public/shieldqr.html +231 -231
  104. package/public/sitemap.xml +13 -1
  105. package/public/terms.html +256 -256
  106. package/public/trust-graph-api.ar.html +92 -0
  107. package/public/trust-graph-api.html +91 -0
  108. package/public/wab-features.html +560 -0
  109. package/public/wab-trust.html +200 -200
  110. package/public/wab-truth.html +375 -0
  111. package/public/wab-vs-protocols.html +210 -210
  112. package/public/whitepaper.html +449 -449
  113. package/script/ai-agent-bridge.js +1754 -1754
  114. package/sdk/README.md +99 -99
  115. package/sdk/agent-mesh.js +449 -449
  116. package/sdk/atp.js +103 -0
  117. package/sdk/auto-discovery.js +301 -288
  118. package/sdk/commander.js +262 -262
  119. package/sdk/governance.js +262 -262
  120. package/sdk/index.d.ts +464 -464
  121. package/sdk/index.js +653 -649
  122. package/sdk/multi-agent.js +318 -318
  123. package/sdk/safe-mode.js +221 -221
  124. package/sdk/safety-shield.js +219 -219
  125. package/sdk/schema-discovery.js +83 -83
  126. package/server/adapters/index.js +520 -520
  127. package/server/config/plans.js +412 -367
  128. package/server/config/secrets.js +102 -102
  129. package/server/control-plane/index.js +301 -301
  130. package/server/data-plane/index.js +354 -354
  131. package/server/index.js +793 -670
  132. package/server/llm/index.js +404 -404
  133. package/server/middleware/adminAuth.js +35 -35
  134. package/server/middleware/api-tier.js +170 -0
  135. package/server/middleware/auth.js +50 -50
  136. package/server/middleware/featureGate.js +88 -88
  137. package/server/middleware/rateLimits.js +100 -100
  138. package/server/middleware/sensitiveAction.js +157 -157
  139. package/server/middleware/wab-trust.js +141 -0
  140. package/server/migrations/001_add_analytics_indexes.sql +7 -7
  141. package/server/migrations/002_premium_features.sql +418 -418
  142. package/server/migrations/003_ads_integer_cents.sql +33 -33
  143. package/server/migrations/004_agent_os.sql +158 -158
  144. package/server/migrations/005_marketplace_metering.sql +126 -126
  145. package/server/migrations/006_growth_suite.sql +138 -0
  146. package/server/migrations/007_governance.sql +106 -106
  147. package/server/migrations/008_plans.sql +144 -144
  148. package/server/migrations/009_shieldqr.sql +30 -30
  149. package/server/migrations/010_extended_trust.sql +33 -33
  150. package/server/migrations/011_outreach.sql +47 -0
  151. package/server/migrations/012_shieldlink.sql +116 -0
  152. package/server/migrations/013_ct_monitor.sql +13 -0
  153. package/server/migrations/014_wab_advanced_features.sql +128 -0
  154. package/server/migrations/015_wab_truth_layer.sql +101 -0
  155. package/server/migrations/016_ring4_external_trust.sql +84 -0
  156. package/server/migrations/017_ring4_extensions.sql +69 -0
  157. package/server/migrations/018_commercial_foundations.sql +167 -0
  158. package/server/migrations/019_unify_tier_constraints.sql +133 -0
  159. package/server/migrations/020_agent_transaction_primitive.sql +119 -0
  160. package/server/models/adapters/index.js +33 -33
  161. package/server/models/adapters/mysql.js +183 -183
  162. package/server/models/adapters/postgresql.js +172 -172
  163. package/server/models/adapters/sqlite.js +7 -7
  164. package/server/models/db.js +740 -740
  165. package/server/observability/failure-analysis.js +337 -337
  166. package/server/observability/index.js +394 -394
  167. package/server/protocol/capabilities.js +223 -223
  168. package/server/protocol/index.js +243 -243
  169. package/server/protocol/schema.js +584 -584
  170. package/server/registry/certification.js +271 -271
  171. package/server/registry/index.js +326 -326
  172. package/server/routes/activate.js +478 -0
  173. package/server/routes/admin-outreach.js +239 -0
  174. package/server/routes/admin-plans.js +76 -76
  175. package/server/routes/admin-premium.js +674 -673
  176. package/server/routes/admin-shieldlink.js +137 -0
  177. package/server/routes/admin-shieldqr.js +90 -90
  178. package/server/routes/admin-trust-monitor.js +139 -83
  179. package/server/routes/admin.js +550 -549
  180. package/server/routes/adopt.js +61 -0
  181. package/server/routes/ads.js +130 -130
  182. package/server/routes/agent-workspace.js +540 -540
  183. package/server/routes/api-keys.js +127 -0
  184. package/server/routes/api.js +150 -150
  185. package/server/routes/auth.js +71 -71
  186. package/server/routes/billing.js +57 -57
  187. package/server/routes/commander.js +316 -316
  188. package/server/routes/customer-shieldlink.js +133 -0
  189. package/server/routes/demo-showcase.js +332 -332
  190. package/server/routes/demo-store.js +154 -154
  191. package/server/routes/diagnose.js +373 -0
  192. package/server/routes/discovery.js +2348 -2348
  193. package/server/routes/enterprise-mesh.js +170 -0
  194. package/server/routes/gateway.js +173 -173
  195. package/server/routes/governance-saas.js +203 -0
  196. package/server/routes/governance.js +208 -208
  197. package/server/routes/growth.js +1048 -0
  198. package/server/routes/intent.js +328 -0
  199. package/server/routes/license.js +251 -251
  200. package/server/routes/mesh.js +469 -469
  201. package/server/routes/noscript.js +543 -543
  202. package/server/routes/partners.js +201 -0
  203. package/server/routes/plans.js +33 -33
  204. package/server/routes/premium-v2.js +686 -686
  205. package/server/routes/premium.js +724 -724
  206. package/server/routes/providers.js +650 -650
  207. package/server/routes/reputation.js +411 -0
  208. package/server/routes/ring4.js +885 -0
  209. package/server/routes/runtime.js +2148 -2148
  210. package/server/routes/shieldlink.js +70 -0
  211. package/server/routes/shieldqr.js +88 -88
  212. package/server/routes/sovereign.js +465 -465
  213. package/server/routes/transactions.js +233 -0
  214. package/server/routes/truth-layer.js +670 -0
  215. package/server/routes/universal.js +200 -200
  216. package/server/routes/unsubscribe.js +51 -0
  217. package/server/routes/wab-api.js +850 -850
  218. package/server/routes/wab-cache.js +282 -0
  219. package/server/runtime/container-worker.js +111 -111
  220. package/server/runtime/container.js +448 -448
  221. package/server/runtime/distributed-worker.js +362 -362
  222. package/server/runtime/event-bus.js +210 -210
  223. package/server/runtime/index.js +253 -253
  224. package/server/runtime/queue.js +599 -599
  225. package/server/runtime/replay.js +666 -666
  226. package/server/runtime/sandbox.js +266 -266
  227. package/server/runtime/scheduler.js +534 -534
  228. package/server/runtime/session-engine.js +293 -293
  229. package/server/runtime/state-manager.js +188 -188
  230. package/server/secrets/wab-signing-key.pem +3 -0
  231. package/server/secrets/wab-signing-pub.pem +3 -0
  232. package/server/security/cross-site-redactor.js +196 -196
  233. package/server/security/dry-run.js +180 -180
  234. package/server/security/human-gate-rate-limit.js +147 -147
  235. package/server/security/human-gate-transports.js +178 -178
  236. package/server/security/human-gate.js +281 -281
  237. package/server/security/index.js +368 -368
  238. package/server/security/intent-engine.js +245 -245
  239. package/server/security/reward-guard.js +171 -171
  240. package/server/security/rollback-store.js +239 -239
  241. package/server/security/token-scope.js +404 -404
  242. package/server/security/url-policy.js +139 -139
  243. package/server/services/adoption-agent.js +182 -0
  244. package/server/services/agent-chat.js +506 -506
  245. package/server/services/agent-learning.js +601 -601
  246. package/server/services/agent-memory.js +625 -625
  247. package/server/services/agent-mesh.js +555 -555
  248. package/server/services/agent-symphony.js +717 -717
  249. package/server/services/agent-tasks.js +1807 -1807
  250. package/server/services/api-key-engine.js +292 -292
  251. package/server/services/cluster.js +894 -894
  252. package/server/services/commander.js +738 -738
  253. package/server/services/edge-compute.js +440 -440
  254. package/server/services/email.js +233 -233
  255. package/server/services/fairness-engine.js +409 -0
  256. package/server/services/fairness.js +420 -0
  257. package/server/services/governance.js +466 -466
  258. package/server/services/hosted-runtime.js +205 -205
  259. package/server/services/lfd.js +635 -635
  260. package/server/services/local-ai.js +389 -389
  261. package/server/services/marketplace.js +270 -270
  262. package/server/services/metering.js +182 -182
  263. package/server/services/modules/affiliate-intelligence.js +93 -93
  264. package/server/services/modules/agent-firewall.js +90 -90
  265. package/server/services/modules/bounty.js +89 -89
  266. package/server/services/modules/collective-bargaining.js +92 -92
  267. package/server/services/modules/dark-pattern.js +66 -66
  268. package/server/services/modules/gov-intelligence.js +45 -45
  269. package/server/services/modules/neural.js +55 -55
  270. package/server/services/modules/notary.js +49 -49
  271. package/server/services/modules/price-time-machine.js +86 -86
  272. package/server/services/modules/protocol.js +104 -104
  273. package/server/services/negotiation.js +439 -439
  274. package/server/services/outreach-agent.js +312 -0
  275. package/server/services/plans.js +214 -214
  276. package/server/services/plugins.js +771 -771
  277. package/server/services/price-intelligence.js +566 -566
  278. package/server/services/price-shield.js +1137 -1137
  279. package/server/services/provider-clients.js +740 -740
  280. package/server/services/reputation.js +465 -465
  281. package/server/services/search-engine.js +357 -357
  282. package/server/services/security.js +513 -513
  283. package/server/services/self-healing.js +843 -843
  284. package/server/services/shieldlink.js +492 -0
  285. package/server/services/shieldqr.js +322 -322
  286. package/server/services/sovereign-shield.js +542 -542
  287. package/server/services/ssl-ct-monitor.js +224 -0
  288. package/server/services/ssl-inspector.js +42 -42
  289. package/server/services/ssl-monitor.js +167 -167
  290. package/server/services/stripe.js +206 -205
  291. package/server/services/swarm.js +788 -788
  292. package/server/services/transactions.js +525 -0
  293. package/server/services/universal-scraper.js +662 -662
  294. package/server/services/verification.js +481 -481
  295. package/server/services/vision.js +1163 -1163
  296. package/server/services/wab-crypto.js +178 -178
  297. package/server/utils/cache.js +125 -125
  298. package/server/utils/migrate.js +81 -81
  299. package/server/utils/safe-fetch.js +228 -228
  300. package/server/utils/secureFields.js +50 -50
  301. package/server/ws.js +161 -161
  302. package/templates/artisan-marketplace.yaml +104 -104
  303. package/templates/book-price-scout.yaml +98 -98
  304. package/templates/electronics-price-tracker.yaml +108 -108
  305. package/templates/flight-deal-hunter.yaml +113 -113
  306. package/templates/freelancer-direct.yaml +116 -116
  307. package/templates/grocery-price-compare.yaml +93 -93
  308. package/templates/hotel-direct-booking.yaml +113 -113
  309. package/templates/local-services.yaml +98 -98
  310. package/templates/olive-oil-tunisia.yaml +88 -88
  311. package/templates/organic-farm-fresh.yaml +101 -101
  312. package/templates/restaurant-direct.yaml +97 -97
  313. package/templates/ring4/banking-sovereign.yaml +55 -0
  314. package/templates/ring4/ecommerce-sovereign.yaml +58 -0
  315. package/templates/ring4/healthcare-sovereign.yaml +60 -0
package/sdk/index.js CHANGED
@@ -1,649 +1,653 @@
1
- /**
2
- * WAB Agent SDK
3
- *
4
- * Helpers for building AI agents that interact with Web Agent Bridge.
5
- * Works with Puppeteer, Playwright, or any browser automation tool.
6
- *
7
- * Usage:
8
- * const { WABAgent } = require('./sdk');
9
- * const agent = new WABAgent(page);
10
- * await agent.waitForBridge();
11
- * const actions = await agent.getActions();
12
- * await agent.execute('signup', { email: 'test@example.com' });
13
- */
14
-
15
- class WABAgent {
16
- /**
17
- * @param {object} page — A Puppeteer or Playwright page object
18
- * @param {object} [options]
19
- * @param {number} [options.timeout=10000] — Default timeout in ms
20
- * @param {boolean} [options.useBiDi=false] — Use BiDi interface instead of AICommands
21
- */
22
- constructor(page, options = {}) {
23
- this.page = page;
24
- this.timeout = options.timeout || 10000;
25
- this.useBiDi = options.useBiDi || false;
26
- this._biDiId = 0;
27
- }
28
-
29
- /**
30
- * Wait for the WAB bridge to be ready on the page.
31
- * @returns {Promise<boolean>}
32
- */
33
- async waitForBridge() {
34
- const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
35
- await this.page.waitForFunction(
36
- (name) => typeof window[name] !== 'undefined',
37
- { timeout: this.timeout },
38
- iface
39
- );
40
- return true;
41
- }
42
-
43
- /**
44
- * Check if the bridge is loaded on the current page.
45
- * @returns {Promise<boolean>}
46
- */
47
- async hasBridge() {
48
- const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
49
- return this.page.evaluate((name) => typeof window[name] !== 'undefined', iface);
50
- }
51
-
52
- /**
53
- * Get all available actions.
54
- * @param {string} [category] — Optional category filter
55
- * @returns {Promise<Array>}
56
- */
57
- async getActions(category) {
58
- if (this.useBiDi) {
59
- const result = await this._bidiSend('wab.getActions', category ? { category } : {});
60
- return result.result || [];
61
- }
62
- return this.page.evaluate((cat) => window.AICommands.getActions(cat), category);
63
- }
64
-
65
- /**
66
- * Get a single action by name.
67
- * @param {string} name
68
- * @returns {Promise<object|null>}
69
- */
70
- async getAction(name) {
71
- return this.page.evaluate((n) => window.AICommands.getAction(n), name);
72
- }
73
-
74
- /**
75
- * Execute an action by name.
76
- * @param {string} name — Action name
77
- * @param {object} [params] — Action parameters
78
- * @returns {Promise<object>}
79
- */
80
- async execute(name, params) {
81
- if (this.useBiDi) {
82
- const result = await this._bidiSend('wab.executeAction', { name, data: params || {} });
83
- return result.result || result;
84
- }
85
- return this.page.evaluate(
86
- (n, p) => window.AICommands.execute(n, p),
87
- name, params
88
- );
89
- }
90
-
91
- /**
92
- * Read text content of an element.
93
- * @param {string} selector — CSS selector
94
- * @returns {Promise<object>}
95
- */
96
- async readContent(selector) {
97
- if (this.useBiDi) {
98
- const result = await this._bidiSend('wab.readContent', { selector });
99
- return result.result || result;
100
- }
101
- return this.page.evaluate((sel) => window.AICommands.readContent(sel), selector);
102
- }
103
-
104
- /**
105
- * Get page info and bridge metadata.
106
- * @returns {Promise<object>}
107
- */
108
- async getPageInfo() {
109
- if (this.useBiDi) {
110
- const result = await this._bidiSend('wab.getPageInfo');
111
- return result.result || result;
112
- }
113
- return this.page.evaluate(() => window.AICommands.getPageInfo());
114
- }
115
-
116
- /**
117
- * Authenticate an agent with the bridge.
118
- * @param {string} apiKey
119
- * @param {object} [meta] — Agent metadata
120
- * @returns {Promise<object>}
121
- */
122
- async authenticate(apiKey, meta) {
123
- return this.page.evaluate(
124
- (key, m) => window.AICommands.authenticate(key, m),
125
- apiKey, meta
126
- );
127
- }
128
-
129
- /**
130
- * Navigate to a URL and wait for the bridge.
131
- * @param {string} url
132
- * @returns {Promise<void>}
133
- */
134
- async navigateAndWait(url) {
135
- await this.page.goto(url, { waitUntil: 'networkidle2' });
136
- await this.waitForBridge();
137
- }
138
-
139
- /**
140
- * Execute multiple actions in sequence.
141
- * @param {Array<{name: string, params?: object}>} steps
142
- * @returns {Promise<Array>}
143
- */
144
- async executeSteps(steps) {
145
- const results = [];
146
- for (const step of steps) {
147
- results.push(await this.execute(step.name, step.params));
148
- }
149
- return results;
150
- }
151
-
152
- /**
153
- * Get BiDi context (only available when useBiDi is true).
154
- * @returns {Promise<object>}
155
- */
156
- async getBiDiContext() {
157
- return this.page.evaluate(() => window.__wab_bidi.getContext());
158
- }
159
-
160
- /**
161
- * Check if the page has granted consent for agent interactions.
162
- * @returns {Promise<boolean>}
163
- */
164
- async hasConsent() {
165
- return this.page.evaluate(() => {
166
- if (typeof window.WABConsent !== 'undefined') return window.WABConsent.hasConsent();
167
- // If no consent script, treat as allowed
168
- return true;
169
- });
170
- }
171
-
172
- /**
173
- * Wait until consent is granted (blocks until user clicks Allow).
174
- * @param {number} [pollMs=500]
175
- * @returns {Promise<boolean>}
176
- */
177
- async waitForConsent(pollMs = 500) {
178
- return this.page.waitForFunction(
179
- () => {
180
- if (typeof window.WABConsent === 'undefined') return true;
181
- return window.WABConsent.hasConsent();
182
- },
183
- { timeout: this.timeout, polling: pollMs }
184
- ).then(() => true);
185
- }
186
-
187
- /**
188
- * Discover the page and return the list of actions.
189
- * Combines bridge discovery with runtime getActions().
190
- * @returns {Promise<object>}
191
- */
192
- async discover() {
193
- return this.page.evaluate(() => {
194
- if (window.WAB && typeof window.WAB.discover === 'function') return window.WAB.discover();
195
- if (window.AICommands && typeof window.AICommands.getActions === 'function') {
196
- return { actions: window.AICommands.getActions(), meta: window.AICommands.getPageInfo ? window.AICommands.getPageInfo() : {} };
197
- }
198
- return { actions: [] };
199
- });
200
- }
201
-
202
- /**
203
- * Run a sequence of actions, stopping on the first failure.
204
- * @param {Array<{name: string, params?: object}>} steps
205
- * @param {{ stopOnError?: boolean }} [options]
206
- * @returns {Promise<Array<{ name: string, ok: boolean, result?: any, error?: string }>>}
207
- */
208
- async runPipeline(steps, options = {}) {
209
- const stopOnError = options.stopOnError !== false;
210
- const results = [];
211
- for (const step of steps) {
212
- try {
213
- const res = await this.execute(step.name, step.params);
214
- results.push({ name: step.name, ok: true, result: res });
215
- } catch (err) {
216
- results.push({ name: step.name, ok: false, error: err.message || String(err) });
217
- if (stopOnError) break;
218
- }
219
- }
220
- return results;
221
- }
222
-
223
- /**
224
- * Execute multiple actions in parallel.
225
- * @param {Array<{name: string, params?: object}>} actions
226
- * @returns {Promise<Array<{ name: string, status: string, value?: any, reason?: string }>>}
227
- */
228
- async executeParallel(actions) {
229
- const promises = actions.map((a) =>
230
- this.execute(a.name, a.params)
231
- .then((value) => ({ name: a.name, status: 'fulfilled', value }))
232
- .catch((err) => ({ name: a.name, status: 'rejected', reason: err.message || String(err) }))
233
- );
234
- return Promise.all(promises);
235
- }
236
-
237
- /**
238
- * Take a screenshot and return as base64 (useful for vision agents).
239
- * @param {{ fullPage?: boolean }} [opts]
240
- * @returns {Promise<string>}
241
- */
242
- async screenshot(opts = {}) {
243
- const buf = await this.page.screenshot({
244
- encoding: 'base64',
245
- fullPage: opts.fullPage || false
246
- });
247
- return buf;
248
- }
249
-
250
- /** @private */
251
- async _bidiSend(method, params = {}) {
252
- const cmd = { id: ++this._biDiId, method, params };
253
- return this.page.evaluate((c) => window.__wab_bidi.send(c), cmd);
254
- }
255
- }
256
-
257
- /**
258
- * WABUniversalAgent — Works on ANY page, no bridge script needed.
259
- * Uses server-side extraction, analysis, and comparison APIs.
260
- */
261
- class WABUniversalAgent {
262
- /**
263
- * @param {string} [serverUrl='http://localhost:3000'] — WAB server URL
264
- */
265
- constructor(serverUrl = 'http://localhost:3000') {
266
- this.serverUrl = serverUrl.replace(/\/$/, '');
267
- }
268
-
269
- /** @private */
270
- async _post(path, body) {
271
- const res = await fetch(`${this.serverUrl}${path}`, {
272
- method: 'POST',
273
- headers: { 'Content-Type': 'application/json' },
274
- body: JSON.stringify(body),
275
- });
276
- if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
277
- return res.json();
278
- }
279
-
280
- /** @private */
281
- async _get(path) {
282
- const res = await fetch(`${this.serverUrl}${path}`);
283
- if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
284
- return res.json();
285
- }
286
-
287
- /**
288
- * Extract products, prices, and metadata from any URL.
289
- * @param {string} url
290
- * @returns {Promise<object>}
291
- */
292
- async extract(url) {
293
- return this._post('/api/universal/extract', { url });
294
- }
295
-
296
- /**
297
- * Full analysis: extract + fairness + fraud detection + dark patterns.
298
- * @param {string} url
299
- * @returns {Promise<object>}
300
- */
301
- async analyze(url) {
302
- return this._post('/api/universal/analyze', { url });
303
- }
304
-
305
- /**
306
- * Compare prices across multiple sources.
307
- * @param {string} query — Product or service to search for
308
- * @param {string} [category='product'] — 'product', 'hotel', 'flight'
309
- * @returns {Promise<object>}
310
- */
311
- async compare(query, category = 'product') {
312
- return this._post('/api/universal/compare', { query, category });
313
- }
314
-
315
- /**
316
- * Find and rank the best deals with fairness scoring.
317
- * @param {string} query
318
- * @param {string} [category='product']
319
- * @param {string} [lang='en']
320
- * @returns {Promise<object>}
321
- */
322
- async deals(query, category = 'product', lang = 'en') {
323
- return this._post('/api/universal/deals', { query, category, lang });
324
- }
325
-
326
- /**
327
- * Get fairness score for a domain.
328
- * @param {string} domain
329
- * @returns {Promise<object>}
330
- */
331
- async fairness(domain) {
332
- return this._post('/api/universal/fairness', { domain });
333
- }
334
-
335
- /**
336
- * Detect dark patterns on a URL.
337
- * @param {string} url
338
- * @returns {Promise<object>}
339
- */
340
- async darkPatterns(url) {
341
- return this._post('/api/universal/dark-patterns', { url });
342
- }
343
-
344
- /**
345
- * Get price history for a domain.
346
- * @param {string} domain
347
- * @returns {Promise<object>}
348
- */
349
- async priceHistory(domain) {
350
- return this._get(`/api/universal/history?domain=${encodeURIComponent(domain)}`);
351
- }
352
-
353
- /**
354
- * Get top fairness-scored sites.
355
- * @param {number} [limit=20]
356
- * @returns {Promise<object>}
357
- */
358
- async topFair(limit = 20) {
359
- return this._get(`/api/universal/top-fair?limit=${limit}`);
360
- }
361
-
362
- /**
363
- * Get all known competing sources.
364
- * @returns {Promise<object>}
365
- */
366
- async sources() {
367
- return this._get('/api/universal/sources');
368
- }
369
- }
370
-
371
- const { WABMultiAgent } = require('./multi-agent');
372
- const { WABAgentMesh } = require('./agent-mesh');
373
-
374
- // ─── WAB Agent OS Client ────────────────────────────────────────────────────
375
-
376
- /**
377
- * WABAgentOS — Client for the Agent OS runtime.
378
- * Provides access to protocol, tasks, execution, registry, observability, and LLM.
379
- */
380
- class WABAgentOS {
381
- /**
382
- * @param {object} options
383
- * @param {string} options.serverUrl — WAB server base URL
384
- * @param {string} [options.agentId] — Pre-registered agent ID
385
- * @param {string} [options.apiKey] — Pre-registered API key
386
- * @param {string} [options.sessionToken] — Active session token
387
- */
388
- constructor(options = {}) {
389
- this.serverUrl = (options.serverUrl || 'http://localhost:3000').replace(/\/$/, '');
390
- this.agentId = options.agentId || null;
391
- this.apiKey = options.apiKey || null;
392
- this.sessionToken = options.sessionToken || null;
393
- this._base = `${this.serverUrl}/api/os`;
394
- }
395
-
396
- // ─── Agent Identity ───────────────────────────────────────────────────
397
-
398
- async register(name, type, capabilities = []) {
399
- const res = await this._post('/agents/register', { name, type, capabilities });
400
- this.agentId = res.agentId;
401
- this.apiKey = res.apiKey;
402
- return res;
403
- }
404
-
405
- async authenticate(apiKey) {
406
- const res = await this._post('/agents/authenticate', { apiKey: apiKey || this.apiKey });
407
- if (res.sessionToken) this.sessionToken = res.sessionToken;
408
- return res;
409
- }
410
-
411
- async negotiateCapabilities(capabilities, siteId) {
412
- return this._post(`/agents/${this.agentId}/capabilities`, { capabilities, siteId });
413
- }
414
-
415
- // ─── Protocol ─────────────────────────────────────────────────────────
416
-
417
- async getProtocol() {
418
- return this._get('/protocol');
419
- }
420
-
421
- async sendMessage(command, payload = {}) {
422
- return this._post('/protocol/message', { command, payload, agentId: this.agentId });
423
- }
424
-
425
- // ─── Tasks ────────────────────────────────────────────────────────────
426
-
427
- async submitTask(task) {
428
- return this._post('/tasks', task);
429
- }
430
-
431
- async getTask(taskId) {
432
- return this._get(`/tasks/${taskId}`);
433
- }
434
-
435
- async listTasks(state, limit) {
436
- const params = [];
437
- if (state) params.push(`state=${state}`);
438
- if (limit) params.push(`limit=${limit}`);
439
- return this._get(`/tasks${params.length ? '?' + params.join('&') : ''}`);
440
- }
441
-
442
- async cancelTask(taskId) {
443
- return this._delete(`/tasks/${taskId}`);
444
- }
445
-
446
- async pauseTask(taskId) {
447
- return this._post(`/tasks/${taskId}/pause`);
448
- }
449
-
450
- async resumeTask(taskId) {
451
- return this._post(`/tasks/${taskId}/resume`);
452
- }
453
-
454
- // ─── Execution ────────────────────────────────────────────────────────
455
-
456
- async execute(command) {
457
- return this._post('/execute', command);
458
- }
459
-
460
- async executeSemantic(domain, action, params = {}) {
461
- return this._post('/execute/semantic', { domain, action, params, agentId: this.agentId });
462
- }
463
-
464
- async executePipeline(steps) {
465
- return this._post('/execute/pipeline', { steps });
466
- }
467
-
468
- async resolveAction(domain, action, siteDomain) {
469
- const params = `domain=${domain}&action=${action}${siteDomain ? `&siteDomain=${siteDomain}` : ''}`;
470
- return this._get(`/execute/resolve?${params}`);
471
- }
472
-
473
- // ─── Registry ─────────────────────────────────────────────────────────
474
-
475
- async searchCommands(query = {}) {
476
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
477
- return this._get(`/registry/commands${params ? '?' + params : ''}`);
478
- }
479
-
480
- async registerCommand(siteId, command) {
481
- return this._post('/registry/commands', { siteId, ...command });
482
- }
483
-
484
- async searchSites(query = {}) {
485
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
486
- return this._get(`/registry/sites${params ? '?' + params : ''}`);
487
- }
488
-
489
- async registerSite(domain, info) {
490
- return this._post('/registry/sites', { domain, ...info });
491
- }
492
-
493
- async searchTemplates(query = {}) {
494
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
495
- return this._get(`/registry/templates${params ? '?' + params : ''}`);
496
- }
497
-
498
- async getTemplate(templateId) {
499
- return this._get(`/registry/templates/${templateId}`);
500
- }
501
-
502
- // ─── LLM ──────────────────────────────────────────────────────────────
503
-
504
- async complete(prompt, options = {}) {
505
- return this._post('/llm/complete', { prompt, options });
506
- }
507
-
508
- async embed(text, options = {}) {
509
- return this._post('/llm/embed', { text, options });
510
- }
511
-
512
- async listModels() {
513
- return this._get('/llm/models');
514
- }
515
-
516
- // ─── Observability ────────────────────────────────────────────────────
517
-
518
- async getMetrics() {
519
- return this._get('/observability/metrics');
520
- }
521
-
522
- async getTraces(query = {}) {
523
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
524
- return this._get(`/observability/traces${params ? '?' + params : ''}`);
525
- }
526
-
527
- async getTrace(traceId) {
528
- return this._get(`/observability/traces/${traceId}`);
529
- }
530
-
531
- async getLogs(query = {}) {
532
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
533
- return this._get(`/observability/logs${params ? '?' + params : ''}`);
534
- }
535
-
536
- async getHealth() {
537
- return this._get('/observability/health');
538
- }
539
-
540
- // ─── Events (SSE) ────────────────────────────────────────────────────
541
-
542
- subscribe(filter, onEvent) {
543
- if (typeof EventSource === 'undefined') {
544
- throw new Error('EventSource not available. Use a polyfill for Node.js.');
545
- }
546
- const url = `${this._base}/events${filter ? '?filter=' + encodeURIComponent(filter) : ''}`;
547
- const es = new EventSource(url);
548
- es.onmessage = (e) => {
549
- try { onEvent(JSON.parse(e.data)); } catch { onEvent(e.data); }
550
- };
551
- return es; // Call es.close() to unsubscribe
552
- }
553
-
554
- // ─── Policies ─────────────────────────────────────────────────────────
555
-
556
- async createPolicy(policy) {
557
- return this._post('/policies', policy);
558
- }
559
-
560
- async evaluatePolicy(entityId, action, context = {}) {
561
- return this._post('/policies/evaluate', { entityId, action, context });
562
- }
563
-
564
- // ─── Deploy ───────────────────────────────────────────────────────────
565
-
566
- async deploy(config = {}) {
567
- return this._post('/deployments', { agentId: this.agentId, config });
568
- }
569
-
570
- async listDeployments(query = {}) {
571
- const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
572
- return this._get(`/deployments${params ? '?' + params : ''}`);
573
- }
574
-
575
- // ─── HTTP Helpers ─────────────────────────────────────────────────────
576
-
577
- async _get(path) {
578
- const url = `${this._base}${path}`;
579
- const headers = this._headers();
580
- const res = await fetch(url, { headers });
581
- if (!res.ok) {
582
- const body = await res.json().catch(() => ({ error: res.statusText }));
583
- throw new Error(body.error || `HTTP ${res.status}`);
584
- }
585
- return res.json();
586
- }
587
-
588
- async _post(path, body) {
589
- const url = `${this._base}${path}`;
590
- const headers = { ...this._headers(), 'Content-Type': 'application/json' };
591
- const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
592
- if (!res.ok) {
593
- const data = await res.json().catch(() => ({ error: res.statusText }));
594
- throw new Error(data.error || `HTTP ${res.status}`);
595
- }
596
- return res.json();
597
- }
598
-
599
- async _delete(path) {
600
- const url = `${this._base}${path}`;
601
- const headers = this._headers();
602
- const res = await fetch(url, { method: 'DELETE', headers });
603
- if (!res.ok) {
604
- const data = await res.json().catch(() => ({ error: res.statusText }));
605
- throw new Error(data.error || `HTTP ${res.status}`);
606
- }
607
- return res.json();
608
- }
609
-
610
- _headers() {
611
- const h = {};
612
- if (this.sessionToken) h['Authorization'] = `Bearer ${this.sessionToken}`;
613
- else if (this.apiKey) h['X-WAB-Key'] = this.apiKey;
614
- if (this.agentId) h['X-WAB-Agent'] = this.agentId;
615
- return h;
616
- }
617
- }
618
-
619
- // Re-export WABToolkit from langchain package for convenience
620
- let WABToolkit;
621
- try { WABToolkit = require('../packages/langchain').WABToolkit; } catch {
622
- try { WABToolkit = require('web-agent-bridge-langchain').WABToolkit; } catch {}
623
- }
624
-
625
- // SPEC §8.10–§8.13 client helper
626
- const { SafetyShieldClient } = require('./safety-shield');
627
- // Phase 19 — Safe Mode trust gate
628
- const { WABSafeMode, WABSafeModeError, POLICIES: WAB_SAFE_POLICIES } = require('./safe-mode');
629
- // Phase 20 — Agent Governance Layer (permissions + approval + audit + kill-switch)
630
- const { WABGovernance, WABGovernanceError } = require('./governance');
631
- // Zero-Config Adoption — Auto-Discovery fallback for sites without /.well-known/wab.json
632
- const autoDiscovery = require('./auto-discovery');
633
-
634
- module.exports = {
635
- WABAgent,
636
- WABUniversalAgent,
637
- WABMultiAgent,
638
- WABAgentMesh,
639
- WABAgentOS,
640
- WABToolkit,
641
- SafetyShieldClient,
642
- WABSafeMode,
643
- WABSafeModeError,
644
- WAB_SAFE_POLICIES,
645
- WABGovernance,
646
- WABGovernanceError,
647
- autoDiscovery,
648
- discover: autoDiscovery.discover,
649
- };
1
+ /**
2
+ * WAB Agent SDK
3
+ *
4
+ * Helpers for building AI agents that interact with Web Agent Bridge.
5
+ * Works with Puppeteer, Playwright, or any browser automation tool.
6
+ *
7
+ * Usage:
8
+ * const { WABAgent } = require('./sdk');
9
+ * const agent = new WABAgent(page);
10
+ * await agent.waitForBridge();
11
+ * const actions = await agent.getActions();
12
+ * await agent.execute('signup', { email: 'test@example.com' });
13
+ */
14
+
15
+ class WABAgent {
16
+ /**
17
+ * @param {object} page — A Puppeteer or Playwright page object
18
+ * @param {object} [options]
19
+ * @param {number} [options.timeout=10000] — Default timeout in ms
20
+ * @param {boolean} [options.useBiDi=false] — Use BiDi interface instead of AICommands
21
+ */
22
+ constructor(page, options = {}) {
23
+ this.page = page;
24
+ this.timeout = options.timeout || 10000;
25
+ this.useBiDi = options.useBiDi || false;
26
+ this._biDiId = 0;
27
+ }
28
+
29
+ /**
30
+ * Wait for the WAB bridge to be ready on the page.
31
+ * @returns {Promise<boolean>}
32
+ */
33
+ async waitForBridge() {
34
+ const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
35
+ await this.page.waitForFunction(
36
+ (name) => typeof window[name] !== 'undefined',
37
+ { timeout: this.timeout },
38
+ iface
39
+ );
40
+ return true;
41
+ }
42
+
43
+ /**
44
+ * Check if the bridge is loaded on the current page.
45
+ * @returns {Promise<boolean>}
46
+ */
47
+ async hasBridge() {
48
+ const iface = this.useBiDi ? '__wab_bidi' : 'AICommands';
49
+ return this.page.evaluate((name) => typeof window[name] !== 'undefined', iface);
50
+ }
51
+
52
+ /**
53
+ * Get all available actions.
54
+ * @param {string} [category] — Optional category filter
55
+ * @returns {Promise<Array>}
56
+ */
57
+ async getActions(category) {
58
+ if (this.useBiDi) {
59
+ const result = await this._bidiSend('wab.getActions', category ? { category } : {});
60
+ return result.result || [];
61
+ }
62
+ return this.page.evaluate((cat) => window.AICommands.getActions(cat), category);
63
+ }
64
+
65
+ /**
66
+ * Get a single action by name.
67
+ * @param {string} name
68
+ * @returns {Promise<object|null>}
69
+ */
70
+ async getAction(name) {
71
+ return this.page.evaluate((n) => window.AICommands.getAction(n), name);
72
+ }
73
+
74
+ /**
75
+ * Execute an action by name.
76
+ * @param {string} name — Action name
77
+ * @param {object} [params] — Action parameters
78
+ * @returns {Promise<object>}
79
+ */
80
+ async execute(name, params) {
81
+ if (this.useBiDi) {
82
+ const result = await this._bidiSend('wab.executeAction', { name, data: params || {} });
83
+ return result.result || result;
84
+ }
85
+ return this.page.evaluate(
86
+ (n, p) => window.AICommands.execute(n, p),
87
+ name, params
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Read text content of an element.
93
+ * @param {string} selector — CSS selector
94
+ * @returns {Promise<object>}
95
+ */
96
+ async readContent(selector) {
97
+ if (this.useBiDi) {
98
+ const result = await this._bidiSend('wab.readContent', { selector });
99
+ return result.result || result;
100
+ }
101
+ return this.page.evaluate((sel) => window.AICommands.readContent(sel), selector);
102
+ }
103
+
104
+ /**
105
+ * Get page info and bridge metadata.
106
+ * @returns {Promise<object>}
107
+ */
108
+ async getPageInfo() {
109
+ if (this.useBiDi) {
110
+ const result = await this._bidiSend('wab.getPageInfo');
111
+ return result.result || result;
112
+ }
113
+ return this.page.evaluate(() => window.AICommands.getPageInfo());
114
+ }
115
+
116
+ /**
117
+ * Authenticate an agent with the bridge.
118
+ * @param {string} apiKey
119
+ * @param {object} [meta] — Agent metadata
120
+ * @returns {Promise<object>}
121
+ */
122
+ async authenticate(apiKey, meta) {
123
+ return this.page.evaluate(
124
+ (key, m) => window.AICommands.authenticate(key, m),
125
+ apiKey, meta
126
+ );
127
+ }
128
+
129
+ /**
130
+ * Navigate to a URL and wait for the bridge.
131
+ * @param {string} url
132
+ * @returns {Promise<void>}
133
+ */
134
+ async navigateAndWait(url) {
135
+ await this.page.goto(url, { waitUntil: 'networkidle2' });
136
+ await this.waitForBridge();
137
+ }
138
+
139
+ /**
140
+ * Execute multiple actions in sequence.
141
+ * @param {Array<{name: string, params?: object}>} steps
142
+ * @returns {Promise<Array>}
143
+ */
144
+ async executeSteps(steps) {
145
+ const results = [];
146
+ for (const step of steps) {
147
+ results.push(await this.execute(step.name, step.params));
148
+ }
149
+ return results;
150
+ }
151
+
152
+ /**
153
+ * Get BiDi context (only available when useBiDi is true).
154
+ * @returns {Promise<object>}
155
+ */
156
+ async getBiDiContext() {
157
+ return this.page.evaluate(() => window.__wab_bidi.getContext());
158
+ }
159
+
160
+ /**
161
+ * Check if the page has granted consent for agent interactions.
162
+ * @returns {Promise<boolean>}
163
+ */
164
+ async hasConsent() {
165
+ return this.page.evaluate(() => {
166
+ if (typeof window.WABConsent !== 'undefined') return window.WABConsent.hasConsent();
167
+ // If no consent script, treat as allowed
168
+ return true;
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Wait until consent is granted (blocks until user clicks Allow).
174
+ * @param {number} [pollMs=500]
175
+ * @returns {Promise<boolean>}
176
+ */
177
+ async waitForConsent(pollMs = 500) {
178
+ return this.page.waitForFunction(
179
+ () => {
180
+ if (typeof window.WABConsent === 'undefined') return true;
181
+ return window.WABConsent.hasConsent();
182
+ },
183
+ { timeout: this.timeout, polling: pollMs }
184
+ ).then(() => true);
185
+ }
186
+
187
+ /**
188
+ * Discover the page and return the list of actions.
189
+ * Combines bridge discovery with runtime getActions().
190
+ * @returns {Promise<object>}
191
+ */
192
+ async discover() {
193
+ return this.page.evaluate(() => {
194
+ if (window.WAB && typeof window.WAB.discover === 'function') return window.WAB.discover();
195
+ if (window.AICommands && typeof window.AICommands.getActions === 'function') {
196
+ return { actions: window.AICommands.getActions(), meta: window.AICommands.getPageInfo ? window.AICommands.getPageInfo() : {} };
197
+ }
198
+ return { actions: [] };
199
+ });
200
+ }
201
+
202
+ /**
203
+ * Run a sequence of actions, stopping on the first failure.
204
+ * @param {Array<{name: string, params?: object}>} steps
205
+ * @param {{ stopOnError?: boolean }} [options]
206
+ * @returns {Promise<Array<{ name: string, ok: boolean, result?: any, error?: string }>>}
207
+ */
208
+ async runPipeline(steps, options = {}) {
209
+ const stopOnError = options.stopOnError !== false;
210
+ const results = [];
211
+ for (const step of steps) {
212
+ try {
213
+ const res = await this.execute(step.name, step.params);
214
+ results.push({ name: step.name, ok: true, result: res });
215
+ } catch (err) {
216
+ results.push({ name: step.name, ok: false, error: err.message || String(err) });
217
+ if (stopOnError) break;
218
+ }
219
+ }
220
+ return results;
221
+ }
222
+
223
+ /**
224
+ * Execute multiple actions in parallel.
225
+ * @param {Array<{name: string, params?: object}>} actions
226
+ * @returns {Promise<Array<{ name: string, status: string, value?: any, reason?: string }>>}
227
+ */
228
+ async executeParallel(actions) {
229
+ const promises = actions.map((a) =>
230
+ this.execute(a.name, a.params)
231
+ .then((value) => ({ name: a.name, status: 'fulfilled', value }))
232
+ .catch((err) => ({ name: a.name, status: 'rejected', reason: err.message || String(err) }))
233
+ );
234
+ return Promise.all(promises);
235
+ }
236
+
237
+ /**
238
+ * Take a screenshot and return as base64 (useful for vision agents).
239
+ * @param {{ fullPage?: boolean }} [opts]
240
+ * @returns {Promise<string>}
241
+ */
242
+ async screenshot(opts = {}) {
243
+ const buf = await this.page.screenshot({
244
+ encoding: 'base64',
245
+ fullPage: opts.fullPage || false
246
+ });
247
+ return buf;
248
+ }
249
+
250
+ /** @private */
251
+ async _bidiSend(method, params = {}) {
252
+ const cmd = { id: ++this._biDiId, method, params };
253
+ return this.page.evaluate((c) => window.__wab_bidi.send(c), cmd);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * WABUniversalAgent — Works on ANY page, no bridge script needed.
259
+ * Uses server-side extraction, analysis, and comparison APIs.
260
+ */
261
+ class WABUniversalAgent {
262
+ /**
263
+ * @param {string} [serverUrl='http://localhost:3000'] — WAB server URL
264
+ */
265
+ constructor(serverUrl = 'http://localhost:3000') {
266
+ this.serverUrl = serverUrl.replace(/\/$/, '');
267
+ }
268
+
269
+ /** @private */
270
+ async _post(path, body) {
271
+ const res = await fetch(`${this.serverUrl}${path}`, {
272
+ method: 'POST',
273
+ headers: { 'Content-Type': 'application/json' },
274
+ body: JSON.stringify(body),
275
+ });
276
+ if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
277
+ return res.json();
278
+ }
279
+
280
+ /** @private */
281
+ async _get(path) {
282
+ const res = await fetch(`${this.serverUrl}${path}`);
283
+ if (!res.ok) throw new Error(`WAB API error ${res.status}: ${await res.text()}`);
284
+ return res.json();
285
+ }
286
+
287
+ /**
288
+ * Extract products, prices, and metadata from any URL.
289
+ * @param {string} url
290
+ * @returns {Promise<object>}
291
+ */
292
+ async extract(url) {
293
+ return this._post('/api/universal/extract', { url });
294
+ }
295
+
296
+ /**
297
+ * Full analysis: extract + fairness + fraud detection + dark patterns.
298
+ * @param {string} url
299
+ * @returns {Promise<object>}
300
+ */
301
+ async analyze(url) {
302
+ return this._post('/api/universal/analyze', { url });
303
+ }
304
+
305
+ /**
306
+ * Compare prices across multiple sources.
307
+ * @param {string} query — Product or service to search for
308
+ * @param {string} [category='product'] — 'product', 'hotel', 'flight'
309
+ * @returns {Promise<object>}
310
+ */
311
+ async compare(query, category = 'product') {
312
+ return this._post('/api/universal/compare', { query, category });
313
+ }
314
+
315
+ /**
316
+ * Find and rank the best deals with fairness scoring.
317
+ * @param {string} query
318
+ * @param {string} [category='product']
319
+ * @param {string} [lang='en']
320
+ * @returns {Promise<object>}
321
+ */
322
+ async deals(query, category = 'product', lang = 'en') {
323
+ return this._post('/api/universal/deals', { query, category, lang });
324
+ }
325
+
326
+ /**
327
+ * Get fairness score for a domain.
328
+ * @param {string} domain
329
+ * @returns {Promise<object>}
330
+ */
331
+ async fairness(domain) {
332
+ return this._post('/api/universal/fairness', { domain });
333
+ }
334
+
335
+ /**
336
+ * Detect dark patterns on a URL.
337
+ * @param {string} url
338
+ * @returns {Promise<object>}
339
+ */
340
+ async darkPatterns(url) {
341
+ return this._post('/api/universal/dark-patterns', { url });
342
+ }
343
+
344
+ /**
345
+ * Get price history for a domain.
346
+ * @param {string} domain
347
+ * @returns {Promise<object>}
348
+ */
349
+ async priceHistory(domain) {
350
+ return this._get(`/api/universal/history?domain=${encodeURIComponent(domain)}`);
351
+ }
352
+
353
+ /**
354
+ * Get top fairness-scored sites.
355
+ * @param {number} [limit=20]
356
+ * @returns {Promise<object>}
357
+ */
358
+ async topFair(limit = 20) {
359
+ return this._get(`/api/universal/top-fair?limit=${limit}`);
360
+ }
361
+
362
+ /**
363
+ * Get all known competing sources.
364
+ * @returns {Promise<object>}
365
+ */
366
+ async sources() {
367
+ return this._get('/api/universal/sources');
368
+ }
369
+ }
370
+
371
+ const { WABMultiAgent } = require('./multi-agent');
372
+ const { WABAgentMesh } = require('./agent-mesh');
373
+
374
+ // ─── WAB Agent OS Client ────────────────────────────────────────────────────
375
+
376
+ /**
377
+ * WABAgentOS — Client for the Agent OS runtime.
378
+ * Provides access to protocol, tasks, execution, registry, observability, and LLM.
379
+ */
380
+ class WABAgentOS {
381
+ /**
382
+ * @param {object} options
383
+ * @param {string} options.serverUrl — WAB server base URL
384
+ * @param {string} [options.agentId] — Pre-registered agent ID
385
+ * @param {string} [options.apiKey] — Pre-registered API key
386
+ * @param {string} [options.sessionToken] — Active session token
387
+ */
388
+ constructor(options = {}) {
389
+ this.serverUrl = (options.serverUrl || 'http://localhost:3000').replace(/\/$/, '');
390
+ this.agentId = options.agentId || null;
391
+ this.apiKey = options.apiKey || null;
392
+ this.sessionToken = options.sessionToken || null;
393
+ this._base = `${this.serverUrl}/api/os`;
394
+ }
395
+
396
+ // ─── Agent Identity ───────────────────────────────────────────────────
397
+
398
+ async register(name, type, capabilities = []) {
399
+ const res = await this._post('/agents/register', { name, type, capabilities });
400
+ this.agentId = res.agentId;
401
+ this.apiKey = res.apiKey;
402
+ return res;
403
+ }
404
+
405
+ async authenticate(apiKey) {
406
+ const res = await this._post('/agents/authenticate', { apiKey: apiKey || this.apiKey });
407
+ if (res.sessionToken) this.sessionToken = res.sessionToken;
408
+ return res;
409
+ }
410
+
411
+ async negotiateCapabilities(capabilities, siteId) {
412
+ return this._post(`/agents/${this.agentId}/capabilities`, { capabilities, siteId });
413
+ }
414
+
415
+ // ─── Protocol ─────────────────────────────────────────────────────────
416
+
417
+ async getProtocol() {
418
+ return this._get('/protocol');
419
+ }
420
+
421
+ async sendMessage(command, payload = {}) {
422
+ return this._post('/protocol/message', { command, payload, agentId: this.agentId });
423
+ }
424
+
425
+ // ─── Tasks ────────────────────────────────────────────────────────────
426
+
427
+ async submitTask(task) {
428
+ return this._post('/tasks', task);
429
+ }
430
+
431
+ async getTask(taskId) {
432
+ return this._get(`/tasks/${taskId}`);
433
+ }
434
+
435
+ async listTasks(state, limit) {
436
+ const params = [];
437
+ if (state) params.push(`state=${state}`);
438
+ if (limit) params.push(`limit=${limit}`);
439
+ return this._get(`/tasks${params.length ? '?' + params.join('&') : ''}`);
440
+ }
441
+
442
+ async cancelTask(taskId) {
443
+ return this._delete(`/tasks/${taskId}`);
444
+ }
445
+
446
+ async pauseTask(taskId) {
447
+ return this._post(`/tasks/${taskId}/pause`);
448
+ }
449
+
450
+ async resumeTask(taskId) {
451
+ return this._post(`/tasks/${taskId}/resume`);
452
+ }
453
+
454
+ // ─── Execution ────────────────────────────────────────────────────────
455
+
456
+ async execute(command) {
457
+ return this._post('/execute', command);
458
+ }
459
+
460
+ async executeSemantic(domain, action, params = {}) {
461
+ return this._post('/execute/semantic', { domain, action, params, agentId: this.agentId });
462
+ }
463
+
464
+ async executePipeline(steps) {
465
+ return this._post('/execute/pipeline', { steps });
466
+ }
467
+
468
+ async resolveAction(domain, action, siteDomain) {
469
+ const params = `domain=${domain}&action=${action}${siteDomain ? `&siteDomain=${siteDomain}` : ''}`;
470
+ return this._get(`/execute/resolve?${params}`);
471
+ }
472
+
473
+ // ─── Registry ─────────────────────────────────────────────────────────
474
+
475
+ async searchCommands(query = {}) {
476
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
477
+ return this._get(`/registry/commands${params ? '?' + params : ''}`);
478
+ }
479
+
480
+ async registerCommand(siteId, command) {
481
+ return this._post('/registry/commands', { siteId, ...command });
482
+ }
483
+
484
+ async searchSites(query = {}) {
485
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
486
+ return this._get(`/registry/sites${params ? '?' + params : ''}`);
487
+ }
488
+
489
+ async registerSite(domain, info) {
490
+ return this._post('/registry/sites', { domain, ...info });
491
+ }
492
+
493
+ async searchTemplates(query = {}) {
494
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
495
+ return this._get(`/registry/templates${params ? '?' + params : ''}`);
496
+ }
497
+
498
+ async getTemplate(templateId) {
499
+ return this._get(`/registry/templates/${templateId}`);
500
+ }
501
+
502
+ // ─── LLM ──────────────────────────────────────────────────────────────
503
+
504
+ async complete(prompt, options = {}) {
505
+ return this._post('/llm/complete', { prompt, options });
506
+ }
507
+
508
+ async embed(text, options = {}) {
509
+ return this._post('/llm/embed', { text, options });
510
+ }
511
+
512
+ async listModels() {
513
+ return this._get('/llm/models');
514
+ }
515
+
516
+ // ─── Observability ────────────────────────────────────────────────────
517
+
518
+ async getMetrics() {
519
+ return this._get('/observability/metrics');
520
+ }
521
+
522
+ async getTraces(query = {}) {
523
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
524
+ return this._get(`/observability/traces${params ? '?' + params : ''}`);
525
+ }
526
+
527
+ async getTrace(traceId) {
528
+ return this._get(`/observability/traces/${traceId}`);
529
+ }
530
+
531
+ async getLogs(query = {}) {
532
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
533
+ return this._get(`/observability/logs${params ? '?' + params : ''}`);
534
+ }
535
+
536
+ async getHealth() {
537
+ return this._get('/observability/health');
538
+ }
539
+
540
+ // ─── Events (SSE) ────────────────────────────────────────────────────
541
+
542
+ subscribe(filter, onEvent) {
543
+ if (typeof EventSource === 'undefined') {
544
+ throw new Error('EventSource not available. Use a polyfill for Node.js.');
545
+ }
546
+ const url = `${this._base}/events${filter ? '?filter=' + encodeURIComponent(filter) : ''}`;
547
+ const es = new EventSource(url);
548
+ es.onmessage = (e) => {
549
+ try { onEvent(JSON.parse(e.data)); } catch { onEvent(e.data); }
550
+ };
551
+ return es; // Call es.close() to unsubscribe
552
+ }
553
+
554
+ // ─── Policies ─────────────────────────────────────────────────────────
555
+
556
+ async createPolicy(policy) {
557
+ return this._post('/policies', policy);
558
+ }
559
+
560
+ async evaluatePolicy(entityId, action, context = {}) {
561
+ return this._post('/policies/evaluate', { entityId, action, context });
562
+ }
563
+
564
+ // ─── Deploy ───────────────────────────────────────────────────────────
565
+
566
+ async deploy(config = {}) {
567
+ return this._post('/deployments', { agentId: this.agentId, config });
568
+ }
569
+
570
+ async listDeployments(query = {}) {
571
+ const params = Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
572
+ return this._get(`/deployments${params ? '?' + params : ''}`);
573
+ }
574
+
575
+ // ─── HTTP Helpers ─────────────────────────────────────────────────────
576
+
577
+ async _get(path) {
578
+ const url = `${this._base}${path}`;
579
+ const headers = this._headers();
580
+ const res = await fetch(url, { headers });
581
+ if (!res.ok) {
582
+ const body = await res.json().catch(() => ({ error: res.statusText }));
583
+ throw new Error(body.error || `HTTP ${res.status}`);
584
+ }
585
+ return res.json();
586
+ }
587
+
588
+ async _post(path, body) {
589
+ const url = `${this._base}${path}`;
590
+ const headers = { ...this._headers(), 'Content-Type': 'application/json' };
591
+ const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
592
+ if (!res.ok) {
593
+ const data = await res.json().catch(() => ({ error: res.statusText }));
594
+ throw new Error(data.error || `HTTP ${res.status}`);
595
+ }
596
+ return res.json();
597
+ }
598
+
599
+ async _delete(path) {
600
+ const url = `${this._base}${path}`;
601
+ const headers = this._headers();
602
+ const res = await fetch(url, { method: 'DELETE', headers });
603
+ if (!res.ok) {
604
+ const data = await res.json().catch(() => ({ error: res.statusText }));
605
+ throw new Error(data.error || `HTTP ${res.status}`);
606
+ }
607
+ return res.json();
608
+ }
609
+
610
+ _headers() {
611
+ const h = {};
612
+ if (this.sessionToken) h['Authorization'] = `Bearer ${this.sessionToken}`;
613
+ else if (this.apiKey) h['X-WAB-Key'] = this.apiKey;
614
+ if (this.agentId) h['X-WAB-Agent'] = this.agentId;
615
+ return h;
616
+ }
617
+ }
618
+
619
+ // Re-export WABToolkit from langchain package for convenience
620
+ let WABToolkit;
621
+ try { WABToolkit = require('../packages/langchain').WABToolkit; } catch {
622
+ try { WABToolkit = require('web-agent-bridge-langchain').WABToolkit; } catch {}
623
+ }
624
+
625
+ // SPEC §8.10–§8.13 client helper
626
+ const { SafetyShieldClient } = require('./safety-shield');
627
+ // Phase 19 — Safe Mode trust gate
628
+ const { WABSafeMode, WABSafeModeError, POLICIES: WAB_SAFE_POLICIES } = require('./safe-mode');
629
+ // Phase 20 — Agent Governance Layer (permissions + approval + audit + kill-switch)
630
+ const { WABGovernance, WABGovernanceError } = require('./governance');
631
+ // Zero-Config Adoption — Auto-Discovery fallback for sites without /.well-known/wab.json
632
+ const autoDiscovery = require('./auto-discovery');
633
+ // Agent Transaction Primitive (v3.9.0) — intent → authorization → execution → receipt.
634
+ const { ATPClient, ATPError } = require('./atp');
635
+
636
+ module.exports = {
637
+ WABAgent,
638
+ WABUniversalAgent,
639
+ WABMultiAgent,
640
+ WABAgentMesh,
641
+ WABAgentOS,
642
+ WABToolkit,
643
+ SafetyShieldClient,
644
+ WABSafeMode,
645
+ WABSafeModeError,
646
+ WAB_SAFE_POLICIES,
647
+ WABGovernance,
648
+ WABGovernanceError,
649
+ autoDiscovery,
650
+ discover: autoDiscovery.discover,
651
+ ATPClient,
652
+ ATPError,
653
+ };