@harrylabsj/kiwi 0.6.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 (636) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +150 -0
  3. package/contracts/candidate-agent-dto-1.0.README.md +39 -0
  4. package/contracts/candidate-agent-dto-1.0.schema.json +172 -0
  5. package/contracts/interop/kiwi-buyer-message-send.json +43 -0
  6. package/contracts/interop/knp-data-part-examples.json +243 -0
  7. package/contracts/kiwi-catalog/1.0/agent-record.schema.json +78 -0
  8. package/contracts/kiwi-catalog/1.0/listing-record.schema.json +88 -0
  9. package/contracts/kiwi-catalog/1.0/listing-search-result.schema.json +60 -0
  10. package/contracts/negotiation/1.0/schema.json +501 -0
  11. package/contracts/shopping.negotiation/0.1/capabilities.schema.json +47 -0
  12. package/contracts/shopping.negotiation/0.1/decision.schema.json +120 -0
  13. package/contracts/shopping.negotiation/0.1/policy-result.schema.json +52 -0
  14. package/contracts/shopping.negotiation/0.1/snapshot.schema.json +172 -0
  15. package/dist/a2a/client/client.d.ts +33 -0
  16. package/dist/a2a/client/client.js +161 -0
  17. package/dist/a2a/client/client.js.map +1 -0
  18. package/dist/a2a/client/error.d.ts +35 -0
  19. package/dist/a2a/client/error.js +34 -0
  20. package/dist/a2a/client/error.js.map +1 -0
  21. package/dist/a2a/client/index.d.ts +29 -0
  22. package/dist/a2a/client/index.js +26 -0
  23. package/dist/a2a/client/index.js.map +1 -0
  24. package/dist/a2a/client/jsonrpc.d.ts +49 -0
  25. package/dist/a2a/client/jsonrpc.js +85 -0
  26. package/dist/a2a/client/jsonrpc.js.map +1 -0
  27. package/dist/a2a/client/parse.d.ts +18 -0
  28. package/dist/a2a/client/parse.js +134 -0
  29. package/dist/a2a/client/parse.js.map +1 -0
  30. package/dist/a2a/client/types.d.ts +102 -0
  31. package/dist/a2a/client/types.js +26 -0
  32. package/dist/a2a/client/types.js.map +1 -0
  33. package/dist/a2a/client/url-policy.d.ts +44 -0
  34. package/dist/a2a/client/url-policy.js +242 -0
  35. package/dist/a2a/client/url-policy.js.map +1 -0
  36. package/dist/a2a/negotiate.d.ts +68 -0
  37. package/dist/a2a/negotiate.js +288 -0
  38. package/dist/a2a/negotiate.js.map +1 -0
  39. package/dist/a2a/node.d.ts +37 -0
  40. package/dist/a2a/node.js +155 -0
  41. package/dist/a2a/node.js.map +1 -0
  42. package/dist/a2a/server/auth.d.ts +38 -0
  43. package/dist/a2a/server/auth.js +112 -0
  44. package/dist/a2a/server/auth.js.map +1 -0
  45. package/dist/a2a/server/card.d.ts +19 -0
  46. package/dist/a2a/server/card.js +81 -0
  47. package/dist/a2a/server/card.js.map +1 -0
  48. package/dist/a2a/server/errors.d.ts +109 -0
  49. package/dist/a2a/server/errors.js +178 -0
  50. package/dist/a2a/server/errors.js.map +1 -0
  51. package/dist/a2a/server/handler.d.ts +22 -0
  52. package/dist/a2a/server/handler.js +57 -0
  53. package/dist/a2a/server/handler.js.map +1 -0
  54. package/dist/a2a/server/inbound-message.d.ts +37 -0
  55. package/dist/a2a/server/inbound-message.js +104 -0
  56. package/dist/a2a/server/inbound-message.js.map +1 -0
  57. package/dist/a2a/server/index.d.ts +43 -0
  58. package/dist/a2a/server/index.js +42 -0
  59. package/dist/a2a/server/index.js.map +1 -0
  60. package/dist/a2a/server/merchant-handler.d.ts +69 -0
  61. package/dist/a2a/server/merchant-handler.js +316 -0
  62. package/dist/a2a/server/merchant-handler.js.map +1 -0
  63. package/dist/a2a/server/pipeline.d.ts +69 -0
  64. package/dist/a2a/server/pipeline.js +329 -0
  65. package/dist/a2a/server/pipeline.js.map +1 -0
  66. package/dist/a2a/server/server.d.ts +64 -0
  67. package/dist/a2a/server/server.js +420 -0
  68. package/dist/a2a/server/server.js.map +1 -0
  69. package/dist/a2a/server/task-registry.d.ts +31 -0
  70. package/dist/a2a/server/task-registry.js +67 -0
  71. package/dist/a2a/server/task-registry.js.map +1 -0
  72. package/dist/a2a/server/throttle.d.ts +154 -0
  73. package/dist/a2a/server/throttle.js +289 -0
  74. package/dist/a2a/server/throttle.js.map +1 -0
  75. package/dist/a2a/server/types.d.ts +191 -0
  76. package/dist/a2a/server/types.js +17 -0
  77. package/dist/a2a/server/types.js.map +1 -0
  78. package/dist/a2a/server/ucp.d.ts +49 -0
  79. package/dist/a2a/server/ucp.js +85 -0
  80. package/dist/a2a/server/ucp.js.map +1 -0
  81. package/dist/a2a/task/index.d.ts +24 -0
  82. package/dist/a2a/task/index.js +22 -0
  83. package/dist/a2a/task/index.js.map +1 -0
  84. package/dist/a2a/task/ledger.d.ts +48 -0
  85. package/dist/a2a/task/ledger.js +65 -0
  86. package/dist/a2a/task/ledger.js.map +1 -0
  87. package/dist/a2a/task/poller.d.ts +93 -0
  88. package/dist/a2a/task/poller.js +184 -0
  89. package/dist/a2a/task/poller.js.map +1 -0
  90. package/dist/a2a/task/state.d.ts +72 -0
  91. package/dist/a2a/task/state.js +119 -0
  92. package/dist/a2a/task/state.js.map +1 -0
  93. package/dist/a2a/ucp-agent.d.ts +49 -0
  94. package/dist/a2a/ucp-agent.js +78 -0
  95. package/dist/a2a/ucp-agent.js.map +1 -0
  96. package/dist/agent/agent-db.d.ts +31 -0
  97. package/dist/agent/agent-db.js +91 -0
  98. package/dist/agent/agent-db.js.map +1 -0
  99. package/dist/agent/buyer/buyer-tools.d.ts +70 -0
  100. package/dist/agent/buyer/buyer-tools.js +1353 -0
  101. package/dist/agent/buyer/buyer-tools.js.map +1 -0
  102. package/dist/agent/buyer/ranker.d.ts +53 -0
  103. package/dist/agent/buyer/ranker.js +153 -0
  104. package/dist/agent/buyer/ranker.js.map +1 -0
  105. package/dist/agent/buyer/scheduler.d.ts +58 -0
  106. package/dist/agent/buyer/scheduler.js +317 -0
  107. package/dist/agent/buyer/scheduler.js.map +1 -0
  108. package/dist/agent/buyer/search-loop.d.ts +42 -0
  109. package/dist/agent/buyer/search-loop.js +280 -0
  110. package/dist/agent/buyer/search-loop.js.map +1 -0
  111. package/dist/agent/buyer/task-store.d.ts +178 -0
  112. package/dist/agent/buyer/task-store.js +637 -0
  113. package/dist/agent/buyer/task-store.js.map +1 -0
  114. package/dist/agent/buyer/types.d.ts +222 -0
  115. package/dist/agent/buyer/types.js +124 -0
  116. package/dist/agent/buyer/types.js.map +1 -0
  117. package/dist/agent/chat-tools.d.ts +41 -0
  118. package/dist/agent/chat-tools.js +193 -0
  119. package/dist/agent/chat-tools.js.map +1 -0
  120. package/dist/agent/chat-tui.d.ts +49 -0
  121. package/dist/agent/chat-tui.js +314 -0
  122. package/dist/agent/chat-tui.js.map +1 -0
  123. package/dist/agent/connector/fake-connector.d.ts +50 -0
  124. package/dist/agent/connector/fake-connector.js +138 -0
  125. package/dist/agent/connector/fake-connector.js.map +1 -0
  126. package/dist/agent/connector/http-connector.d.ts +49 -0
  127. package/dist/agent/connector/http-connector.js +208 -0
  128. package/dist/agent/connector/http-connector.js.map +1 -0
  129. package/dist/agent/connector/types.d.ts +103 -0
  130. package/dist/agent/connector/types.js +97 -0
  131. package/dist/agent/connector/types.js.map +1 -0
  132. package/dist/agent/fake-chat-model.d.ts +22 -0
  133. package/dist/agent/fake-chat-model.js +134 -0
  134. package/dist/agent/fake-chat-model.js.map +1 -0
  135. package/dist/agent/kernel.d.ts +258 -0
  136. package/dist/agent/kernel.js +1099 -0
  137. package/dist/agent/kernel.js.map +1 -0
  138. package/dist/agent/memory/schema.d.ts +32 -0
  139. package/dist/agent/memory/schema.js +291 -0
  140. package/dist/agent/memory/schema.js.map +1 -0
  141. package/dist/agent/memory/store.d.ts +193 -0
  142. package/dist/agent/memory/store.js +881 -0
  143. package/dist/agent/memory/store.js.map +1 -0
  144. package/dist/agent/memory/types.d.ts +139 -0
  145. package/dist/agent/memory/types.js +119 -0
  146. package/dist/agent/memory/types.js.map +1 -0
  147. package/dist/agent/memory/vault.d.ts +49 -0
  148. package/dist/agent/memory/vault.js +125 -0
  149. package/dist/agent/memory/vault.js.map +1 -0
  150. package/dist/agent/merchant/action-candidate.d.ts +106 -0
  151. package/dist/agent/merchant/action-candidate.js +241 -0
  152. package/dist/agent/merchant/action-candidate.js.map +1 -0
  153. package/dist/agent/merchant/credential-broker.d.ts +67 -0
  154. package/dist/agent/merchant/credential-broker.js +76 -0
  155. package/dist/agent/merchant/credential-broker.js.map +1 -0
  156. package/dist/agent/merchant/fake-merchant-client.d.ts +47 -0
  157. package/dist/agent/merchant/fake-merchant-client.js +143 -0
  158. package/dist/agent/merchant/fake-merchant-client.js.map +1 -0
  159. package/dist/agent/merchant/merchant-client.d.ts +49 -0
  160. package/dist/agent/merchant/merchant-client.js +186 -0
  161. package/dist/agent/merchant/merchant-client.js.map +1 -0
  162. package/dist/agent/merchant/merchant-tools.d.ts +74 -0
  163. package/dist/agent/merchant/merchant-tools.js +582 -0
  164. package/dist/agent/merchant/merchant-tools.js.map +1 -0
  165. package/dist/agent/merchant/types.d.ts +119 -0
  166. package/dist/agent/merchant/types.js +133 -0
  167. package/dist/agent/merchant/types.js.map +1 -0
  168. package/dist/agent/mode.d.ts +32 -0
  169. package/dist/agent/mode.js +34 -0
  170. package/dist/agent/mode.js.map +1 -0
  171. package/dist/agent/negotiation-chat.d.ts +81 -0
  172. package/dist/agent/negotiation-chat.js +330 -0
  173. package/dist/agent/negotiation-chat.js.map +1 -0
  174. package/dist/agent/session.d.ts +22 -0
  175. package/dist/agent/session.js +164 -0
  176. package/dist/agent/session.js.map +1 -0
  177. package/dist/agent/system-prompt.d.ts +26 -0
  178. package/dist/agent/system-prompt.js +77 -0
  179. package/dist/agent/system-prompt.js.map +1 -0
  180. package/dist/agent/write-gate.d.ts +98 -0
  181. package/dist/agent/write-gate.js +76 -0
  182. package/dist/agent/write-gate.js.map +1 -0
  183. package/dist/cli.d.ts +18 -0
  184. package/dist/cli.js +1139 -0
  185. package/dist/cli.js.map +1 -0
  186. package/dist/commerce/data-source.d.ts +88 -0
  187. package/dist/commerce/data-source.js +25 -0
  188. package/dist/commerce/data-source.js.map +1 -0
  189. package/dist/commerce/erp-source.d.ts +51 -0
  190. package/dist/commerce/erp-source.js +184 -0
  191. package/dist/commerce/erp-source.js.map +1 -0
  192. package/dist/commerce/fake-client.d.ts +167 -0
  193. package/dist/commerce/fake-client.js +549 -0
  194. package/dist/commerce/fake-client.js.map +1 -0
  195. package/dist/commerce/http-client.d.ts +73 -0
  196. package/dist/commerce/http-client.js +284 -0
  197. package/dist/commerce/http-client.js.map +1 -0
  198. package/dist/commerce/local-db-source.d.ts +50 -0
  199. package/dist/commerce/local-db-source.js +162 -0
  200. package/dist/commerce/local-db-source.js.map +1 -0
  201. package/dist/commerce/shopping-cli-source.d.ts +57 -0
  202. package/dist/commerce/shopping-cli-source.js +206 -0
  203. package/dist/commerce/shopping-cli-source.js.map +1 -0
  204. package/dist/commerce/types.d.ts +146 -0
  205. package/dist/commerce/types.js +31 -0
  206. package/dist/commerce/types.js.map +1 -0
  207. package/dist/config/profile.d.ts +122 -0
  208. package/dist/config/profile.js +386 -0
  209. package/dist/config/profile.js.map +1 -0
  210. package/dist/contracts/negotiation-schema.d.ts +28 -0
  211. package/dist/contracts/negotiation-schema.js +101 -0
  212. package/dist/contracts/negotiation-schema.js.map +1 -0
  213. package/dist/contracts/schemas.d.ts +31 -0
  214. package/dist/contracts/schemas.js +122 -0
  215. package/dist/contracts/schemas.js.map +1 -0
  216. package/dist/counterparty/a2a-direct/index.d.ts +41 -0
  217. package/dist/counterparty/a2a-direct/index.js +330 -0
  218. package/dist/counterparty/a2a-direct/index.js.map +1 -0
  219. package/dist/counterparty/channel.d.ts +200 -0
  220. package/dist/counterparty/channel.js +61 -0
  221. package/dist/counterparty/channel.js.map +1 -0
  222. package/dist/counterparty/index.d.ts +28 -0
  223. package/dist/counterparty/index.js +24 -0
  224. package/dist/counterparty/index.js.map +1 -0
  225. package/dist/counterparty/platform-api/index.d.ts +41 -0
  226. package/dist/counterparty/platform-api/index.js +65 -0
  227. package/dist/counterparty/platform-api/index.js.map +1 -0
  228. package/dist/counterparty/registry.d.ts +51 -0
  229. package/dist/counterparty/registry.js +71 -0
  230. package/dist/counterparty/registry.js.map +1 -0
  231. package/dist/counterparty/shopping-cli-hosted/index.d.ts +36 -0
  232. package/dist/counterparty/shopping-cli-hosted/index.js +337 -0
  233. package/dist/counterparty/shopping-cli-hosted/index.js.map +1 -0
  234. package/dist/discovery/agent-card/error.d.ts +28 -0
  235. package/dist/discovery/agent-card/error.js +31 -0
  236. package/dist/discovery/agent-card/error.js.map +1 -0
  237. package/dist/discovery/agent-card/extensions.d.ts +20 -0
  238. package/dist/discovery/agent-card/extensions.js +59 -0
  239. package/dist/discovery/agent-card/extensions.js.map +1 -0
  240. package/dist/discovery/agent-card/index.d.ts +29 -0
  241. package/dist/discovery/agent-card/index.js +38 -0
  242. package/dist/discovery/agent-card/index.js.map +1 -0
  243. package/dist/discovery/agent-card/secrets.d.ts +30 -0
  244. package/dist/discovery/agent-card/secrets.js +240 -0
  245. package/dist/discovery/agent-card/secrets.js.map +1 -0
  246. package/dist/discovery/agent-card/types.d.ts +110 -0
  247. package/dist/discovery/agent-card/types.js +37 -0
  248. package/dist/discovery/agent-card/types.js.map +1 -0
  249. package/dist/discovery/agent-card/validate.d.ts +31 -0
  250. package/dist/discovery/agent-card/validate.js +210 -0
  251. package/dist/discovery/agent-card/validate.js.map +1 -0
  252. package/dist/discovery/capability/error.d.ts +23 -0
  253. package/dist/discovery/capability/error.js +28 -0
  254. package/dist/discovery/capability/error.js.map +1 -0
  255. package/dist/discovery/capability/index.d.ts +21 -0
  256. package/dist/discovery/capability/index.js +21 -0
  257. package/dist/discovery/capability/index.js.map +1 -0
  258. package/dist/discovery/capability/intersect.d.ts +56 -0
  259. package/dist/discovery/capability/intersect.js +137 -0
  260. package/dist/discovery/capability/intersect.js.map +1 -0
  261. package/dist/discovery/catalog-source/errors.d.ts +32 -0
  262. package/dist/discovery/catalog-source/errors.js +41 -0
  263. package/dist/discovery/catalog-source/errors.js.map +1 -0
  264. package/dist/discovery/catalog-source/index.d.ts +30 -0
  265. package/dist/discovery/catalog-source/index.js +29 -0
  266. package/dist/discovery/catalog-source/index.js.map +1 -0
  267. package/dist/discovery/catalog-source/kiwi-record.d.ts +183 -0
  268. package/dist/discovery/catalog-source/kiwi-record.js +72 -0
  269. package/dist/discovery/catalog-source/kiwi-record.js.map +1 -0
  270. package/dist/discovery/catalog-source/kiwi-schema.d.ts +33 -0
  271. package/dist/discovery/catalog-source/kiwi-schema.js +106 -0
  272. package/dist/discovery/catalog-source/kiwi-schema.js.map +1 -0
  273. package/dist/discovery/catalog-source/kiwi-source.d.ts +38 -0
  274. package/dist/discovery/catalog-source/kiwi-source.js +318 -0
  275. package/dist/discovery/catalog-source/kiwi-source.js.map +1 -0
  276. package/dist/discovery/catalog-source/register.d.ts +48 -0
  277. package/dist/discovery/catalog-source/register.js +83 -0
  278. package/dist/discovery/catalog-source/register.js.map +1 -0
  279. package/dist/discovery/catalog-source/schema.d.ts +21 -0
  280. package/dist/discovery/catalog-source/schema.js +63 -0
  281. package/dist/discovery/catalog-source/schema.js.map +1 -0
  282. package/dist/discovery/catalog-source/source.d.ts +45 -0
  283. package/dist/discovery/catalog-source/source.js +197 -0
  284. package/dist/discovery/catalog-source/source.js.map +1 -0
  285. package/dist/discovery/catalog-source/types.d.ts +122 -0
  286. package/dist/discovery/catalog-source/types.js +30 -0
  287. package/dist/discovery/catalog-source/types.js.map +1 -0
  288. package/dist/discovery/index.d.ts +25 -0
  289. package/dist/discovery/index.js +25 -0
  290. package/dist/discovery/index.js.map +1 -0
  291. package/dist/discovery/resolve.d.ts +175 -0
  292. package/dist/discovery/resolve.js +367 -0
  293. package/dist/discovery/resolve.js.map +1 -0
  294. package/dist/discovery/ucp/error.d.ts +25 -0
  295. package/dist/discovery/ucp/error.js +27 -0
  296. package/dist/discovery/ucp/error.js.map +1 -0
  297. package/dist/discovery/ucp/index.d.ts +33 -0
  298. package/dist/discovery/ucp/index.js +28 -0
  299. package/dist/discovery/ucp/index.js.map +1 -0
  300. package/dist/discovery/ucp/intersect.d.ts +148 -0
  301. package/dist/discovery/ucp/intersect.js +312 -0
  302. package/dist/discovery/ucp/intersect.js.map +1 -0
  303. package/dist/discovery/ucp/resolver.d.ts +62 -0
  304. package/dist/discovery/ucp/resolver.js +214 -0
  305. package/dist/discovery/ucp/resolver.js.map +1 -0
  306. package/dist/discovery/ucp/types.d.ts +97 -0
  307. package/dist/discovery/ucp/types.js +103 -0
  308. package/dist/discovery/ucp/types.js.map +1 -0
  309. package/dist/discovery/ucp/validate.d.ts +38 -0
  310. package/dist/discovery/ucp/validate.js +232 -0
  311. package/dist/discovery/ucp/validate.js.map +1 -0
  312. package/dist/discovery/ucp/vendor.d.ts +60 -0
  313. package/dist/discovery/ucp/vendor.js +61 -0
  314. package/dist/discovery/ucp/vendor.js.map +1 -0
  315. package/dist/doctor.d.ts +26 -0
  316. package/dist/doctor.js +113 -0
  317. package/dist/doctor.js.map +1 -0
  318. package/dist/exit-codes.d.ts +26 -0
  319. package/dist/exit-codes.js +27 -0
  320. package/dist/exit-codes.js.map +1 -0
  321. package/dist/fanout/disclosure.d.ts +138 -0
  322. package/dist/fanout/disclosure.js +188 -0
  323. package/dist/fanout/disclosure.js.map +1 -0
  324. package/dist/fanout/index.d.ts +32 -0
  325. package/dist/fanout/index.js +30 -0
  326. package/dist/fanout/index.js.map +1 -0
  327. package/dist/fanout/orchestrator.d.ts +153 -0
  328. package/dist/fanout/orchestrator.js +439 -0
  329. package/dist/fanout/orchestrator.js.map +1 -0
  330. package/dist/fanout/policy.d.ts +128 -0
  331. package/dist/fanout/policy.js +130 -0
  332. package/dist/fanout/policy.js.map +1 -0
  333. package/dist/handoff/acp-commerce.d.ts +58 -0
  334. package/dist/handoff/acp-commerce.js +69 -0
  335. package/dist/handoff/acp-commerce.js.map +1 -0
  336. package/dist/handoff/authorization.d.ts +127 -0
  337. package/dist/handoff/authorization.js +107 -0
  338. package/dist/handoff/authorization.js.map +1 -0
  339. package/dist/handoff/candidate.d.ts +94 -0
  340. package/dist/handoff/candidate.js +172 -0
  341. package/dist/handoff/candidate.js.map +1 -0
  342. package/dist/handoff/channel.d.ts +88 -0
  343. package/dist/handoff/channel.js +189 -0
  344. package/dist/handoff/channel.js.map +1 -0
  345. package/dist/handoff/completion.d.ts +44 -0
  346. package/dist/handoff/completion.js +136 -0
  347. package/dist/handoff/completion.js.map +1 -0
  348. package/dist/handoff/delivery.d.ts +59 -0
  349. package/dist/handoff/delivery.js +185 -0
  350. package/dist/handoff/delivery.js.map +1 -0
  351. package/dist/handoff/destination.d.ts +39 -0
  352. package/dist/handoff/destination.js +99 -0
  353. package/dist/handoff/destination.js.map +1 -0
  354. package/dist/handoff/errors.d.ts +34 -0
  355. package/dist/handoff/errors.js +47 -0
  356. package/dist/handoff/errors.js.map +1 -0
  357. package/dist/handoff/idempotency.d.ts +51 -0
  358. package/dist/handoff/idempotency.js +168 -0
  359. package/dist/handoff/idempotency.js.map +1 -0
  360. package/dist/handoff/index.d.ts +46 -0
  361. package/dist/handoff/index.js +48 -0
  362. package/dist/handoff/index.js.map +1 -0
  363. package/dist/handoff/ledger.d.ts +94 -0
  364. package/dist/handoff/ledger.js +195 -0
  365. package/dist/handoff/ledger.js.map +1 -0
  366. package/dist/handoff/lifecycle.d.ts +29 -0
  367. package/dist/handoff/lifecycle.js +102 -0
  368. package/dist/handoff/lifecycle.js.map +1 -0
  369. package/dist/handoff/metrics.d.ts +56 -0
  370. package/dist/handoff/metrics.js +78 -0
  371. package/dist/handoff/metrics.js.map +1 -0
  372. package/dist/handoff/operator-approval.d.ts +143 -0
  373. package/dist/handoff/operator-approval.js +287 -0
  374. package/dist/handoff/operator-approval.js.map +1 -0
  375. package/dist/handoff/order-record.d.ts +104 -0
  376. package/dist/handoff/order-record.js +235 -0
  377. package/dist/handoff/order-record.js.map +1 -0
  378. package/dist/handoff/package.d.ts +102 -0
  379. package/dist/handoff/package.js +132 -0
  380. package/dist/handoff/package.js.map +1 -0
  381. package/dist/handoff/transaction.d.ts +96 -0
  382. package/dist/handoff/transaction.js +263 -0
  383. package/dist/handoff/transaction.js.map +1 -0
  384. package/dist/handoff/ucp-checkout/cart-channel.d.ts +111 -0
  385. package/dist/handoff/ucp-checkout/cart-channel.js +370 -0
  386. package/dist/handoff/ucp-checkout/cart-channel.js.map +1 -0
  387. package/dist/handoff/ucp-checkout/cart-parse.d.ts +22 -0
  388. package/dist/handoff/ucp-checkout/cart-parse.js +102 -0
  389. package/dist/handoff/ucp-checkout/cart-parse.js.map +1 -0
  390. package/dist/handoff/ucp-checkout/cart-types.d.ts +93 -0
  391. package/dist/handoff/ucp-checkout/cart-types.js +38 -0
  392. package/dist/handoff/ucp-checkout/cart-types.js.map +1 -0
  393. package/dist/handoff/ucp-checkout/channel.d.ts +159 -0
  394. package/dist/handoff/ucp-checkout/channel.js +636 -0
  395. package/dist/handoff/ucp-checkout/channel.js.map +1 -0
  396. package/dist/handoff/ucp-checkout/client.d.ts +88 -0
  397. package/dist/handoff/ucp-checkout/client.js +228 -0
  398. package/dist/handoff/ucp-checkout/client.js.map +1 -0
  399. package/dist/handoff/ucp-checkout/endpoint.d.ts +36 -0
  400. package/dist/handoff/ucp-checkout/endpoint.js +145 -0
  401. package/dist/handoff/ucp-checkout/endpoint.js.map +1 -0
  402. package/dist/handoff/ucp-checkout/index.d.ts +35 -0
  403. package/dist/handoff/ucp-checkout/index.js +36 -0
  404. package/dist/handoff/ucp-checkout/index.js.map +1 -0
  405. package/dist/handoff/ucp-checkout/parse.d.ts +71 -0
  406. package/dist/handoff/ucp-checkout/parse.js +349 -0
  407. package/dist/handoff/ucp-checkout/parse.js.map +1 -0
  408. package/dist/handoff/ucp-checkout/totals.d.ts +41 -0
  409. package/dist/handoff/ucp-checkout/totals.js +36 -0
  410. package/dist/handoff/ucp-checkout/totals.js.map +1 -0
  411. package/dist/handoff/ucp-checkout/types.d.ts +149 -0
  412. package/dist/handoff/ucp-checkout/types.js +58 -0
  413. package/dist/handoff/ucp-checkout/types.js.map +1 -0
  414. package/dist/handoff/url-safety.d.ts +44 -0
  415. package/dist/handoff/url-safety.js +121 -0
  416. package/dist/handoff/url-safety.js.map +1 -0
  417. package/dist/i18n.d.ts +24 -0
  418. package/dist/i18n.js +27 -0
  419. package/dist/i18n.js.map +1 -0
  420. package/dist/negotiation/action-candidate.d.ts +97 -0
  421. package/dist/negotiation/action-candidate.js +160 -0
  422. package/dist/negotiation/action-candidate.js.map +1 -0
  423. package/dist/negotiation/condition/evaluator.d.ts +36 -0
  424. package/dist/negotiation/condition/evaluator.js +123 -0
  425. package/dist/negotiation/condition/evaluator.js.map +1 -0
  426. package/dist/negotiation/context-map/index.d.ts +23 -0
  427. package/dist/negotiation/context-map/index.js +22 -0
  428. package/dist/negotiation/context-map/index.js.map +1 -0
  429. package/dist/negotiation/context-map/store.d.ts +51 -0
  430. package/dist/negotiation/context-map/store.js +186 -0
  431. package/dist/negotiation/context-map/store.js.map +1 -0
  432. package/dist/negotiation/context-map/types.d.ts +29 -0
  433. package/dist/negotiation/context-map/types.js +57 -0
  434. package/dist/negotiation/context-map/types.js.map +1 -0
  435. package/dist/negotiation/domain/common.d.ts +95 -0
  436. package/dist/negotiation/domain/common.js +216 -0
  437. package/dist/negotiation/domain/common.js.map +1 -0
  438. package/dist/negotiation/domain/envelope.d.ts +55 -0
  439. package/dist/negotiation/domain/envelope.js +110 -0
  440. package/dist/negotiation/domain/envelope.js.map +1 -0
  441. package/dist/negotiation/domain/identifiers.d.ts +65 -0
  442. package/dist/negotiation/domain/identifiers.js +130 -0
  443. package/dist/negotiation/domain/identifiers.js.map +1 -0
  444. package/dist/negotiation/domain/objects.d.ts +149 -0
  445. package/dist/negotiation/domain/objects.js +335 -0
  446. package/dist/negotiation/domain/objects.js.map +1 -0
  447. package/dist/negotiation/idempotency/index.d.ts +26 -0
  448. package/dist/negotiation/idempotency/index.js +25 -0
  449. package/dist/negotiation/idempotency/index.js.map +1 -0
  450. package/dist/negotiation/idempotency/store.d.ts +52 -0
  451. package/dist/negotiation/idempotency/store.js +189 -0
  452. package/dist/negotiation/idempotency/store.js.map +1 -0
  453. package/dist/negotiation/idempotency/types.d.ts +102 -0
  454. package/dist/negotiation/idempotency/types.js +47 -0
  455. package/dist/negotiation/idempotency/types.js.map +1 -0
  456. package/dist/negotiation/jcs.d.ts +21 -0
  457. package/dist/negotiation/jcs.js +114 -0
  458. package/dist/negotiation/jcs.js.map +1 -0
  459. package/dist/negotiation/ledger/event.d.ts +142 -0
  460. package/dist/negotiation/ledger/event.js +206 -0
  461. package/dist/negotiation/ledger/event.js.map +1 -0
  462. package/dist/negotiation/ledger/index.d.ts +26 -0
  463. package/dist/negotiation/ledger/index.js +25 -0
  464. package/dist/negotiation/ledger/index.js.map +1 -0
  465. package/dist/negotiation/ledger/store.d.ts +97 -0
  466. package/dist/negotiation/ledger/store.js +338 -0
  467. package/dist/negotiation/ledger/store.js.map +1 -0
  468. package/dist/negotiation/prompt.d.ts +34 -0
  469. package/dist/negotiation/prompt.js +113 -0
  470. package/dist/negotiation/prompt.js.map +1 -0
  471. package/dist/negotiation/recovery/index.d.ts +26 -0
  472. package/dist/negotiation/recovery/index.js +24 -0
  473. package/dist/negotiation/recovery/index.js.map +1 -0
  474. package/dist/negotiation/recovery/outbound.d.ts +49 -0
  475. package/dist/negotiation/recovery/outbound.js +34 -0
  476. package/dist/negotiation/recovery/outbound.js.map +1 -0
  477. package/dist/negotiation/recovery/recover.d.ts +59 -0
  478. package/dist/negotiation/recovery/recover.js +486 -0
  479. package/dist/negotiation/recovery/recover.js.map +1 -0
  480. package/dist/negotiation/recovery/types.d.ts +85 -0
  481. package/dist/negotiation/recovery/types.js +17 -0
  482. package/dist/negotiation/recovery/types.js.map +1 -0
  483. package/dist/negotiation/state/phase.d.ts +70 -0
  484. package/dist/negotiation/state/phase.js +200 -0
  485. package/dist/negotiation/state/phase.js.map +1 -0
  486. package/dist/negotiation/types.d.ts +139 -0
  487. package/dist/negotiation/types.js +24 -0
  488. package/dist/negotiation/types.js.map +1 -0
  489. package/dist/net/safe-http.d.ts +54 -0
  490. package/dist/net/safe-http.js +116 -0
  491. package/dist/net/safe-http.js.map +1 -0
  492. package/dist/operator/controller.d.ts +181 -0
  493. package/dist/operator/controller.js +784 -0
  494. package/dist/operator/controller.js.map +1 -0
  495. package/dist/operator/runner.d.ts +128 -0
  496. package/dist/operator/runner.js +248 -0
  497. package/dist/operator/runner.js.map +1 -0
  498. package/dist/operator/store.d.ts +39 -0
  499. package/dist/operator/store.js +169 -0
  500. package/dist/operator/store.js.map +1 -0
  501. package/dist/operator/strategy.d.ts +54 -0
  502. package/dist/operator/strategy.js +249 -0
  503. package/dist/operator/strategy.js.map +1 -0
  504. package/dist/operator/tui.d.ts +27 -0
  505. package/dist/operator/tui.js +395 -0
  506. package/dist/operator/tui.js.map +1 -0
  507. package/dist/operator/types.d.ts +224 -0
  508. package/dist/operator/types.js +17 -0
  509. package/dist/operator/types.js.map +1 -0
  510. package/dist/product-buyer.d.ts +74 -0
  511. package/dist/product-buyer.js +161 -0
  512. package/dist/product-buyer.js.map +1 -0
  513. package/dist/product-cli.d.ts +56 -0
  514. package/dist/product-cli.js +175 -0
  515. package/dist/product-cli.js.map +1 -0
  516. package/dist/product-compat.d.ts +50 -0
  517. package/dist/product-compat.js +63 -0
  518. package/dist/product-compat.js.map +1 -0
  519. package/dist/product-init.d.ts +73 -0
  520. package/dist/product-init.js +203 -0
  521. package/dist/product-init.js.map +1 -0
  522. package/dist/product-publish.d.ts +85 -0
  523. package/dist/product-publish.js +216 -0
  524. package/dist/product-publish.js.map +1 -0
  525. package/dist/protocol/legacy-shopping-negotiation/adapter.d.ts +42 -0
  526. package/dist/protocol/legacy-shopping-negotiation/adapter.js +561 -0
  527. package/dist/protocol/legacy-shopping-negotiation/adapter.js.map +1 -0
  528. package/dist/protocol/legacy-shopping-negotiation/mapping.d.ts +78 -0
  529. package/dist/protocol/legacy-shopping-negotiation/mapping.js +321 -0
  530. package/dist/protocol/legacy-shopping-negotiation/mapping.js.map +1 -0
  531. package/dist/protocol/legacy-shopping-negotiation/money.d.ts +49 -0
  532. package/dist/protocol/legacy-shopping-negotiation/money.js +70 -0
  533. package/dist/protocol/legacy-shopping-negotiation/money.js.map +1 -0
  534. package/dist/protocol/legacy-shopping-negotiation/types.d.ts +107 -0
  535. package/dist/protocol/legacy-shopping-negotiation/types.js +34 -0
  536. package/dist/protocol/legacy-shopping-negotiation/types.js.map +1 -0
  537. package/dist/runtime/buyer-policy.d.ts +58 -0
  538. package/dist/runtime/buyer-policy.js +89 -0
  539. package/dist/runtime/buyer-policy.js.map +1 -0
  540. package/dist/runtime/fake-model.d.ts +77 -0
  541. package/dist/runtime/fake-model.js +307 -0
  542. package/dist/runtime/fake-model.js.map +1 -0
  543. package/dist/runtime/foreground.d.ts +56 -0
  544. package/dist/runtime/foreground.js +97 -0
  545. package/dist/runtime/foreground.js.map +1 -0
  546. package/dist/runtime/heartbeat.d.ts +36 -0
  547. package/dist/runtime/heartbeat.js +49 -0
  548. package/dist/runtime/heartbeat.js.map +1 -0
  549. package/dist/runtime/merchant-turn.d.ts +35 -0
  550. package/dist/runtime/merchant-turn.js +20 -0
  551. package/dist/runtime/merchant-turn.js.map +1 -0
  552. package/dist/runtime/model.d.ts +40 -0
  553. package/dist/runtime/model.js +86 -0
  554. package/dist/runtime/model.js.map +1 -0
  555. package/dist/runtime/negotiation-turn.d.ts +101 -0
  556. package/dist/runtime/negotiation-turn.js +317 -0
  557. package/dist/runtime/negotiation-turn.js.map +1 -0
  558. package/dist/runtime/tools.d.ts +64 -0
  559. package/dist/runtime/tools.js +236 -0
  560. package/dist/runtime/tools.js.map +1 -0
  561. package/dist/supervisor/init.d.ts +31 -0
  562. package/dist/supervisor/init.js +222 -0
  563. package/dist/supervisor/init.js.map +1 -0
  564. package/dist/supervisor/logs.d.ts +28 -0
  565. package/dist/supervisor/logs.js +101 -0
  566. package/dist/supervisor/logs.js.map +1 -0
  567. package/dist/supervisor/manage.d.ts +72 -0
  568. package/dist/supervisor/manage.js +419 -0
  569. package/dist/supervisor/manage.js.map +1 -0
  570. package/dist/supervisor/manifest.d.ts +69 -0
  571. package/dist/supervisor/manifest.js +209 -0
  572. package/dist/supervisor/manifest.js.map +1 -0
  573. package/dist/supervisor/stack-config.d.ts +79 -0
  574. package/dist/supervisor/stack-config.js +262 -0
  575. package/dist/supervisor/stack-config.js.map +1 -0
  576. package/dist/supervisor/wrapper.d.ts +17 -0
  577. package/dist/supervisor/wrapper.js +138 -0
  578. package/dist/supervisor/wrapper.js.map +1 -0
  579. package/dist/trust/identity/auth-verifier.d.ts +96 -0
  580. package/dist/trust/identity/auth-verifier.js +166 -0
  581. package/dist/trust/identity/auth-verifier.js.map +1 -0
  582. package/dist/trust/identity/identity-binding.d.ts +63 -0
  583. package/dist/trust/identity/identity-binding.js +59 -0
  584. package/dist/trust/identity/identity-binding.js.map +1 -0
  585. package/dist/trust/identity/index.d.ts +38 -0
  586. package/dist/trust/identity/index.js +31 -0
  587. package/dist/trust/identity/index.js.map +1 -0
  588. package/dist/trust/identity/jws.d.ts +64 -0
  589. package/dist/trust/identity/jws.js +178 -0
  590. package/dist/trust/identity/jws.js.map +1 -0
  591. package/dist/trust/identity/keys.d.ts +71 -0
  592. package/dist/trust/identity/keys.js +118 -0
  593. package/dist/trust/identity/keys.js.map +1 -0
  594. package/dist/trust/identity/message-signature.d.ts +105 -0
  595. package/dist/trust/identity/message-signature.js +297 -0
  596. package/dist/trust/identity/message-signature.js.map +1 -0
  597. package/dist/trust/identity/nonce.d.ts +45 -0
  598. package/dist/trust/identity/nonce.js +50 -0
  599. package/dist/trust/identity/nonce.js.map +1 -0
  600. package/dist/trust/identity/signature-base.d.ts +84 -0
  601. package/dist/trust/identity/signature-base.js +261 -0
  602. package/dist/trust/identity/signature-base.js.map +1 -0
  603. package/dist/trust/identity/trust-policy.d.ts +92 -0
  604. package/dist/trust/identity/trust-policy.js +95 -0
  605. package/dist/trust/identity/trust-policy.js.map +1 -0
  606. package/dist/trust/index.d.ts +21 -0
  607. package/dist/trust/index.js +22 -0
  608. package/dist/trust/index.js.map +1 -0
  609. package/dist/trust/records/evaluator.d.ts +76 -0
  610. package/dist/trust/records/evaluator.js +122 -0
  611. package/dist/trust/records/evaluator.js.map +1 -0
  612. package/dist/trust/records/index.d.ts +28 -0
  613. package/dist/trust/records/index.js +26 -0
  614. package/dist/trust/records/index.js.map +1 -0
  615. package/dist/trust/records/store.d.ts +75 -0
  616. package/dist/trust/records/store.js +339 -0
  617. package/dist/trust/records/store.js.map +1 -0
  618. package/dist/trust/records/types.d.ts +159 -0
  619. package/dist/trust/records/types.js +40 -0
  620. package/dist/trust/records/types.js.map +1 -0
  621. package/dist/tui/banner.d.ts +46 -0
  622. package/dist/tui/banner.js +99 -0
  623. package/dist/tui/banner.js.map +1 -0
  624. package/dist/tui/styles.d.ts +70 -0
  625. package/dist/tui/styles.js +197 -0
  626. package/dist/tui/styles.js.map +1 -0
  627. package/dist/tui/theme.d.ts +63 -0
  628. package/dist/tui/theme.js +136 -0
  629. package/dist/tui/theme.js.map +1 -0
  630. package/examples/profiles/buyer.deepseek.yaml +34 -0
  631. package/examples/profiles/buyer.fake.yaml +36 -0
  632. package/examples/profiles/buyer.local.yaml +40 -0
  633. package/examples/profiles/merchant.deepseek.yaml +32 -0
  634. package/examples/profiles/merchant.fake.yaml +31 -0
  635. package/examples/profiles/merchant.local.yaml +34 -0
  636. package/package.json +55 -0
