@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,4 @@
1
+ import { Command } from "commander";
2
+ import { type CliDeps } from "./cli-shared.js";
3
+ /** Registers the long-running servers: `jevitate mcp` and `jevitate ui`. */
4
+ export declare function registerServeCommands(program: Command, deps: CliDeps, buildProgram: (deps: CliDeps) => Command): void;
@@ -0,0 +1,95 @@
1
+ import { envCredentialStore, OpenRouterGenerationGateway } from "@jevitate/ai-core";
2
+ import { loadLocalCredentials } from "./credentials-file.js";
3
+ import { fail } from "./envelope.js";
4
+ import { startMcpServer } from "./mcp-api.js";
5
+ import { realOpenRouterCall } from "./openrouter-call.js";
6
+ import { startUiServer } from "./ui-api.js";
7
+ import { intArg } from "./cli-args.js";
8
+ import { renderPrintConfig } from "./init-mcp.js";
9
+ import { mcpToolDeps } from "./mcp-cli-bridge.js";
10
+ import { makeInProcessCliRunner } from "./mcp-cli-runner.js";
11
+ import { resolveJourneysDir, resolveInboxDir, emitJson, DEFAULT_EXPLORE_CATALOG, DEFAULT_EXPLORE_CONSTRAINTS, } from "./cli-shared.js";
12
+ /** Registers the long-running servers: `jevitate mcp` and `jevitate ui`. */
13
+ export function registerServeCommands(program, deps, buildProgram) {
14
+ // Additive: `jevitate mcp` (Ticket #20) — start an MCP stdio server that
15
+ // exposes ONLY `@jevitate/mcp-facade`'s allowlisted tools (never the raw
16
+ // browser primitives in FORBIDDEN_TOOLS). This is the subcommand form of the
17
+ // MCP server (single-bundle deployment — no separate published package).
18
+ // The server owns stdin/stdout as the MCP protocol channel, so on success it
19
+ // blocks and writes NOTHING to stdout; only a setup failure (before the
20
+ // transport connects) emits a JSON envelope.
21
+ program
22
+ .command("mcp")
23
+ .description("start an MCP stdio server exposing only the allowlisted Jevitate tools")
24
+ .option("--dir <path>", "journeys directory (default: the repo's .jevitate/journeys; outside a repo ~/.jevitate/journeys)")
25
+ .option("--print-config <harness>", "print the config snippet to register `jevitate mcp` in a harness (claude | cursor | codex | json) and exit — prints only, writes nothing")
26
+ .action(async function () {
27
+ const { dir, printConfig } = this.opts();
28
+ // `--print-config <harness>` is the universal escape hatch: render the
29
+ // exact registration snippet and exit WITHOUT starting the server (safe:
30
+ // no writes, no stdio takeover). An unknown harness is a fail envelope.
31
+ if (printConfig !== undefined) {
32
+ const harness = printConfig;
33
+ if (harness !== "claude" && harness !== "cursor" && harness !== "codex" && harness !== "json") {
34
+ emitJson(program, fail("E_MCP_PRINT_CONFIG", `--print-config must be one of claude | cursor | codex | json (got '${printConfig}')`));
35
+ return;
36
+ }
37
+ program.configureOutput().writeOut?.(`${renderPrintConfig(harness)}\n`);
38
+ process.exitCode = 0;
39
+ return;
40
+ }
41
+ try {
42
+ // Credential store + generation gateway for the allowlisted
43
+ // `ai_generate_text` tool. The gateway is the REAL OpenRouter adapter:
44
+ // the key is read only inside it (Authorization header only), every
45
+ // outbound payload passes the never-to-model guard, and the facade's
46
+ // preflight returns a typed `setup_required` when the key is absent —
47
+ // so no `--real/--fake` flag is needed for the non-interactive server.
48
+ const aiStore = envCredentialStore(deps.ai?.env ?? process.env, deps.ai?.localConfig ?? loadLocalCredentials());
49
+ const generationGateway = deps.ai?.gateway ??
50
+ new OpenRouterGenerationGateway({
51
+ store: aiStore,
52
+ catalog: deps.ai?.catalog ?? DEFAULT_EXPLORE_CATALOG,
53
+ constraints: deps.ai?.constraints ?? DEFAULT_EXPLORE_CONSTRAINTS,
54
+ call: await realOpenRouterCall(),
55
+ });
56
+ // #254: the same default stores the CLI's `inbox`/`mission queue`/`mission result` read (mcpToolDeps).
57
+ // #255: the CLI-mirroring tools run the SAME program in process, over the same journeys dir.
58
+ const journeysDir = resolveJourneysDir(deps, dir);
59
+ const runCli = makeInProcessCliRunner(() => buildProgram({ ...deps, journeysDir }));
60
+ await startMcpServer(mcpToolDeps(deps, { journeysDir, credentialStore: aiStore, generationGateway, runCli }));
61
+ }
62
+ catch (err) {
63
+ emitJson(program, fail("E_MCP_SERVE", String(err instanceof Error ? err.message : err)));
64
+ }
65
+ });
66
+ // Additive: `jevitate ui` (Task 8) — starts the local, loopback-only HTTP
67
+ // HITL approval dashboard (ui-api.ts's `startUiServer`). Resolves the SAME
68
+ // inbox dir `jevitate mcp`'s inbox tools serve (resolveInboxDir), so the
69
+ // two commands agree on where approvals/handbacks/reviews live. On success
70
+ // it prints the bound URL (carrying the capability token) and stays alive —
71
+ // the open HTTP server keeps the process running, the same way `mcp`'s open
72
+ // stdio transport does.
73
+ program
74
+ .command("ui")
75
+ .description("start the local HITL approval dashboard (loopback-only HTTP server)")
76
+ .option("--port <n>", "explicit port (fails on conflict; default 4180, retries on conflict)", intArg({ min: 0, max: 65535 }))
77
+ .option("--no-open", "do not open the dashboard URL in the default browser")
78
+ .option("--inbox-dir <path>", "inbox store directory (default: ~/.jevitate/inbox — same dir `jevitate mcp` serves)")
79
+ .action(async function () {
80
+ const o = this.opts();
81
+ try {
82
+ const start = deps.ui?.startUiServer ?? startUiServer;
83
+ const handle = await start({
84
+ inboxDir: resolveInboxDir(deps, o.inboxDir),
85
+ open: o.open ?? true,
86
+ ...(o.port !== undefined ? { port: Number(o.port) } : {}),
87
+ });
88
+ program.configureOutput().writeOut?.(`${handle.url}\n`);
89
+ }
90
+ catch (err) {
91
+ emitJson(program, fail("E_UI_SERVE", String(err instanceof Error ? err.message : err)));
92
+ }
93
+ });
94
+ }
95
+ //# sourceMappingURL=serve-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve-cli.js","sourceRoot":"","sources":["../src/serve-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { Recording } from "@jevitate/recording";
2
+ import { type VerifyFixResult, type VerifySession } from "@jevitate/explore";
3
+ /**
4
+ * `verify-fix` for a `server-log` defect (#142): NOT a re-check of `@jevitate/explore`'s
5
+ * `verifyFix` (which looks for a fingerprint among DOM/console/network signals — a server log line
6
+ * is none of those). Instead, this replays the defect's recorded steps in a fresh browser session
7
+ * AND re-opens the SAME log sources for the SAME drain window, and asks whether a line matching
8
+ * the SAME matcher and the SAME normalized message reappears. Kept entirely in the CLI layer (new
9
+ * file) — `packages/explore/src/verify-fix.ts` is untouched.
10
+ *
11
+ * Mirrors `verifyFix`'s own replay discipline (#74): `replays` fresh-context attempts, only ones
12
+ * that actually reached the defect's step count as evidence, and the pure `verifyReplayVerdict`
13
+ * rule (fired on every ran attempt ⇒ still-reproduces, none ⇒ fixed, a mix ⇒ intermittent — never
14
+ * "fixed" off one clean replay).
15
+ */
16
+ export interface VerifyServerLogParams {
17
+ readonly recording: Recording;
18
+ /** Flat index of the last Recording step to replay (the defect's `repro.recordingStepIndex`). */
19
+ readonly recordingStepIndex: number;
20
+ readonly fingerprint: string;
21
+ /** The defect's persisted log sources (raw `--log-source` specs) and matcher (raw `--log-defect`). */
22
+ readonly sources: readonly string[];
23
+ readonly matcher: string;
24
+ readonly normalizedMessage: string;
25
+ readonly drainMs: number;
26
+ readonly allowLogCmd: boolean;
27
+ /** Opens a FRESH browser session (never the one the defect was found in). */
28
+ readonly openSession: () => Promise<VerifySession>;
29
+ readonly settleCeilingMs?: number;
30
+ readonly targetTimeoutMs?: number;
31
+ /** Fresh-context replays (#74). Default `DEFAULT_VERIFY_REPLAYS` (mirrors `@jevitate/explore`). */
32
+ readonly replays?: number;
33
+ }
34
+ export declare function verifyServerLogDefect(params: VerifyServerLogParams): Promise<VerifyFixResult>;
@@ -0,0 +1,115 @@
1
+ import { RecordingInterpreter } from "@jevitate/interpreter";
2
+ import { perceive, verifyReplayVerdict } from "@jevitate/explore";
3
+ import { closeLogSources, openLogSources, parseLogSourceSpecs } from "./log-sources.js";
4
+ import { matchesLogDefect, normalizeLogMessage, parseLogDefectSpec, parseLogLine } from "./log-lines.js";
5
+ const DEFAULT_REPLAYS = 3;
6
+ function firstLine(e) {
7
+ return e instanceof Error ? e.message.split("\n")[0] ?? e.message : String(e);
8
+ }
9
+ function sleep(ms) {
10
+ return new Promise((resolve) => {
11
+ const t = setTimeout(resolve, ms);
12
+ t.unref?.();
13
+ });
14
+ }
15
+ async function runOneServerLogReplay(params, sourceSpecs) {
16
+ const lines = [];
17
+ const handles = openLogSources(sourceSpecs, {
18
+ onLine: (raw, arrivalEpochMs) => {
19
+ if (lines.length >= 5_000)
20
+ return;
21
+ lines.push(parseLogLine(raw, arrivalEpochMs, ""));
22
+ },
23
+ });
24
+ let session;
25
+ try {
26
+ session = await params.openSession();
27
+ }
28
+ catch (e) {
29
+ await closeLogSources(handles);
30
+ return {
31
+ ran: false,
32
+ fired: false,
33
+ detail: `could not open a fresh session: ${firstLine(e)}`,
34
+ replay: { outcome: "failed", at: -1, error: firstLine(e) },
35
+ };
36
+ }
37
+ try {
38
+ const interpreter = new RecordingInterpreter(params.targetTimeoutMs === undefined ? {} : { targetTimeoutMs: params.targetTimeoutMs });
39
+ const outcome = await interpreter.runToCheckpoint(session.actor, params.recording, params.recordingStepIndex);
40
+ await perceive(session.page, {
41
+ ...(params.settleCeilingMs === undefined ? {} : { renderWaitMs: params.settleCeilingMs }),
42
+ }).catch(() => undefined);
43
+ // Hold the log sources open for the SAME drain window the original run used, so async backend
44
+ // work that settles late is caught here too — never blocking anything but this one attempt.
45
+ await sleep(params.drainMs);
46
+ await closeLogSources(handles);
47
+ const matcher = parseLogDefectSpec(params.matcher);
48
+ const fired = lines.some((l) => matchesLogDefect(l, matcher) && normalizeLogMessage(l.message) === params.normalizedMessage);
49
+ if (outcome.outcome !== "completed") {
50
+ const replay = outcome.outcome === "failed"
51
+ ? { outcome: "failed", at: outcome.at, error: outcome.error.split("\n")[0] ?? outcome.error, ...(outcome.reason === undefined ? {} : { reason: outcome.reason }) }
52
+ : { outcome: "failed", at: outcome.at, error: "replay paused for a human hand-back" };
53
+ const mismatch = outcome.outcome === "failed" && outcome.reason !== undefined;
54
+ return {
55
+ ran: false,
56
+ fired,
57
+ replay,
58
+ detail: mismatch
59
+ ? `replay stopped at step ${outcome.at}: ${outcome.reason} — the recorded path was not reproduced, so this proves nothing`
60
+ : `replay could not reach step ${params.recordingStepIndex} (failed at ${outcome.at}); the log source was not re-checked against the intended step`,
61
+ };
62
+ }
63
+ return {
64
+ ran: true,
65
+ fired,
66
+ replay: { outcome: "completed" },
67
+ detail: fired
68
+ ? "a matching server log line reappeared during the drain window"
69
+ : "replay reached the defect's step and no matching server log line appeared within the drain window",
70
+ };
71
+ }
72
+ catch (e) {
73
+ await closeLogSources(handles).catch(() => undefined);
74
+ return { ran: false, fired: false, detail: `replay failed: ${firstLine(e)}`, replay: { outcome: "failed", at: -1, error: firstLine(e) } };
75
+ }
76
+ finally {
77
+ await session.close().catch(() => undefined);
78
+ }
79
+ }
80
+ export async function verifyServerLogDefect(params) {
81
+ const base = { fingerprint: params.fingerprint };
82
+ let sourceSpecs;
83
+ try {
84
+ sourceSpecs = parseLogSourceSpecs(params.sources, params.allowLogCmd);
85
+ parseLogDefectSpec(params.matcher); // validated once up front, fail closed
86
+ }
87
+ catch (e) {
88
+ return {
89
+ ...base,
90
+ verdict: "inconclusive",
91
+ observedFingerprints: [],
92
+ replay: { outcome: "failed", at: -1, error: "not replayed" },
93
+ reason: `the defect's log source(s)/matcher no longer parse: ${firstLine(e)}`,
94
+ };
95
+ }
96
+ const replays = params.replays ?? DEFAULT_REPLAYS;
97
+ if (!Number.isInteger(replays) || replays < 1)
98
+ throw new Error(`verifyServerLogDefect: replays must be >= 1, got ${replays}`);
99
+ const runs = [];
100
+ for (let i = 0; i < replays; i++)
101
+ runs.push(await runOneServerLogReplay(params, sourceSpecs));
102
+ const last = runs[runs.length - 1];
103
+ const verdict = verifyReplayVerdict(runs);
104
+ const ran = runs.filter((r) => r.ran).length;
105
+ const fired = runs.filter((r) => r.ran && r.fired).length;
106
+ const reason = verdict === "inconclusive"
107
+ ? last.detail
108
+ : verdict === "still-reproduces"
109
+ ? `the matching server log line reappeared on all ${fired}/${ran} replay(s) that ran`
110
+ : verdict === "fixed"
111
+ ? `no matching server log line appeared on any of the ${ran}/${runs.length} replay(s) that ran`
112
+ : `the matching server log line appeared on ${fired}/${ran} replay(s) that ran — intermittent on the current code, never reported as fixed`;
113
+ return { ...base, verdict, observedFingerprints: fired > 0 ? [params.fingerprint] : [], replay: last.replay, reason, attempts: runs.map((r) => ({ ran: r.ran, fired: r.fired, detail: r.detail })) };
114
+ }
115
+ //# sourceMappingURL=server-log-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-log-verify.js","sourceRoot":"","sources":["../src/server-log-verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * #213: was a run's `--storage-state` (a persona's) session honoured? A dead session (an expired or
3
+ * bogus cookie) does not fail the run by itself: the app shows its sign-in form, and a goal run's
4
+ * model may simply sign in on its own — the run then passes, silently testing as whoever it logged
5
+ * in as, not the persona. Code-decided from the FIRST page the run decided on (its seed landing):
6
+ * a login-like URL (the #82 pattern), or a sign-in form — a visible password field — on it.
7
+ *
8
+ * Returns why the session was not honoured, or undefined (no storage state given, or the first page
9
+ * was not a sign-in page). Never a verdict about the app: a warning on the result and the summary.
10
+ */
11
+ export declare function sessionLostReason(data: {
12
+ readonly target?: unknown;
13
+ readonly transcript?: unknown;
14
+ }): string | undefined;
@@ -0,0 +1,44 @@
1
+ import { basename } from "node:path";
2
+ import { isLoginLikeUrl } from "@jevitate/explore";
3
+ /**
4
+ * #213: was a run's `--storage-state` (a persona's) session honoured? A dead session (an expired or
5
+ * bogus cookie) does not fail the run by itself: the app shows its sign-in form, and a goal run's
6
+ * model may simply sign in on its own — the run then passes, silently testing as whoever it logged
7
+ * in as, not the persona. Code-decided from the FIRST page the run decided on (its seed landing):
8
+ * a login-like URL (the #82 pattern), or a sign-in form — a visible password field — on it.
9
+ *
10
+ * Returns why the session was not honoured, or undefined (no storage state given, or the first page
11
+ * was not a sign-in page). Never a verdict about the app: a warning on the result and the summary.
12
+ */
13
+ export function sessionLostReason(data) {
14
+ const target = isRecord(data.target) ? data.target : undefined;
15
+ const state = typeof target?.storageStatePath === "string" ? target.storageStatePath : undefined;
16
+ if (state === undefined)
17
+ return undefined;
18
+ const first = Array.isArray(data.transcript) ? data.transcript.find(isRecord) : undefined;
19
+ if (first === undefined)
20
+ return undefined;
21
+ const url = typeof first.url === "string" ? first.url : "";
22
+ const controls = Array.isArray(first.controls) ? first.controls.filter((c) => typeof c === "string") : [];
23
+ const loginUrl = url !== "" && isLoginLikeUrl(url);
24
+ const passwordField = controls.some((c) => PASSWORD_CONTROL.test(c));
25
+ if (!loginUrl && !passwordField)
26
+ return undefined;
27
+ const where = pathOf(url);
28
+ const what = loginUrl ? `the first page was a sign-in page (${where})` : `the first page (${where}) showed a sign-in form (a password field)`;
29
+ return `the session in ${basename(state)} was not honoured — ${what}; the run did not start signed in as that session (re-save the storage state, or check its cookie is still valid)`;
30
+ }
31
+ /** A password field's control identity (`textbox "Password"`, `textbox "Passcode"`, …). */
32
+ const PASSWORD_CONTROL = /^(?:textbox|searchbox)\s+"[^"]*\b(?:password|passcode|passwort|mot de passe)\b[^"]*"$/i;
33
+ function pathOf(url) {
34
+ try {
35
+ return new URL(url).pathname;
36
+ }
37
+ catch {
38
+ return url === "" ? "?" : url;
39
+ }
40
+ }
41
+ function isRecord(v) {
42
+ return v !== null && typeof v === "object" && !Array.isArray(v);
43
+ }
44
+ //# sourceMappingURL=session-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-check.js","sourceRoot":"","sources":["../src/session-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkE;IAClG,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,MAAM,EAAE,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;IACjG,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvH,MAAM,QAAQ,GAAG,GAAG,KAAK,EAAE,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,sCAAsC,KAAK,GAAG,CAAC,CAAC,CAAC,mBAAmB,KAAK,4CAA4C,CAAC;IAC9I,OAAO,kBAAkB,QAAQ,CAAC,KAAK,CAAC,uBAAuB,IAAI,mHAAmH,CAAC;AACzL,CAAC;AAED,2FAA2F;AAC3F,MAAM,gBAAgB,GAAG,wFAAwF,CAAC;AAElH,SAAS,MAAM,CAAC,GAAW;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ import { type CliDeps } from "./cli-shared.js";
3
+ /** Registers `jevitate site`: `policy get|set` and `simulate`. */
4
+ export declare function registerSiteCommands(program: Command, deps: CliDeps): void;
@@ -0,0 +1,127 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { SitePolicySchema, simulateTiming } from "@jevitate/domain";
3
+ import { ok, fail } from "./envelope.js";
4
+ import { sitePolicyKey } from "./site-gate-cli.js";
5
+ import { resolveDbPath, withSitePolicyRepository, parsePlannedScript, emitJson } from "./cli-shared.js";
6
+ /** Registers `jevitate site`: `policy get|set` and `simulate`. */
7
+ export function registerSiteCommands(program, deps) {
8
+ const site = program
9
+ .command("site")
10
+ .description("per-site policies for Journey runs: human-like pacing, throttles, run budgets and quiet hours");
11
+ const sitePolicy = site
12
+ .command("policy")
13
+ .description("read or set a site's policy (the site is the Journey's origin, e.g. https://app.example.com)");
14
+ sitePolicy
15
+ .command("get <site>")
16
+ .description("print the policy for a site (an origin) and account")
17
+ .option("--account <account>", "account id", "primary")
18
+ .option("--db <path>", "sqlite db path")
19
+ .option("--json", "emit a JSON envelope")
20
+ .action(async function (siteId) {
21
+ const { account, db, json } = this.opts();
22
+ try {
23
+ const dbPath = resolveDbPath(deps, db);
24
+ const policy = await withSitePolicyRepository(dbPath, (repository) => repository.get(sitePolicyKey(siteId), account));
25
+ const envelope = ok(policy);
26
+ if (json) {
27
+ emitJson(program, envelope);
28
+ }
29
+ else {
30
+ if (policy) {
31
+ program.configureOutput().writeOut?.(`policy for '${siteId}' (version ${policy.version}): ${JSON.stringify(policy)}\n`);
32
+ }
33
+ else {
34
+ program.configureOutput().writeOut?.(`no policy configured for '${siteId}' (account '${account}')\n`);
35
+ }
36
+ process.exitCode = 0;
37
+ }
38
+ }
39
+ catch (err) {
40
+ emitJson(program, fail("E_SITE_POLICY_GET", String(err)));
41
+ }
42
+ });
43
+ sitePolicy
44
+ .command("set <site>")
45
+ .description("set the policy for a site (an origin): Journey runs there are paced, throttled, budgeted and kept out of quiet hours " +
46
+ "(journey run, source run, check, MCP run_journey); load run applies the pacing only")
47
+ .requiredOption("--file <path>", "path to a policy JSON file")
48
+ .option("--account <account>", "account id", "primary")
49
+ .option("--db <path>", "sqlite db path")
50
+ .option("--json", "emit a JSON envelope")
51
+ .action(async function (siteId) {
52
+ const { account, db, file, json } = this.opts();
53
+ let policy;
54
+ try {
55
+ const raw = await readFile(file, "utf8");
56
+ policy = SitePolicySchema.parse(JSON.parse(raw));
57
+ }
58
+ catch (err) {
59
+ emitJson(program, fail("E_INVALID_POLICY", String(err)));
60
+ return;
61
+ }
62
+ try {
63
+ const dbPath = resolveDbPath(deps, db);
64
+ // The policy is stored (and reported) under the site's origin: a page URL names its origin.
65
+ const site = sitePolicyKey(siteId);
66
+ await withSitePolicyRepository(dbPath, (repository) => repository.set(site, account, policy));
67
+ const envelope = ok({ site, account, version: policy.version });
68
+ if (json) {
69
+ emitJson(program, envelope);
70
+ }
71
+ else {
72
+ program.configureOutput().writeOut?.(`policy for '${site}' (account '${account}') set to version ${policy.version}\n`);
73
+ process.exitCode = 0;
74
+ }
75
+ }
76
+ catch (err) {
77
+ emitJson(program, fail("E_SITE_POLICY_SET", String(err)));
78
+ }
79
+ });
80
+ site
81
+ .command("simulate <site>")
82
+ .description("estimate, offline, how long a planned step script takes under a site's pacing policy")
83
+ .requiredOption("--script <path>", "path to a planned-step script JSON file")
84
+ .option("--seed <n>", "deterministic RNG seed", "0")
85
+ .option("--account <account>", "account id", "primary")
86
+ .option("--db <path>", "sqlite db path")
87
+ .option("--json", "emit a JSON envelope")
88
+ .action(async function (siteId) {
89
+ const { account, db, script, seed, json } = this.opts();
90
+ let plannedScript;
91
+ try {
92
+ const raw = await readFile(script, "utf8");
93
+ plannedScript = parsePlannedScript(raw);
94
+ }
95
+ catch (err) {
96
+ emitJson(program, fail("E_INVALID_SCRIPT", String(err)));
97
+ return;
98
+ }
99
+ const seedNum = Number(seed);
100
+ if (!Number.isFinite(seedNum)) {
101
+ emitJson(program, fail("E_INVALID_SEED", `--seed must be a finite number, got ${JSON.stringify(seed)}`));
102
+ return;
103
+ }
104
+ try {
105
+ const dbPath = resolveDbPath(deps, db);
106
+ const policy = await withSitePolicyRepository(dbPath, (repository) => repository.get(sitePolicyKey(siteId), account));
107
+ const interaction = policy?.interaction ?? {};
108
+ const profile = simulateTiming(interaction, seedNum, plannedScript);
109
+ const envelope = ok(profile);
110
+ if (json) {
111
+ emitJson(program, envelope);
112
+ }
113
+ else {
114
+ const out = program.configureOutput().writeOut;
115
+ for (const step of profile.steps) {
116
+ out?.(`${step.kind} '${step.label}': ${step.delayMs}ms\n`);
117
+ }
118
+ out?.(`totalMs: ${profile.totalMs}\n`);
119
+ process.exitCode = 0;
120
+ }
121
+ }
122
+ catch (err) {
123
+ emitJson(program, fail("E_SITE_SIMULATE", String(err)));
124
+ }
125
+ });
126
+ }
127
+ //# sourceMappingURL=site-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-cli.js","sourceRoot":"","sources":["../src/site-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Recording } from "@jevitate/recording";
2
+ import type { Ability } from "@jevitate/screenplay";
3
+ import { type SiteGateDeps } from "@jevitate/runtime";
4
+ /**
5
+ * The site-policy gate's repositories (`jevitate site policy set`), opened from the policy database
6
+ * for the duration of `fn`. No database file means no policy was ever set: `fn` gets `undefined`,
7
+ * and nothing is created on disk.
8
+ */
9
+ export declare function withSiteGate<T>(dbPath: string | undefined, fn: (deps: SiteGateDeps | undefined) => Promise<T>): Promise<T>;
10
+ /** A site policy's key: the origin of a URL (`https://app.example.com/login` → `https://app.example.com`); any other id as given. */
11
+ export declare function sitePolicyKey(site: string): string;
12
+ /** What a gated Journey run gives its actor, and records once it has run. */
13
+ export interface JourneyGate {
14
+ /** The pacing ability (none when no policy declares pacing), spread into `whoCan(...)`. */
15
+ readonly abilities: Ability[];
16
+ /** Records the run against the site's throttle class; call once the run executed, pass or fail. */
17
+ readonly done: () => Promise<void>;
18
+ }
19
+ /**
20
+ * The site-policy gate for one Journey run on `recording.site`'s origin — before any fixture or
21
+ * browser. Throws `SiteGateRefusedError` (quiet hours, min interval, budget) with when to retry.
22
+ * `enforceLimits: false` (a load run) applies only the pacing.
23
+ */
24
+ export declare function gateJourney(siteGate: SiteGateDeps | undefined, recording: Recording, opts: {
25
+ readonly account?: string;
26
+ readonly enforceLimits: boolean;
27
+ readonly runId?: string;
28
+ }): Promise<JourneyGate>;
@@ -0,0 +1,58 @@
1
+ import { existsSync } from "node:fs";
2
+ import { openDatabase, migrateToLatest, SqliteActivityRepository, SqliteBudgetRepository, SqliteSitePolicyRepository } from "@jevitate/storage-sqlite";
3
+ import { randomUUID } from "node:crypto";
4
+ import { SiteGateRefusedError, enterSiteGate, throttleClassOf } from "@jevitate/runtime";
5
+ /**
6
+ * The site-policy gate's repositories (`jevitate site policy set`), opened from the policy database
7
+ * for the duration of `fn`. No database file means no policy was ever set: `fn` gets `undefined`,
8
+ * and nothing is created on disk.
9
+ */
10
+ export async function withSiteGate(dbPath, fn) {
11
+ if (dbPath === undefined || !existsSync(dbPath))
12
+ return fn(undefined);
13
+ const db = openDatabase(dbPath);
14
+ try {
15
+ await migrateToLatest(db);
16
+ const clock = { nowIso: () => new Date().toISOString(), monotonicMs: () => Date.now() };
17
+ return await fn({
18
+ policies: new SqliteSitePolicyRepository(db, clock),
19
+ budgets: new SqliteBudgetRepository(db),
20
+ activity: new SqliteActivityRepository(db),
21
+ });
22
+ }
23
+ finally {
24
+ await db.destroy();
25
+ }
26
+ }
27
+ /** A site policy's key: the origin of a URL (`https://app.example.com/login` → `https://app.example.com`); any other id as given. */
28
+ export function sitePolicyKey(site) {
29
+ try {
30
+ const u = new URL(site);
31
+ return u.origin === "null" ? site : u.origin;
32
+ }
33
+ catch {
34
+ return site;
35
+ }
36
+ }
37
+ const UNGATED = { abilities: [], done: async () => undefined };
38
+ /**
39
+ * The site-policy gate for one Journey run on `recording.site`'s origin — before any fixture or
40
+ * browser. Throws `SiteGateRefusedError` (quiet hours, min interval, budget) with when to retry.
41
+ * `enforceLimits: false` (a load run) applies only the pacing.
42
+ */
43
+ export async function gateJourney(siteGate, recording, opts) {
44
+ if (siteGate === undefined)
45
+ return UNGATED;
46
+ const site = sitePolicyKey(recording.site);
47
+ const gate = await enterSiteGate(siteGate, {
48
+ site,
49
+ account: opts.account ?? "primary",
50
+ throttleClass: throttleClassOf(recording),
51
+ runId: opts.runId ?? randomUUID(),
52
+ enforceLimits: opts.enforceLimits,
53
+ });
54
+ if (!gate.ok)
55
+ throw new SiteGateRefusedError(site, gate.reason, gate.retryAfter);
56
+ return { abilities: gate.pace === null ? [] : [gate.pace], done: gate.done };
57
+ }
58
+ //# sourceMappingURL=site-gate-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-gate-cli.js","sourceRoot":"","sources":["../src/site-gate-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACvJ,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,eAAe,EAAqB,MAAM,mBAAmB,CAAC;AAE5G;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,MAA0B,EAAE,EAAkD;IAClH,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACtE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACxF,OAAO,MAAM,EAAE,CAAC;YACd,QAAQ,EAAE,IAAI,0BAA0B,CAAC,EAAE,EAAE,KAAK,CAAC;YACnD,OAAO,EAAE,IAAI,sBAAsB,CAAC,EAAE,CAAC;YACvC,QAAQ,EAAE,IAAI,wBAAwB,CAAC,EAAE,CAAC;SAC3C,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,qIAAqI;AACrI,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAUD,MAAM,OAAO,GAAgB,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;AAE5E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAkC,EAClC,SAAoB,EACpB,IAA6F;IAE7F,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC3C,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE;QACzC,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS;QAClC,aAAa,EAAE,eAAe,CAAC,SAAS,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,UAAU,EAAE;QACjC,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACjF,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC/E,CAAC"}
@@ -30,6 +30,15 @@ export class NoDeclaredOriginsError extends Error {
30
30
  this.name = "NoDeclaredOriginsError";
31
31
  }
32
32
  }
