@jevitate/cli 0.1.0 → 0.2.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 (375) hide show
  1. package/README.md +23 -0
  2. package/dist/ai-cli.js +40 -30
  3. package/dist/ai-cli.js.map +1 -1
  4. package/dist/author-journey-cli.d.ts +4 -0
  5. package/dist/author-journey-cli.js +109 -0
  6. package/dist/author-journey-cli.js.map +1 -0
  7. package/dist/bin.js +58077 -22454
  8. package/dist/bin.js.map +1 -1
  9. package/dist/browser-run-options.d.ts +58 -0
  10. package/dist/browser-run-options.js +106 -0
  11. package/dist/browser-run-options.js.map +1 -0
  12. package/dist/build-info.generated.d.ts +2 -0
  13. package/dist/build-info.generated.js +10 -0
  14. package/dist/build-info.generated.js.map +1 -0
  15. package/dist/check-api.d.ts +5 -0
  16. package/dist/check-api.js +233 -0
  17. package/dist/check-api.js.map +1 -0
  18. package/dist/check-budget.d.ts +26 -0
  19. package/dist/check-budget.js +89 -0
  20. package/dist/check-budget.js.map +1 -0
  21. package/dist/check-cli.d.ts +31 -0
  22. package/dist/check-cli.js +109 -0
  23. package/dist/check-cli.js.map +1 -0
  24. package/dist/check-execute.d.ts +25 -0
  25. package/dist/check-execute.js +385 -0
  26. package/dist/check-execute.js.map +1 -0
  27. package/dist/check-plan.d.ts +113 -0
  28. package/dist/check-plan.js +448 -0
  29. package/dist/check-plan.js.map +1 -0
  30. package/dist/check-suite.d.ts +171 -0
  31. package/dist/check-suite.js +515 -0
  32. package/dist/check-suite.js.map +1 -0
  33. package/dist/check-types.d.ts +181 -0
  34. package/dist/check-types.js +35 -0
  35. package/dist/check-types.js.map +1 -0
  36. package/dist/cli-args.d.ts +26 -0
  37. package/dist/cli-args.js +50 -0
  38. package/dist/cli-args.js.map +1 -0
  39. package/dist/cli-output.d.ts +102 -0
  40. package/dist/cli-output.js +516 -0
  41. package/dist/cli-output.js.map +1 -0
  42. package/dist/cli-reference.d.ts +3 -0
  43. package/dist/cli-reference.js +81 -0
  44. package/dist/cli-reference.js.map +1 -0
  45. package/dist/cli-refusal.d.ts +12 -0
  46. package/dist/cli-refusal.js +52 -0
  47. package/dist/cli-refusal.js.map +1 -0
  48. package/dist/cli-shared.d.ts +330 -0
  49. package/dist/cli-shared.js +492 -0
  50. package/dist/cli-shared.js.map +1 -0
  51. package/dist/cli-surface.d.ts +33 -0
  52. package/dist/cli-surface.js +48 -0
  53. package/dist/cli-surface.js.map +1 -0
  54. package/dist/conversation-options.d.ts +15 -0
  55. package/dist/conversation-options.js +10 -0
  56. package/dist/conversation-options.js.map +1 -0
  57. package/dist/credentials-file.d.ts +15 -0
  58. package/dist/credentials-file.js +56 -0
  59. package/dist/credentials-file.js.map +1 -0
  60. package/dist/data-dir.d.ts +1 -1
  61. package/dist/data-dir.js +1 -1
  62. package/dist/defect-evidence.d.ts +141 -0
  63. package/dist/defect-evidence.js +502 -0
  64. package/dist/defect-evidence.js.map +1 -0
  65. package/dist/demo-aspect-api.d.ts +209 -0
  66. package/dist/demo-aspect-api.js +397 -0
  67. package/dist/demo-aspect-api.js.map +1 -0
  68. package/dist/demo-aspect-cli.d.ts +3 -0
  69. package/dist/demo-aspect-cli.js +241 -0
  70. package/dist/demo-aspect-cli.js.map +1 -0
  71. package/dist/demo-capture.d.ts +108 -0
  72. package/dist/demo-capture.js +438 -0
  73. package/dist/demo-capture.js.map +1 -0
  74. package/dist/engine.d.ts +35 -0
  75. package/dist/engine.js +25 -0
  76. package/dist/engine.js.map +1 -0
  77. package/dist/environments.d.ts +155 -0
  78. package/dist/environments.js +364 -0
  79. package/dist/environments.js.map +1 -0
  80. package/dist/exit-codes.d.ts +46 -0
  81. package/dist/exit-codes.js +91 -0
  82. package/dist/exit-codes.js.map +1 -0
  83. package/dist/explore-adversarial.d.ts +137 -0
  84. package/dist/explore-adversarial.js +218 -0
  85. package/dist/explore-adversarial.js.map +1 -0
  86. package/dist/explore-api.d.ts +7 -187
  87. package/dist/explore-api.js +7 -301
  88. package/dist/explore-api.js.map +1 -1
  89. package/dist/explore-author.d.ts +79 -0
  90. package/dist/explore-author.js +86 -0
  91. package/dist/explore-author.js.map +1 -0
  92. package/dist/explore-cli.d.ts +7 -0
  93. package/dist/explore-cli.js +963 -0
  94. package/dist/explore-cli.js.map +1 -0
  95. package/dist/explore-coverage.d.ts +158 -0
  96. package/dist/explore-coverage.js +240 -0
  97. package/dist/explore-coverage.js.map +1 -0
  98. package/dist/explore-feature.d.ts +127 -0
  99. package/dist/explore-feature.js +220 -0
  100. package/dist/explore-feature.js.map +1 -0
  101. package/dist/explore-goal.d.ts +253 -0
  102. package/dist/explore-goal.js +374 -0
  103. package/dist/explore-goal.js.map +1 -0
  104. package/dist/explore-shared.d.ts +152 -0
  105. package/dist/explore-shared.js +129 -0
  106. package/dist/explore-shared.js.map +1 -0
  107. package/dist/explore-specs.d.ts +53 -0
  108. package/dist/explore-specs.js +333 -0
  109. package/dist/explore-specs.js.map +1 -0
  110. package/dist/findings-filing.d.ts +64 -0
  111. package/dist/findings-filing.js +108 -0
  112. package/dist/findings-filing.js.map +1 -0
  113. package/dist/fixture-auth.d.ts +52 -0
  114. package/dist/fixture-auth.js +82 -0
  115. package/dist/fixture-auth.js.map +1 -0
  116. package/dist/fixture-cli.d.ts +70 -0
  117. package/dist/fixture-cli.js +178 -0
  118. package/dist/fixture-cli.js.map +1 -0
  119. package/dist/github-issue-filer.d.ts +62 -0
  120. package/dist/github-issue-filer.js +188 -0
  121. package/dist/github-issue-filer.js.map +1 -0
  122. package/dist/host-health-run.d.ts +24 -0
  123. package/dist/host-health-run.js +27 -0
  124. package/dist/host-health-run.js.map +1 -0
  125. package/dist/http-5xx-outcome.d.ts +6 -0
  126. package/dist/http-5xx-outcome.js +39 -0
  127. package/dist/http-5xx-outcome.js.map +1 -0
  128. package/dist/inbox-cli.d.ts +7 -0
  129. package/dist/inbox-cli.js +197 -0
  130. package/dist/inbox-cli.js.map +1 -0
  131. package/dist/index.d.ts +1 -0
  132. package/dist/index.js +1 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/init-cli.d.ts +4 -0
  135. package/dist/init-cli.js +127 -0
  136. package/dist/init-cli.js.map +1 -0
  137. package/dist/init-keys.d.ts +19 -2
  138. package/dist/init-keys.js +15 -4
  139. package/dist/init-keys.js.map +1 -1
  140. package/dist/init-next-steps.d.ts +35 -0
  141. package/dist/init-next-steps.js +79 -0
  142. package/dist/init-next-steps.js.map +1 -0
  143. package/dist/invariants-file.d.ts +34 -0
  144. package/dist/invariants-file.js +68 -0
  145. package/dist/invariants-file.js.map +1 -0
  146. package/dist/invariants-validate.d.ts +30 -0
  147. package/dist/invariants-validate.js +105 -0
  148. package/dist/invariants-validate.js.map +1 -0
  149. package/dist/journey-annotate-api.d.ts +76 -0
  150. package/dist/journey-annotate-api.js +256 -0
  151. package/dist/journey-annotate-api.js.map +1 -0
  152. package/dist/journey-annotate-cli.d.ts +9 -0
  153. package/dist/journey-annotate-cli.js +179 -0
  154. package/dist/journey-annotate-cli.js.map +1 -0
  155. package/dist/journey-api.d.ts +79 -2
  156. package/dist/journey-api.js +136 -19
  157. package/dist/journey-api.js.map +1 -1
  158. package/dist/journey-cli.d.ts +4 -0
  159. package/dist/journey-cli.js +370 -0
  160. package/dist/journey-cli.js.map +1 -0
  161. package/dist/journey-demo-api.d.ts +112 -0
  162. package/dist/journey-demo-api.js +392 -0
  163. package/dist/journey-demo-api.js.map +1 -0
  164. package/dist/journey-demo-cli.d.ts +10 -0
  165. package/dist/journey-demo-cli.js +155 -0
  166. package/dist/journey-demo-cli.js.map +1 -0
  167. package/dist/kill-signal.d.ts +193 -0
  168. package/dist/kill-signal.js +284 -0
  169. package/dist/kill-signal.js.map +1 -0
  170. package/dist/launch-armed.d.ts +37 -0
  171. package/dist/launch-armed.js +31 -0
  172. package/dist/launch-armed.js.map +1 -0
  173. package/dist/ledger-api.d.ts +106 -0
  174. package/dist/ledger-api.js +237 -0
  175. package/dist/ledger-api.js.map +1 -0
  176. package/dist/ledger-cli.d.ts +18 -0
  177. package/dist/ledger-cli.js +107 -0
  178. package/dist/ledger-cli.js.map +1 -0
  179. package/dist/load-api.d.ts +29 -11
  180. package/dist/load-api.js +23 -15
  181. package/dist/load-api.js.map +1 -1
  182. package/dist/load-cli.d.ts +4 -0
  183. package/dist/load-cli.js +97 -0
  184. package/dist/load-cli.js.map +1 -0
  185. package/dist/log-correlation.d.ts +147 -0
  186. package/dist/log-correlation.js +325 -0
  187. package/dist/log-correlation.js.map +1 -0
  188. package/dist/log-lines.d.ts +131 -0
  189. package/dist/log-lines.js +389 -0
  190. package/dist/log-lines.js.map +1 -0
  191. package/dist/log-sources.d.ts +71 -0
  192. package/dist/log-sources.js +235 -0
  193. package/dist/log-sources.js.map +1 -0
  194. package/dist/logs-cli.d.ts +3 -0
  195. package/dist/logs-cli.js +51 -0
  196. package/dist/logs-cli.js.map +1 -0
  197. package/dist/logs-retention.d.ts +28 -0
  198. package/dist/logs-retention.js +84 -0
  199. package/dist/logs-retention.js.map +1 -0
  200. package/dist/mcp-api.d.ts +89 -1
  201. package/dist/mcp-api.js +472 -18
  202. package/dist/mcp-api.js.map +1 -1
  203. package/dist/mcp-args.d.ts +38 -0
  204. package/dist/mcp-args.js +131 -0
  205. package/dist/mcp-args.js.map +1 -0
  206. package/dist/mcp-cli-bridge.d.ts +34 -0
  207. package/dist/mcp-cli-bridge.js +62 -0
  208. package/dist/mcp-cli-bridge.js.map +1 -0
  209. package/dist/mcp-cli-runner.d.ts +29 -0
  210. package/dist/mcp-cli-runner.js +44 -0
  211. package/dist/mcp-cli-runner.js.map +1 -0
  212. package/dist/mcp-cli-tools.d.ts +125 -0
  213. package/dist/mcp-cli-tools.js +680 -0
  214. package/dist/mcp-cli-tools.js.map +1 -0
  215. package/dist/mcp-paths.d.ts +28 -0
  216. package/dist/mcp-paths.js +76 -0
  217. package/dist/mcp-paths.js.map +1 -0
  218. package/dist/mission-actors.d.ts +40 -0
  219. package/dist/mission-actors.js +72 -0
  220. package/dist/mission-actors.js.map +1 -0
  221. package/dist/mission-api.d.ts +35 -0
  222. package/dist/mission-api.js +58 -2
  223. package/dist/mission-api.js.map +1 -1
  224. package/dist/mission-cli.d.ts +4 -0
  225. package/dist/mission-cli.js +247 -0
  226. package/dist/mission-cli.js.map +1 -0
  227. package/dist/mission-exit.d.ts +22 -0
  228. package/dist/mission-exit.js +26 -0
  229. package/dist/mission-exit.js.map +1 -0
  230. package/dist/mission-fixtures.d.ts +225 -0
  231. package/dist/mission-fixtures.js +828 -0
  232. package/dist/mission-fixtures.js.map +1 -0
  233. package/dist/mission-journal.d.ts +60 -0
  234. package/dist/mission-journal.js +115 -0
  235. package/dist/mission-journal.js.map +1 -0
  236. package/dist/mission-queue-cli.d.ts +10 -0
  237. package/dist/mission-queue-cli.js +198 -0
  238. package/dist/mission-queue-cli.js.map +1 -0
  239. package/dist/mission-queue-runner.d.ts +126 -0
  240. package/dist/mission-queue-runner.js +397 -0
  241. package/dist/mission-queue-runner.js.map +1 -0
  242. package/dist/multi-run-cli.d.ts +37 -0
  243. package/dist/multi-run-cli.js +110 -0
  244. package/dist/multi-run-cli.js.map +1 -0
  245. package/dist/multi-run.d.ts +339 -0
  246. package/dist/multi-run.js +619 -0
  247. package/dist/multi-run.js.map +1 -0
  248. package/dist/openrouter-call.d.ts +22 -0
  249. package/dist/openrouter-call.js +63 -0
  250. package/dist/openrouter-call.js.map +1 -0
  251. package/dist/profile-cli.d.ts +4 -0
  252. package/dist/profile-cli.js +57 -0
  253. package/dist/profile-cli.js.map +1 -0
  254. package/dist/program.d.ts +3 -75
  255. package/dist/program.js +119 -1921
  256. package/dist/program.js.map +1 -1
  257. package/dist/project-dir.d.ts +96 -0
  258. package/dist/project-dir.js +220 -0
  259. package/dist/project-dir.js.map +1 -0
  260. package/dist/record-api.d.ts +10 -6
  261. package/dist/record-api.js +39 -28
  262. package/dist/record-api.js.map +1 -1
  263. package/dist/record-cli.d.ts +4 -0
  264. package/dist/record-cli.js +64 -0
  265. package/dist/record-cli.js.map +1 -0
  266. package/dist/recording-cli.d.ts +4 -0
  267. package/dist/recording-cli.js +248 -0
  268. package/dist/recording-cli.js.map +1 -0
  269. package/dist/regression-api.d.ts +101 -0
  270. package/dist/regression-api.js +384 -5
  271. package/dist/regression-api.js.map +1 -1
  272. package/dist/regression-cli.d.ts +4 -0
  273. package/dist/regression-cli.js +232 -0
  274. package/dist/regression-cli.js.map +1 -0
  275. package/dist/report-api.d.ts +146 -0
  276. package/dist/report-api.js +430 -0
  277. package/dist/report-api.js.map +1 -0
  278. package/dist/report-cli.d.ts +12 -0
  279. package/dist/report-cli.js +147 -0
  280. package/dist/report-cli.js.map +1 -0
  281. package/dist/result-schema.d.ts +22 -0
  282. package/dist/result-schema.js +28 -0
  283. package/dist/result-schema.js.map +1 -0
  284. package/dist/run-index.d.ts +29 -0
  285. package/dist/run-index.js +70 -0
  286. package/dist/run-index.js.map +1 -0
  287. package/dist/run-screenshots.d.ts +123 -0
  288. package/dist/run-screenshots.js +229 -0
  289. package/dist/run-screenshots.js.map +1 -0
  290. package/dist/runtime-env.d.ts +8 -0
  291. package/dist/runtime-env.js +22 -0
  292. package/dist/runtime-env.js.map +1 -0
  293. package/dist/secret-args.d.ts +23 -0
  294. package/dist/secret-args.js +45 -0
  295. package/dist/secret-args.js.map +1 -0
  296. package/dist/serve-cli.d.ts +4 -0
  297. package/dist/serve-cli.js +95 -0
  298. package/dist/serve-cli.js.map +1 -0
  299. package/dist/server-log-verify.d.ts +34 -0
  300. package/dist/server-log-verify.js +115 -0
  301. package/dist/server-log-verify.js.map +1 -0
  302. package/dist/session-check.d.ts +14 -0
  303. package/dist/session-check.js +44 -0
  304. package/dist/session-check.js.map +1 -0
  305. package/dist/site-cli.d.ts +4 -0
  306. package/dist/site-cli.js +127 -0
  307. package/dist/site-cli.js.map +1 -0
  308. package/dist/site-gate-cli.d.ts +28 -0
  309. package/dist/site-gate-cli.js +58 -0
  310. package/dist/site-gate-cli.js.map +1 -0
  311. package/dist/source-api.js +18 -3
  312. package/dist/source-api.js.map +1 -1
  313. package/dist/source-cli.d.ts +4 -0
  314. package/dist/source-cli.js +284 -0
  315. package/dist/source-cli.js.map +1 -0
  316. package/dist/source-run-api.d.ts +27 -1
  317. package/dist/source-run-api.js +22 -11
  318. package/dist/source-run-api.js.map +1 -1
  319. package/dist/storage-state-snapshot.d.ts +50 -0
  320. package/dist/storage-state-snapshot.js +87 -0
  321. package/dist/storage-state-snapshot.js.map +1 -0
  322. package/dist/suite-explore-options.d.ts +289 -0
  323. package/dist/suite-explore-options.js +140 -0
  324. package/dist/suite-explore-options.js.map +1 -0
  325. package/dist/target-config.d.ts +109 -0
  326. package/dist/target-config.js +216 -0
  327. package/dist/target-config.js.map +1 -0
  328. package/dist/transcript-file.d.ts +12 -0
  329. package/dist/transcript-file.js +23 -0
  330. package/dist/transcript-file.js.map +1 -0
  331. package/dist/ui-api.d.ts +3 -0
  332. package/dist/ui-api.js +7 -1
  333. package/dist/ui-api.js.map +1 -1
  334. package/dist/usability-capture.d.ts +43 -0
  335. package/dist/usability-capture.js +326 -0
  336. package/dist/usability-capture.js.map +1 -0
  337. package/dist/usage-config.d.ts +36 -0
  338. package/dist/usage-config.js +114 -0
  339. package/dist/usage-config.js.map +1 -0
  340. package/dist/ux-api.d.ts +3 -75
  341. package/dist/ux-api.js +3 -220
  342. package/dist/ux-api.js.map +1 -1
  343. package/dist/ux-cli.d.ts +4 -0
  344. package/dist/ux-cli.js +102 -0
  345. package/dist/ux-cli.js.map +1 -0
  346. package/dist/ux-config.d.ts +29 -0
  347. package/dist/ux-config.js +103 -0
  348. package/dist/ux-config.js.map +1 -0
  349. package/dist/ux-evidence.d.ts +54 -0
  350. package/dist/ux-evidence.js +197 -0
  351. package/dist/ux-evidence.js.map +1 -0
  352. package/dist/ux-review.d.ts +112 -0
  353. package/dist/ux-review.js +151 -0
  354. package/dist/ux-review.js.map +1 -0
  355. package/dist/ux-usability.d.ts +238 -0
  356. package/dist/ux-usability.js +494 -0
  357. package/dist/ux-usability.js.map +1 -0
  358. package/dist/verify-fix-api.d.ts +173 -0
  359. package/dist/verify-fix-api.js +454 -0
  360. package/dist/verify-fix-api.js.map +1 -0
  361. package/dist/verify-fix-cli.d.ts +4 -0
  362. package/dist/verify-fix-cli.js +110 -0
  363. package/dist/verify-fix-cli.js.map +1 -0
  364. package/package.json +19 -14
  365. package/skills/jevitate-ci-check/SKILL.md +77 -0
  366. package/skills/jevitate-demo/SKILL.md +61 -0
  367. package/skills/jevitate-explore/SKILL.md +88 -87
  368. package/skills/jevitate-getting-started/SKILL.md +88 -0
  369. package/skills/jevitate-load-test/SKILL.md +11 -2
  370. package/skills/jevitate-mission-scope/SKILL.md +19 -11
  371. package/skills/jevitate-record/SKILL.md +23 -5
  372. package/skills/jevitate-run-journey/SKILL.md +61 -17
  373. package/skills/jevitate-sources/SKILL.md +57 -14
  374. package/skills/jevitate-ux-review/SKILL.md +106 -16
  375. package/skills/jevitate-verify-fix/SKILL.md +76 -0