@@ -0,0 +1,784 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * OperatorController — the typed operator control plane (design §13).
18
+ *
19
+ * Owns the operator session: strategy, mode, approval state, pause/resume
20
+ * and shutdown. Every state transition is recorded as an append-only event
21
+ * and the state itself is derived by folding the event stream (reducer),
22
+ * so a restart rebuilds the session from the store.
23
+ *
24
+ * Boundaries:
25
+ * - no HTTP: formal writes go through NegotiationRunner -> CommerceClient;
26
+ * - HardPolicy (profile) is never widened by a strategy patch;
27
+ * - supervised is the default mode and never submits before approve();
28
+ * - approve is idempotent per candidate_id (no duplicate formal messages);
29
+ * - waiting approval, timeout-free: shutdown/reject/revise abandon the
30
+ * claim, they never complete an unsubmitted one;
31
+ * - operator messages are private; only candidate drafts (already produced
32
+ * by the backend) are ever submitted, and only after the gate.
33
+ */
34
+ import { randomUUID } from "node:crypto";
35
+ import { OPERATOR_MODES, } from "./types.js";
36
+ export const DEFAULT_OPERATOR_MODE = "supervised";
37
+ // ---------------------------------------------------------------------------
38
+ // Approval gate (design §9)
39
+ // ---------------------------------------------------------------------------
40
+ /** Route a candidate by mode; autopilot escalates to approval on risk. */
41
+ export function routeCandidate(decision, mode, profile) {
42
+ if (mode === "manual")
43
+ return "advice_only";
44
+ if (mode === "supervised")
45
+ return "await_approval";
46
+ // autopilot: risk escalation paths still require a human (design §9).
47
+ if (decision.request_human_review || decision.action === "escalate")
48
+ return "await_approval";
49
+ if ((decision.confidence ?? 1) < 0.5)
50
+ return "await_approval";
51
+ const reviewOn = profile.role === "buyer"
52
+ ? (profile.buyer_policy?.human_review_on ?? [])
53
+ : (profile.merchant_policy?.human_review_on ?? []);
54
+ if (decision.reason_codes.some((code) => reviewOn.includes(code)))
55
+ return "await_approval";
56
+ return "auto_submit";
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // Reducer: OperatorState is a fold over the event stream
60
+ // ---------------------------------------------------------------------------
61
+ export function initialOperatorState() {
62
+ return {
63
+ started: false,
64
+ shutdown: false,
65
+ mode: DEFAULT_OPERATOR_MODE,
66
+ paused: false,
67
+ strategy: { version: 1, directives: [] },
68
+ approval: { kind: "idle" },
69
+ candidates: new Map(),
70
+ stats: {
71
+ operator_messages: 0,
72
+ patches_applied: 0,
73
+ patches_rejected: 0,
74
+ candidates_generated: 0,
75
+ decisions_submitted: 0,
76
+ approvals: 0,
77
+ rejections: 0,
78
+ revisions: 0,
79
+ },
80
+ event_count: 0,
81
+ };
82
+ }
83
+ function clearApprovalFor(state, candidateId) {
84
+ if (state.approval.kind !== "idle" && state.approval.candidate_id === candidateId) {
85
+ state.approval = { kind: "idle" };
86
+ }
87
+ }
88
+ /**
89
+ * Fold one event into the state (mutates and returns `state`, fold-style).
90
+ * Pure with respect to its inputs: same events -> same state.
91
+ */
92
+ export function reduceOperatorEvent(state, event) {
93
+ state.event_count += 1;
94
+ switch (event.type) {
95
+ case "operator.message":
96
+ state.stats.operator_messages += 1;
97
+ break;
98
+ case "strategy.patch.proposed":
99
+ // A relax patch parks here until an explicit confirmation applies it.
100
+ if (event.payload.patch.kind === "relax") {
101
+ state.strategy.pending_relax = event.payload.patch;
102
+ }
103
+ break;
104
+ case "strategy.patch.applied": {
105
+ const patch = event.payload.patch;
106
+ delete state.strategy.pending_relax;
107
+ // out_of_scope / chat are rejected before application, but the fold
108
+ // must never trust that invariant — keep them out of directives so a
109
+ // corrupted or replayed event cannot steer candidate generation.
110
+ if (patch.kind !== "forbidden" && patch.kind !== "out_of_scope" && patch.kind !== "chat") {
111
+ state.strategy.directives.push({
112
+ kind: patch.kind,
113
+ scope: patch.scope,
114
+ directive: patch.directive,
115
+ summary: patch.summary,
116
+ applied_at: event.occurred_at,
117
+ });
118
+ state.stats.patches_applied += 1;
119
+ }
120
+ break;
121
+ }
122
+ case "strategy.patch.rejected":
123
+ delete state.strategy.pending_relax;
124
+ state.stats.patches_rejected += 1;
125
+ break;
126
+ case "mode.changed":
127
+ state.mode = event.payload.to;
128
+ break;
129
+ case "negotiation.paused":
130
+ state.paused = true;
131
+ break;
132
+ case "negotiation.resumed":
133
+ state.paused = false;
134
+ break;
135
+ case "candidate.generated": {
136
+ const candidate = event.payload.candidate;
137
+ state.candidates.set(candidate.candidate_id, candidate);
138
+ state.stats.candidates_generated += 1;
139
+ if (candidate.route === "await_approval") {
140
+ state.approval = { kind: "awaiting_approval", candidate_id: candidate.candidate_id };
141
+ }
142
+ else if (candidate.route === "advice_only") {
143
+ state.approval = { kind: "advice_ready", candidate_id: candidate.candidate_id };
144
+ }
145
+ break;
146
+ }
147
+ case "candidate.approved": {
148
+ const candidate = state.candidates.get(event.payload.candidate_id);
149
+ if (candidate)
150
+ candidate.status = "approved";
151
+ state.stats.approvals += 1;
152
+ break;
153
+ }
154
+ case "candidate.rejected": {
155
+ const candidate = state.candidates.get(event.payload.candidate_id);
156
+ if (candidate)
157
+ candidate.status = "rejected";
158
+ clearApprovalFor(state, event.payload.candidate_id);
159
+ state.stats.rejections += 1;
160
+ break;
161
+ }
162
+ case "candidate.revised": {
163
+ const candidate = state.candidates.get(event.payload.candidate_id);
164
+ if (candidate)
165
+ candidate.status = "superseded";
166
+ clearApprovalFor(state, event.payload.candidate_id);
167
+ state.stats.revisions += 1;
168
+ break;
169
+ }
170
+ case "decision.submitted": {
171
+ const candidate = state.candidates.get(event.payload.candidate_id);
172
+ if (candidate)
173
+ candidate.status = "submitted";
174
+ state.stats.decisions_submitted += 1;
175
+ break;
176
+ }
177
+ case "turn.settled": {
178
+ const candidate = state.candidates.get(event.payload.candidate_id);
179
+ if (candidate) {
180
+ if (event.payload.settlement === "completed") {
181
+ candidate.status = "settled";
182
+ }
183
+ else if (candidate.status !== "rejected" && candidate.status !== "superseded") {
184
+ // failed / abandoned: the candidate must never be submitted later.
185
+ candidate.status = "expired";
186
+ }
187
+ }
188
+ clearApprovalFor(state, event.payload.candidate_id);
189
+ // Turn-scope directives expire once a candidate settles (design §7.3).
190
+ state.strategy.directives = state.strategy.directives.filter((d) => d.scope !== "turn");
191
+ break;
192
+ }
193
+ }
194
+ return state;
195
+ }
196
+ export class OperatorController {
197
+ profile;
198
+ store;
199
+ engine;
200
+ runner;
201
+ now;
202
+ origin;
203
+ state;
204
+ eventsLog = [];
205
+ /** Live prepared turns for candidates generated by this process. */
206
+ prepared = new Map();
207
+ /** Messages rejected this session; not re-claimed until a later run. */
208
+ rejectedMessageIds = new Set();
209
+ /** Candidate ids whose submit is currently in flight (approve idempotency). */
210
+ submitting = new Set();
211
+ /** Last counterpart public message seen by prepare (TUI transcript pane). */
212
+ lastCounterpartMessage;
213
+ eventSeq = 0;
214
+ candidateSeq = 0;
215
+ constructor(options) {
216
+ this.profile = options.profile;
217
+ this.store = options.store;
218
+ this.engine = options.engine;
219
+ this.runner = options.runner;
220
+ this.now = options.now ?? (() => new Date().toISOString());
221
+ this.origin = options.origin ?? "local_tui";
222
+ this.state = initialOperatorState();
223
+ }
224
+ getState() {
225
+ return this.state;
226
+ }
227
+ /** Load and fold the persisted event stream (fail closed on corruption). */
228
+ async start() {
229
+ const events = await this.store.readAll();
230
+ for (const event of events) {
231
+ reduceOperatorEvent(this.state, event);
232
+ this.eventsLog.push(event);
233
+ }
234
+ this.eventSeq = events.length;
235
+ this.candidateSeq = events.filter((e) => e.type === "candidate.generated").length;
236
+ // Recovery rule (design §14.3/§14.4): a candidate from a previous run
237
+ // cannot be re-validated against the live claim, so it is expired —
238
+ // never submitted. The operator regenerates with fresh state. `submitted`
239
+ // is included: a crash between decision.submitted and turn.settled would
240
+ // otherwise leave the session wedged (approve/reject/revise all refuse and
241
+ // prepareNextCandidate stays blocked), because the approval is only
242
+ // cleared by turn.settled.
243
+ for (const candidate of this.state.candidates.values()) {
244
+ if (candidate.status === "awaiting_approval" ||
245
+ candidate.status === "advice_only" ||
246
+ candidate.status === "approved" ||
247
+ candidate.status === "submitted") {
248
+ candidate.status = "expired";
249
+ }
250
+ }
251
+ if (this.state.approval.kind !== "idle") {
252
+ const candidate = this.state.candidates.get(this.state.approval.candidate_id);
253
+ if (!candidate || candidate.status === "expired") {
254
+ this.state.approval = { kind: "idle" };
255
+ }
256
+ }
257
+ this.state.started = true;
258
+ }
259
+ // ---- event plumbing -----------------------------------------------------
260
+ nextBase(visibility) {
261
+ this.eventSeq += 1;
262
+ return {
263
+ // A random suffix keeps ids unique across restarts even when a rejected
264
+ // append consumed a sequence number without persisting (design §6).
265
+ event_id: `evt-${this.eventSeq}-${randomUUID().slice(0, 8)}`,
266
+ occurred_at: this.now(),
267
+ agent_id: this.profile.agent_id,
268
+ role: this.profile.role,
269
+ origin: this.origin,
270
+ visibility,
271
+ };
272
+ }
273
+ async record(event) {
274
+ await this.store.append(event);
275
+ reduceOperatorEvent(this.state, event);
276
+ this.eventsLog.push(event);
277
+ }
278
+ /**
279
+ * Compile context: profile HardPolicy values overridden by the LAST applied
280
+ * budget/floor directive, so compiling again sees the session-effective
281
+ * values (e.g. after a confirmed raise, "提高到 500" is no longer a raise).
282
+ */
283
+ strategyContext() {
284
+ const context = { role: this.profile.role };
285
+ if (this.profile.buyer_policy) {
286
+ let max = this.profile.buyer_policy.max_total_price_private;
287
+ for (const d of this.state.strategy.directives) {
288
+ // Only numeric constraint directives carry a budget hint. A
289
+ // soft_preference mentioning 预算 must not override it.
290
+ if ((d.kind === "tighten" || d.kind === "relax") &&
291
+ /预算|budget/i.test(d.directive)) {
292
+ const n = /\d+(?:\.\d+)?/.exec(d.directive);
293
+ if (n !== null)
294
+ max = Number(n[0]);
295
+ }
296
+ }
297
+ context.buyer_max_total_price = max;
298
+ }
299
+ if (this.profile.merchant_policy?.min_unit_price_private !== undefined) {
300
+ let floor = this.profile.merchant_policy.min_unit_price_private;
301
+ for (const d of this.state.strategy.directives) {
302
+ if ((d.kind === "tighten" || d.kind === "relax") &&
303
+ /底价|最低价|floor/i.test(d.directive)) {
304
+ const n = /\d+(?:\.\d+)?/.exec(d.directive);
305
+ if (n !== null)
306
+ floor = Number(n[0]);
307
+ }
308
+ }
309
+ context.merchant_min_unit_price = floor;
310
+ }
311
+ return context;
312
+ }
313
+ // ---- strategy + operator messages ---------------------------------------
314
+ async sendOperatorMessage(text) {
315
+ const trimmed = text.trim();
316
+ if (trimmed === "")
317
+ return { kind: "rejected", reason: "空消息" };
318
+ if (this.state.shutdown)
319
+ return { kind: "rejected", reason: "控制器已关闭" };
320
+ try {
321
+ await this.record({
322
+ ...this.nextBase("private"),
323
+ type: "operator.message",
324
+ payload: { text: trimmed },
325
+ });
326
+ }
327
+ catch {
328
+ // The event store refuses secret-like values (fail closed). This must
329
+ // reject the message inline — never crash the whole TUI session.
330
+ return {
331
+ kind: "rejected",
332
+ reason: "该消息疑似包含敏感值(token/密钥等),未记录(fail closed)。请去掉敏感内容后重试。",
333
+ };
334
+ }
335
+ const patch = this.engine.compile(trimmed, this.strategyContext());
336
+ await this.record({
337
+ ...this.nextBase("private"),
338
+ type: "strategy.patch.proposed",
339
+ payload: { patch },
340
+ });
341
+ const risk = this.engine.assess(patch);
342
+ if (risk.level === "blocked") {
343
+ await this.record({
344
+ ...this.nextBase("private"),
345
+ type: "strategy.patch.rejected",
346
+ payload: { patch, reason: risk.reason },
347
+ });
348
+ return { kind: "rejected", patch, reason: risk.reason };
349
+ }
350
+ if (risk.level === "confirm") {
351
+ // The reducer parked the patch in strategy.pending_relax.
352
+ return { kind: "needs_confirmation", patch };
353
+ }
354
+ await this.record({
355
+ ...this.nextBase("private"),
356
+ type: "strategy.patch.applied",
357
+ payload: { patch },
358
+ });
359
+ return { kind: "applied", patch };
360
+ }
361
+ /** Apply the parked relax patch after the operator's explicit confirmation. */
362
+ async confirmStrategy() {
363
+ const pending = this.state.strategy.pending_relax;
364
+ if (!pending)
365
+ return { ok: false, error: "没有待确认的策略变更" };
366
+ await this.record({
367
+ ...this.nextBase("private"),
368
+ type: "strategy.patch.applied",
369
+ payload: { patch: pending },
370
+ });
371
+ return { ok: true };
372
+ }
373
+ // ---- mode ---------------------------------------------------------------
374
+ async setMode(mode, options) {
375
+ if (this.state.shutdown)
376
+ return { kind: "error", error: "控制器已关闭" };
377
+ if (!OPERATOR_MODES.includes(mode)) {
378
+ return { kind: "error", error: `未知模式: ${mode}(可选 ${OPERATOR_MODES.join("/")})` };
379
+ }
380
+ const from = this.state.mode;
381
+ if (from === mode)
382
+ return { kind: "unchanged", mode };
383
+ // Design §8: switching INTO autopilot requires explicit confirmation.
384
+ if (mode === "autopilot" && options?.confirmed !== true) {
385
+ return {
386
+ kind: "needs_confirmation",
387
+ mode,
388
+ reason: "切换到 autopilot 需要显式确认:/mode autopilot confirm",
389
+ };
390
+ }
391
+ await this.record({
392
+ ...this.nextBase("private"),
393
+ type: "mode.changed",
394
+ payload: { from, to: mode },
395
+ });
396
+ return { kind: "changed", mode };
397
+ }
398
+ // ---- candidate lifecycle --------------------------------------------------
399
+ /**
400
+ * Pull the next pending message and generate a candidate. No Commerce
401
+ * write happens unless the gate routes to auto_submit (autopilot).
402
+ */
403
+ async prepareNextCandidate() {
404
+ if (this.state.shutdown)
405
+ return { kind: "blocked", reason: "控制器已关闭" };
406
+ if (this.state.paused)
407
+ return { kind: "blocked", reason: "已暂停,/resume 后恢复" };
408
+ if (this.state.approval.kind !== "idle") {
409
+ return { kind: "blocked", reason: "已有待处理候选,请先 /approve、/reject 或 /revise" };
410
+ }
411
+ // Applied session/turn directives steer candidate generation (design §7).
412
+ // The runner clamps them to the profile's HardPolicy, so they can narrow
413
+ // but never widen the submit-time gates.
414
+ const prepared = await this.runner.prepare({
415
+ skipMessageIds: this.rejectedMessageIds,
416
+ directives: [...this.state.strategy.directives],
417
+ });
418
+ if (!prepared)
419
+ return { kind: "no_work" };
420
+ this.candidateSeq += 1;
421
+ const candidateId = `cand-${this.candidateSeq}`;
422
+ const route = routeCandidate(prepared.decision, this.state.mode, this.profile);
423
+ const candidate = {
424
+ candidate_id: candidateId,
425
+ binding: prepared.binding,
426
+ decision: prepared.decision,
427
+ analysis: prepared.analysis,
428
+ route,
429
+ status: route === "await_approval"
430
+ ? "awaiting_approval"
431
+ : route === "advice_only"
432
+ ? "advice_only"
433
+ : "approved",
434
+ created_at: this.now(),
435
+ };
436
+ if (prepared.counterpart_message !== undefined) {
437
+ this.lastCounterpartMessage = prepared.counterpart_message;
438
+ }
439
+ this.prepared.set(candidateId, prepared);
440
+ // Keep the claim alive while the operator deliberates (design §10): a
441
+ // >300s decision must not let stale recovery steal the claim.
442
+ this.runner.startHeartbeat(prepared);
443
+ await this.record({
444
+ ...this.nextBase("public_draft"),
445
+ type: "candidate.generated",
446
+ payload: { candidate },
447
+ });
448
+ if (route === "await_approval")
449
+ return { kind: "awaiting_approval", candidate };
450
+ if (route === "advice_only")
451
+ return { kind: "advice_ready", candidate };
452
+ const submitted = await this.submitCandidate(candidateId);
453
+ if (submitted.kind === "submitted") {
454
+ const result = {
455
+ kind: "auto_submitted",
456
+ candidate_id: candidateId,
457
+ policy_result: submitted.policy_result,
458
+ };
459
+ if (submitted.message_id !== undefined)
460
+ result.message_id = submitted.message_id;
461
+ return result;
462
+ }
463
+ if (submitted.kind === "invalid")
464
+ return { kind: "blocked", reason: submitted.reason };
465
+ return { kind: "blocked", reason: "auto submit replayed" };
466
+ }
467
+ async submitCandidate(candidateId) {
468
+ const candidate = this.state.candidates.get(candidateId);
469
+ if (!candidate)
470
+ return { kind: "invalid", reason: `未知候选 ${candidateId}` };
471
+ // Idempotent approval replay: one candidate_id -> at most one formal message.
472
+ if (candidate.status === "submitted" || candidate.status === "settled") {
473
+ return { kind: "replayed", candidate_id: candidateId };
474
+ }
475
+ // A second approve while the first submit is still in flight (web/mobile
476
+ // concurrency) must not re-submit or crash on the settled claim.
477
+ if (this.submitting.has(candidateId)) {
478
+ return { kind: "replayed", candidate_id: candidateId };
479
+ }
480
+ const prepared = this.prepared.get(candidateId);
481
+ if (!prepared || candidate.status === "expired") {
482
+ return { kind: "invalid", reason: "候选已过期(需重新生成),不会提交" };
483
+ }
484
+ this.submitting.add(candidateId);
485
+ let outcome;
486
+ try {
487
+ outcome = await this.runner.submit(prepared);
488
+ }
489
+ catch (err) {
490
+ // 提交异常兜底(评审项 M7):网关瞬时故障时 submit 抛错——此前
491
+ // finally 只清 submitting,心跳继续每 60s 续命 claim:消息永远不被
492
+ // stale recovery 回收、也不回到 pending,会话永久楔死(对照 headless
493
+ // turn 路径有完整 abandon 兜底,本路径缺失)。此处停心跳 + abandon
494
+ // claim(消息重新可领取)+ 落 failed 事件 + 返回可读错误;prepared
495
+ // 保留——重试 /approve 走 submit 的幂等键,不重复提交。
496
+ await this.runner.stopHeartbeat().catch(() => undefined);
497
+ await this.runner.abandon(prepared, "submit error").catch(() => undefined);
498
+ await this.record({
499
+ ...this.nextBase("private"),
500
+ type: "turn.settled",
501
+ payload: {
502
+ candidate_id: candidateId,
503
+ settlement: "failed",
504
+ reason: `submit error: ${err instanceof Error ? err.message : String(err)}`,
505
+ },
506
+ }).catch(() => undefined);
507
+ return {
508
+ kind: "invalid",
509
+ reason: `提交失败(claim 已释放,可重新尝试):${err instanceof Error ? err.message : String(err)}`,
510
+ };
511
+ }
512
+ finally {
513
+ this.submitting.delete(candidateId);
514
+ }
515
+ if (outcome.settlement === "failed") {
516
+ // A failed settle leaves the message reclaimable; stop the autopilot
517
+ // TUI loop from silently re-claiming + re-submitting on every input.
518
+ this.rejectedMessageIds.add(prepared.binding.message_id);
519
+ }
520
+ const submittedPayload = {
521
+ candidate_id: candidateId,
522
+ action: candidate.decision.action,
523
+ policy_result: outcome.policy_result.result,
524
+ };
525
+ if (outcome.policy_result.message_id !== undefined) {
526
+ submittedPayload.message_id = outcome.policy_result.message_id;
527
+ }
528
+ await this.record({
529
+ ...this.nextBase("public_sent"),
530
+ type: "decision.submitted",
531
+ payload: submittedPayload,
532
+ });
533
+ await this.record({
534
+ ...this.nextBase("private"),
535
+ type: "turn.settled",
536
+ payload: {
537
+ candidate_id: candidateId,
538
+ settlement: outcome.settlement,
539
+ ...(outcome.settlement === "failed" ? { reason: outcome.policy_result.public_reason } : {}),
540
+ },
541
+ });
542
+ this.prepared.delete(candidateId);
543
+ await this.runner.stopHeartbeat();
544
+ const result = {
545
+ kind: "submitted",
546
+ candidate_id: candidateId,
547
+ policy_result: outcome.policy_result.result,
548
+ settlement: outcome.settlement,
549
+ };
550
+ if (outcome.policy_result.message_id !== undefined) {
551
+ result.message_id = outcome.policy_result.message_id;
552
+ }
553
+ return result;
554
+ }
555
+ /** Approve the current awaiting candidate (idempotent per candidate_id). */
556
+ async approve(candidateId) {
557
+ if (this.state.shutdown)
558
+ return { kind: "invalid", reason: "控制器已关闭" };
559
+ const id = candidateId ??
560
+ (this.state.approval.kind === "awaiting_approval"
561
+ ? this.state.approval.candidate_id
562
+ : undefined);
563
+ if (id === undefined) {
564
+ return {
565
+ kind: "invalid",
566
+ reason: this.state.approval.kind === "advice_ready"
567
+ ? "manual 模式只提供建议,不自动提交;可 /reject 放弃或 /revise 重算"
568
+ : "没有等待审批的候选",
569
+ };
570
+ }
571
+ if (this.state.approval.kind !== "awaiting_approval" ||
572
+ this.state.approval.candidate_id !== id) {
573
+ const existing = this.state.candidates.get(id);
574
+ if (existing && (existing.status === "submitted" || existing.status === "settled")) {
575
+ return { kind: "replayed", candidate_id: id };
576
+ }
577
+ return { kind: "invalid", reason: `候选 ${id} 不在待审批状态` };
578
+ }
579
+ await this.record({
580
+ ...this.nextBase("private"),
581
+ type: "candidate.approved",
582
+ payload: { candidate_id: id },
583
+ });
584
+ return this.submitCandidate(id);
585
+ }
586
+ currentCandidateId(allowAdvice) {
587
+ if (this.state.approval.kind === "awaiting_approval")
588
+ return this.state.approval.candidate_id;
589
+ if (allowAdvice && this.state.approval.kind === "advice_ready") {
590
+ return this.state.approval.candidate_id;
591
+ }
592
+ return undefined;
593
+ }
594
+ /** Reject the current candidate and abandon its claim. Never submits. */
595
+ async reject(candidateId, reason) {
596
+ if (this.state.shutdown)
597
+ return { ok: false, error: "控制器已关闭" };
598
+ const id = candidateId ?? this.currentCandidateId(true);
599
+ if (id === undefined)
600
+ return { ok: false, error: "没有待处理的候选" };
601
+ const candidate = this.state.candidates.get(id);
602
+ if (!candidate ||
603
+ (candidate.status !== "awaiting_approval" && candidate.status !== "advice_only")) {
604
+ return { ok: false, error: `候选 ${id} 不可驳回` };
605
+ }
606
+ await this.record({
607
+ ...this.nextBase("private"),
608
+ type: "candidate.rejected",
609
+ payload: { candidate_id: id, ...(reason !== undefined ? { reason } : {}) },
610
+ });
611
+ this.rejectedMessageIds.add(candidate.binding.message_id);
612
+ const prepared = this.prepared.get(id);
613
+ if (prepared) {
614
+ await this.runner.abandon(prepared, reason ?? "operator rejected candidate");
615
+ this.prepared.delete(id);
616
+ await this.runner.stopHeartbeat();
617
+ }
618
+ await this.record({
619
+ ...this.nextBase("private"),
620
+ type: "turn.settled",
621
+ payload: { candidate_id: id, settlement: "abandoned", reason: "operator rejected" },
622
+ });
623
+ return { ok: true };
624
+ }
625
+ /**
626
+ * Record a turn instruction, abandon the old candidate's claim and
627
+ * regenerate. The instruction is compiled as a turn-scope directive and
628
+ * expires when the next candidate settles (design §7.3).
629
+ */
630
+ async revise(instruction, candidateId) {
631
+ if (this.state.shutdown)
632
+ return { kind: "blocked", reason: "控制器已关闭" };
633
+ const trimmed = instruction.trim();
634
+ if (trimmed === "")
635
+ return { kind: "blocked", reason: "用法: /revise <新指令>" };
636
+ const id = candidateId ?? this.currentCandidateId(true);
637
+ if (id === undefined)
638
+ return { kind: "blocked", reason: "没有可重算的候选" };
639
+ const candidate = this.state.candidates.get(id);
640
+ if (!candidate ||
641
+ (candidate.status !== "awaiting_approval" && candidate.status !== "advice_only")) {
642
+ return { kind: "blocked", reason: `候选 ${id} 不可重算` };
643
+ }
644
+ // Compile BEFORE touching the candidate: a relax instruction must never
645
+ // apply silently (design §8 — relax requires an explicit confirmation),
646
+ // and a forbidden one is refused outright. Both leave the current
647
+ // candidate, its claim and the strategy untouched.
648
+ const patch = this.engine.compile(trimmed, this.strategyContext());
649
+ if (patch.kind === "relax" ||
650
+ patch.kind === "forbidden" ||
651
+ patch.kind === "out_of_scope" ||
652
+ patch.kind === "chat") {
653
+ // A refused /revise must still leave an audit trail (§6).
654
+ await this.record({
655
+ ...this.nextBase("private"),
656
+ type: "strategy.patch.rejected",
657
+ payload: { patch, reason: "operator /revise 指令被拒绝" },
658
+ });
659
+ if (patch.kind === "relax") {
660
+ return {
661
+ kind: "blocked",
662
+ reason: `放宽约束不能通过 /revise 直接生效:${patch.summary}。候选保持不变;` +
663
+ "如确需放宽,请以普通指令发送并用 /strategy confirm 确认(仍不会突破 profile 硬约束)。",
664
+ };
665
+ }
666
+ if (patch.kind === "forbidden") {
667
+ return { kind: "blocked", reason: `指令被拒绝:${patch.summary}。候选保持不变。` };
668
+ }
669
+ return {
670
+ kind: "blocked",
671
+ reason: `该指令无法用于重算:${patch.summary}。候选保持不变。`,
672
+ };
673
+ }
674
+ await this.record({
675
+ ...this.nextBase("private"),
676
+ type: "candidate.revised",
677
+ payload: { candidate_id: id, instruction: trimmed },
678
+ });
679
+ const prepared = this.prepared.get(id);
680
+ if (prepared) {
681
+ await this.runner.abandon(prepared, "operator requested revise");
682
+ this.prepared.delete(id);
683
+ await this.runner.stopHeartbeat();
684
+ }
685
+ await this.record({
686
+ ...this.nextBase("private"),
687
+ type: "turn.settled",
688
+ payload: { candidate_id: id, settlement: "abandoned", reason: "operator revised" },
689
+ });
690
+ // Apply the instruction as a turn-scope strategy patch before regenerating.
691
+ await this.record({
692
+ ...this.nextBase("private"),
693
+ type: "strategy.patch.applied",
694
+ payload: { patch: { ...patch, scope: "turn" } },
695
+ });
696
+ return this.prepareNextCandidate();
697
+ }
698
+ // ---- pause / resume -------------------------------------------------------
699
+ async pause() {
700
+ if (this.state.shutdown)
701
+ return { ok: false, error: "控制器已关闭" };
702
+ if (this.state.paused)
703
+ return { ok: true };
704
+ await this.record({ ...this.nextBase("private"), type: "negotiation.paused", payload: {} });
705
+ return { ok: true };
706
+ }
707
+ async resume() {
708
+ if (this.state.shutdown)
709
+ return { ok: false, error: "控制器已关闭" };
710
+ if (!this.state.paused)
711
+ return { ok: true };
712
+ await this.record({ ...this.nextBase("private"), type: "negotiation.resumed", payload: {} });
713
+ return { ok: true };
714
+ }
715
+ // ---- inspection -----------------------------------------------------------
716
+ why() {
717
+ const id = this.currentCandidateId(true);
718
+ const directives = this.state.strategy.directives.map((d) => `[${d.kind}/${d.scope}] ${d.summary}`);
719
+ if (id === undefined) {
720
+ return {
721
+ analysis: [],
722
+ reason_codes: [],
723
+ active_directives: directives,
724
+ note: "当前没有候选决策",
725
+ };
726
+ }
727
+ const candidate = this.state.candidates.get(id);
728
+ if (!candidate) {
729
+ return {
730
+ analysis: [],
731
+ reason_codes: [],
732
+ active_directives: directives,
733
+ note: "当前没有候选决策",
734
+ };
735
+ }
736
+ return {
737
+ candidate_id: id,
738
+ route: candidate.route,
739
+ analysis: [...candidate.analysis],
740
+ reason_codes: [...candidate.decision.reason_codes],
741
+ active_directives: directives,
742
+ };
743
+ }
744
+ /** Recent events, newest last. Private to this operator session. */
745
+ history(limit = 20) {
746
+ return this.eventsLog.slice(-Math.max(1, limit));
747
+ }
748
+ usage() {
749
+ return { ...this.state.stats, events: this.state.event_count };
750
+ }
751
+ // ---- shutdown ---------------------------------------------------------------
752
+ /**
753
+ * Safe shutdown (design §17): a candidate still waiting for approval is
754
+ * best-effort abandoned (never completed) and kept as an audit record.
755
+ */
756
+ async shutdown() {
757
+ if (this.state.shutdown)
758
+ return { events: this.state.event_count };
759
+ const result = { events: 0 };
760
+ const pendingId = this.currentCandidateId(true);
761
+ if (pendingId !== undefined) {
762
+ const prepared = this.prepared.get(pendingId);
763
+ if (prepared) {
764
+ await this.runner.abandon(prepared, "operator shutdown with pending candidate");
765
+ this.prepared.delete(pendingId);
766
+ await this.runner.stopHeartbeat();
767
+ }
768
+ await this.record({
769
+ ...this.nextBase("private"),
770
+ type: "turn.settled",
771
+ payload: {
772
+ candidate_id: pendingId,
773
+ settlement: "abandoned",
774
+ reason: "operator shutdown",
775
+ },
776
+ });
777
+ result.abandoned_candidate = pendingId;
778
+ }
779
+ this.state.shutdown = true;
780
+ result.events = this.state.event_count;
781
+ return result;
782
+ }
783
+ }
784
+ //# sourceMappingURL=controller.js.map