33
+ /** Parses `site`'s origin, or `null` if it isn't a valid absolute URL. */
34
+ function originOf(site) {
35
+ try {
36
+ return new URL(site).origin;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
33
42
  function mgrOf(deps) {
34
43
  return new GitSourceManager(deps.sourcesDir, deps.git);
35
44
  }
@@ -171,9 +180,15 @@ export async function publishJourneyToSource(deps, req) {
171
180
  if (!journey.metadata.promoted) {
172
181
  throw new NotPromotedError(`journey '${req.id}' is not promoted; promote it before publishing`);
173
182
  }
174
- const declaredOrigins = req.declareOrigins && req.declareOrigins.length > 0
175
- ? req.declareOrigins
176
- : collectNavigateOrigins(journey.recording);
183
+ // #125: `explore-author-journey` writes RELATIVE `navigate` urls (the recorded steps are
184
+ // relative to `recording.site`), so `collectNavigateOrigins` — which only resolves ABSOLUTE
185
+ // navigate urls — finds nothing to derive from. Fall back to `recording.site` itself: it's
186
+ // the origin the whole Recording was authored against, and exactly what an explore-authored
187
+ // Journey's relative navigates implicitly stay within.
188
+ const navigateOrigins = collectNavigateOrigins(journey.recording);
189
+ const siteOrigin = originOf(journey.recording.site);
190
+ const derivedOrigins = navigateOrigins.length > 0 ? navigateOrigins : siteOrigin ? [siteOrigin] : [];
191
+ const declaredOrigins = req.declareOrigins && req.declareOrigins.length > 0 ? req.declareOrigins : derivedOrigins;
177
192
  if (declaredOrigins.length === 0) {
178
193
  throw new NoDeclaredOriginsError(`journey '${req.id}' declares no origins and navigates to no absolute origin; pass --declare-origin <origin>`);
179
194
  }