@@ -0,0 +1,235 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createReadStream, statSync } from "node:fs";
3
+ export class LogSourceSpecError extends Error {
4
+ code = "E_LOG_SOURCE_SPEC";
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "LogSourceSpecError";
8
+ }
9
+ }
10
+ /** Parses one `--log-source` value. Throws `LogSourceSpecError` on an unrecognized/empty spec. */
11
+ export function parseLogSourceSpec(raw) {
12
+ const i = raw.indexOf(":");
13
+ if (i < 0)
14
+ throw new LogSourceSpecError(`--log-source must be file:<path>, docker:<container> or cmd:<command>: got ${JSON.stringify(raw)}`);
15
+ const kind = raw.slice(0, i);
16
+ const rest = raw.slice(i + 1);
17
+ if (rest.trim() === "")
18
+ throw new LogSourceSpecError(`--log-source ${kind}: missing value`);
19
+ if (kind === "file")
20
+ return { kind: "file", path: rest, raw };
21
+ if (kind === "docker")
22
+ return { kind: "docker", container: rest, raw };
23
+ if (kind === "cmd")
24
+ return { kind: "cmd", command: rest, raw };
25
+ throw new LogSourceSpecError(`--log-source: unknown source kind ${JSON.stringify(kind)} (want file:, docker: or cmd:)`);
26
+ }
27
+ /**
28
+ * Validates every spec up front, INCLUDING the `cmd:` + `--allow-log-cmd` gate — so a run refuses
29
+ * before any browser opens, the same fail-closed discipline as `--invariants`.
30
+ */
31
+ export function parseLogSourceSpecs(raw, allowLogCmd) {
32
+ const specs = raw.map(parseLogSourceSpec);
33
+ for (const s of specs) {
34
+ if (s.kind === "cmd" && !allowLogCmd) {
35
+ throw new LogSourceSpecError(`--log-source ${s.raw} needs --allow-log-cmd (an operator-declared command is run as a subprocess)`);
36
+ }
37
+ }
38
+ return specs;
39
+ }
40
+ const DEFAULT_MAX_LINES = 20_000;
41
+ const DEFAULT_FILE_POLL_MS = 250;
42
+ function lineSplitter(onLine) {
43
+ let carry = "";
44
+ return (chunk) => {
45
+ carry += chunk.toString("utf8");
46
+ const lines = carry.split(/\r?\n/);
47
+ carry = lines.pop() ?? "";
48
+ for (const line of lines)
49
+ if (line !== "")
50
+ onLine(line, Date.now());
51
+ };
52
+ }
53
+ function boundedOnLine(handle, opts) {
54
+ const max = opts.maxLines ?? DEFAULT_MAX_LINES;
55
+ return (raw, epochMs) => {
56
+ if (handle.linesRead >= max) {
57
+ handle.truncated = true;
58
+ return;
59
+ }
60
+ handle.linesRead += 1;
61
+ opts.onLine(raw, epochMs);
62
+ };
63
+ }
64
+ /**
65
+ * `file:` — tails from the CURRENT end by polling the file's size (no `fs.watch`: flaky across
66
+ * filesystems, notably over WSL's `/mnt/c` drvfs — AGENTS.md). Handles truncation/rotation, AND a
67
+ * file that does not exist yet at open time (a backend that has not logged anything until later in
68
+ * the run is the common case, not an error): if the file already exists, its EXISTING content is
69
+ * history and skipped (`position` starts at its current size); if it does not exist yet, nothing
70
+ * can predate this run, so `position` starts at 0 and the first line written after the source
71
+ * opened is the first one delivered, however long the file takes to appear.
72
+ */
73
+ function openFileSource(spec, opts) {
74
+ let closed = false;
75
+ let timer;
76
+ let position = 0;
77
+ const handle = {
78
+ spec,
79
+ opened: false,
80
+ linesRead: 0,
81
+ truncated: false,
82
+ close: async () => {
83
+ closed = true;
84
+ if (timer !== undefined)
85
+ clearInterval(timer);
86
+ if (!handle.opened)
87
+ handle.error = `${spec.path}: never appeared during the run`;
88
+ },
89
+ killSync: () => {
90
+ closed = true;
91
+ if (timer !== undefined)
92
+ clearInterval(timer);
93
+ },
94
+ };
95
+ const deliver = lineSplitter(boundedOnLine(handle, opts));
96
+ try {
97
+ // The file already exists: its content predates this source and is skipped (never replayed).
98
+ position = statSync(spec.path).size;
99
+ handle.opened = true;
100
+ }
101
+ catch {
102
+ // Does not exist yet: `position` stays 0, so whatever is written once it appears is ALL new.
103
+ }
104
+ const poll = () => {
105
+ if (closed)
106
+ return;
107
+ let size;
108
+ try {
109
+ size = statSync(spec.path).size;
110
+ }
111
+ catch {
112
+ return; // still not there, or a transient stat failure — the next poll tries again
113
+ }
114
+ handle.opened = true; // confirmed readable now, even if it appeared after the initial check
115
+ if (size <= position) {
116
+ if (size < position)
117
+ position = 0; // truncated/rotated: resume from the new start
118
+ return;
119
+ }
120
+ const stream = createReadStream(spec.path, { start: position, end: size - 1 });
121
+ stream.on("data", (chunk) => deliver(chunk));
122
+ stream.on("error", () => undefined);
123
+ position = size;
124
+ };
125
+ timer = setInterval(poll, opts.filePollMs ?? DEFAULT_FILE_POLL_MS);
126
+ timer.unref?.();
127
+ return handle;
128
+ }
129
+ /** Kills a spawned child's whole process GROUP (POSIX): `docker logs`/`cmd:`'s own children die
130
+ * too, not just the immediate process. Falls back to killing just the child if the group send fails. */
131
+ function killGroup(child) {
132
+ const pid = child.pid;
133
+ if (pid === undefined)
134
+ return;
135
+ try {
136
+ process.kill(-pid, "SIGTERM");
137
+ }
138
+ catch {
139
+ try {
140
+ child.kill("SIGTERM");
141
+ }
142
+ catch {
143
+ // Already gone.
144
+ }
145
+ }
146
+ }
147
+ function openProcessSource(spec, command, args, opts, useShell) {
148
+ let child;
149
+ // #199: set the moment WE ask the child to stop (mission end) — BEFORE `killGroup` sends the
150
+ // signal, so the (always-async) `exit` event below, whenever it lands, can tell "we stopped this"
151
+ // from "it died on its own". A source jevitate stopped itself is a normal end of tailing, not a
152
+ // failure, no matter what exit code the child reports for its own signal handling (a `docker logs
153
+ // -f`/`cmd:` child commonly self-exits 143 for SIGTERM rather than dying to the raw signal).
154
+ let stopRequested = false;
155
+ const handle = {
156
+ spec,
157
+ opened: false,
158
+ linesRead: 0,
159
+ truncated: false,
160
+ close: async () => {
161
+ stopRequested = true;
162
+ if (child === undefined)
163
+ return;
164
+ killGroup(child);
165
+ await new Promise((resolve) => {
166
+ if (child === undefined || child.exitCode !== null || child.signalCode !== null) {
167
+ resolve();
168
+ return;
169
+ }
170
+ const done = () => resolve();
171
+ child.once("exit", done);
172
+ const t = setTimeout(done, 2000);
173
+ t.unref?.();
174
+ });
175
+ },
176
+ killSync: () => {
177
+ stopRequested = true;
178
+ if (child !== undefined)
179
+ killGroup(child);
180
+ },
181
+ };
182
+ try {
183
+ child = spawn(command, args, { detached: true, shell: useShell, stdio: ["ignore", "pipe", "pipe"] });
184
+ }
185
+ catch (e) {
186
+ handle.error = `cannot start ${spec.raw}: ${e instanceof Error ? e.message : String(e)}`;
187
+ return handle;
188
+ }
189
+ handle.opened = true;
190
+ const deliver = lineSplitter(boundedOnLine(handle, opts));
191
+ child.stdout.on("data", deliver);
192
+ child.stderr.on("data", deliver); // most backends interleave logs on stderr too (docker logs does)
193
+ child.on("error", (e) => {
194
+ handle.error = `${spec.raw}: ${e.message}`;
195
+ });
196
+ // Startup health check (#169): `docker logs -f <container>` on a container that isn't running (or
197
+ // doesn't exist) exits almost immediately with a non-zero code — its stderr ("Error: No such
198
+ // container: …") would otherwise just look like an ordinary, if odd, log line and count toward
199
+ // `linesRead`, hiding the failure. An early non-zero exit is decisive regardless of what was piped
200
+ // through in the meantime: this source was never actually tailing the backend.
201
+ //
202
+ // #199: BUT only when the child died on its own. `close()`/`killSync()` set `stopRequested` before
203
+ // signaling, so an exit that lands after WE asked this source to stop (mission end) is a normal
204
+ // end of tailing — never a failure, whatever code/signal the child reports for handling its own
205
+ // termination (SIGTERM commonly comes back as a self-reported exit code like 143, not `signal`).
206
+ child.on("exit", (code, signal) => {
207
+ if (stopRequested)
208
+ return;
209
+ if (code !== null && code !== 0 && handle.error === undefined) {
210
+ handle.error = `${spec.raw}: exited with code ${code}${signal === null ? "" : ` (signal ${signal})`} — the source may not be running`;
211
+ }
212
+ });
213
+ child.unref();
214
+ return handle;
215
+ }
216
+ /**
217
+ * Opens one already-validated `--log-source`. Never throws: an unreadable/unspawnable source comes
218
+ * back with `.error` set rather than aborting a run that has other sources (the caller decides
219
+ * whether that's fatal — a `--log-defect` oracle must not count an unreadable source as "held").
220
+ */
221
+ export function openLogSource(spec, opts) {
222
+ if (spec.kind === "file")
223
+ return openFileSource(spec, opts);
224
+ if (spec.kind === "docker")
225
+ return openProcessSource(spec, "docker", ["logs", "-f", "--since", "0s", spec.container], opts, false);
226
+ return openProcessSource(spec, spec.command, [], opts, true);
227
+ }
228
+ export function openLogSources(specs, opts) {
229
+ return specs.map((spec) => openLogSource(spec, opts));
230
+ }
231
+ /** Closes every handle, best-effort, in parallel. Never throws. */
232
+ export async function closeLogSources(handles) {
233
+ await Promise.all(handles.map((h) => h.close().catch(() => undefined)));
234
+ }
235
+ //# sourceMappingURL=log-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-sources.js","sourceRoot":"","sources":["../src/log-sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import { type CliDeps } from "./cli-shared.js";
3
+ export declare function registerLogsCommands(program: Command, deps: CliDeps): void;
@@ -0,0 +1,51 @@
1
+ import { ok, fail } from "./envelope.js";
2
+ import { LogsConfigError, loadLogsRetention, pruneLogs } from "./logs-retention.js";
3
+ import { logsRoot } from "./project-dir.js";
4
+ import { resolveDataDir } from "./data-dir.js";
5
+ import { emitJson } from "./cli-shared.js";
6
+ /** The commands that write run output under `.jevitate/logs` — pruned before, when auto-prune is on. */
7
+ const LOG_WRITING_COMMANDS = new Set(["explore", "explore-author-journey", "record", "ux", "check", "run", "verify-fix", "capture"]);
8
+ export function registerLogsCommands(program, deps) {
9
+ const configPath = deps.logs?.configPath ?? resolveDataDir(["config.json"]);
10
+ if (deps.logs?.autoPrune === true) {
11
+ program.hook("preAction", (_root, action) => {
12
+ if (!LOG_WRITING_COMMANDS.has(action.name()))
13
+ return;
14
+ // A malformed retention config fails closed (the command is refused); a file that cannot be
15
+ // deleted is housekeeping, not the run's business: it is reported and the command goes on.
16
+ const retention = loadLogsRetention(configPath);
17
+ try {
18
+ pruneLogs(deps.logs?.logsRoot ?? logsRoot(), retention);
19
+ }
20
+ catch (e) {
21
+ process.stderr.write(`warning: log pruning skipped: ${e instanceof Error ? e.message : String(e)}\n`);
22
+ }
23
+ });
24
+ }
25
+ const logs = program.command("logs").description("run output under .jevitate/logs (dated; pruned by retention)");
26
+ logs
27
+ .command("prune")
28
+ .description("delete runs older than the retention TTL, always keeping the newest runs (config.json logs.ttlDays / logs.keepLatest; defaults 14 and 50)")
29
+ .option("--dir <dir>", "logs root to prune (default: the project's .jevitate/logs, else ~/.jevitate/logs)")
30
+ .option("--dry-run", "list what would be deleted, deleting nothing")
31
+ .option("--json", "emit a JSON envelope")
32
+ .action(function () {
33
+ const o = this.opts();
34
+ try {
35
+ const retention = loadLogsRetention(configPath);
36
+ const report = pruneLogs(o.dir ?? deps.logs?.logsRoot ?? logsRoot(), retention, { ...(o.dryRun === true ? { dryRun: true } : {}) });
37
+ const data = { ...report, retention, dryRun: o.dryRun === true };
38
+ if (o.json === true)
39
+ emitJson(program, ok(data));
40
+ else
41
+ program.configureOutput().writeOut?.(`${o.dryRun === true ? "would remove" : "removed"} ${report.removed.length} run(s); kept ${report.keptRuns} (ttl ${retention.ttlDays}d, keep latest ${retention.keepLatest})\n`);
42
+ }
43
+ catch (err) {
44
+ if (err instanceof LogsConfigError)
45
+ emitJson(program, fail(err.code, err.message));
46
+ else
47
+ emitJson(program, fail("E_LOGS_PRUNE", err instanceof Error ? err.message : String(err)));
48
+ }
49
+ });
50
+ }
51
+ //# sourceMappingURL=logs-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-cli.js","sourceRoot":"","sources":["../src/logs-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Retention for run output under `.jevitate/logs/<date>/` (0.2.0): a run older than `ttlDays` is
3
+ * deleted, but the newest `keepLatest` runs are always kept, so a quiet project is never wiped.
4
+ * A run is every file and folder sharing its artifact stem (`explore-2026-09-25T01-26-29-787Z.*`).
5
+ * Pruned at the start of each command that writes logs, or on demand with `jevitate logs prune`.
6
+ * Configured in `~/.jevitate/config.json`: `{ "logs": { "ttlDays": 14, "keepLatest": 50 } }`.
7
+ */
8
+ export interface LogsRetention {
9
+ readonly ttlDays: number;
10
+ readonly keepLatest: number;
11
+ }
12
+ export declare const DEFAULT_LOGS_RETENTION: LogsRetention;
13
+ export declare class LogsConfigError extends Error {
14
+ readonly code: "E_LOGS_CONFIG";
15
+ }
16
+ /** The `logs` section of the config file; the defaults when the file or section is absent. A malformed value fails closed. */
17
+ export declare function loadLogsRetention(path?: string): LogsRetention;
18
+ export interface PruneReport {
19
+ readonly root: string;
20
+ /** Runs deleted (`<date>/<stem>`). */
21
+ readonly removed: string[];
22
+ readonly keptRuns: number;
23
+ }
24
+ /** Applies `retention` to the logs under `root`. `dryRun` reports what would go, deleting nothing. */
25
+ export declare function pruneLogs(root: string, retention: LogsRetention, opts?: {
26
+ readonly nowMs?: number;
27
+ readonly dryRun?: boolean;
28
+ }): PruneReport;
@@ -0,0 +1,84 @@
1
+ import { readFileSync, readdirSync, rmSync, rmdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { resolveDataDir } from "./data-dir.js";
4
+ export const DEFAULT_LOGS_RETENTION = { ttlDays: 14, keepLatest: 50 };
5
+ export class LogsConfigError extends Error {
6
+ code = "E_LOGS_CONFIG";
7
+ }
8
+ /** The `logs` section of the config file; the defaults when the file or section is absent. A malformed value fails closed. */
9
+ export function loadLogsRetention(path = resolveDataDir(["config.json"])) {
10
+ let raw;
11
+ try {
12
+ raw = readFileSync(path, "utf8");
13
+ }
14
+ catch (e) {
15
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT")
16
+ return DEFAULT_LOGS_RETENTION;
17
+ throw new LogsConfigError(`cannot read ${path}: ${e instanceof Error ? e.message : String(e)}`);
18
+ }
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(raw);
22
+ }
23
+ catch {
24
+ throw new LogsConfigError(`${path} is not valid JSON`);
25
+ }
26
+ const logs = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed.logs : undefined;
27
+ if (logs === undefined)
28
+ return DEFAULT_LOGS_RETENTION;
29
+ if (logs === null || typeof logs !== "object" || Array.isArray(logs))
30
+ throw new LogsConfigError(`${path}: "logs" must be an object`);
31
+ const o = logs;
32
+ const int = (k) => {
33
+ const v = o[k];
34
+ if (v === undefined)
35
+ return DEFAULT_LOGS_RETENTION[k];
36
+ if (typeof v !== "number" || !Number.isInteger(v) || v < 0)
37
+ throw new LogsConfigError(`${path}: logs.${k} must be a non-negative integer, got ${JSON.stringify(v)}`);
38
+ return v;
39
+ };
40
+ return { ttlDays: int("ttlDays"), keepLatest: int("keepLatest") };
41
+ }
42
+ const RUN_KEY = /^([a-z][a-z-]*-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)/;
43
+ function runsIn(root) {
44
+ let dates;
45
+ try {
46
+ dates = readdirSync(root).filter((d) => /^\d{4}-\d{2}-\d{2}$/.test(d));
47
+ }
48
+ catch (e) {
49
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT")
50
+ return { runs: [], dateDirs: [] };
51
+ throw e;
52
+ }
53
+ const byKey = new Map();
54
+ for (const date of dates) {
55
+ for (const name of readdirSync(join(root, date))) {
56
+ const path = join(root, date, name);
57
+ const key = `${date}/${RUN_KEY.exec(name)?.[1] ?? name}`;
58
+ const run = byKey.get(key) ?? { paths: [], mtimeMs: 0 };
59
+ run.paths.push(path);
60
+ run.mtimeMs = Math.max(run.mtimeMs, statSync(path).mtimeMs);
61
+ byKey.set(key, run);
62
+ }
63
+ }
64
+ return { runs: [...byKey].map(([key, r]) => ({ key, ...r })), dateDirs: dates.map((d) => join(root, d)) };
65
+ }
66
+ /** Applies `retention` to the logs under `root`. `dryRun` reports what would go, deleting nothing. */
67
+ export function pruneLogs(root, retention, opts = {}) {
68
+ const nowMs = opts.nowMs ?? Date.now();
69
+ const { runs, dateDirs } = runsIn(root);
70
+ const newestFirst = [...runs].sort((a, b) => b.mtimeMs - a.mtimeMs);
71
+ const cutoff = nowMs - retention.ttlDays * 86_400_000;
72
+ const doomed = newestFirst.slice(retention.keepLatest).filter((r) => r.mtimeMs < cutoff);
73
+ if (opts.dryRun !== true) {
74
+ for (const r of doomed)
75
+ for (const p of r.paths)
76
+ rmSync(p, { recursive: true, force: true });
77
+ for (const d of dateDirs) {
78
+ if (readdirSync(d).length === 0)
79
+ rmdirSync(d);
80
+ }
81
+ }
82
+ return { root, removed: doomed.map((r) => r.key).sort(), keptRuns: runs.length - doomed.length };
83
+ }
84
+ //# sourceMappingURL=logs-retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-retention.js","sourceRoot":"","sources":["../src/logs-retention.ts"],"names":[],"mappings":"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"}
package/dist/mcp-api.d.ts CHANGED
@@ -1,6 +1,17 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { type AiGenerateTextArgs, type AiGenerateTextResult } from "@jevitate/mcp-facade";
3
3
  import { type CredentialStore, type GenerationPort, type SetupRequiredResult } from "@jevitate/ai-core";
