@kya-os/cli 1.8.1 → 1.8.3

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 (385) hide show
  1. package/dist/commands/agent.d.ts +35 -0
  2. package/dist/commands/agent.d.ts.map +1 -0
  3. package/dist/commands/agent.js +321 -0
  4. package/dist/commands/agent.js.map +1 -0
  5. package/dist/commands/build.js +2 -2
  6. package/dist/commands/build.js.map +1 -1
  7. package/dist/commands/check.js +3 -3
  8. package/dist/commands/check.js.map +1 -1
  9. package/dist/commands/checkpoint-init.d.ts +1 -1
  10. package/dist/commands/checkpoint-init.d.ts.map +1 -1
  11. package/dist/commands/checkpoint-init.js +8 -41
  12. package/dist/commands/checkpoint-init.js.map +1 -1
  13. package/dist/commands/claim.js +2 -2
  14. package/dist/commands/claim.js.map +1 -1
  15. package/dist/commands/dco.d.ts +59 -0
  16. package/dist/commands/dco.d.ts.map +1 -1
  17. package/dist/commands/dco.js +280 -5
  18. package/dist/commands/dco.js.map +1 -1
  19. package/dist/commands/dev.js +1 -1
  20. package/dist/commands/dev.js.map +1 -1
  21. package/dist/commands/doctor.d.ts.map +1 -1
  22. package/dist/commands/doctor.js +18 -24
  23. package/dist/commands/doctor.js.map +1 -1
  24. package/dist/commands/env.js +6 -6
  25. package/dist/commands/env.js.map +1 -1
  26. package/dist/commands/identity.js +3 -3
  27. package/dist/commands/identity.js.map +1 -1
  28. package/dist/commands/init-stages.d.ts +141 -0
  29. package/dist/commands/init-stages.d.ts.map +1 -0
  30. package/dist/commands/init-stages.js +684 -0
  31. package/dist/commands/init-stages.js.map +1 -0
  32. package/dist/commands/init.d.ts +46 -16
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +229 -279
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/orchestrator.d.ts +18 -0
  37. package/dist/commands/orchestrator.d.ts.map +1 -0
  38. package/dist/commands/orchestrator.js +251 -0
  39. package/dist/commands/orchestrator.js.map +1 -0
  40. package/dist/commands/register.d.ts +1 -1
  41. package/dist/commands/register.d.ts.map +1 -1
  42. package/dist/commands/register.js +35 -7
  43. package/dist/commands/register.js.map +1 -1
  44. package/dist/commands/review.d.ts +48 -0
  45. package/dist/commands/review.d.ts.map +1 -0
  46. package/dist/commands/review.js +220 -0
  47. package/dist/commands/review.js.map +1 -0
  48. package/dist/commands/rotate.js +4 -4
  49. package/dist/commands/rotate.js.map +1 -1
  50. package/dist/commands/score.d.ts +15 -0
  51. package/dist/commands/score.d.ts.map +1 -0
  52. package/dist/commands/score.js +471 -0
  53. package/dist/commands/score.js.map +1 -0
  54. package/dist/commands/start.js +3 -3
  55. package/dist/commands/start.js.map +1 -1
  56. package/dist/commands/status.js +1 -1
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/commands/verify.js +6 -6
  59. package/dist/commands/verify.js.map +1 -1
  60. package/dist/dco.d.ts +4 -0
  61. package/dist/dco.d.ts.map +1 -0
  62. package/dist/dco.js +23 -0
  63. package/dist/dco.js.map +1 -0
  64. package/dist/index.js +52 -9
  65. package/dist/orchestrator/daemon.d.ts +137 -0
  66. package/dist/orchestrator/daemon.d.ts.map +1 -0
  67. package/dist/orchestrator/daemon.js +242 -0
  68. package/dist/orchestrator/daemon.js.map +1 -0
  69. package/dist/orchestrator/db/dispatches.d.ts +108 -0
  70. package/dist/orchestrator/db/dispatches.d.ts.map +1 -0
  71. package/dist/orchestrator/db/dispatches.js +122 -0
  72. package/dist/orchestrator/db/dispatches.js.map +1 -0
  73. package/dist/orchestrator/db/index.d.ts +50 -0
  74. package/dist/orchestrator/db/index.d.ts.map +1 -0
  75. package/dist/orchestrator/db/index.js +116 -0
  76. package/dist/orchestrator/db/index.js.map +1 -0
  77. package/dist/orchestrator/db/journal.d.ts +93 -0
  78. package/dist/orchestrator/db/journal.d.ts.map +1 -0
  79. package/dist/orchestrator/db/journal.js +91 -0
  80. package/dist/orchestrator/db/journal.js.map +1 -0
  81. package/dist/orchestrator/db/liveness.d.ts +97 -0
  82. package/dist/orchestrator/db/liveness.d.ts.map +1 -0
  83. package/dist/orchestrator/db/liveness.js +105 -0
  84. package/dist/orchestrator/db/liveness.js.map +1 -0
  85. package/dist/orchestrator/db/mission.d.ts +78 -0
  86. package/dist/orchestrator/db/mission.d.ts.map +1 -0
  87. package/dist/orchestrator/db/mission.js +99 -0
  88. package/dist/orchestrator/db/mission.js.map +1 -0
  89. package/dist/orchestrator/db/schema.d.ts +14 -0
  90. package/dist/orchestrator/db/schema.d.ts.map +1 -0
  91. package/dist/orchestrator/db/schema.js +169 -0
  92. package/dist/orchestrator/db/schema.js.map +1 -0
  93. package/dist/orchestrator/db/tickets.d.ts +147 -0
  94. package/dist/orchestrator/db/tickets.d.ts.map +1 -0
  95. package/dist/orchestrator/db/tickets.js +238 -0
  96. package/dist/orchestrator/db/tickets.js.map +1 -0
  97. package/dist/orchestrator/db/verdicts.d.ts +187 -0
  98. package/dist/orchestrator/db/verdicts.d.ts.map +1 -0
  99. package/dist/orchestrator/db/verdicts.js +197 -0
  100. package/dist/orchestrator/db/verdicts.js.map +1 -0
  101. package/dist/orchestrator/events.d.ts +69 -0
  102. package/dist/orchestrator/events.d.ts.map +1 -0
  103. package/dist/orchestrator/events.js +20 -0
  104. package/dist/orchestrator/events.js.map +1 -0
  105. package/dist/orchestrator/github-credential-anchor-sender.d.ts +159 -0
  106. package/dist/orchestrator/github-credential-anchor-sender.d.ts.map +1 -0
  107. package/dist/orchestrator/github-credential-anchor-sender.js +313 -0
  108. package/dist/orchestrator/github-credential-anchor-sender.js.map +1 -0
  109. package/dist/orchestrator/hub-dispatch.d.ts +120 -0
  110. package/dist/orchestrator/hub-dispatch.d.ts.map +1 -0
  111. package/dist/orchestrator/hub-dispatch.js +257 -0
  112. package/dist/orchestrator/hub-dispatch.js.map +1 -0
  113. package/dist/orchestrator/hub-observer.d.ts +201 -0
  114. package/dist/orchestrator/hub-observer.d.ts.map +1 -0
  115. package/dist/orchestrator/hub-observer.js +474 -0
  116. package/dist/orchestrator/hub-observer.js.map +1 -0
  117. package/dist/orchestrator/journal-writer.d.ts +80 -0
  118. package/dist/orchestrator/journal-writer.d.ts.map +1 -0
  119. package/dist/orchestrator/journal-writer.js +113 -0
  120. package/dist/orchestrator/journal-writer.js.map +1 -0
  121. package/dist/orchestrator/mcp/server.d.ts +136 -0
  122. package/dist/orchestrator/mcp/server.d.ts.map +1 -0
  123. package/dist/orchestrator/mcp/server.js +582 -0
  124. package/dist/orchestrator/mcp/server.js.map +1 -0
  125. package/dist/orchestrator/mcp/stdio.d.ts +22 -0
  126. package/dist/orchestrator/mcp/stdio.d.ts.map +1 -0
  127. package/dist/orchestrator/mcp/stdio.js +51 -0
  128. package/dist/orchestrator/mcp/stdio.js.map +1 -0
  129. package/dist/orchestrator/review.d.ts +131 -0
  130. package/dist/orchestrator/review.d.ts.map +1 -0
  131. package/dist/orchestrator/review.js +322 -0
  132. package/dist/orchestrator/review.js.map +1 -0
  133. package/dist/tui/app.d.ts +33 -0
  134. package/dist/tui/app.d.ts.map +1 -0
  135. package/dist/tui/app.js +71 -0
  136. package/dist/tui/app.js.map +1 -0
  137. package/dist/tui/components.d.ts +110 -0
  138. package/dist/tui/components.d.ts.map +1 -0
  139. package/dist/tui/components.js +118 -0
  140. package/dist/tui/components.js.map +1 -0
  141. package/dist/tui/index.d.ts +30 -0
  142. package/dist/tui/index.d.ts.map +1 -0
  143. package/dist/tui/index.js +95 -0
  144. package/dist/tui/index.js.map +1 -0
  145. package/dist/tui/keymap.d.ts +33 -0
  146. package/dist/tui/keymap.d.ts.map +1 -0
  147. package/dist/tui/keymap.js +49 -0
  148. package/dist/tui/keymap.js.map +1 -0
  149. package/dist/tui/nav.d.ts +29 -0
  150. package/dist/tui/nav.d.ts.map +1 -0
  151. package/dist/tui/nav.js +39 -0
  152. package/dist/tui/nav.js.map +1 -0
  153. package/dist/tui/sanitize.d.ts +25 -0
  154. package/dist/tui/sanitize.d.ts.map +1 -0
  155. package/dist/tui/sanitize.js +36 -0
  156. package/dist/tui/sanitize.js.map +1 -0
  157. package/dist/tui/theme.d.ts +32 -0
  158. package/dist/tui/theme.d.ts.map +1 -0
  159. package/dist/tui/theme.js +63 -0
  160. package/dist/tui/theme.js.map +1 -0
  161. package/dist/tui/views/agents.d.ts +67 -0
  162. package/dist/tui/views/agents.d.ts.map +1 -0
  163. package/dist/tui/views/agents.js +231 -0
  164. package/dist/tui/views/agents.js.map +1 -0
  165. package/dist/tui/views/index.d.ts +93 -0
  166. package/dist/tui/views/index.d.ts.map +1 -0
  167. package/dist/tui/views/index.js +150 -0
  168. package/dist/tui/views/index.js.map +1 -0
  169. package/dist/tui/views/registry.d.ts +22 -0
  170. package/dist/tui/views/registry.d.ts.map +1 -0
  171. package/dist/tui/views/registry.js +110 -0
  172. package/dist/tui/views/registry.js.map +1 -0
  173. package/dist/utils/agent/backoff.d.ts +31 -0
  174. package/dist/utils/agent/backoff.d.ts.map +1 -0
  175. package/dist/utils/agent/backoff.js +51 -0
  176. package/dist/utils/agent/backoff.js.map +1 -0
  177. package/dist/utils/agent/markers.d.ts +87 -0
  178. package/dist/utils/agent/markers.d.ts.map +1 -0
  179. package/dist/utils/agent/markers.js +147 -0
  180. package/dist/utils/agent/markers.js.map +1 -0
  181. package/dist/utils/agent/review.d.ts +67 -0
  182. package/dist/utils/agent/review.d.ts.map +1 -0
  183. package/dist/utils/agent/review.js +305 -0
  184. package/dist/utils/agent/review.js.map +1 -0
  185. package/dist/utils/agent/spawn-agent.d.ts +117 -0
  186. package/dist/utils/agent/spawn-agent.d.ts.map +1 -0
  187. package/dist/utils/agent/spawn-agent.js +177 -0
  188. package/dist/utils/agent/spawn-agent.js.map +1 -0
  189. package/dist/utils/agent/task.d.ts +101 -0
  190. package/dist/utils/agent/task.d.ts.map +1 -0
  191. package/dist/utils/agent/task.js +357 -0
  192. package/dist/utils/agent/task.js.map +1 -0
  193. package/dist/utils/agent/verify.d.ts +47 -0
  194. package/dist/utils/agent/verify.d.ts.map +1 -0
  195. package/dist/utils/agent/verify.js +144 -0
  196. package/dist/utils/agent/verify.js.map +1 -0
  197. package/dist/utils/agent-detector.d.ts +48 -0
  198. package/dist/utils/agent-detector.d.ts.map +1 -0
  199. package/dist/utils/agent-detector.js +74 -0
  200. package/dist/utils/agent-detector.js.map +1 -0
  201. package/dist/utils/agent-profile-stage.d.ts +70 -0
  202. package/dist/utils/agent-profile-stage.d.ts.map +1 -0
  203. package/dist/utils/agent-profile-stage.js +153 -0
  204. package/dist/utils/agent-profile-stage.js.map +1 -0
  205. package/dist/utils/agent-profiles.d.ts +27 -0
  206. package/dist/utils/agent-profiles.d.ts.map +1 -0
  207. package/dist/utils/agent-profiles.js +61 -0
  208. package/dist/utils/agent-profiles.js.map +1 -0
  209. package/dist/utils/checkpoint-api.d.ts +1 -1
  210. package/dist/utils/checkpoint-api.js +1 -1
  211. package/dist/utils/checkpoint-env.d.ts +1 -1
  212. package/dist/utils/checkpoint-env.js +2 -2
  213. package/dist/utils/checkpoint-env.js.map +1 -1
  214. package/dist/utils/checkpoint-scaffold.d.ts +1 -1
  215. package/dist/utils/checkpoint-scaffold.js +1 -1
  216. package/dist/utils/cli-kit/browser.d.ts +24 -0
  217. package/dist/utils/cli-kit/browser.d.ts.map +1 -0
  218. package/dist/utils/cli-kit/browser.js +58 -0
  219. package/dist/utils/cli-kit/browser.js.map +1 -0
  220. package/dist/utils/cli-kit/claim-polling.d.ts +18 -0
  221. package/dist/utils/cli-kit/claim-polling.d.ts.map +1 -0
  222. package/dist/utils/{claim-polling.js → cli-kit/claim-polling.js} +19 -26
  223. package/dist/utils/cli-kit/claim-polling.js.map +1 -0
  224. package/dist/utils/cli-kit/diagnostics.d.ts +9 -0
  225. package/dist/utils/cli-kit/diagnostics.d.ts.map +1 -0
  226. package/dist/utils/cli-kit/diagnostics.js +11 -0
  227. package/dist/utils/cli-kit/diagnostics.js.map +1 -0
  228. package/dist/utils/cli-kit/fs-safe.d.ts +14 -0
  229. package/dist/utils/cli-kit/fs-safe.d.ts.map +1 -0
  230. package/dist/utils/cli-kit/fs-safe.js +20 -0
  231. package/dist/utils/cli-kit/fs-safe.js.map +1 -0
  232. package/dist/utils/cli-kit/index.d.ts +15 -0
  233. package/dist/utils/cli-kit/index.d.ts.map +1 -0
  234. package/dist/utils/cli-kit/index.js +10 -0
  235. package/dist/utils/cli-kit/index.js.map +1 -0
  236. package/dist/utils/cli-kit/json-file.d.ts +21 -0
  237. package/dist/utils/cli-kit/json-file.d.ts.map +1 -0
  238. package/dist/utils/cli-kit/json-file.js +51 -0
  239. package/dist/utils/cli-kit/json-file.js.map +1 -0
  240. package/dist/utils/cli-kit/marker-block.d.ts +26 -0
  241. package/dist/utils/cli-kit/marker-block.d.ts.map +1 -0
  242. package/dist/utils/cli-kit/marker-block.js +61 -0
  243. package/dist/utils/cli-kit/marker-block.js.map +1 -0
  244. package/dist/utils/cli-kit/paths.d.ts +15 -0
  245. package/dist/utils/cli-kit/paths.d.ts.map +1 -0
  246. package/dist/utils/cli-kit/paths.js +21 -0
  247. package/dist/utils/cli-kit/paths.js.map +1 -0
  248. package/dist/utils/cli-kit/secure-storage.d.ts +14 -0
  249. package/dist/utils/cli-kit/secure-storage.d.ts.map +1 -0
  250. package/dist/utils/cli-kit/secure-storage.js +20 -0
  251. package/dist/utils/cli-kit/secure-storage.js.map +1 -0
  252. package/dist/utils/cli-kit/step-report.d.ts +16 -0
  253. package/dist/utils/cli-kit/step-report.d.ts.map +1 -0
  254. package/dist/utils/cli-kit/step-report.js +36 -0
  255. package/dist/utils/cli-kit/step-report.js.map +1 -0
  256. package/dist/utils/dco/agent-metadata.d.ts +1 -1
  257. package/dist/utils/dco/agent-metadata.js +1 -1
  258. package/dist/utils/dco/agent-metadata.js.map +1 -1
  259. package/dist/utils/dco/claude-config.d.ts +18 -14
  260. package/dist/utils/dco/claude-config.d.ts.map +1 -1
  261. package/dist/utils/dco/claude-config.js +31 -97
  262. package/dist/utils/dco/claude-config.js.map +1 -1
  263. package/dist/utils/dco/dispatch.d.ts +134 -0
  264. package/dist/utils/dco/dispatch.d.ts.map +1 -0
  265. package/dist/utils/dco/dispatch.js +399 -0
  266. package/dist/utils/dco/dispatch.js.map +1 -0
  267. package/dist/utils/dco/fix.d.ts +122 -0
  268. package/dist/utils/dco/fix.d.ts.map +1 -0
  269. package/dist/utils/dco/fix.js +560 -0
  270. package/dist/utils/dco/fix.js.map +1 -0
  271. package/dist/utils/dco/git-config.d.ts.map +1 -1
  272. package/dist/utils/dco/git-config.js +5 -3
  273. package/dist/utils/dco/git-config.js.map +1 -1
  274. package/dist/utils/dco/github.d.ts +101 -0
  275. package/dist/utils/dco/github.d.ts.map +1 -1
  276. package/dist/utils/dco/github.js +133 -0
  277. package/dist/utils/dco/github.js.map +1 -1
  278. package/dist/utils/dco/paths.d.ts +1 -8
  279. package/dist/utils/dco/paths.d.ts.map +1 -1
  280. package/dist/utils/dco/paths.js +3 -12
  281. package/dist/utils/dco/paths.js.map +1 -1
  282. package/dist/utils/dco/render.d.ts +1 -1
  283. package/dist/utils/dco/render.d.ts.map +1 -1
  284. package/dist/utils/dco/render.js +4 -21
  285. package/dist/utils/dco/render.js.map +1 -1
  286. package/dist/utils/dco/resolve-agent.d.ts +54 -0
  287. package/dist/utils/dco/resolve-agent.d.ts.map +1 -0
  288. package/dist/utils/dco/resolve-agent.js +164 -0
  289. package/dist/utils/dco/resolve-agent.js.map +1 -0
  290. package/dist/utils/dco/setup.d.ts +10 -7
  291. package/dist/utils/dco/setup.d.ts.map +1 -1
  292. package/dist/utils/dco/setup.js +264 -200
  293. package/dist/utils/dco/setup.js.map +1 -1
  294. package/dist/utils/dco/signing-key-writer.d.ts +40 -0
  295. package/dist/utils/dco/signing-key-writer.d.ts.map +1 -0
  296. package/dist/utils/dco/signing-key-writer.js +76 -0
  297. package/dist/utils/dco/signing-key-writer.js.map +1 -0
  298. package/dist/utils/dco/ssh-key.d.ts +50 -0
  299. package/dist/utils/dco/ssh-key.d.ts.map +1 -1
  300. package/dist/utils/dco/ssh-key.js +129 -8
  301. package/dist/utils/dco/ssh-key.js.map +1 -1
  302. package/dist/utils/dco/status.d.ts +1 -1
  303. package/dist/utils/dco/status.d.ts.map +1 -1
  304. package/dist/utils/dco/status.js +3 -3
  305. package/dist/utils/dco/status.js.map +1 -1
  306. package/dist/utils/dco/verify.d.ts +170 -0
  307. package/dist/utils/dco/verify.d.ts.map +1 -0
  308. package/dist/utils/dco/verify.js +550 -0
  309. package/dist/utils/dco/verify.js.map +1 -0
  310. package/dist/utils/dependency-installer.d.ts +37 -0
  311. package/dist/utils/dependency-installer.d.ts.map +1 -0
  312. package/dist/utils/dependency-installer.js +32 -0
  313. package/dist/utils/dependency-installer.js.map +1 -0
  314. package/dist/utils/github-credential-stage.d.ts +87 -0
  315. package/dist/utils/github-credential-stage.d.ts.map +1 -0
  316. package/dist/utils/github-credential-stage.js +168 -0
  317. package/dist/utils/github-credential-stage.js.map +1 -0
  318. package/dist/utils/github-credential.d.ts +160 -0
  319. package/dist/utils/github-credential.d.ts.map +1 -0
  320. package/dist/utils/github-credential.js +308 -0
  321. package/dist/utils/github-credential.js.map +1 -0
  322. package/dist/utils/gitignore.d.ts +17 -0
  323. package/dist/utils/gitignore.d.ts.map +1 -0
  324. package/dist/utils/gitignore.js +40 -0
  325. package/dist/utils/gitignore.js.map +1 -0
  326. package/dist/utils/hub-config.d.ts +21 -0
  327. package/dist/utils/hub-config.d.ts.map +1 -0
  328. package/dist/utils/hub-config.js +28 -0
  329. package/dist/utils/hub-config.js.map +1 -0
  330. package/dist/utils/identity-heal.d.ts +16 -0
  331. package/dist/utils/identity-heal.d.ts.map +1 -0
  332. package/dist/utils/identity-heal.js +37 -0
  333. package/dist/utils/identity-heal.js.map +1 -0
  334. package/dist/utils/init/pipeline.d.ts +74 -0
  335. package/dist/utils/init/pipeline.d.ts.map +1 -0
  336. package/dist/utils/init/pipeline.js +96 -0
  337. package/dist/utils/init/pipeline.js.map +1 -0
  338. package/dist/utils/poll.d.ts +15 -1
  339. package/dist/utils/poll.d.ts.map +1 -1
  340. package/dist/utils/poll.js +6 -3
  341. package/dist/utils/poll.js.map +1 -1
  342. package/dist/utils/register-agent-identity.d.ts +67 -0
  343. package/dist/utils/register-agent-identity.d.ts.map +1 -0
  344. package/dist/utils/register-agent-identity.js +34 -0
  345. package/dist/utils/register-agent-identity.js.map +1 -0
  346. package/dist/utils/review/did-web-key.d.ts +34 -0
  347. package/dist/utils/review/did-web-key.d.ts.map +1 -0
  348. package/dist/utils/review/did-web-key.js +104 -0
  349. package/dist/utils/review/did-web-key.js.map +1 -0
  350. package/dist/utils/review/load-registry.d.ts +33 -0
  351. package/dist/utils/review/load-registry.d.ts.map +1 -0
  352. package/dist/utils/review/load-registry.js +62 -0
  353. package/dist/utils/review/load-registry.js.map +1 -0
  354. package/dist/utils/review/verdict-verify.d.ts +43 -0
  355. package/dist/utils/review/verdict-verify.d.ts.map +1 -0
  356. package/dist/utils/review/verdict-verify.js +53 -0
  357. package/dist/utils/review/verdict-verify.js.map +1 -0
  358. package/dist/utils/review-registry-writer.d.ts +52 -0
  359. package/dist/utils/review-registry-writer.d.ts.map +1 -0
  360. package/dist/utils/review-registry-writer.js +79 -0
  361. package/dist/utils/review-registry-writer.js.map +1 -0
  362. package/dist/utils/should-install-dependency.d.ts +17 -0
  363. package/dist/utils/should-install-dependency.d.ts.map +1 -0
  364. package/dist/utils/should-install-dependency.js +25 -0
  365. package/dist/utils/should-install-dependency.js.map +1 -0
  366. package/dist/utils/tool-readiness.d.ts +57 -0
  367. package/dist/utils/tool-readiness.d.ts.map +1 -0
  368. package/dist/utils/tool-readiness.js +114 -0
  369. package/dist/utils/tool-readiness.js.map +1 -0
  370. package/dist/utils/which.d.ts +2 -0
  371. package/dist/utils/which.d.ts.map +1 -0
  372. package/dist/utils/which.js +22 -0
  373. package/dist/utils/which.js.map +1 -0
  374. package/dist/version.d.ts +15 -0
  375. package/dist/version.d.ts.map +1 -0
  376. package/dist/version.js +29 -0
  377. package/dist/version.js.map +1 -0
  378. package/package.json +19 -6
  379. package/dist/utils/claim-polling.d.ts +0 -21
  380. package/dist/utils/claim-polling.d.ts.map +0 -1
  381. package/dist/utils/claim-polling.js.map +0 -1
  382. package/dist/utils/dco/fs-safe.d.ts +0 -14
  383. package/dist/utils/dco/fs-safe.d.ts.map +0 -1
  384. package/dist/utils/dco/fs-safe.js +0 -20
  385. package/dist/utils/dco/fs-safe.js.map +0 -1