4
+ import type { JudgmentPort, UsageTracker } from "@jevitate/ai-core";
5
+ import type { SelfHealer } from "@jevitate/runtime";
6
+ import type { EmulationSpec } from "@jevitate/playwright";
7
+ import { type RunPolicy } from "@jevitate/domain";
8
+ import { type RunVerifyFixOptions, type VerifyFixReport } from "./verify-fix-api.js";
9
+ import { type BrowserRunOptions } from "./browser-run-options.js";
10
+ import { type ResolvedJourneyEnvironment } from "./environments.js";
11
+ import { type MissionFixtures } from "./mission-fixtures.js";
12
+ import { type ScreenshotsSpec } from "./run-screenshots.js";
13
+ import type { McpCliRunner } from "./mcp-cli-runner.js";
14
+ import { type EngineInfo } from "./engine.js";
4
15
  /**
5
16
  * The MCP stdio server behind `jevitate mcp`. It exposes ONLY the tools in
6
17
  * `@jevitate/mcp-facade`'s `ALLOWED_TOOLS` and structurally CANNOT serve any
@@ -27,12 +38,34 @@ export interface McpTool {
27
38
  type: "object";
28
39
  properties: Record<string, unknown>;
29
40
  required?: string[];
41
+ additionalProperties?: boolean;
30
42
  };
31
43
  handler: (args: Record<string, unknown>) => Promise<McpToolResult>;
32
44
  }
45
+ /** #255: what an extended `run_journey` call adds — every field resolved and validated by the handler. */
46
+ export interface McpJourneyRunOptions {
47
+ readonly policy?: RunPolicy;
48
+ readonly selfHealer?: SelfHealer;
49
+ readonly environment?: ResolvedJourneyEnvironment;
50
+ readonly browser?: BrowserRunOptions;
51
+ readonly emulation?: EmulationSpec;
52
+ readonly screenshots?: ScreenshotsSpec;
53
+ readonly fixtures?: (site: string) => MissionFixtures | undefined;
54
+ }
55
+ /**
56
+ * #255: what `verify_fix` hands the runner — the finding (resolved result path + fingerprint) and
57
+ * the CLI-parity replay options. Operator-only settings (shell hooks, `cmd:` log sources, re-sending
58
+ * paid/destructive hang writes, redaction literals) are never MCP arguments: targets.json decides.
59
+ */
60
+ export type McpVerifyFixArgs = Pick<RunVerifyFixOptions, "resultPath" | "fingerprint"> & Partial<Pick<RunVerifyFixOptions, "storageState" | "browser" | "replays" | "invariantFiles" | "fixtureFlags" | "emulation" | "allowEmulationOverride" | "screenshots">>;
33
61
  export interface McpApiDeps {
34
62
  /** Journeys store directory (`~/.jevitate/journeys` in production). */
35
63
  journeysDir: string;
64
+ /**
65
+ * The site-policy database (`jevitate site policy set`): `run_journey` is paced, throttled,
66
+ * budgeted and kept out of quiet hours per the Journey's origin. Absent file = no policy.
67
+ */
68
+ sitePolicyDbPath?: string;
36
69
  /**
37
70
  * Test seam. Defaults to the real promoted-only projection over the
38
71
  * journeys store (`@jevitate/mcp-facade`'s `findCapabilities`).
@@ -41,8 +74,37 @@ export interface McpApiDeps {
41
74
  /**
42
75
  * Test seam. Defaults to `runJourneyProgrammatically` with a fail-closed
43
76
  * `safeRunPolicy()` (invariant #5: PUBLISHED-id-only, never inline steps).
77
+ * `storageState` (#118) is a PATH to a Playwright storageState JSON file — the file is
78
+ * read only by the server's own browser launch; its contents never enter this handler,
79
+ * an MCP result, or a log.
80
+ */
81
+ runJourney?: (id: string, params: Record<string, string>, storageState?: string, options?: McpJourneyRunOptions) => Promise<unknown>;
82
+ /**
83
+ * #255: the directories MCP path arguments (storage states, fixtures, invariants, output dirs)
84
+ * must resolve inside — default: the project and `~/.jevitate` (mcp-paths.ts).
85
+ */
86
+ pathRoots?: readonly string[];
87
+ /** #255 (`run_journey {env}`): the environments file (default: the repo's `.jevitate/environments.json`). */
88
+ environmentsFile?: string;
89
+ /** `~/.jevitate/targets.json` override (environment sessions, verify_fix target config). */
90
+ targetsConfigPath?: string;
91
+ /**
92
+ * #255 (`run_journey {selfHeal: hybrid|full}`): builds the self-heal gateways exactly as the CLI's
93
+ * `--real`/`--fake-ai` do (`buildExploreGateways`). Absent: a heal mode is refused (setup_required).
94
+ */
95
+ selfHealGateways?: (sel: {
96
+ real: boolean;
97
+ fakeAi: boolean;
98
+ }) => Promise<{
99
+ judge: JudgmentPort;
100
+ gen: GenerationPort;
101
+ usage: UsageTracker;
102
+ }>;
103
+ /**
104
+ * #255: the CLI in-process (mcp-cli-runner.ts) — backs every MCP tool that mirrors a CLI command
105
+ * (mcp-cli-tools.ts). Absent: those tools refuse with `not_configured`.
44
106
  */
45
- runJourney?: (id: string, params: Record<string, string>) => Promise<unknown>;
107
+ runCli?: McpCliRunner;
46
108
  /**
47
109
  * Promoted mission-target store directory (`~/.jevitate/missions/targets` in
48
110
  * production — the SAME store `jevitate mission target` writes). Required for
@@ -89,6 +151,32 @@ export interface McpApiDeps {
89
151
  * returns a typed `setup_required` result instead of calling the model.
90
152
  */
91
153
  aiGenerateText?: (args: AiGenerateTextArgs) => Promise<AiGenerateTextResult | SetupRequiredResult>;
154
+ /**
155
+ * Directory holding mission artifacts (the logs root in production): the typed
156
+ * `<id>.result.json` files `get_mission_result` reads. A missing dir is a config refusal.
157
+ */
158
+ recordingsDir?: string;
159
+ /**
160
+ * Where usability reviews write their artifacts (0.1.0: `~/.jevitate/ux-reports`): a
161
+ * `usability-<stamp>` result is looked up here after `recordingsDir`.
162
+ */
163
+ uxReportsDir?: string;
164
+ /**
165
+ * The directories a result id's files may be in, most likely first (production: its dated
166
+ * `.jevitate/logs/<date>` dir in the project, then `~/.jevitate`, then the 0.1.0 locations).
167
+ * Replaces `recordingsDir`/`uxReportsDir` for the lookup when given.
168
+ */
169
+ resultDirsFor?: (resultId: string) => string[];
170
+ /**
171
+ * Test seam. Defaults to `runVerifyFix` over `<recordingsDir>/<id>.result.json`: replays the
172
+ * finding's repro in a fresh browser (authorized against the mission's own allowlist).
173
+ */
174
+ verifyFix?: (args: McpVerifyFixArgs) => Promise<VerifyFixReport>;
175
+ /**
176
+ * The serving build's identity (#112) — reported by `initialize` (`serverInfo.version`) and by
177
+ * `get_site_health`. Defaults to this build's `currentEngineInfo()`.
178
+ */
179
+ engine?: EngineInfo;
92
180
  }
93
181
  /**
94
182
  * Builds the served tool descriptors — EXACTLY one per `ALLOWED_TOOLS` entry.