@@ -0,0 +1,257 @@
1
+ /**
2
+ * The TUI's one control-plane action (review-loop P18 commit 4): dispatch
3
+ * a task to a connected agent.
4
+ *
5
+ * Trust boundary: this opens a short-lived, authenticated observer
6
+ * connection -- the SAME wire pattern `hub-observer.ts`'s long-lived
7
+ * `HubObserver` uses (contracts `./handshake`'s hello/challenge/proof
8
+ * frames, the #686 precedent), reusing its exported helpers rather than
9
+ * re-deriving the handshake. It sends exactly one `fleet.dispatch` frame,
10
+ * waits for exactly one `fleet.dispatch.result`, and closes -- no
11
+ * reconnect, no history, no long-lived state, because a TUI keystroke is
12
+ * a single request, not a subscription.
13
+ *
14
+ * `fleet.dispatch` here is NOT `@kya-os/compute`'s HTTP `fleet-mcp`
15
+ * surface (`packages/compute/src/didcomm/fleet-mcp.ts`), which is bearer-
16
+ * token/org-scoped and has no notion of a per-agent signing key. It is
17
+ * the wire-level message `packages/compute/src/didcomm/hub.ts` already
18
+ * handles directly on an admitted OBSERVER socket
19
+ * (`ws.on("message", ...)` inside `transport.onObserver`): a JSON frame
20
+ * `{ type: "fleet.dispatch", taskId, toDid, description, context?,
21
+ * timeoutMs? }`, answered with `{ type: "fleet.dispatch.result", taskId,
22
+ * status, response?, error?, ... }`. Reusing this existing hub-side
23
+ * handler is why this file adds nothing to `@kya-os/contracts` or
24
+ * `@kya-os/compute` -- the wire shape already exists and this PR's
25
+ * `Package:` line is `@kya-os/cli` alone.
26
+ *
27
+ * The hub proposes, the target's on-disk command allowlist (P17, epic
28
+ * decision 10) disposes: a refusal comes back as an ordinary
29
+ * `fleet.dispatch.result` with a non-"completed" status, which the caller
30
+ * renders as a refusal, not an error (see `AgentsView`'s handling of
31
+ * `status === "refused"`).
32
+ *
33
+ * @module cli/orchestrator/hub-dispatch
34
+ */
35
+ import { randomUUID } from "node:crypto";
36
+ import { readFileSync } from "node:fs";
37
+ import WebSocket from "ws";
38
+ import { DIDCommChallengeSchema, DIDCommProofSchema } from "@kya-os/contracts/handshake";
39
+ import { buildObserverHello, signChallenge, isPlaintextNonLoopback, LOOPBACK_HOSTS, } from "./hub-observer.js";
40
+ import { signingKeyPath } from "../utils/dco/paths.js";
41
+ import { parseEd25519SshPrivateKeyPem } from "../utils/dco/ssh-key.js";
42
+ import { readHubConfig } from "../utils/hub-config.js";
43
+ const DEFAULT_HANDSHAKE_TIMEOUT_MS = 10000;
44
+ const DEFAULT_DISPATCH_TIMEOUT_MS = 30000;
45
+ /**
46
+ * Opens one observer connection, authenticates if asked to, sends one
47
+ * `fleet.dispatch` frame for `targetDid`/`command`, and resolves with its
48
+ * `fleet.dispatch.result` -- or rejects on a connection/handshake/timeout
49
+ * failure. Always closes the socket before settling, on every path.
50
+ */
51
+ export function dispatchTask(config, targetDid, command) {
52
+ return new Promise((resolve, reject) => {
53
+ const ws = (config.wsFactory ?? ((endpoint) => new WebSocket(endpoint)))(config.endpoint);
54
+ const taskId = randomUUID().slice(0, 8);
55
+ let settled = false;
56
+ let handshakeDone = false;
57
+ let dispatchTimer;
58
+ const finish = (outcome) => {
59
+ if (settled)
60
+ return;
61
+ settled = true;
62
+ clearTimeout(handshakeTimer);
63
+ if (dispatchTimer)
64
+ clearTimeout(dispatchTimer);
65
+ try {
66
+ ws.close();
67
+ }
68
+ catch {
69
+ /* already closing/closed */
70
+ }
71
+ if (outcome instanceof Error)
72
+ reject(outcome);
73
+ else
74
+ resolve(outcome);
75
+ };
76
+ const handshakeTimer = setTimeout(() => {
77
+ finish(new Error(`hub at ${config.endpoint} did not complete the observer handshake in time`));
78
+ }, config.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS);
79
+ ws.on("open", () => {
80
+ try {
81
+ ws.send(JSON.stringify(buildObserverHello(config.identity)));
82
+ }
83
+ catch (err) {
84
+ finish(err instanceof Error ? err : new Error(String(err)));
85
+ }
86
+ });
87
+ ws.on("message", (raw) => {
88
+ void handleFrame(raw.toString());
89
+ });
90
+ async function handleFrame(text) {
91
+ let msg;
92
+ try {
93
+ const parsed = JSON.parse(text);
94
+ if (typeof parsed !== "object" || parsed === null)
95
+ return;
96
+ msg = parsed;
97
+ }
98
+ catch {
99
+ return; // a frame we cannot parse is not a frame we can act on
100
+ }
101
+ const type = msg["type"];
102
+ if (type === "challenge") {
103
+ const challenge = DIDCommChallengeSchema.safeParse(msg);
104
+ if (!challenge.success || !config.identity)
105
+ return;
106
+ try {
107
+ const jws = await signChallenge(config.identity, challenge.data.nonce);
108
+ ws.send(JSON.stringify(DIDCommProofSchema.parse({ type: "proof", jws })));
109
+ }
110
+ catch (err) {
111
+ finish(err instanceof Error ? err : new Error(String(err)));
112
+ }
113
+ return;
114
+ }
115
+ // "snapshot" is the hub's readiness signal (same as HubObserver):
116
+ // the handshake is complete exactly once this arrives. Only send
117
+ // the dispatch frame on the FIRST snapshot -- a hub that (unusually)
118
+ // sent more than one must not trigger a second dispatch.
119
+ if (type === "snapshot" && !handshakeDone) {
120
+ handshakeDone = true;
121
+ clearTimeout(handshakeTimer);
122
+ try {
123
+ ws.send(JSON.stringify({
124
+ type: "fleet.dispatch",
125
+ taskId,
126
+ toDid: targetDid,
127
+ description: command,
128
+ timeoutMs: config.dispatchTimeoutMs ?? DEFAULT_DISPATCH_TIMEOUT_MS,
129
+ }));
130
+ }
131
+ catch (err) {
132
+ finish(err instanceof Error ? err : new Error(String(err)));
133
+ return;
134
+ }
135
+ dispatchTimer = setTimeout(() => {
136
+ finish(new Error("dispatch timed out waiting for a result"));
137
+ }, config.dispatchTimeoutMs ?? DEFAULT_DISPATCH_TIMEOUT_MS);
138
+ return;
139
+ }
140
+ if (type === "fleet.dispatch.result" && msg["taskId"] === taskId) {
141
+ const status = typeof msg["status"] === "string" ? msg["status"] : "unknown";
142
+ finish({
143
+ taskId,
144
+ status,
145
+ response: typeof msg["response"] === "string" ? msg["response"] : undefined,
146
+ error: typeof msg["error"] === "string" ? msg["error"] : undefined,
147
+ // Allowlist, not a blacklist: `status` here is whatever the
148
+ // target agent's own task-response body reports, forwarded
149
+ // verbatim by the hub (dispatchAndWait in
150
+ // packages/compute/src/didcomm/hub.ts has no fixed status enum
151
+ // and no "failed" handling of its own). A blacklist of known
152
+ // failure strings reads any UNANTICIPATED one -- including the
153
+ // agent-reported "failed" itself -- as success. "completed" is
154
+ // the one value both that hub code and fleet-server's HubClient
155
+ // (packages/fleet-server/src/hub-client.ts, the other existing
156
+ // consumer of this same fleet.dispatch.result message) treat as
157
+ // an unambiguous success; that HubClient collapses everything
158
+ // else to a failure the same way.
159
+ ok: status === "completed",
160
+ });
161
+ }
162
+ }
163
+ ws.on("error", (err) => finish(err));
164
+ ws.on("close", (code, reason) => {
165
+ if (settled)
166
+ return;
167
+ finish(new Error(`hub closed the connection (${code}${reason.length ? `: ${reason.toString()}` : ""})`));
168
+ });
169
+ });
170
+ }
171
+ /**
172
+ * Is this endpoint loopback-only? Mirrors `isPlaintextNonLoopback`'s host
173
+ * set but answers a different question: that function asks "is this
174
+ * unencrypted AND remote" (a warn-but-allow case); this asks "is this
175
+ * unreachable from anywhere but this machine" (the ONLY case where
176
+ * connecting with no identity at all -- `--anonymous`-equivalent -- is
177
+ * appropriate for a write action like dispatch).
178
+ */
179
+ export function isLoopbackEndpoint(endpoint) {
180
+ try {
181
+ return LOOPBACK_HOSTS.has(new URL(endpoint).hostname.toLowerCase());
182
+ }
183
+ catch {
184
+ return false;
185
+ }
186
+ }
187
+ /**
188
+ * Builds the identity used to authenticate the dispatch connection, from
189
+ * the profile whose row is focused in the TUI. Every profile's key
190
+ * lives under `~/.mcpi/keys/<slug>` in the SSH-signing format
191
+ * `dco setup` writes (see `signing-key-writer.ts`); profiles never
192
+ * persist a raw seed on disk, so the seed is recovered from that SSH
193
+ * key via the same parser `dco fix` already uses to sign a fix
194
+ * attestation from the same file (`parseEd25519SshPrivateKeyPem`) rather
195
+ * than adding a second place that stores key material.
196
+ *
197
+ * Authenticating AS the profile being dispatched to -- rather than some
198
+ * separate "which of my identities is primary" concept, which does not
199
+ * exist anywhere else in this codebase -- is a deliberate scope
200
+ * decision: every profile under `~/.mcpi/keys/` belongs to the one
201
+ * operator running this TUI, so proving control of the row already in
202
+ * view is sufficient authorization and needs no new concept.
203
+ *
204
+ * Undefined if the key file is missing or not in the format this
205
+ * codebase writes -- the caller falls back to loopback-only anonymous
206
+ * dispatch in that case, matching `orchestrator daemon`'s own
207
+ * `--anonymous` precedent.
208
+ */
209
+ export function resolveProfileIdentity(profile) {
210
+ try {
211
+ const pem = readFileSync(signingKeyPath(profile.slug), "utf-8");
212
+ const { seed } = parseEd25519SshPrivateKeyPem(pem);
213
+ return { did: profile.did, privateKey: seed.toString("base64") };
214
+ }
215
+ catch {
216
+ return undefined;
217
+ }
218
+ }
219
+ /**
220
+ * The TUI-facing entry point: resolve the hub and the dispatching
221
+ * identity, dispatch, and reduce every failure mode (no hub configured,
222
+ * no usable key on a non-loopback hub, a transport/handshake error) to
223
+ * the same `DispatchOutcome` shape the agents view renders -- so the UI
224
+ * never has to distinguish "the wire call threw" from "the wire call
225
+ * returned an unhappy status".
226
+ */
227
+ export async function dispatchToProfile(profile, command, wsFactory) {
228
+ const hubConfig = readHubConfig();
229
+ if (!hubConfig) {
230
+ return { ok: false, status: "error", detail: "no hub configured (~/.mcpi/hub.json is absent)" };
231
+ }
232
+ const warning = isPlaintextNonLoopback(hubConfig.endpoint)
233
+ ? `${hubConfig.endpoint} is plaintext ws:// to a non-loopback host -- the DID, public key, and signed proof are sent unencrypted.`
234
+ : undefined;
235
+ const identity = resolveProfileIdentity(profile);
236
+ if (!identity && !isLoopbackEndpoint(hubConfig.endpoint)) {
237
+ return {
238
+ ok: false,
239
+ status: "error",
240
+ detail: `no usable signing key for ${profile.slug}, and ${hubConfig.endpoint} is not loopback`,
241
+ warning,
242
+ };
243
+ }
244
+ try {
245
+ const result = await dispatchTask({ endpoint: hubConfig.endpoint, identity, wsFactory }, profile.did, command);
246
+ return { ok: result.ok, status: result.status, detail: result.error ?? result.response, warning };
247
+ }
248
+ catch (error) {
249
+ return {
250
+ ok: false,
251
+ status: "error",
252
+ detail: error instanceof Error ? error.message : String(error),
253
+ warning,
254
+ };
255
+ }
256
+ }
257
+ //# sourceMappingURL=hub-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-dispatch.js","sourceRoot":"","sources":["../../src/orchestrator/hub-dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * A coordination hub, observed from outside its process.
3
+ *
4
+ * This is what makes the daemon host pluggable. `OrchestratorDaemon` takes a
5
+ * structural `EventSource` -- `onEvent` plus `getRecentEvents` -- rather than the
6
+ * concrete hub, so anything that can supply those two methods can drive it. In
7
+ * process, the hub itself supplies them. Here they come over a WebSocket, which
8
+ * lets the daemon run wherever the operator already runs things and attach to
9
+ * whichever hub they already point their agents at.
10
+ *
11
+ * The CLI deliberately does not depend on @kya-os/compute: compute is PID 1 in a
12
+ * Fly worker, this is a published CLI. So the observer protocol is spoken
13
+ * directly, against the wire format in @kya-os/contracts/handshake rather than
14
+ * a copy of it. (Not `/proof`: both a `proof.ts` and a `proof/index.ts` exist
15
+ * there, and Node and tsc disagree about which one that subpath means.)
16
+ *
17
+ * ## Why connect() waits for the snapshot
18
+ *
19
+ * `getRecentEvents` is synchronous, because in-process it reads an array. Over a
20
+ * socket the history arrives in a frame, so `connect()` does not resolve until
21
+ * that frame lands. A daemon started before it arrives would reconcile against
22
+ * an empty window and silently skip the recovery a restart exists to perform --
23
+ * the failure mode is a quiet no-op, which is the kind that survives review.
24
+ *
25
+ * @module cli/orchestrator/hub-observer
26
+ */
27
+ import { type ObserverHello } from "@kya-os/contracts/handshake";
28
+ import { type EventSource, type HubEventLike } from "./events.js";
29
+ /** The identity fields this needs out of `.mcpi/identity.json`. */
30
+ export interface ObserverIdentity {
31
+ did: string;
32
+ /** Raw Ed25519 seed, base64 — the shape identity.json stores. */
33
+ privateKey: string;
34
+ }
35
+ export interface HubObserverConfig {
36
+ /** e.g. `ws://127.0.0.1:18821`, normally from DIDCOMM_HUB_ENDPOINT. */
37
+ endpoint: string;
38
+ /** Omit to observe anonymously, which only a loopback hub will accept. */
39
+ identity?: ObserverIdentity;
40
+ /** How long to wait for the snapshot before giving up on a connection. */
41
+ handshakeTimeoutMs?: number;
42
+ /** Reconnect backoff ceiling. */
43
+ maxBackoffMs?: number;
44
+ }
45
+ /**
46
+ * Read an identity file, returning undefined rather than throwing.
47
+ *
48
+ * A missing or malformed identity is a normal state -- the operator may not have
49
+ * run `dco setup` -- and it only matters if the hub demands authentication. The
50
+ * hub's rejection message says far more about what is wrong than a parse error
51
+ * raised here would.
52
+ */
53
+ export declare function readObserverIdentity(path: string): ObserverIdentity | undefined;
54
+ /** The public JWK the hub needs to bind a did:key to the presented key. */
55
+ export declare function publicJwkFor(identity: ObserverIdentity): string;
56
+ /**
57
+ * The `observe` hello frame for an optional identity -- shared by every
58
+ * observer-wire client (this file's long-lived `HubObserver` and
59
+ * `hub-dispatch.ts`'s short-lived one-shot client), so the two cannot
60
+ * silently drift on what an anonymous vs. authenticated hello looks like.
61
+ */
62
+ export declare function buildObserverHello(identity?: ObserverIdentity): ObserverHello;
63
+ /** Sign the hub's challenge, per the wire format in contracts. */
64
+ export declare function signChallenge(identity: ObserverIdentity, nonce: string): Promise<string>;
65
+ /**
66
+ * Validate a raw `challenge` frame and, if well-formed, answer it: sign its
67
+ * nonce and build the wire `proof` frame to send back. Returns `undefined`
68
+ * for a frame that fails `DIDCommChallengeSchema` (not this caller's to
69
+ * handle -- the same "ignore, don't fail" choice both callers already made
70
+ * before this was factored out). Every caller of the observer
71
+ * `observe`/`challenge`/`proof` handshake shares this exact step -- {@link
72
+ * HubObserver}'s long-lived `connect()` and the one-shot
73
+ * `github-credential-anchor-sender.ts` -- so it lives here once rather than
74
+ * being reimplemented per caller.
75
+ */
76
+ export declare function respondToObserverChallenge(identity: ObserverIdentity, rawChallenge: unknown): Promise<string | undefined>;
77
+ /**
78
+ * Hosts that need no transport encryption because nothing off this machine
79
+ * can reach them. Both `::1` and `[::1]` are listed because `URL#hostname`
80
+ * keeps an IPv6 literal's brackets rather than stripping them.
81
+ */
82
+ export declare const LOOPBACK_HOSTS: Set<string>;
83
+ /**
84
+ * Is this an unencrypted `ws://` endpoint pointed somewhere other than this
85
+ * machine?
86
+ *
87
+ * A loopback hub genuinely does not need TLS -- nothing but this machine can
88
+ * see the socket. Anything else sends the DID, the public key, and the signed
89
+ * proof of possession over a transport anyone on the path can read; `wss://`
90
+ * is the production default for exactly this reason, and a plain `ws://` to a
91
+ * remote host is far more likely a dev config that escaped dev than a
92
+ * deliberate choice. An endpoint this cannot even parse is left alone: it
93
+ * fails at `connect()`, with a clearer error than anything said here.
94
+ */
95
+ export declare function isPlaintextNonLoopback(endpoint: string): boolean;
96
+ export declare class HubObserver implements EventSource {
97
+ private readonly config;
98
+ private ws;
99
+ private handlers;
100
+ private history;
101
+ private closedByUs;
102
+ private backoffMs;
103
+ /**
104
+ * Has a handshake ever completed?
105
+ *
106
+ * Reconnecting is only right after a connection that WORKED. Retrying a first
107
+ * failure means a misconfigured or unauthorised hub is retried forever in the
108
+ * background while the caller has already been told it failed -- a daemon that
109
+ * looks alive and records nothing, which is the outcome connect() rejects to
110
+ * avoid.
111
+ */
112
+ private hasConnected;
113
+ /** The pending reconnect. Held so close() can cancel it, not merely ignore it. */
114
+ private reconnectTimer;
115
+ /**
116
+ * Serializes `handleFrame` across messages.
117
+ *
118
+ * `ws.on("message")` fires and forgets (`void this.handleFrame(...)`), which
119
+ * was harmless while every frame finished synchronously within one tick.
120
+ * Retrying a replay's failed write does not: it `await`s a `setTimeout`, and
121
+ * without this queue a live frame arriving during that wait ran a SECOND,
122
+ * concurrent `handleFrame` -- pushing onto `this.history` right before the
123
+ * still-in-flight snapshot handler clobbered it with `this.history = window`,
124
+ * and dispatching that live event ahead of the gap it was meant to follow
125
+ * (review finding on #686). Chaining onto this instead makes every frame
126
+ * fully finish before the next one starts, socket-wide.
127
+ */
128
+ private frameQueue;
129
+ constructor(config: HubObserverConfig);
130
+ /** Queue a frame behind whatever is still being processed for this socket. */
131
+ private enqueueFrame;
132
+ /**
133
+ * Connect, authenticate if asked to, and resolve once the snapshot has landed.
134
+ *
135
+ * Rejects rather than retrying: a first connection that cannot authenticate is
136
+ * a configuration problem, and retrying it forever would leave a daemon that
137
+ * looks alive and records nothing. Reconnection after a WORKING connection is
138
+ * a different case and is handled silently below.
139
+ */
140
+ connect(): Promise<void>;
141
+ private handleFrame;
142
+ /**
143
+ * Hand one event to every handler, once.
144
+ *
145
+ * Shared by live delivery and reconnect replay (through {@link
146
+ * dispatchReplayed}) so the two cannot diverge -- a replay that skipped a
147
+ * handler would recover the journal and not the ticket status, which reads
148
+ * as the reactor having run and disagreed. Returns whether every handler
149
+ * succeeded, so a caller that can retry (replay) knows whether it needs to.
150
+ *
151
+ * This is now the ONLY place a handler's failure is caught. The handlers
152
+ * themselves (`registerJournalWriter`, `registerReviewReactor`) deliberately
153
+ * do not swallow their own write errors -- a handler that always reports
154
+ * success by catching internally makes `allOk` a lie, which is what made
155
+ * `dispatchReplayed`'s retry dead code against the real handlers even though
156
+ * it worked against a mock that threw directly.
157
+ */
158
+ private dispatch;
159
+ /**
160
+ * Dispatch one event from a reconnect's gap replay, retrying instead of
161
+ * letting a write failure disappear it.
162
+ *
163
+ * All handlers together, every attempt, not just the ones that failed: safe
164
+ * because journal ids are content-derived and verdicts are keyed on their
165
+ * subject, so re-dispatching an event a handler already wrote collapses
166
+ * rather than double-applying. SQLite's own `busy_timeout` already absorbs a
167
+ * same-instant lock collision between two writers; this covers whatever
168
+ * survives that -- a slower disk, any other transient failure -- during the
169
+ * one window where a dropped write has no later chance to be recovered.
170
+ */
171
+ private dispatchReplayed;
172
+ /**
173
+ * Schedule the next attempt.
174
+ *
175
+ * The timer is deliberately NOT unref'd, and that is the whole point. While
176
+ * reconnecting there is no socket, and in `kya-os orchestrator daemon` the
177
+ * socket is the only handle keeping the process alive -- the liveness beat is
178
+ * unref'd and the command holds no stdin. An unref'd timer here therefore let
179
+ * the process exit during the exact window it was supposed to be recovering
180
+ * in: a hub restart quietly killed the daemon, with no error and no exit
181
+ * message. This timer stands in for the socket, so it has to hold the loop
182
+ * exactly as the socket does.
183
+ *
184
+ * The rule the two now share: the observer owns the daemon's liveness while
185
+ * it is attached or trying to be, and everything else (the beat, the signal
186
+ * handlers) is incidental and stays unref'd.
187
+ */
188
+ private scheduleReconnect;
189
+ /**
190
+ * Is a reconnect scheduled -- i.e. is this observer still holding the process
191
+ * open on purpose? Distinguishes a cancelled timer from a merely neutered one,
192
+ * which is invisible from the outside and is the difference between a stopped
193
+ * daemon exiting and hanging.
194
+ */
195
+ hasPendingReconnect(): boolean;
196
+ onEvent(handler: (event: HubEventLike) => void): () => void;
197
+ getRecentEvents(limit?: number): HubEventLike[];
198
+ /** Stop observing. Idempotent, and suppresses the reconnect. */
199
+ close(): void;
200
+ }
201
+ //# sourceMappingURL=hub-observer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-observer.d.ts","sourceRoot":"","sources":["../../src/orchestrator/hub-observer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtF,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAkB/E;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAG/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAK7E;AAED,kEAAkE;AAClE,wBAAsB,aAAa,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,gBAAgB,EAC1B,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK7B;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,aAAsD,CAAC;AAElF;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQhE;AAsBD,qBAAa,WAAY,YAAW,WAAW;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,EAAE,CAAwB;IAClC,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAO;IACxB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY,CAAS;IAC7B,kFAAkF;IAClF,OAAO,CAAC,cAAc,CAA4C;IAClE;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,UAAU,CAAoC;gBAE1C,MAAM,EAAE,iBAAiB;IAIrC,8EAA8E;IAC9E,OAAO,CAAC,YAAY;IAUpB;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAyEV,WAAW;IA8FzB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,QAAQ;IAkBhB;;;;;;;;;;;OAWG;YACW,gBAAgB;IAa9B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;;;;OAKG;IACH,mBAAmB,IAAI,OAAO;IAI9B,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3D,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAI/C,gEAAgE;IAChE,KAAK,IAAI,IAAI;CAYd"}