stackvitals 0.1.0__py3-none-any.whl

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 (465) hide show
  1. mergescout/__init__.py +1 -0
  2. mergescout/archive/__init__.py +0 -0
  3. mergescout/archive/__main__.py +30 -0
  4. mergescout/archive/convert.py +83 -0
  5. mergescout/archive/events.py +55 -0
  6. mergescout/archive/manifest.py +45 -0
  7. mergescout/archive/stream.py +83 -0
  8. mergescout/bench/__init__.py +1 -0
  9. mergescout/bench/__main__.py +135 -0
  10. mergescout/bench/ci.py +257 -0
  11. mergescout/bench/deploys.py +115 -0
  12. mergescout/bench/matched.py +22 -0
  13. mergescout/bench/prior.py +42 -0
  14. mergescout/bench/report.py +230 -0
  15. mergescout/bench/shared.py +112 -0
  16. mergescout/bench/stars.py +57 -0
  17. mergescout/cli.py +89 -0
  18. mergescout/config.py +35 -0
  19. mergescout/crawl/__init__.py +0 -0
  20. mergescout/crawl/__main__.py +97 -0
  21. mergescout/crawl/chain.py +34 -0
  22. mergescout/crawl/fetch.py +146 -0
  23. mergescout/crawl/outcomes.py +69 -0
  24. mergescout/crawl/queries.py +250 -0
  25. mergescout/crawl/runner.py +176 -0
  26. mergescout/crawl/seed.py +77 -0
  27. mergescout/crawl/state.py +169 -0
  28. mergescout/crawl/writer.py +87 -0
  29. mergescout/discover/__init__.py +0 -0
  30. mergescout/discover/__main__.py +58 -0
  31. mergescout/discover/sweep.py +286 -0
  32. mergescout/github/__init__.py +0 -0
  33. mergescout/github/graphql.py +202 -0
  34. mergescout/github/identities.py +35 -0
  35. mergescout/github/releases.py +137 -0
  36. mergescout/labels.py +20 -0
  37. mergescout/mcp_server.py +228 -0
  38. mergescout/measure/__init__.py +0 -0
  39. mergescout/measure/__main__.py +75 -0
  40. mergescout/measure/api_cost.py +91 -0
  41. mergescout/measure/count_repos.py +30 -0
  42. mergescout/measure/jsonl.py +14 -0
  43. mergescout/measure/report.py +56 -0
  44. mergescout/measure/sample.py +37 -0
  45. mergescout/owners.py +22 -0
  46. mergescout/setup_check.py +64 -0
  47. mergescout/signals/__init__.py +0 -0
  48. mergescout/signals/__main__.py +96 -0
  49. mergescout/signals/bump_ledger.py +258 -0
  50. mergescout/signals/bumps.py +104 -0
  51. mergescout/signals/check.py +141 -0
  52. mergescout/signals/community_bench.py +149 -0
  53. mergescout/signals/delivery_bench.py +103 -0
  54. mergescout/signals/deps_map.py +261 -0
  55. mergescout/signals/deps_trends.py +117 -0
  56. mergescout/signals/evidence.py +94 -0
  57. mergescout/signals/exploits.py +43 -0
  58. mergescout/signals/flow_bench.py +258 -0
  59. mergescout/signals/identity.py +73 -0
  60. mergescout/signals/issues.py +76 -0
  61. mergescout/signals/labels.py +79 -0
  62. mergescout/signals/osv.py +232 -0
  63. mergescout/signals/owners_watch.py +80 -0
  64. mergescout/signals/repo_stats.py +96 -0
  65. mergescout/signals/rules.py +70 -0
  66. mergescout/signals/silver.py +33 -0
  67. mergescout/signals/top_packages.py +26 -0
  68. mergescout/signals/triage.py +71 -0
  69. mergescout/signals/triage_math.py +120 -0
  70. mergescout/signals/walls.py +91 -0
  71. mergescout/snapshot/__init__.py +0 -0
  72. mergescout/snapshot/__main__.py +215 -0
  73. mergescout/snapshot/build.py +147 -0
  74. mergescout/snapshot/publish.py +70 -0
  75. mergescout/snapshot/schema.py +34 -0
  76. mergescout/snapshot/score.py +30 -0
  77. mergescout/store/__init__.py +0 -0
  78. mergescout/store/__main__.py +46 -0
  79. mergescout/store/sync.py +148 -0
  80. mergescout/timeutil.py +11 -0
  81. mergescout/tool/__init__.py +0 -0
  82. mergescout/tool/action_pack.py +62 -0
  83. mergescout/tool/live.py +201 -0
  84. mergescout/tool/queries.py +293 -0
  85. mergescout/tool/refs.py +31 -0
  86. mergescout/tool/store.py +129 -0
  87. mergescout/tool/tracking.py +83 -0
  88. stackvitals/__init__.py +2 -0
  89. stackvitals/__main__.py +4 -0
  90. stackvitals/ci/__init__.py +1 -0
  91. stackvitals/ci/action.py +574 -0
  92. stackvitals/ci/analyze.py +577 -0
  93. stackvitals/ci/api.py +218 -0
  94. stackvitals/ci/automation.py +212 -0
  95. stackvitals/ci/bench.py +195 -0
  96. stackvitals/ci/burnin.py +102 -0
  97. stackvitals/ci/cli.py +570 -0
  98. stackvitals/ci/collect.py +239 -0
  99. stackvitals/ci/cost.py +107 -0
  100. stackvitals/ci/coverage.py +155 -0
  101. stackvitals/ci/feedback.py +699 -0
  102. stackvitals/ci/fingerprint.py +220 -0
  103. stackvitals/ci/gitlab.py +121 -0
  104. stackvitals/ci/gitlab_action.py +125 -0
  105. stackvitals/ci/impact.py +125 -0
  106. stackvitals/ci/investigate.py +59 -0
  107. stackvitals/ci/kinds.py +52 -0
  108. stackvitals/ci/monitors.py +105 -0
  109. stackvitals/ci/owners.py +116 -0
  110. stackvitals/ci/quarantine_runtime.py +90 -0
  111. stackvitals/ci/report.py +435 -0
  112. stackvitals/ci/retry.py +67 -0
  113. stackvitals/ci/selfheal.py +102 -0
  114. stackvitals/ci/shards.py +120 -0
  115. stackvitals/ci/share.py +59 -0
  116. stackvitals/ci/store.py +93 -0
  117. stackvitals/ci/testreports.py +351 -0
  118. stackvitals/ci/tickets.py +106 -0
  119. stackvitals/ci/track_record.json +11 -0
  120. stackvitals/ci/triage.py +130 -0
  121. stackvitals/ci/triggers.py +147 -0
  122. stackvitals/ci/upload.py +85 -0
  123. stackvitals/ci/validate.py +91 -0
  124. stackvitals/cli.py +111 -0
  125. stackvitals/codeowners.py +69 -0
  126. stackvitals/community/__init__.py +0 -0
  127. stackvitals/community/action.py +140 -0
  128. stackvitals/community/affiliation.py +51 -0
  129. stackvitals/community/analyze.py +507 -0
  130. stackvitals/community/build.py +56 -0
  131. stackvitals/community/chaoss.py +70 -0
  132. stackvitals/community/cli.py +79 -0
  133. stackvitals/community/collect.py +240 -0
  134. stackvitals/community/context.py +54 -0
  135. stackvitals/community/report.py +250 -0
  136. stackvitals/connectors/__init__.py +244 -0
  137. stackvitals/connectors/ai_spend.py +190 -0
  138. stackvitals/connectors/base.py +82 -0
  139. stackvitals/connectors/check.py +686 -0
  140. stackvitals/connectors/copilot.py +104 -0
  141. stackvitals/connectors/discord.py +103 -0
  142. stackvitals/connectors/discourse.py +117 -0
  143. stackvitals/connectors/incident_io.py +106 -0
  144. stackvitals/connectors/jira.py +210 -0
  145. stackvitals/connectors/linear.py +140 -0
  146. stackvitals/connectors/pagerduty.py +96 -0
  147. stackvitals/connectors/slack.py +110 -0
  148. stackvitals/connectors/sonar.py +77 -0
  149. stackvitals/connectors/store.py +120 -0
  150. stackvitals/connectors/tracker.py +108 -0
  151. stackvitals/connectors/writeback.py +105 -0
  152. stackvitals/contribute/__init__.py +1 -0
  153. stackvitals/contribute/brief.py +297 -0
  154. stackvitals/contribute/cli.py +64 -0
  155. stackvitals/core/__init__.py +1 -0
  156. stackvitals/core/actors.py +103 -0
  157. stackvitals/core/agent_ledger.py +120 -0
  158. stackvitals/core/agreements.py +95 -0
  159. stackvitals/core/ai_outcomes.py +276 -0
  160. stackvitals/core/alerts.py +224 -0
  161. stackvitals/core/appdata.py +112 -0
  162. stackvitals/core/bucket.py +190 -0
  163. stackvitals/core/bugs.py +43 -0
  164. stackvitals/core/calendar.py +34 -0
  165. stackvitals/core/capex.py +57 -0
  166. stackvitals/core/change_risk.py +181 -0
  167. stackvitals/core/changes.py +133 -0
  168. stackvitals/core/chat.py +143 -0
  169. stackvitals/core/config.py +373 -0
  170. stackvitals/core/dataflow.py +168 -0
  171. stackvitals/core/decisions.py +275 -0
  172. stackvitals/core/delivery.py +954 -0
  173. stackvitals/core/delivery_peers.py +98 -0
  174. stackvitals/core/delivery_report.py +429 -0
  175. stackvitals/core/deliverycli.py +147 -0
  176. stackvitals/core/devlake_dora.sql +485 -0
  177. stackvitals/core/digest.py +333 -0
  178. stackvitals/core/explaincli.py +107 -0
  179. stackvitals/core/explore.py +296 -0
  180. stackvitals/core/export.py +342 -0
  181. stackvitals/core/exportcli.py +117 -0
  182. stackvitals/core/findings.py +350 -0
  183. stackvitals/core/health.py +94 -0
  184. stackvitals/core/identity.py +82 -0
  185. stackvitals/core/insights.py +365 -0
  186. stackvitals/core/insightscli.py +43 -0
  187. stackvitals/core/installdoc.py +69 -0
  188. stackvitals/core/investment.py +187 -0
  189. stackvitals/core/joins.py +43 -0
  190. stackvitals/core/llmsdoc.py +40 -0
  191. stackvitals/core/merge_queue.py +70 -0
  192. stackvitals/core/metrics.py +109 -0
  193. stackvitals/core/model.py +285 -0
  194. stackvitals/core/projectcli.py +66 -0
  195. stackvitals/core/propose.py +86 -0
  196. stackvitals/core/pulse.py +85 -0
  197. stackvitals/core/recorded.py +145 -0
  198. stackvitals/core/releases.py +39 -0
  199. stackvitals/core/requests.py +528 -0
  200. stackvitals/core/resync.py +35 -0
  201. stackvitals/core/schema.py +205 -0
  202. stackvitals/core/services.py +203 -0
  203. stackvitals/core/settings.py +96 -0
  204. stackvitals/core/sqlcli.py +111 -0
  205. stackvitals/core/stats.py +222 -0
  206. stackvitals/core/store.py +125 -0
  207. stackvitals/core/summary.py +104 -0
  208. stackvitals/core/time.py +29 -0
  209. stackvitals/core/tomledit.py +149 -0
  210. stackvitals/core/uicli.py +138 -0
  211. stackvitals/core/webapp.py +79 -0
  212. stackvitals/core/what_changed.py +76 -0
  213. stackvitals/core/workspace.py +194 -0
  214. stackvitals/deps/__init__.py +1 -0
  215. stackvitals/deps/action.py +299 -0
  216. stackvitals/deps/actions_vulns.py +89 -0
  217. stackvitals/deps/cli.py +77 -0
  218. stackvitals/deps/dossier.py +341 -0
  219. stackvitals/deps/evidence.py +44 -0
  220. stackvitals/deps/fixplan.py +40 -0
  221. stackvitals/deps/guarddog.py +32 -0
  222. stackvitals/deps/hygiene.py +47 -0
  223. stackvitals/deps/imports.py +113 -0
  224. stackvitals/deps/lockfiles.py +198 -0
  225. stackvitals/deps/lookalike.py +80 -0
  226. stackvitals/deps/reach.py +59 -0
  227. stackvitals/deps/release.py +110 -0
  228. stackvitals/deps/runtimes.py +161 -0
  229. stackvitals/deps/supply.py +454 -0
  230. stackvitals/deps/vulns.py +588 -0
  231. stackvitals/editors/__init__.py +40 -0
  232. stackvitals/editors/vscode/extension.js +101 -0
  233. stackvitals/editors/vscode/marks.js +92 -0
  234. stackvitals/editors/vscode/package.json +26 -0
  235. stackvitals/flow/__init__.py +1 -0
  236. stackvitals/flow/action.py +178 -0
  237. stackvitals/flow/analyze.py +418 -0
  238. stackvitals/flow/automate.py +72 -0
  239. stackvitals/flow/build.py +46 -0
  240. stackvitals/flow/cli.py +93 -0
  241. stackvitals/flow/code_hosts.py +146 -0
  242. stackvitals/flow/collect.py +451 -0
  243. stackvitals/flow/gitlab_mr.py +75 -0
  244. stackvitals/flow/knowledge.py +202 -0
  245. stackvitals/flow/peers.py +90 -0
  246. stackvitals/flow/preflight.py +210 -0
  247. stackvitals/flow/report.py +253 -0
  248. stackvitals/flow/rules.py +135 -0
  249. stackvitals/flow/store.py +108 -0
  250. stackvitals/flow/survival.py +84 -0
  251. stackvitals/flow/triage.py +62 -0
  252. stackvitals/mcp_server.py +670 -0
  253. stackvitals/portal/__init__.py +0 -0
  254. stackvitals/portal/action.py +205 -0
  255. stackvitals/portal/batch.py +80 -0
  256. stackvitals/portal/campaigns.py +104 -0
  257. stackvitals/portal/catalog.py +104 -0
  258. stackvitals/portal/checks.py +63 -0
  259. stackvitals/portal/cli.py +172 -0
  260. stackvitals/portal/descriptor.py +105 -0
  261. stackvitals/portal/export.py +43 -0
  262. stackvitals/portal/github.py +48 -0
  263. stackvitals/portal/golden.py +95 -0
  264. stackvitals/portal/history.py +30 -0
  265. stackvitals/portal/inventory.py +264 -0
  266. stackvitals/portal/owners.py +78 -0
  267. stackvitals/portal/pages.py +153 -0
  268. stackvitals/portal/rollup.py +32 -0
  269. stackvitals/portal/scorecard.py +366 -0
  270. stackvitals/security/__init__.py +2 -0
  271. stackvitals/security/probes.py +154 -0
  272. stackvitals/security/repo_checks.py +132 -0
  273. stackvitals/security/workflows.py +111 -0
  274. stackvitals/shell.py +107 -0
  275. stackvitals/site.py +51 -0
  276. stackvitals/web/app/LICENSES.md +428 -0
  277. stackvitals/web/app/boot.js +1 -0
  278. stackvitals/web/app/chunks/AddRepo-KRPZXWCY.js +1 -0
  279. stackvitals/web/app/chunks/SetupRunning-XWFQAKRZ.js +1 -0
  280. stackvitals/web/app/chunks/accuracy-data-OQTDXI7Y.js +1 -0
  281. stackvitals/web/app/chunks/agents-data-BAL6QAOF.js +11 -0
  282. stackvitals/web/app/chunks/chunk-24LFKFZ6.js +1 -0
  283. stackvitals/web/app/chunks/chunk-3G4SQNUC.js +1 -0
  284. stackvitals/web/app/chunks/chunk-3IXWEOIJ.js +154 -0
  285. stackvitals/web/app/chunks/chunk-3ROQFHPV.js +1 -0
  286. stackvitals/web/app/chunks/chunk-45PGAQRO.js +8 -0
  287. stackvitals/web/app/chunks/chunk-4H53OYLG.js +1 -0
  288. stackvitals/web/app/chunks/chunk-4LUI7O5P.js +1 -0
  289. stackvitals/web/app/chunks/chunk-4SQPQ5TB.js +1 -0
  290. stackvitals/web/app/chunks/chunk-4WKQTWUC.js +2 -0
  291. stackvitals/web/app/chunks/chunk-576YHDEK.js +8 -0
  292. stackvitals/web/app/chunks/chunk-6BDBXA6V.js +1 -0
  293. stackvitals/web/app/chunks/chunk-6RLVD2DT.js +1 -0
  294. stackvitals/web/app/chunks/chunk-763NH7PP.js +1 -0
  295. stackvitals/web/app/chunks/chunk-76WAVKUG.js +1 -0
  296. stackvitals/web/app/chunks/chunk-7II2BD5F.js +1 -0
  297. stackvitals/web/app/chunks/chunk-7TJCBOAY.js +1 -0
  298. stackvitals/web/app/chunks/chunk-ASYNLVOP.js +1 -0
  299. stackvitals/web/app/chunks/chunk-CTKDYZMG.js +1 -0
  300. stackvitals/web/app/chunks/chunk-CVB26NMC.js +1 -0
  301. stackvitals/web/app/chunks/chunk-G7NGB5UX.js +1 -0
  302. stackvitals/web/app/chunks/chunk-GPVLJRZD.js +1 -0
  303. stackvitals/web/app/chunks/chunk-GQYFN4PE.js +75 -0
  304. stackvitals/web/app/chunks/chunk-GT4EAKAO.js +2 -0
  305. stackvitals/web/app/chunks/chunk-IYMBFPCV.js +1 -0
  306. stackvitals/web/app/chunks/chunk-LAAGCPU3.js +1 -0
  307. stackvitals/web/app/chunks/chunk-MAPYGK3P.js +1 -0
  308. stackvitals/web/app/chunks/chunk-P5TXDD45.js +1 -0
  309. stackvitals/web/app/chunks/chunk-PABICGBL.js +1 -0
  310. stackvitals/web/app/chunks/chunk-RPXHAG6F.js +1 -0
  311. stackvitals/web/app/chunks/chunk-RQZPSJ2Y.js +1 -0
  312. stackvitals/web/app/chunks/chunk-S2ZBMEVA.js +1 -0
  313. stackvitals/web/app/chunks/chunk-S654BBEP.js +6 -0
  314. stackvitals/web/app/chunks/chunk-T7QVTNXF.js +1 -0
  315. stackvitals/web/app/chunks/chunk-THFUOCPC.js +273 -0
  316. stackvitals/web/app/chunks/chunk-TO4VVRZ7.js +1 -0
  317. stackvitals/web/app/chunks/chunk-VQ5YXO54.js +1 -0
  318. stackvitals/web/app/chunks/chunk-VWKSMFWJ.js +1 -0
  319. stackvitals/web/app/chunks/chunk-Y6LUXDM6.js +1 -0
  320. stackvitals/web/app/chunks/chunk-YTANGYYH.js +1 -0
  321. stackvitals/web/app/chunks/connect-KONYWYTT.js +1 -0
  322. stackvitals/web/app/chunks/connections-data-2DYS4UVW.js +32 -0
  323. stackvitals/web/app/chunks/logos-N5IINUAM.js +1 -0
  324. stackvitals/web/app/chunks/more-KMJMJQD3.js +10 -0
  325. stackvitals/web/app/chunks/more-PC6FVS3P.js +1 -0
  326. stackvitals/web/app/chunks/more-RCIVCUDE.js +2 -0
  327. stackvitals/web/app/chunks/more-ZKKRY6NO.css +1 -0
  328. stackvitals/web/app/chunks/sealbox-35YL4EUH.js +3 -0
  329. stackvitals/web/app/chunks/session-DYYTOE2K.js +1 -0
  330. stackvitals/web/app/chunks/settingsApply-2HRJEZYM.js +1 -0
  331. stackvitals/web/app/chunks/settingsReview-GX2FZQ4M.js +3 -0
  332. stackvitals/web/app/chunks/uPlot.esm-OIWT3AHJ.js +3 -0
  333. stackvitals/web/app/demo/ci/impact.json +1 -0
  334. stackvitals/web/app/demo/ci/quarantine.json +1 -0
  335. stackvitals/web/app/demo/ci/tickets.json +1 -0
  336. stackvitals/web/app/demo/mobile/alerts.json +1 -0
  337. stackvitals/web/app/demo/mobile/app.json +1 -0
  338. stackvitals/web/app/demo/mobile/community.json +1 -0
  339. stackvitals/web/app/demo/mobile/connectors.json +1 -0
  340. stackvitals/web/app/demo/mobile/data.json +1 -0
  341. stackvitals/web/app/demo/mobile/decisions.json +1 -0
  342. stackvitals/web/app/demo/mobile/delivery.json +1 -0
  343. stackvitals/web/app/demo/mobile/deps.json +1 -0
  344. stackvitals/web/app/demo/mobile/flow.json +1 -0
  345. stackvitals/web/app/demo/mobile/health.json +1 -0
  346. stackvitals/web/app/demo/mobile/insights.json +1 -0
  347. stackvitals/web/app/demo/mobile/pulse.json +1 -0
  348. stackvitals/web/app/demo/mobile/security.json +1 -0
  349. stackvitals/web/app/demo/mobile/summary/ci_jobs.jsonl +5 -0
  350. stackvitals/web/app/demo/mobile/summary/devlake_project_pr_metrics.jsonl +14 -0
  351. stackvitals/web/app/demo/mobile/summary/devlake_pull_requests.jsonl +14 -0
  352. stackvitals/web/app/demo/mobile/summary/manifest.json +1 -0
  353. stackvitals/web/app/demo/mobile/summary/prs.jsonl +19 -0
  354. stackvitals/web/app/demo/mobile/summary/tests.jsonl +1 -0
  355. stackvitals/web/app/demo/mobile/supply.json +1 -0
  356. stackvitals/web/app/demo/mobile/vulns.json +1 -0
  357. stackvitals/web/app/demo/payments-api/alerts.json +1 -0
  358. stackvitals/web/app/demo/payments-api/app.json +1 -0
  359. stackvitals/web/app/demo/payments-api/community.json +1 -0
  360. stackvitals/web/app/demo/payments-api/connectors.json +1 -0
  361. stackvitals/web/app/demo/payments-api/data.json +1 -0
  362. stackvitals/web/app/demo/payments-api/decisions.json +1 -0
  363. stackvitals/web/app/demo/payments-api/delivery.json +1 -0
  364. stackvitals/web/app/demo/payments-api/deps.json +1 -0
  365. stackvitals/web/app/demo/payments-api/flow.json +1 -0
  366. stackvitals/web/app/demo/payments-api/health.json +1 -0
  367. stackvitals/web/app/demo/payments-api/insights.json +1 -0
  368. stackvitals/web/app/demo/payments-api/pulse.json +1 -0
  369. stackvitals/web/app/demo/payments-api/security.json +1 -0
  370. stackvitals/web/app/demo/payments-api/summary/ci_jobs.jsonl +5 -0
  371. stackvitals/web/app/demo/payments-api/summary/devlake_project_pr_metrics.jsonl +14 -0
  372. stackvitals/web/app/demo/payments-api/summary/devlake_pull_requests.jsonl +14 -0
  373. stackvitals/web/app/demo/payments-api/summary/manifest.json +1 -0
  374. stackvitals/web/app/demo/payments-api/summary/prs.jsonl +22 -0
  375. stackvitals/web/app/demo/payments-api/summary/tests.jsonl +3 -0
  376. stackvitals/web/app/demo/payments-api/supply.json +1 -0
  377. stackvitals/web/app/demo/payments-api/vulns.json +1 -0
  378. stackvitals/web/app/demo/portal.json +1 -0
  379. stackvitals/web/app/demo/settings.json +1 -0
  380. stackvitals/web/app/demo/web-app/alerts.json +1 -0
  381. stackvitals/web/app/demo/web-app/app.json +1 -0
  382. stackvitals/web/app/demo/web-app/community.json +1 -0
  383. stackvitals/web/app/demo/web-app/connectors.json +1 -0
  384. stackvitals/web/app/demo/web-app/data.json +1 -0
  385. stackvitals/web/app/demo/web-app/decisions.json +1 -0
  386. stackvitals/web/app/demo/web-app/delivery.json +1 -0
  387. stackvitals/web/app/demo/web-app/deps.json +1 -0
  388. stackvitals/web/app/demo/web-app/flow.json +1 -0
  389. stackvitals/web/app/demo/web-app/health.json +1 -0
  390. stackvitals/web/app/demo/web-app/insights.json +1 -0
  391. stackvitals/web/app/demo/web-app/pulse.json +1 -0
  392. stackvitals/web/app/demo/web-app/security.json +1 -0
  393. stackvitals/web/app/demo/web-app/summary/ci_jobs.jsonl +5 -0
  394. stackvitals/web/app/demo/web-app/summary/devlake_project_pr_metrics.jsonl +14 -0
  395. stackvitals/web/app/demo/web-app/summary/devlake_pull_requests.jsonl +14 -0
  396. stackvitals/web/app/demo/web-app/summary/manifest.json +1 -0
  397. stackvitals/web/app/demo/web-app/summary/prs.jsonl +18 -0
  398. stackvitals/web/app/demo/web-app/summary/tests.jsonl +2 -0
  399. stackvitals/web/app/demo/web-app/supply.json +1 -0
  400. stackvitals/web/app/demo/web-app/vulns.json +1 -0
  401. stackvitals/web/app/fonts/plex-mono-400.woff2 +0 -0
  402. stackvitals/web/app/fonts/plex-sans-400.woff2 +0 -0
  403. stackvitals/web/app/fonts/plex-sans-600.woff2 +0 -0
  404. stackvitals/web/app/fonts/plex-sans-condensed-700.woff2 +0 -0
  405. stackvitals/web/app/help/accuracy.json +1 -0
  406. stackvitals/web/app/help/connectors.json +1 -0
  407. stackvitals/web/app/help/getting-started.json +1 -0
  408. stackvitals/web/app/help/index.json +1 -0
  409. stackvitals/web/app/help/modules.json +1 -0
  410. stackvitals/web/app/help/privacy-and-security.json +1 -0
  411. stackvitals/web/app/help/reference.json +1 -0
  412. stackvitals/web/app/main.css +1 -0
  413. stackvitals/web/app/main.js +1 -0
  414. stackvitals/web/app/pages/about.css +1 -0
  415. stackvitals/web/app/pages/about.js +1 -0
  416. stackvitals/web/app/pages/activity.css +1 -0
  417. stackvitals/web/app/pages/activity.js +1 -0
  418. stackvitals/web/app/pages/agents.css +1 -0
  419. stackvitals/web/app/pages/agents.js +2 -0
  420. stackvitals/web/app/pages/ci.css +1 -0
  421. stackvitals/web/app/pages/ci.js +1 -0
  422. stackvitals/web/app/pages/community.css +1 -0
  423. stackvitals/web/app/pages/community.js +1 -0
  424. stackvitals/web/app/pages/connections.css +1 -0
  425. stackvitals/web/app/pages/connections.js +6 -0
  426. stackvitals/web/app/pages/delivery.css +1 -0
  427. stackvitals/web/app/pages/delivery.js +45 -0
  428. stackvitals/web/app/pages/deps.css +1 -0
  429. stackvitals/web/app/pages/deps.js +7 -0
  430. stackvitals/web/app/pages/explore.css +1 -0
  431. stackvitals/web/app/pages/explore.js +7 -0
  432. stackvitals/web/app/pages/health.css +1 -0
  433. stackvitals/web/app/pages/health.js +1 -0
  434. stackvitals/web/app/pages/help.css +1 -0
  435. stackvitals/web/app/pages/help.js +6 -0
  436. stackvitals/web/app/pages/insights.css +1 -0
  437. stackvitals/web/app/pages/insights.js +1 -0
  438. stackvitals/web/app/pages/investment.css +1 -0
  439. stackvitals/web/app/pages/investment.js +3 -0
  440. stackvitals/web/app/pages/overview.css +1 -0
  441. stackvitals/web/app/pages/overview.js +1 -0
  442. stackvitals/web/app/pages/portal.css +1 -0
  443. stackvitals/web/app/pages/portal.js +51 -0
  444. stackvitals/web/app/pages/prs.css +1 -0
  445. stackvitals/web/app/pages/prs.js +4 -0
  446. stackvitals/web/app/pages/settings.css +1 -0
  447. stackvitals/web/app/pages/settings.js +1 -0
  448. stackvitals/web/app/pages/setup.css +1 -0
  449. stackvitals/web/app/pages/setup.js +2 -0
  450. stackvitals/web/app/pages/standing.css +1 -0
  451. stackvitals/web/app/pages/standing.js +1 -0
  452. stackvitals/web/app/pages/welcome-sheet.js +1 -0
  453. stackvitals/web/app/pages/welcome.js +1 -0
  454. stackvitals/web/app/settings-workflow.json +1 -0
  455. stackvitals/web/index.html +34 -0
  456. stackvitals/web/site/index.html +108 -0
  457. stackvitals/web/site/integrations.html +15 -0
  458. stackvitals/web/site/setup.html +15 -0
  459. stackvitals/web/site/site.css +68 -0
  460. stackvitals-0.1.0.dist-info/METADATA +134 -0
  461. stackvitals-0.1.0.dist-info/RECORD +465 -0
  462. stackvitals-0.1.0.dist-info/WHEEL +4 -0
  463. stackvitals-0.1.0.dist-info/entry_points.txt +3 -0
  464. stackvitals-0.1.0.dist-info/licenses/LICENSE +202 -0
  465. stackvitals-0.1.0.dist-info/licenses/NOTICE +16 -0
@@ -0,0 +1,4 @@
1
+ import{a as ve}from"../chunks/chunk-3ROQFHPV.js";import{d as _e}from"../chunks/chunk-S654BBEP.js";import{f as ye,g as ke}from"../chunks/chunk-CVB26NMC.js";import"../chunks/chunk-S2ZBMEVA.js";import"../chunks/chunk-ASYNLVOP.js";import{a as z,c as B,d as j,e as x,f as xe}from"../chunks/chunk-4H53OYLG.js";import{a as me,b as he,c as ge,d as we,e as fe}from"../chunks/chunk-3G4SQNUC.js";import"../chunks/chunk-LAAGCPU3.js";import"../chunks/chunk-24LFKFZ6.js";import"../chunks/chunk-6BDBXA6V.js";import"../chunks/chunk-MAPYGK3P.js";import{a as $}from"../chunks/chunk-6RLVD2DT.js";import{b as be}from"../chunks/chunk-45PGAQRO.js";import{d as pe}from"../chunks/chunk-4WKQTWUC.js";import"../chunks/chunk-VQ5YXO54.js";import{b as U,c as _,d as ce,e as E,h as J,i as q}from"../chunks/chunk-76WAVKUG.js";import{d as Z,e as Q}from"../chunks/chunk-VWKSMFWJ.js";import{L as oe,N as le,O as G,P as M,Q as de,R as ue,a as O,c as W,d as ne,j as Y,k as ae,l as k,m as S,n as ie,o as K,r as V,s as X,w as e,z as F}from"../chunks/chunk-GT4EAKAO.js";import{d as D}from"../chunks/chunk-G7NGB5UX.js";D();D();D();var Ie=/(^|\/)(tests?|__tests__|spec|testing)(\/|$)|(_test|\.test|\.spec|_spec)\.[a-z]+$|(^|\/)test_[^/]+$/i,We=/(^|\/)(CHANGELOG|CHANGES|HISTORY|NEWS)(\.[a-z]+)?$|(^|\/)(changelog\.d|changes|news|\.changeset|changelog)\//i,Be=/(^|\/)docs?\/|\.(md|rst|adoc)$/i,je=new Set(["Cargo.lock","package-lock.json","yarn.lock","pnpm-lock.yaml","poetry.lock","uv.lock","go.sum","Gemfile.lock","composer.lock","Pipfile.lock","bun.lockb","flake.lock","mix.lock","pubspec.lock"]),ee=.6,Se=["tests","changelog","docs"],De={tests:"test files",changelog:"a changelog entry",docs:"docs"},H=10;function $e(a){let n=[];for(let o of a.split(/[\s,]+/)){let m=o.trim().replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/+/,"");m&&!n.includes(m)&&n.push(m)}return n}function Le(a){let n=new Set;for(let o of a)Ie.test(o)&&n.add("tests"),We.test(o)?n.add("changelog"):Be.test(o)&&n.add("docs");return n}function He(a){let n=a.split("/");return n.length===1?"(root)":n.length===2?n[0]:n.slice(0,2).join("/")}function te(a){return[...new Set(a.filter(n=>!je.has(n.split("/").pop()||"")).map(He))].sort()}function qe(a,n,o){let m=Le(a),g=o.scope||"whole repo",y=Se.map(p=>{let u=o.include?.[p]??null,f=m.has(p);return{what:p,share:u,have:f,verdict:f?"included":u!=null&&u>=ee?"missing":"optional"}}),d=[];if(o.merged_prs){if(a.length)for(let u of y)u.verdict==="missing"&&d.push({what:u.what,why:`${Math.round((u.share??0)*100)}% of merged PRs in ${g} include ${De[u.what]}`});let p=o.size?.p90_lines;n!=null&&p!=null&&n>p&&d.push({what:"size",why:`${n} lines; 90% of merged PRs in ${g} have at most ${p}`})}let w=o.size?.p75_lines,c=o.size?.p90_lines,s=n==null||c==null?null:n>c?"unusual":w!=null&&n>w?"big":"usual";return{rows:a.length?y:y.map(p=>({...p,verdict:p.verdict==="missing"?"expected":p.verdict})),lines:n,size:s,gaps:d}}function Pe(a,n,o=[]){let m=te(a),g=(n.folders||[]).filter(i=>m.includes(i.area)),y=m.filter(i=>!g.some(h=>h.area===i)&&o.includes(i)),d={h:n,asks:n.asks||[],kind:"repo",used:[],left:y};if(!g.length)return d;let w=g.map(i=>i.area).sort();if(g.length===1&&!y.length){let i=g[0];return{h:{...i,scope:i.area},asks:(i.reviewed_prs??0)>=H?i.asks||[]:n.asks||[],kind:"folder",used:w,left:y}}let c=g.reduce((i,h)=>i+(h.merged_prs||0),0);if(!c)return d;let s=(i,h)=>{let N=g.filter(A=>i(A)!=null),r=N.reduce((A,I)=>A+(I.merged_prs||0),0);if(!r)return null;let b=N.reduce((A,I)=>A+i(I)*(I.merged_prs||0),0)/r,C=10**h;return Math.round(b*C)/C},p=Object.fromEntries(Se.map(i=>[i,s(h=>h.include?.[i],4)])),u={median_lines:s(i=>i.size?.median_lines,0),p75_lines:s(i=>i.size?.p75_lines,0),p90_lines:s(i=>i.size?.p90_lines,0)},f=g.filter(i=>(i.reviewed_prs??0)>=H),T=f.reduce((i,h)=>i+(h.reviewed_prs||0),0),P=new Map;for(let i of f)for(let h of i.asks||[])P.set(h.ask,(P.get(h.ask)||0)+h.prs);let v=T?[...P].map(([i,h])=>({ask:i,prs:h,share:Math.round(h/T*1e4)/1e4})).sort((i,h)=>h.prs-i.prs):n.asks||[];return{h:{scope:w.join(", "),merged_prs:c,include:p,size:u},asks:v,kind:"folders",used:w,left:y}}var Ne={tests:"Tests",changelog:"A changelog entry",docs:"Docs"},se={missing:["watch","Missing"],included:["good","Included"],optional:["neutral","Optional here"],expected:["accent","Usually included"]},Ke={unusual:["bad","Unusually big"],big:["watch","Bigger than most"],usual:["good","Usual size"]};function Me({repo:a,h:n,known:o}){let[m,g]=W(""),[y,d]=W(""),w=$e(m),c=/^\d+$/.test(y.trim())?Number(y.trim()):null,s=Pe(w,n,o.filter(r=>(r.prs||0)>0).map(r=>String(r.area))),p=s.h,u=qe(w,c,p),f=te(w),T=r=>o.filter(b=>b.area===r||String(b.area).startsWith(r+"/")||r.startsWith(b.area+"/")),P=r=>{let b=T(r);return b.length?Math.max(...b.map(C=>C.prs||0)):null},v=`stackvitals flow preflight ${a}${w.length?` --paths ${w.map(r=>/[\s"'$]/.test(r)?JSON.stringify(r):r).join(" ")}`:" --paths src/app.ts"} --lines ${c??180}`,i=u.rows.filter(r=>r.verdict==="missing").map(r=>`- [ ] ${Ne[r.what]} (${S(r.share)} of merged PRs here include them)`);u.size==="unusual"&&i.push(`- [ ] Split it: ${c} lines, while 90% of merged PRs here have at most ${p.size?.p90_lines}`);let h=i.length?`Before opening this pull request:
2
+ ${i.join(`
3
+ `)}`:"This pull request matches what merged pull requests here usually include.",N=u.size?Ke[u.size]:null;return e(B,{title:"Check a planned pull request",class:"pr-pre",state:u.gaps.length?e(x,{tone:"watch",children:[u.gaps.length," to look at"]}):w.length||c!=null?e(x,{tone:"good",children:"Nothing stands out"}):e(x,{tone:"neutral",children:"Fill in the files and size"}),bar:e(O,{children:[e(le,{text:h,label:"Copy as a checklist",small:!0}),e("span",{class:"blk-note",children:"Runs in this page from the published history; nothing is sent anywhere."})]}),children:[e("div",{class:"blk-form",children:[e(Z,{label:"Files it changes",hint:"One per line, or separated by commas. Only the names are read.",children:r=>e("textarea",{id:r,class:"input",value:m,placeholder:`${o[0]?.area||"src"}/handler.ts
4
+ ${o[0]?.area||"src"}/handler.test.ts`,spellcheck:!1,onInput:b=>g(b.currentTarget.value)})}),e(Z,{label:"Lines added plus removed",hint:"What git diff --shortstat says, added and removed together.",children:r=>e(Q,{id:r,value:y,onInput:b=>d(b.replace(/[^\d]/g,"")),placeholder:"180",maxLength:7})})]}),e(j,{rows:[["Compared with",Ge(s.kind,p.merged_prs??0,s.used)],s.kind==="folders"&&s.used.length>1?["How","Combined from each folder's published figures, so a pull request in two of them counts twice; the command below pools them exactly."]:null,s.left.length?["Left out",`${s.left.map(Oe).join(", ")}: under ${H} merged pull requests there (or not among the busiest folders published), so its numbers aren't published${s.kind==="repo"?"; the whole repo is used instead, as the command does for thin folders":""}.`]:null,s.kind==="repo"&&f.length&&!s.left.length?["Note",`None of its folders has ${H} or more merged pull requests, so the whole repo is used, as the command does.`]:null,f.length?["Its folders",f.map(r=>`${r} (${P(r)!=null?`${P(r)} merged PRs`:"no merged history yet"})`).join(", ")]:null]}),e(z,{title:"What merged pull requests here include",note:`a habit is something ${S(ee)} or more of them do`,children:e($,{name:"preflight",search:!1,rows:u.rows.map(r=>({...r,id:r.what})),columns:[{key:"what",label:"Item",primary:!0,raw:r=>Ne[r.what]},{key:"share",label:"Merged PRs with it",num:!0,render:r=>S(r.share)},{key:"have",label:"Yours",raw:r=>w.length?r.have?"Yes":"No":"\u2013"},{key:"verdict",label:"Reading",raw:r=>se[r.verdict][1],render:r=>e(x,{tone:se[r.verdict][0],children:se[r.verdict][1]})}]})}),e(z,{title:"Size",note:"lines added plus removed, against merged pull requests here",children:e($,{name:"preflight-size",search:!1,rows:[{id:"size"}],columns:[{key:"yours",label:"Yours",num:!0,raw:()=>c==null?"\u2013":String(c)},{key:"p50",label:"Median",num:!0,raw:()=>p.size?.median_lines??"\u2013"},{key:"p75",label:"3 in 4 within",num:!0,raw:()=>p.size?.p75_lines??"\u2013"},{key:"p90",label:"9 in 10 within",num:!0,raw:()=>p.size?.p90_lines??"\u2013"},{key:"reading",label:"Reading",raw:()=>N?N[1]:"Enter the size",render:()=>N?e(x,{tone:N[0],children:N[1]}):e("span",{class:"muted",children:"Enter the size"})}]})}),s.asks.length?e(j,{rows:[[s.kind==="repo"?"Reviewers here often ask for":"Reviewers in these folders often ask for",s.asks.slice(0,3).map(r=>`${r.ask} (${S(r.share)} of reviewed PRs)`).join(", ")]]}):null,e("div",{class:"pr-pre-cli",children:[e("p",{class:"blk-note",children:"The same check from your machine, pooling every merged pull request in exactly these folders (it reads per-pull-request history, which isn't published with this page)."}),e(G,{inline:!0,code:v})]})]})}var Oe=a=>a==="(root)"?"top-level files":`${a}/`;function Ge(a,n,o){return a==="repo"?`${n} merged pull requests by people across the whole repo, last 12 months`:`${a==="folders"?"about ":""}${n} merged pull requests by people in ${o.map(Oe).join(", ")}, last 12 months`}function Fe({app:a,values:n}){let o=_e(n,"automation.preflight_comments"),m=o===!0;return e(B,{title:"Post this check on new outside pull requests",class:"pr-auto",state:m?e(x,{tone:"good",children:"On"}):e(x,{tone:"neutral",children:o===!1?"Off":"Off (the default)"}),children:[e(j,{rows:[["What it does","One short note on each new pull request from an outside contributor that misses what merged pull requests here usually include, or is unusually big. Nothing is posted when it matches; drafts and the team's own PRs are skipped."],["When it posts","On the Team Flow run after the pull request opens (every 3 hours); one note per pull request, never edited again."],["Setting",e("code",{children:"automation.preflight_comments"})],o==null?["Note","Not set in .github/stackvitals.toml, so the workflow's preflight-comments input decides (false unless you changed it)."]:null]}),e(ye,{app:a,title:`StackVitals: turn ${m?"off":"on"} the pre-flight note`,req:be([],{"automation.preflight_comments":!m}),who:"anyone with write access to this repo",lands:".github/stackvitals.toml on the default branch (a pull request when it is protected)",when:`from the next run; the button ${m?"turns it off":"turns it on"}`})]})}function Ee({repo:a}){return e(xe,{title:"Outside pull requests most likely to merge",does:"Each open outside pull request's chance of merging within 30 days and why, with the model's Brier score on past pull requests against always guessing the usual rate.",why:"It is private by design: the scores are worked out on demand for maintainers and never stored, posted or put on a page, so the published data the app reads doesn't carry them.",needs:e(O,{children:["Python with ",e("code",{children:"pip install stackvitals"})," and your own GitHub token (",e("code",{children:"GITHUB_TOKEN"}),", or ",e("code",{children:"gh auth login"}),") that can read ",a,"."]}),children:[e(G,{inline:!0,code:`stackvitals flow triage ${a}`,note:"Every open outside pull request, likeliest first."}),e(G,{inline:!0,code:`stackvitals flow triage ${a} --pr 123`,note:"Only one pull request: put its number in place of 123."})]})}var Ue={review_within_hours:" h",merge_within_days:" days",max_pr_lines:" lines"},Je={hanging_review:"Review asked, not started for 3+ days",long_lived:"Ready for more than 30 days",high_interaction:"10+ comments or reviews",red_and_idle:"Failing checks nobody acted on for a day"},ze={author:"Author",reviewer:"Reviewer",maintainer:"Maintainer",merger:"Whoever merges"},Qe={pickup:"Waiting for first review",review:"First to final review",merge:"Approved to merged",cycle:"Ready to merge"},Te=null;function Ce({name:a,...n}){let[o,m]=W(null);if(ne(()=>{(Te||(Te=import("../chunks/more-PC6FVS3P.js"))).then(m)},[]),!o)return e(de,{lines:4});let g=o[a];return e(g,{...n})}function Ye({children:a}){return e("p",{class:"sv-dimline pr-dim","aria-hidden":"true",children:e("span",{children:a})})}var Ae={tests:"No tests",changelog:"No changelog entry",docs:"No docs",size:"Unusually big"};function Ve({app:a}){let n=pe({flow:"flow.json",del:"delivery.json",pulse:"pulse.json",settings:"settings.json"}),[o,m]=W(()=>Y.get("me","")),[g,y]=me(),[d,w]=W(null),c="Pull Requests";if(!a)return e(U,{title:c,children:e(M,{icon:"setup",title:"No StackVitals data here yet",action:e(F,{variant:"filled",href:"#/setup",children:"Set it up"})})});if(!n.ready)return e(ue,{});let s=n.flow;if(!s)return e(U,{title:c,subtitle:"Who acts next, stuck pull requests and how long reviews take.",children:e(M,{icon:"prs",title:"Team Flow hasn't run here yet.",action:e(F,{variant:"filled",href:"#/settings",icon:"settings",children:"Turn it on"}),children:["Add ",e("code",{children:"flow"})," to the workflow's modules; it runs every 3 hours."]})});let p=t=>`https://github.com/${a.repo}${t}`,u=o.trim().replace(/^@/,"").toLowerCase(),f=s.queue||[],T=f.filter(t=>!u||(t.author||"").toLowerCase()===u||(t.who||[]).some(l=>String(l).toLowerCase()===u)),P=Object.entries(n.del?.stuck||{}).flatMap(([t,l])=>(l||[]).map(L=>({...L,kind:Je[t]||t}))),v=n.del?.agreements,i=s.stages||{},h=s.monthly||[],N=(t,l)=>t===void 0?void 0:l?.low!=null?`n = ${t}, likely ${k(l.low)} to ${k(l.high)}`:`n = ${t}`,r=t=>h.filter(l=>t(l)!=null).map(l=>({label:X(l.month),value:t(l)})),b=[{id:"pickup",name:"First review",sub:"Median wait, by month",kind:"secs",better:"down",period:"month",points:r(t=>t.pickup_median_s),meaning:t=>`Half of the pull requests asking for review got a first answer within ${k(t)}.`,info:{title:"First review",body:"Time from a pull request being ready for review until someone else first comments or reviews it. The median of that month's pull requests.",doc:"methods.md"}},{id:"cycle",name:"Ready to merge",sub:"Median, by month",kind:"secs",better:"down",period:"month",points:r(t=>t.cycle_median_s),meaning:t=>`Half of the merged pull requests went from ready to merged within ${k(t)}.`,info:{title:"Ready to merge",body:"Time from a pull request being ready for review until it merged, by month of merge.",doc:"methods.md"}},{id:"merged",name:"Merged",sub:"Pull requests by month",kind:"count",better:"up",period:"month",points:r(t=>t.merged),meaning:t=>`${Math.round(t)} pull requests merged that month.`},{id:"opened",name:"Opened",sub:"Pull requests by month",kind:"count",better:null,period:"month",points:r(t=>t.opened),meaning:t=>`${Math.round(t)} pull requests opened that month.`}].filter(t=>t.points.length),C=b.find(t=>t.id===d)||b[0],A=t=>{m(t),Y.set("me",t)},I=Object.entries(s.groups||{}),R=s.habits;return e(U,{title:c,subtitle:`Open pull requests and who has the next move, from the last ${s.window_days??90} days.`,toolbar:a.modules?.flow?.page?e(F,{variant:"plain",href:a.modules.flow.page,iconEnd:"external",children:"Printable page"}):null,children:[C?e(_,{title:"Review flow",description:"Month by month. Drag across the chart, or pick a row to chart it.",children:e(ce,{ratio:"lead",children:[e(E,{children:e(he,{metric:C,ranges:g,setRange:y})}),e(we,{label:"Review flow",items:b.map(t=>ge(t,g[t.period]||6)),selected:C.id,onSelect:w,tones:fe(b,g)})]})}):null,e(_,{title:"Key numbers",class:"pr-key",description:`Last ${s.window_days??90} days.`,children:[e(Ye,{children:["last ",s.window_days??90," days"]}),e(J,{children:[e(q,{label:"Open",value:s.open??0,note:`${s.drafts||0} drafts`}),e(q,{label:"Merged",value:s.merged??0,note:`${s.closed_unmerged??0} closed without merging`}),e(q,{label:"First review, median",value:k(i.pickup?.median_s),note:N(i.pickup?.n,s.measures?.["flow.pickup_time"])}),e(q,{label:"Ready to merge, median",value:k(i.cycle?.median_s),note:N(i.cycle?.n,s.measures?.["flow.cycle_time"])}),e(q,{label:"Stale",value:s.stale??0,note:"waiting over 30 days"}),s.merged_without_review!==void 0?e(q,{label:"Merged without review",value:s.merged_without_review}):null]}),s.bots||s.excluded?e(B,{title:"Left out of every number",class:"pr-left",children:e(j,{rows:[s.bots?["Bots' pull requests",`${s.bots.open??0} open, ${s.bots.closed??0} closed`]:null,s.excluded?["Left out by the team",`${ie(s.excluded,"pull request")} (a label or /stackvitals exclude)`]:null]})}):null]}),e(_,{title:"Who acts next",description:"Each open pull request, whoever holds the next move and why, longest wait first.",action:e("div",{class:"pr-me",children:[e(Q,{value:o,onInput:A,placeholder:"Only mine: your handle",label:"Only mine: your GitHub handle, kept on this device"}),o?e(F,{size:"sm",variant:"plain",onClick:()=>A(""),children:"Show all"}):null]}),children:e("div",{class:"pr-queue",children:e($,{name:"who-acts-next",caption:"Who acts next",rows:T,initialSort:{key:"waiting_s",desc:!0},columns:[{key:"n",label:"Pull request",primary:!0,raw:t=>`#${t.n} ${t.title}`,render:t=>e(O,{children:[e("a",{href:p(`/pull/${t.n}`),target:"_blank",rel:"noopener noreferrer",children:["#",t.n]})," ",V(t.title,80)]})},{key:"author",label:"Author",raw:t=>t.author||"",render:t=>e(O,{children:[t.author||"\u2013",t.outsider?e("div",{children:e(x,{tone:"accent",children:"Outside contributor"})}):null]})},...f.some(t=>t.actor||t.who?.length)?[{key:"actor",label:"Next move",filter:!0,raw:t=>ze[t.actor||""]||t.actor||"\u2013",render:t=>e(O,{children:[e("b",{children:ze[t.actor||""]||t.actor||"\u2013"}),t.who?.length?e("div",{class:"muted",children:t.who.join(", ")}):null]})}]:[],{key:"why",label:"Why",render:t=>e("span",{class:"pr-why",children:V(t.why,90)})},...f.some(t=>t.gaps?.length)?[{key:"gaps",label:"Differs from merged PRs",raw:t=>(t.gaps||[]).map(l=>Ae[l.what]||l.what).join(", "),render:t=>t.gaps?.length?e("ul",{class:"pr-gaps",children:t.gaps.map(l=>e("li",{title:l.why,children:[e(x,{tone:"watch",children:Ae[l.what]||l.what}),e("span",{class:"muted small",children:l.why})]}))}):e("span",{class:"muted",children:"\u2013"})}]:[],{key:"waiting_s",label:"Waiting",num:!0,raw:t=>t.waiting_s??0,render:t=>e(O,{children:[t.waiting_s!=null?k(t.waiting_s):`since ${K(t.since)}`,t.usual_s?e("div",{class:"muted small",children:["usual ",k(t.usual_s)]}):null,t.stale?e("div",{children:e(x,{tone:"watch",children:"Stale"})}):null]})},{key:"decide",label:"Decide",nowrap:!0,raw:()=>"",render:t=>e(ke,{app:a,kind:"pr",id:String(t.n),verbs:["exclude"],label:"Leave out"})}],empty:e(E,{children:e(M,{icon:"check",title:u?`Nothing waits on ${u}.`:"Nothing is waiting.",children:"Open pull requests appear here with whoever holds the next move."})})})})}),e(_,{title:"Stuck",description:"Waiting on a review for days, red and idle, or dragging on.",action:e(x,{tone:P.length?"watch":"good",children:P.length?`${P.length} stuck`:"None stuck"}),children:e($,{name:"stuck",caption:"Stuck pull requests",rows:P,columns:[{key:"pr",label:"Pull request",primary:!0,render:t=>e("a",{href:p(`/pull/${t.pr}`),target:"_blank",rel:"noopener noreferrer",children:["#",t.pr]})},{key:"kind",label:"Stuck because",filter:!0},{key:"why",label:"Detail",render:t=>e("span",{class:"muted",children:t.why||(t.hours?ae(t.hours):"")})},{key:"since",label:"Since",render:t=>K(t.since)}],empty:e(E,{children:e(M,{icon:"check",title:"Nothing is stuck.",children:"Pull requests waiting on a review for days, red and idle, or dragging on show up here."})})})}),s.rules?.length?e(_,{title:"Rules",description:"Your [[rules]]: what each matches now, and what it would have matched among recent merged pull requests.",children:e($,{name:"pr-rules",caption:"PR rules",search:!1,rows:s.rules,columns:[{key:"name",label:"Rule",primary:!0},{key:"dry_run",label:"Mode",raw:t=>t.dry_run?"Dry run":"Acting",render:t=>t.dry_run?e(x,{tone:"neutral",children:"Dry run"}):e(x,{tone:"good",children:"Acting"})},{key:"open",label:"Open PRs matched",num:!0,raw:t=>(t.open||[]).length,render:t=>(t.open||[]).length?t.open.slice(0,5).map(l=>`#${l}`).join(", "):"none"},{key:"replay",label:"Recent merged matched",num:!0,raw:t=>t.replay?.matched,render:t=>`${t.replay?.matched??0} of ${t.replay?.of??0}`}]})}):null,e(_,{title:"Working agreements",description:"The team's own rules and the pull requests that broke them.",info:e(oe,{info:{title:"Working agreements",body:"Rules a team sets for itself, such as a first review within 24 hours or pull requests under 400 lines. Each merged pull request that broke one is listed, with its value.",doc:"methods.md"}}),action:e(F,{size:"sm",variant:"plain",href:"#/settings?module=agreements",iconEnd:"right",children:"Set agreements"}),children:v?e(O,{children:[e(J,{children:Object.entries(v.labels).map(([t,l])=>e(q,{label:l,value:v.counts[t]??0,note:`broken in ${v.window_days} days, of ${v.merged} merged`}))}),e(z,{title:"Exceptions",note:"merged pull requests that broke an agreement, with the value they had",children:e($,{name:"agreement-exceptions",caption:"Agreement exceptions",rows:v.exceptions.map(t=>({...t,label:v.labels[t.rule]||t.rule})),columns:[{key:"pr",label:"Pull request",primary:!0,render:t=>e("a",{href:p(`/pull/${t.pr}`),target:"_blank",rel:"noopener noreferrer",children:["#",t.pr]})},{key:"label",label:"Agreement",filter:!0},{key:"value",label:"Was",num:!0,render:t=>t.value==null||t.value===!0?"\u2013":`${t.value}${Ue[t.rule]||""}`},{key:"open",label:"Now",raw:t=>t.open?"still open":"merged"}],empty:e(E,{children:e(M,{icon:"check",title:"No agreement broken in this window."})})})}),Object.keys(v.weekly||{}).length?e("div",{class:"pr-weeks blk-grid",children:Object.entries(v.weekly||{}).map(([t,l])=>e(B,{title:v.labels[t]||t,state:e("span",{class:"muted",children:"broken, per week"}),children:l.some(L=>L[1])?e(ve,{label:`${v.labels[t]||t}: pull requests that broke it, per week`,height:150,bars:l.map(([L,re])=>({label:X(L),value:re,tone:re?"watch":"neutral"}))}):e("p",{class:"blk-note",children:["Nobody broke it in the last ",l.length," weeks."]})}))}):null]}):e(E,{children:e(M,{icon:"settings",title:"No working agreements set.",action:e(F,{variant:"tinted",href:"#/settings?module=agreements",children:"Set agreements"}),children:["A team sets its own rules (first review within 24 hours, pull requests under 400 lines, a review before every merge) in Settings or under ",e("code",{children:"[agreements]"})," in ",e("code",{children:".github/stackvitals.toml"}),"."]})})}),e(_,{title:"Review stages",description:"Where review time goes, for insiders and outside contributors side by side.",children:[Object.keys(i).length?null:e(E,{children:e(M,{icon:"clock",title:"No review stages measured yet.",children:"They show once pull requests get reviewed and merged."})}),Object.keys(i).length?e(z,{title:"By stage",note:"every reviewed pull request in the window",children:e($,{name:"stages",caption:"Review stages",search:!1,rows:Object.entries(i).map(([t,l])=>({k:t,...l})),columns:[{key:"k",label:"Stage",primary:!0,raw:t=>Qe[t.k]||t.k},{key:"median_s",label:"Median",num:!0,render:t=>k(t.median_s)},{key:"p90_s",label:"90th percentile",num:!0,render:t=>k(t.p90_s)},{key:"n",label:"PRs",num:!0}]})}):null,I.length?e(z,{title:"Insiders and outside contributors",note:"medians, side by side",children:e($,{name:"groups",caption:"Insiders and outside contributors",search:!1,rows:I.map(([t,l])=>({k:t,...l})),columns:[{key:"k",label:"Who",primary:!0,raw:t=>t.k==="outsider"?"Outside contributors":t.k==="insider"?"Insiders":t.k},{key:"merged",label:"Merged",num:!0},{key:"merge_rate",label:"Merge rate",num:!0,render:t=>S(t.merge_rate)},{key:"pickup",label:"First review",num:!0,raw:t=>t.pickup?.median_s,render:t=>k(t.pickup?.median_s)},{key:"cycle",label:"Ready to merge",num:!0,raw:t=>t.cycle?.median_s,render:t=>k(t.cycle?.median_s)},{key:"merged_without_review",label:"No review",num:!0}]})}):null,(s.load||[]).length?e(z,{title:"Open review requests",note:"per reviewer, busiest first",children:e($,{name:"review-load",caption:"Open review requests",rows:s.load,initialSort:{key:"open_requests",desc:!0},columns:[{key:"reviewer",label:"Reviewer",primary:!0},{key:"open_requests",label:"Open requests",num:!0},{key:"oldest_since",label:"Oldest asked",render:t=>t.oldest_since?K(t.oldest_since):"\u2013"}]})}):null,s.baselines&&Object.values(s.baselines).some(t=>t!=null)?e(B,{title:"What counts as slow here",state:e("span",{class:"muted",children:"75th percentile of merged PRs"}),children:[e(j,{rows:[["First review",k(s.baselines.pickup)],["Approved to merged",k(s.baselines.merge)],["The author's answer to a review",k(s.baselines.author)]]}),e("p",{class:"blk-note",children:"A pull request waiting longer than this shows its usual time in Who acts next."})]}):null]}),e(_,{title:"Who knows what",class:"pr-know",description:"Each folder's main author and their share of its merged pull requests. An area one person carries needs a second reviewer before they're away.",children:s.knowledge?e(Ce,{name:"Knowledge",k:s.knowledge}):e(E,{children:e(M,{icon:"clock",title:"Not mapped yet.",children:"The next Team Flow run maps who works on each folder."})})}),s.delivery?e(_,{title:"Releases",description:`From GitHub releases in the last ${s.window_days??90} days, for repos that don't record deployments. Delivery has the full DORA numbers.`,action:e(F,{size:"sm",variant:"plain",href:"#/delivery",iconEnd:"right",children:"Delivery"}),children:e(Ce,{name:"Releases",d:s.delivery})}):null,R?e(_,{title:"Habits",description:`What merged pull requests carry, ${R.scope||"whole repo"}, ${R.merged_prs??0} merged.`,children:[e(J,{children:[e(q,{label:"With tests",value:S(R.include?.tests)}),e(q,{label:"With docs",value:S(R.include?.docs)}),e(q,{label:"With a changelog entry",value:S(R.include?.changelog)}),e(q,{label:"Size, median",value:R.size?.median_lines!=null?`${R.size.median_lines} lines`:"\u2013",note:`75th percentile ${R.size?.p75_lines??"\u2013"}, 90th ${R.size?.p90_lines??"\u2013"}`})]}),R.asks?.length?e(z,{title:"What maintainers ask for in reviews",note:"share of reviewed pull requests where it came up",children:e($,{name:"review-asks",search:!1,rows:R.asks.map(t=>({...t,id:t.ask})),initialSort:{key:"share",desc:!0},columns:[{key:"ask",label:"Ask",primary:!0},{key:"share",label:"Reviewed PRs",num:!0,render:t=>S(t.share)},{key:"prs",label:"PRs",num:!0}]})}):null]}):null,R?e(_,{title:"Before opening a pull request",id:"preflight",description:"Check a planned change against what merged pull requests here include, or have the workflow post the same check on new outside pull requests.",children:e("div",{class:"pr-pre-wrap",children:[e(Me,{repo:a.repo,h:R,known:s.knowledge?.areas||[]}),e(Fe,{app:a,values:n.settings?.values})]})}):null,n.pulse?.weeks?.length?e(tt,{p:n.pulse}):e(_,{title:"Team pulse",description:"Three questions a week, answered by reaction on the digest issue.",children:e(E,{children:e(M,{icon:"community",title:"No pulse answers yet.",action:e(F,{variant:"tinted",href:"#/settings?module=digest",children:"Turn on the digest"}),children:"With the weekly digest on, its issue asks the team three yes-or-no questions; only the counts are kept."})})}),e(_,{title:"From your machine",description:"A private answer that needs your own token; nothing is written to the repo.",children:e(Ee,{repo:a.repo})})]})}var Xe=[["flow","Got work done without waiting on others"],["friction","CI and reviews stayed out of the way"],["satisfaction","Happy with how the team shipped"]],Ze={pickup:["Pickup time","#/prs"],first_try:["First-try green","#/ci"],deployments:["Deployments","#/delivery"]},et={flow:"pickup",friction:"first_try",satisfaction:"deployments"};function tt({p:a}){let n=a.min_answers||5,o=(d,w)=>{let c=d?.[w],s=c?c.yes+c.no+c.mixed:0;return{n:s,s:c&&s>=n?c.yes/s:null}},m=a.weeks[a.weeks.length-1],g=a.weeks.slice(-4),y=Xe.map(([d,w])=>{let[c,s]=Ze[(a.beside||et)[d]||""]||[(a.beside||{})[d]||"\u2013","#/"],p=o(m,d),u=g.map(f=>o(f,d)).filter(f=>f.s!=null);return{k:d,label:w,beside:c,href:s,n:p.n,now:p.s,avg:u.length?u.reduce((f,T)=>f+T.s,0)/u.length:null}});return e(_,{title:"Team pulse",description:`The digest issue's three questions, answered by reaction; week ${m.week}. A share needs ${n} answers.`,children:[e($,{name:"pulse",caption:"Team pulse",search:!1,rows:y,columns:[{key:"label",label:"Question",primary:!0},{key:"now",label:"Yes, last week",num:!0,render:d=>d.now==null?d.n?`${d.n} answers`:"\u2013":S(d.now)},{key:"avg",label:"Yes, last 4 weeks",num:!0,render:d=>d.avg==null?"\u2013":S(d.avg)},{key:"beside",label:"Read with",render:d=>e("a",{href:d.href,children:d.beside})}]}),e("p",{class:"blk-note",children:"StackVitals keeps only the counts; GitHub shows who reacted to anyone who can see the issue. On a public repo only the team's own people count."})]})}export{Ve as default};
@@ -0,0 +1 @@
1
+ .link-btn{color:var(--accent);font-weight:700;font-size:13.5px;padding:2px 0;text-decoration:none}.link-btn:hover{text-decoration:underline}.set-status{align-items:center;flex-wrap:wrap}.set-status>span:nth-child(2){flex:1 1 240px}.set-status .spin{margin-top:0;color:var(--accent)}.set-layout{display:grid;grid-template-columns:250px minmax(0,1fr);gap:28px;align-items:start;margin-top:8px}.set-nav{position:sticky;top:calc(var(--top-h) + 12px);display:flex;flex-direction:column;gap:10px;min-width:0}.set-search{display:block;flex:none}.set-search .input{background:var(--surface);border-color:var(--line)}.set-nav-list{list-style:none;margin:0;padding:6px;display:flex;flex-direction:column;gap:1px}.set-nav-item{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:11px;color:var(--ink);text-decoration:none;font-weight:650;font-size:14.5px;min-height:40px}.set-nav-item:hover{background:color-mix(in srgb,var(--ink) 5%,transparent)}.set-nav-item[aria-current=page]{background:var(--accent-soft);color:var(--accent)}.set-nav-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.set-ic{width:28px;height:28px;border-radius:8px;display:grid;place-items:center;color:#fff;background:#8e99a6;flex:none}.set-ic .ic{width:17px;height:17px;stroke-width:2}.set-ic[data-g=alerts]{background:#e5534b}.set-ic[data-g=agreements]{background:#2e9d61}.set-ic[data-g=digest]{background:#d88a1d}.set-ic[data-g=automation]{background:#7b61d9}.set-ic[data-g=ci]{background:#2e9d61}.set-ic[data-g=delivery]{background:#2b7fe0}.set-ic[data-g=people]{background:#c2477e}.set-ic[data-g=deps]{background:#9a6b3c}.set-ic[data-g=community]{background:#1e9cb0}.set-ic[data-g=integrations]{background:#4f6bd8}.set-ic[data-g=benchmarks]{background:#5e8a3a}.set-ic[data-g=workflow]{background:#4b5663}.set-ic[data-g=appearance]{background:#2b7fe0}.set-ic[data-g=account]{background:#6b7480}.set-chev{display:none;width:18px;height:18px;color:var(--ink-3)}.set-main{min-width:0;max-width:780px;display:flex;flex-direction:column;gap:18px;padding-bottom:96px;animation:set-in var(--dur-3) var(--spring) both}@keyframes set-in{0%{opacity:0;transform:translateY(6px)}}.set-back{display:none;align-items:center;gap:4px;font-weight:700;color:var(--accent);text-decoration:none;width:max-content;margin-left:-6px;padding:4px 6px;border-radius:10px}.set-head{display:flex;align-items:baseline;gap:12px;justify-content:space-between;flex-wrap:wrap}.set-title{font-size:24px;font-weight:800;letter-spacing:-.02em}.sgroup{display:flex;flex-direction:column;gap:6px;min-width:0}.sgroup-h{font-size:15px;font-weight:650;color:var(--ink);margin:4px 16px 0}.sgroup-note{font-size:13.5px;color:var(--ink-2);margin:0 4px;max-width:70ch}.sform{padding:2px 0;overflow:hidden}.srow{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px 14px;align-items:center;padding:12px 12px 12px 16px;position:relative;scroll-margin:90px;transition:background-color var(--dur-2)}.srow+.srow:before{content:"";position:absolute;top:0;left:16px;right:0;height:1px;background:var(--line)}.srow.is-stack{grid-template-columns:minmax(0,1fr) auto}.srow.is-stack .srow-ctl{grid-column:1 / -1;grid-row:2;justify-self:stretch}.srow.is-changed{background:color-mix(in srgb,var(--accent) 6%,transparent)}.srow.is-flash{animation:flash 1.6s var(--ease-out)}@keyframes flash{0%,40%{background:color-mix(in srgb,var(--accent) 20%,transparent)}}.srow-text{min-width:0;display:flex;flex-direction:column;gap:2px}.srow-label{display:flex;align-items:center;gap:7px;font-weight:650;font-size:15px}.srow-help{color:var(--ink-2);font-size:13px;line-height:1.4}.srow-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:12.5px;color:var(--ink-3);font-weight:600;margin-top:2px}.srow-meta:empty{display:none}.srow-meta .link-btn{font-size:12.5px}.srow .field-error{margin-top:4px}.srow-ctl{min-width:0;display:flex;align-items:center;gap:8px;justify-self:end}.srow-ctl>.input,.srow-ctl>.select{width:240px;max-width:100%}.srow.is-stack .srow-ctl>.input,.srow.is-stack .srow-ctl>.select,.srow.is-stack .chips{width:100%}.srow .info-btn{width:22px;height:22px;font-size:11.5px;align-self:start;margin-top:2px}.cdot{width:8px;height:8px;border-radius:50%;background:var(--accent);flex:none;animation:pop var(--dur-3) var(--spring-pop) both}@keyframes pop{0%{transform:scale(0)}}.replay{display:flex;gap:6px;align-items:center;font-size:13px;font-weight:650;color:var(--accent);margin-top:4px}.replay .ic{width:15px;height:15px}.date-ctl{display:inline-flex;align-items:center;gap:10px}.date-ctl .input{width:auto}.chipset{display:flex;flex-wrap:wrap;gap:6px}.chip-t{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:99px;font-size:13.5px;font-weight:650;background:var(--field);color:var(--ink-2);border:1.5px solid transparent}.chip-t[aria-pressed=true]{background:var(--accent-soft);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 35%,transparent)}.chip-t .ic{width:14px;height:14px;stroke-width:2.6}.pairs{display:flex;flex-direction:column;gap:6px;width:100%}.pair{display:flex;align-items:center;gap:10px;padding:6px 6px 6px 12px;border-radius:12px;background:var(--surface-2);min-width:0;flex-wrap:wrap}.pair-k{font-weight:700;font-size:14px;overflow-wrap:anywhere;min-width:0}.pair-v{color:var(--ink-2);font-size:13.5px;margin-left:auto}.pair .chips{flex:1 1 220px;background:var(--surface)}.pair-x{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;color:var(--ink-3);flex:none;margin-left:auto}.pair-x:hover{background:var(--neutral-soft);color:var(--ink)}.pair-x .ic{width:14px;height:14px}.pair-add{display:flex;gap:6px;flex-wrap:wrap;align-items:center}.pair-add>.input,.pair-add>.select{flex:1 1 150px;width:auto}.savebar{position:fixed;left:50%;bottom:24px;z-index:40;display:flex;align-items:center;gap:8px;padding:7px 7px 7px 16px;border-radius:99px;background:var(--surface);border:1px solid var(--line);box-shadow:var(--shadow-pop);max-width:calc(100vw - 24px);transform:translate(-50%,160%);opacity:0;pointer-events:none;transition:transform var(--dur-3) var(--spring),opacity var(--dur-1)}.savebar.is-on{transform:translate(-50%);opacity:1;pointer-events:auto}.savebar b{white-space:nowrap;margin-right:4px}@media(min-width:821px){.savebar{margin-left:calc(var(--side-w) / 2)}}.fact-wide{grid-column:1 / -1}.fact dd.mono{font-family:var(--mono);font-size:13.5px;font-weight:600}.diff{list-style:none;margin:4px 0 14px;padding:0;border:1px solid var(--line);border-radius:16px;overflow:hidden}.diff li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 12px;padding:11px 14px;align-items:center}.diff li+li{border-top:1px solid var(--line)}.diff-t{font-weight:650;display:flex;flex-direction:column;min-width:0}.diff-t small{font-family:var(--mono);font-weight:500;font-size:12px;color:var(--ink-3);overflow-wrap:anywhere}.diff-v{display:flex;align-items:center;gap:6px;font-size:14px;flex-wrap:wrap;justify-content:flex-end;min-width:0;overflow-wrap:anywhere}.diff-v s{color:var(--ink-3)}.diff-v .ic{width:15px;height:15px;color:var(--ink-3)}.diff .replay{grid-column:1 / -1}.how{display:flex;flex-direction:column;gap:10px;padding-top:4px}.how .kv{font-size:13px}.how-actions{display:flex;gap:8px;flex-wrap:wrap}@media(max-width:820px){.set-layout{grid-template-columns:minmax(0,1fr);gap:12px}.set-nav{position:static}.set-nav-list{padding:2px 0;gap:0}.set-nav-item{padding:9px 12px 9px 14px;min-height:50px;border-radius:0;font-size:15.5px}.set-nav-list li+li .set-nav-item{box-shadow:inset 52px 1px 0 -51px var(--line)}.set-nav-item[aria-current=page]{background:none;color:var(--ink)}.set-chev{display:block}.set-layout.has-group .set-nav{display:none}.set-layout:not(.has-group) .set-main{display:none}.set-back{display:inline-flex}.set-main{animation-name:set-push}.srow{grid-template-columns:minmax(0,1fr) auto;padding:12px 12px 12px 14px}.srow-ctl{grid-column:1 / -1;grid-row:2;justify-self:start}.srow .info-btn{grid-column:2;grid-row:1}.srow:has(.switch){grid-template-columns:minmax(0,1fr) auto auto}.srow:has(.switch) .srow-ctl,.srow:has(.switch) .info-btn{grid-column:auto;grid-row:auto;justify-self:end}.srow-ctl>.input,.srow-ctl>.select{width:100%}.srow-ctl:has(>.input,>.select){justify-self:stretch}.savebar{bottom:calc(84px + env(safe-area-inset-bottom))}}@keyframes set-push{0%{opacity:0;transform:translate(24px)}}@media(max-width:640px){.diff li{grid-template-columns:minmax(0,1fr)}.diff-v{justify-content:flex-start}}[data-design=sheet][data-page=settings] .link-btn{font-weight:600;font-size:14px;color:var(--accent);text-decoration:underline;text-underline-offset:3px;text-decoration-color:color-mix(in srgb,currentColor 45%,transparent)}[data-design=sheet][data-page=settings] .link-btn:hover{text-decoration-color:currentColor}[data-design=sheet][data-page=settings] .set-search .input{background:var(--surface);border-color:var(--line-strong)}[data-design=sheet][data-page=settings] .set-nav-list{padding:0;gap:0;counter-reset:sg;background:var(--surface);border:1.5px solid var(--frame)}[data-design=sheet][data-page=settings] .set-nav-list li{counter-increment:sg}[data-design=sheet][data-page=settings] .set-nav-list li+li{border-top:1px solid var(--line)}[data-design=sheet][data-page=settings] .set-nav-item{position:relative;gap:12px;padding:8px 14px;min-height:44px;font-weight:400;font-size:15.5px}[data-design=sheet][data-page=settings] .set-nav-item:before{content:counter(sg);font:600 14px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--ink-2);width:20px;flex:none;text-align:right}[data-design=sheet][data-page=settings] .set-nav-item:hover{background:color-mix(in srgb,var(--ink) 5%,transparent)}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page]{color:var(--ink);font-weight:700;background:linear-gradient(var(--sv-blue),var(--sv-blue)) left / 4px 100% no-repeat,var(--accent-soft)}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page]:before{color:var(--accent)}[data-design=sheet][data-page=settings] .set-ic{width:20px;height:20px;background:none;color:var(--ink-2)}[data-design=sheet][data-page=settings] .set-ic .ic{width:18px;height:18px;stroke-width:1.7}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page] .set-ic{color:var(--accent)}[data-design=sheet][data-page=settings] .set-main{animation-name:svFade}[data-design=sheet][data-page=settings] .set-back{font-weight:600}[data-design=sheet][data-page=settings] .set-head{align-items:flex-end}[data-design=sheet][data-page=settings] .set-title{font-family:var(--display);font-weight:700;font-size:30px;line-height:1.1;letter-spacing:-.005em;border-bottom:3px solid var(--mod);padding-bottom:4px}[data-design=sheet][data-page=settings] .sgroup-h{font-weight:700;font-size:16.5px;margin:6px 0 2px}[data-design=sheet][data-page=settings] .sgroup:has(>.sgroup-h+.sform){gap:0}[data-design=sheet][data-page=settings] .sgroup-h:has(+.sform){margin:0;padding:9px 16px;min-height:42px;background:var(--strip);border:1.5px solid var(--frame);border-bottom:1px solid var(--line-strong)}[data-design=sheet][data-page=settings] .sgroup-note{margin:0;font-size:15px;color:var(--ink-2)}[data-design=sheet][data-page=settings] .sform.card{background:var(--surface);border:1.5px solid var(--frame)}[data-design=sheet][data-page=settings] .sgroup-h+.sform.card{border-top:0}[data-design=sheet][data-page=settings] .srow+.srow:before{left:0;background:var(--line)}[data-design=sheet][data-page=settings] .srow-label{font-weight:600;font-size:16px}[data-design=sheet][data-page=settings] .srow-help{font-size:15px;line-height:1.45}[data-design=sheet][data-page=settings] .srow-meta{font:400 14px/1.4 var(--font);color:var(--ink-2)}[data-design=sheet][data-page=settings] .srow-meta .link-btn{font-size:14px}[data-design=sheet][data-page=settings] .srow.is-changed{background:linear-gradient(var(--sv-blue),var(--sv-blue)) left / 4px 100% no-repeat,var(--accent-soft)}[data-design=sheet][data-page=settings] .srow.is-flash{animation:svSetFlash 1.6s var(--sv-ease)}@keyframes svSetFlash{0%,40%{outline:2px solid var(--focus);outline-offset:-2px}to{outline:2px solid transparent;outline-offset:-2px}}[data-design=sheet][data-page=settings] .cdot{width:9px;height:9px;background:var(--sv-blue);animation:none}[data-design=sheet][data-page=settings] .replay{font:600 14px/1.4 var(--font);color:var(--accent)}[data-design=sheet][data-page=settings] .chip-t{padding:5px 12px;font-weight:600;font-size:14px;background:var(--surface);color:var(--ink);border:1.5px solid var(--line-strong)}[data-design=sheet][data-page=settings] .chip-t:hover{border-color:var(--ink)}[data-design=sheet][data-page=settings] .chip-t[aria-pressed=true]{background:var(--accent-soft);color:var(--ink);border-color:var(--sv-blue)}[data-design=sheet][data-page=settings] .chip-t[aria-pressed=true] .ic{color:var(--accent)}[data-design=sheet][data-page=settings] .pair{background:var(--surface-2);border:1px solid var(--line)}[data-design=sheet][data-page=settings] .pair-k{font-weight:600;font-size:15px}[data-design=sheet][data-page=settings] .pair-v{font-size:14px}[data-design=sheet][data-page=settings] .pair .chips{background:var(--surface)}[data-design=sheet][data-page=settings] .pair-x{border:1px solid transparent}[data-design=sheet][data-page=settings] .pair-x:hover{background:none;border-color:var(--ink)}[data-design=sheet][data-page=settings] .savebar{background:var(--surface);border:1.5px solid var(--frame);padding:8px 8px 8px 16px}[data-design=sheet][data-page=settings] .savebar b{font:600 15px var(--font)}[data-design=sheet][data-page=settings] .fact dd.mono{font-family:var(--mono);font-weight:400;font-size:14px}[data-design=sheet][data-page=settings] .diff{border:1.5px solid var(--frame);background:var(--surface)}[data-design=sheet][data-page=settings] .diff-t{font-weight:600}[data-design=sheet][data-page=settings] .diff-t small{font-weight:400;font-size:13px;color:var(--ink-2)}[data-design=sheet][data-page=settings] .diff-v,[data-design=sheet][data-page=settings] .how .kv{font-size:15px}@media(max-width:820px){[data-design=sheet][data-page=settings] .set-nav-item{min-height:50px;padding:9px 12px}[data-design=sheet][data-page=settings] .set-nav-list li+li .set-nav-item{box-shadow:none!important}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page]{background:none;font-weight:400}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page] :is(.set-ic){color:var(--ink-2)}[data-design=sheet][data-page=settings] .set-nav-item[aria-current=page]:before{color:var(--ink-2)}[data-design=sheet][data-page=settings] .set-main{animation-name:svFade}[data-design=sheet][data-page=settings] .set-title{font-size:26px}}@media(prefers-reduced-motion:reduce){[data-design=sheet][data-page=settings] .srow.is-flash{animation:none}}
@@ -0,0 +1 @@
1
+ import{a as De,b as Be,c as Pe}from"../chunks/chunk-7II2BD5F.js";import{c as Ie}from"../chunks/chunk-7TJCBOAY.js";import{a as Q,b as xe,c as Y,d as T,e as Z,f as B,g as Oe,h as je,i as W,j as ve}from"../chunks/chunk-S654BBEP.js";import{b as me}from"../chunks/chunk-763NH7PP.js";import"../chunks/chunk-6BDBXA6V.js";import"../chunks/chunk-MAPYGK3P.js";import{c as ge,d as Re}from"../chunks/chunk-4WKQTWUC.js";import{k as pe,q as ce,s as ze}from"../chunks/chunk-VQ5YXO54.js";import{b as K}from"../chunks/chunk-76WAVKUG.js";import{a as $e,b as ue,c as _e,e as V,f as fe,h as X,i as he}from"../chunks/chunk-VWKSMFWJ.js";import{G as Ce,I as Se,P as de,Q as J,a as _,c as C,d as N,g as le,h as H,i as I,w as e,x as w,z as O}from"../chunks/chunk-GT4EAKAO.js";import{d as D}from"../chunks/chunk-G7NGB5UX.js";D();D();var He=t=>t.trim().toLowerCase().replace(/[^\p{L}\p{N}\p{M}\s_-]/gu,"").replace(/\s/g,"-");function ee(t,n){let[s="",r]=t.split("#"),c=s.replace(/^docs\//,"").replace(/\.md$/,"").replace(/\//g,"-"),l=n?He(n):r;return`#/help/${c}${l?"#"+l:""}`}D();var Ee=["ok","heads_up","miss"];function Je(t,n,s,r,c,l){return t==null||n<r?"not enough data":t>s?l==null||l>s?"miss":"heads_up":t>=c*s?"heads_up":"ok"}function we(t,n,{headsUp:s=.8,minN:r=10}={}){let c=Object.fromEntries(Object.keys(n).map(i=>[i,0])),l={},g=Math.max(0,...Object.keys(n).map(i=>(t[i]||[]).length));for(let i=0;i<g;i++)for(let[d,o]of Object.entries(n)){let f=(t[d]||[])[i];if(!f)continue;let[,x,k,ae]=f,S=l[d]||{},A=S.verdict||"ok",m=Je(x,k??1/0,o,r,s,ae);m==="heads_up"&&S.open&&x!==null&&x!==void 0&&x>o&&(m="miss");let y=S.open||!1;(m==="heads_up"||m==="miss")&&Ee.indexOf(m)>Ee.indexOf(A)?(c[d]++,y=y||m==="miss"):m==="ok"&&S.open&&(c[d]++,y=!1),l[d]={verdict:m==="not enough data"?A:m,open:y}}return c}var te=H({}),be=H(null),F=H({}),Ke=document.querySelector('script[type="module"][src]')?.src||location.href,Ne=!1;function Ve(){Ne||(Ne=!0,fetch(new URL("settings-workflow.json",Ke).href).then(t=>t.ok?t.json():[],()=>[]).then(t=>be.set(t),()=>be.set([])))}var Xe=t=>({key:"wf:"+t.name,kind:t.secret?"secret":t.kind,default:t.default,help:t.help,module:"workflow",...t.choices?{choices:t.choices}:{}}),Qe=new Set(["list","choices"]),P=(t,n)=>n??(/text|regex|date/.test(t.kind)?"":/int|number|hours|share/.test(t.kind)?0:Qe.has(t.kind)?[]:n),Ye=new Set(["list","choices","dates","map","teams","regex","services","rules"]),Te=["pickup_p75_hours","review_p75_hours","cycle_p75_hours","change_failure_rate"],ne=t=>t==="ci"?"CI":t.charAt(0).toUpperCase()+t.slice(1);function Ze({d:t,v:n,set:s,wf:r}){let c=`l-${t.key}`,l=B(t.key),g=t.key.startsWith("wf:");switch(t.kind){case"bool":return e(ue,{checked:g?n==="true":!!n,onChange:i=>s(g?String(i):i),labelledBy:c});case"switch":{let i=t.key.split(".").pop().replace(/_/g,"-");return e(ue,{checked:n==null?(r?.[i]??"")==="true":!!n,onChange:s,labelledBy:c})}case"int":case"number":case"hours":case"share":{let i=t.kind==="share",d=g?Number(n)||0:Number(n??0);return e(_e,{label:l,value:i?Math.round(d*1e3)/10:d,min:0,max:i?100:t.key==="digest.hour"?23:t.key.endsWith("min_scorecard")?10:1/0,step:t.kind==="number"?.5:1,unit:i?"%":t.unit==="UTC"?"UTC":t.unit||(t.kind==="hours"?"h":""),onChange:o=>s(g?String(o):i?Number((o/100).toFixed(6)):o)})}case"choice":{let i=(t.choices||[]).map(d=>({value:d,label:ne(d)}));return i.length<=4&&i.every(d=>d.label.length<=10)?e($e,{size:"sm",label:l,value:String(n??""),onChange:s,options:i}):e(X,{label:l,value:String(n??""),onChange:s,options:i})}case"choices":{let i=g?String(n??"").split(",").map(d=>d.trim()).filter(Boolean):n||[];return e("div",{class:"chipset",role:"group","aria-labelledby":c,children:(t.choices||[]).map(d=>{let o=i.includes(d),f=(t.choices||[]).filter(x=>x===d?!o:i.includes(x));return e("button",{type:"button",class:"chip-t press","aria-pressed":o,onClick:()=>s(g?f.join(","):f),children:[o?e(w,{name:"check"}):null,ne(d)]})})})}case"list":return e(he,{label:l,values:n||[],onChange:s,placeholder:"Add, then Enter"});case"date":return e("span",{class:"date-ctl",children:[e(fe,{value:String(n||""),onInput:s}),n?e("button",{type:"button",class:"link-btn",onClick:()=>s(""),children:"Clear"}):null]});case"dates":case"map":case"teams":return e(et,{d:t,v:n||{},set:s});case"rules":{let i=n||[];return e("div",{class:"pairs",children:i.length?i.map(d=>e("div",{class:"pair",children:[e("span",{class:"pair-k",children:d.name}),e("span",{class:"pair-v mono-soft",children:d.dry_run?"dry run: reports only":"acts on matching pull requests"})]})):e("span",{class:"muted small",children:"None yet: add [[rules]] with a name, when and then in the settings file."})})}case"services":{let i=Object.entries(n||{});return e("div",{class:"pairs",children:i.length?i.map(([d,o])=>e("div",{class:"pair",children:[e("span",{class:"pair-k",children:d}),e("span",{class:"pair-v mono-soft",children:[(o.paths||[]).join(", "),o.deploy?` \xB7 deploys ${o.deploy}`:""]})]})):e("span",{class:"muted small",children:"None yet: add [services.<name>] with paths (and deploy) in the settings file."})})}case"secret":return e("code",{class:"code-inline",children:`${t.key.slice(3)}: \${{ secrets.\u2026 }}`});default:return t.key==="deps.policy.max_severity"?e(X,{label:l,value:String(n??""),onChange:i=>s(i||null),options:["","low","moderate","high","critical"].map(i=>({value:i,label:i?ne(i):"Off"}))}):e(V,{label:l,value:String(n??""),onInput:s,mono:t.kind==="regex"||g,placeholder:t.kind==="regex"?"(?i)(deploy|release)":"Not set"})}}function et({d:t,v:n,set:s}){let[r,c]=C(t.key==="investment.labels"?"feature":""),[l,g]=C(""),i=t.kind==="teams",d=()=>{!r.trim()||!l.trim()||(s({...n,[r.trim()]:i?l.split(",").map(f=>f.trim()).filter(Boolean):l.trim()}),c(t.key==="investment.labels"?"feature":""),g(""))},o=t.kind==="dates"?["Test id or pattern","Muted until"]:t.kind==="map"?["Old login","Current login"]:t.key==="investment.labels"?["Kind of work","Labels, comma separated"]:["Team name","Logins, comma separated"];return e("div",{class:"pairs",children:[Object.entries(n).map(([f,x])=>e("div",{class:"pair",children:[e("span",{class:"pair-k",children:f}),i?e(he,{label:`${f} members`,values:x||[],onChange:k=>s({...n,[f]:k})}):e("span",{class:"pair-v",children:t.kind==="dates"?`until ${x}`:`now ${x}`}),e("button",{type:"button",class:"pair-x press","aria-label":`Remove ${f}`,onClick:()=>{let k={...n};delete k[f],s(k)},children:e(w,{name:"x"})})]})),e("div",{class:"pair-add",children:[t.key==="investment.labels"?e(X,{label:o[0],value:r,onChange:c,options:["feature","fix","maintenance","security","docs"].map(f=>({value:f,label:ne(f)}))}):e(V,{label:o[0],value:r,onInput:c,placeholder:o[0],mono:t.kind==="dates"}),t.kind==="dates"?e(fe,{value:l,onInput:g}):e(V,{label:o[1],value:l,onInput:g,placeholder:o[1]}),e(O,{size:"sm",icon:"plus",disabled:!r.trim()||!l.trim(),onClick:d,children:"Add"})]})]})}var ke=(t,n)=>t.key.startsWith("wf:")?n.wf?.[t.key.slice(3)]??t.default:T(n.values,t.key);function We({d:t,c:n}){let s=ke(t,n),r=n.pend[t.key],c=r===void 0?s:r===null?t.default:r,l=r!==void 0&&!Z(P(t,c),P(t,s)),g=!Z(P(t,s),P(t,t.default))&&!(t.kind==="switch"&&s==null),i=l?ve(t.key,t.kind,c):"",d=n.replays[t.key];return e("div",{class:"srow"+(Ye.has(t.kind)||t.kind==="text"&&t.key!=="deps.policy.max_severity"?" is-stack":"")+(l?" is-changed":""),id:`set-${t.key}`,children:[e("div",{class:"srow-text",children:[e("span",{class:"srow-label",id:`l-${t.key}`,children:[l?e("span",{class:"cdot","aria-label":"Changed"}):null,B(t.key)]}),e("span",{class:"srow-help",children:[je(t.help),t.kind==="switch"&&c==null?" Follows the workflow input now.":""]}),e("span",{class:"srow-meta",children:[t.kind!=="secret"&&t.kind!=="switch"&&W(t.default,t.kind,t.unit)!=="Not set"?e("span",{children:["Default ",W(t.default,t.kind,t.unit)]}):null,g&&!l?e(Se,{tone:"accent",icon:null,children:t.key.startsWith("wf:")?"Set in the workflow":"Changed in the file"}):null,l?e("button",{type:"button",class:"link-btn",onClick:()=>n.set(t.key,void 0),children:"Undo"}):g&&t.kind!=="secret"?e("button",{type:"button",class:"link-btn",onClick:()=>n.set(t.key,null),children:"Use default"}):null]}),i?e("span",{class:"field-error",role:"alert",children:[e(w,{name:"warn"}),i]}):null,d&&l?e("span",{class:"replay",children:[e(w,{name:"refresh"}),d[2]?c===0?"Turns this alert off.":`Over the last 90 days it would have alerted ${d[1]} time${d[1]===1?"":"s"} (now ${d[0]}).`:"Not enough data to replay the last 90 days."]}):null]}),e("div",{class:"srow-ctl",children:e(Ze,{d:t,v:c,set:o=>n.set(t.key,o),wf:n.wf})}),e("button",{type:"button",class:"info-btn press","aria-label":`About ${B(t.key)}`,onClick:()=>n.info(t),children:e(w,{name:"info"})})]})}function tt({defs:t,c:n}){let s=[],r=null,c=[],l=()=>{c.length&&s.push(e("div",{class:"sgroup",children:[r?e("h3",{class:"sgroup-h",children:r}):null,e("div",{class:"sform card",children:c})]})),c=[]};for(let g of t){let i=g.kind==="secret"?"Secrets (set in the repo's secrets, named here)":g.key.startsWith("wf:")?"Inputs":Oe(g.key);i!==r&&(l(),r=i),c.push(e(We,{d:g,c:n}))}return l(),e(_,{children:s})}function nt({p:t,app:n,done:s}){let r=Object.keys(t.settings).length,c=`${r} change${r===1?"":"s"}`,l=()=>{Be(n.repo,null),ge()};if(s)return e("div",{class:"note note-good set-status",role:"status",children:[e(w,{name:"check"}),e("span",{children:[e("b",{children:"Applied."})," The last run shows your ",c,"."]}),e("button",{type:"button",class:"link-btn",onClick:l,children:"Dismiss"})]});let g={issue:"sent as a GitHub issue; the workflow applies it once the issue is submitted",copy:"copied as TOML; paste it into the file and commit",committed:"committed; the next run publishes it",pr:"waiting in a pull request; it applies once merged",compare:"on a branch; open the pull request to apply it",dispatch:t.run?`applying in run #${t.run.run_number}`:"sent to the workflow"}[t.via];return e("div",{class:"note note-accent set-status",role:"status",children:[e("span",{class:"spin","aria-hidden":"true"}),e("span",{children:[e("b",{children:"Pending:"})," ",c," ",g,".",t.url?e(_,{children:[" ",e("a",{href:t.url,target:"_blank",rel:"noopener noreferrer",children:"Open"})]}):null]}),e("button",{type:"button",class:"link-btn",onClick:ge,children:"Check again"}),e("button",{type:"button",class:"link-btn",onClick:l,children:"Forget"})]})}function at({app:t}){let n=I(pe),[s,r]=C(null);return N(()=>{import("../chunks/connect-KONYWYTT.js").then(r,()=>{})},[]),s?e("div",{class:"sgroup",children:[e("p",{class:"sgroup-note",children:n?"Saving commits straight to the repo with this account (a pull request when the branch is protected).":"Optional. Without GitHub, changes go as a prefilled issue the workflow applies. Connected, Save commits in one click."}),e("div",{class:"card card-pad",children:n?e(s.AccountBar,{}):e(s.ConnectPanel,{app:t})})]}):e(J,{lines:2})}function st({app:t,route:n}){let s=Re({s:"settings.json",alerts:"alerts.json"}),r=I(ze),c=I(te),l=I(be),g=I(F);I(pe);let[i,d]=C(n.query.get("q")||""),[o,f]=C(null),[x,k]=C(null),[ae,S]=C(!1),A=n.rest[0]||n.query.get("module")||"",m=A||"alerts",y=c[r.id]||{},L=g[r.id]??null;N(Ve,[]),N(()=>{!t||ce||r.id in F.get()||(F.set(a=>({...a,[r.id]:null})),import("../chunks/settingsApply-2HRJEZYM.js").then(a=>a.workflowNow(t)).then(a=>F.set(p=>({...p,[r.id]:a})),()=>{}))},[r.id,!!t]);let se=n.query.get("key");N(()=>{let a=se&&document.getElementById(`set-${se}`);a&&(a.scrollIntoView({block:"center",behavior:"smooth"}),a.classList.add("is-flash"))},[se,s.ready]);let M=le(()=>[...s.s?.settings||[],...(l||[]).map(Xe)],[s.s,l]),z=s.s?.values,Fe={values:z,pend:y,wf:L},R={},E=0;for(let a of M){let p=y[a.key];if(p===void 0)continue;let u=ke(a,Fe),h=p===null?a.default:p;Z(P(a,h),P(a,u))||(R[a.key]=p,ve(a.key,a.kind,h)&&E++)}let q=Object.keys(R).length,ye=le(()=>{let a={},p=s.alerts;if(!p?.series)return a;let u={headsUp:p.heads_up??.8,minN:p.min_n??10},h=v=>Object.fromEntries(Te.map(b=>[b,Number(v(`alerts.${b}`))||0]).filter(([,b])=>b)),j=we(p.series,h(v=>T(z,v)),u),G=we(p.series,h(v=>v in R?R[v]??T(s.s?.settings?.find(b=>b.key===v),"default"):T(z,v)),u);for(let v of Te)p.series[v]&&(a[`alerts.${v}`]=[j[v]??0,G[v]??0,p.series[v].some(b=>b[1]!=null&&(b[2]??0)>=u.minN)]);return a},[s.alerts,z,JSON.stringify(R)]);if(!s.ready)return e(K,{title:"Settings",children:e(J,{lines:6})});if(!t||!s.s?.settings)return e(K,{title:"Settings",children:e(de,{icon:"settings",title:"Settings appear after the next run.",children:"The workflow publishes every setting with its default and the value in force."})});let ie={values:z,pend:y,set:(a,p)=>te.set(u=>{let h={...u[r.id]||{}};return p===void 0?delete h[a]:h[a]=p,{...u,[r.id]:h}}),info:f,wf:L,replays:ye},U=De(t.repo),Le=!!U&&Pe(U,s.s.settings,z),$=i.trim().toLowerCase(),re=$?M.filter(a=>`${B(a.key)} ${a.key} ${a.help}`.toLowerCase().includes($)):[],oe=a=>M.filter(p=>(p.key.startsWith("wf:")?"workflow":Y(p))===a).sort((p,u)=>+(p.kind==="secret")-+(u.kind==="secret")),Me=a=>oe(a).filter(p=>p.key in R).length,qe=Q.find(a=>a[0]===m)?.[1]||"Settings",Ue=()=>{import("../chunks/settingsReview-GX2FZQ4M.js").then(a=>{k(a),S(!0)})},Ge=a=>a==="appearance"?e("div",{class:"sgroup",children:e("div",{class:"sform card card-pad",children:e(Ie,{})})}):a==="account"?e(at,{app:t}):e(_,{children:[a==="workflow"?e("p",{class:"sgroup-note",children:["Inputs of the StackVitals step in ",e("code",{children:[".github/workflows/",t.links?.workflow||"stackvitals.yml"]}),L?"":ce?"; the demo shows the defaults":"; showing defaults until the file can be read",". A setting in the file wins over its input. Modules running now: ",Object.keys(t.modules||{}).join(", ")||"none yet","."]}):null,oe(a).length?e(tt,{defs:oe(a),c:ie}):e(J,{lines:3})]});return e(K,{title:"Settings",subtitle:e(_,{children:["Kept in ",e("a",{href:t.links?.settings_file,target:"_blank",rel:"noopener noreferrer",children:e("code",{children:s.s.file||".github/stackvitals.toml"})})," on ",t.default_branch||"main",". Change them here, review, save once."]}),toolbar:t.links?.edit_settings?e(O,{variant:"plain",icon:"external",href:t.links.edit_settings,external:!0,children:"Edit on GitHub"}):null,children:[U?e(nt,{p:U,app:t,done:Le}):null,s.s.notes?.length?e("div",{class:"note note-watch",children:[e(w,{name:"warn"}),e("span",{children:[e("b",{children:"The last run couldn't use part of the file:"})," ",s.s.notes.join(" ")]})]}):null,e("div",{class:"set-layout"+(A||$?" has-group":""),children:[e("nav",{class:"set-nav","aria-label":"Settings groups",children:[e("label",{class:"search-field set-search",children:[e(w,{name:"search"}),e("input",{class:"input",type:"search",placeholder:"Search settings","aria-label":"Search settings",value:i,onInput:a=>d(a.currentTarget.value)})]}),e("ul",{class:"set-nav-list card",children:Q.map(([a,p,u])=>{let h=Me(a);return e("li",{children:e("a",{class:"set-nav-item press",href:me("settings",a),"aria-current":!$&&a===m?"page":void 0,children:[e("span",{class:"set-ic","data-g":a,children:e(w,{name:u})}),e("span",{class:"set-nav-t",children:p}),h?e("span",{class:"badge badge-accent num","aria-label":`${h} changed`,children:h}):null,e(w,{name:"right",class:"set-chev"})]})})})})]}),e("section",{class:"set-main","aria-labelledby":"set-h",children:[e("a",{class:"set-back press",href:me("settings"),onClick:()=>d(""),children:[e(w,{name:"left"}),"Settings"]}),e("div",{class:"set-head",children:[e("h2",{id:"set-h",class:"set-title",children:$?`Results for "${i.trim()}"`:qe}),$?null:e("a",{class:"link-btn",href:ee(xe[m]||"settings",xe[m]?"":`[${m==="people"?"identity":m}]`),children:"Learn more"})]}),$?re.length?Q.filter(([a])=>re.some(p=>(p.key.startsWith("wf:")?"workflow":Y(p))===a)).map(([a,p])=>e("div",{class:"sgroup",children:[e("h3",{class:"sgroup-h",children:p}),e("div",{class:"sform card",children:re.filter(u=>(u.key.startsWith("wf:")?"workflow":Y(u))===a).map(u=>e(We,{d:u,c:ie}))})]})):e(de,{icon:"search",title:`No setting matches "${i.trim()}"`,children:"Try a word like review, flaky, digest or Jira."}):Ge(m)]})]}),e("div",{class:"savebar"+(q?" is-on":""),role:"region","aria-label":"Unsaved changes","aria-hidden":!q,children:[e("span",{class:"cdot","aria-hidden":"true"}),e("b",{children:[q," change",q===1?"":"s"]}),e(O,{size:"sm",variant:"plain",onClick:()=>te.set(a=>({...a,[r.id]:{}})),children:"Discard"}),e(O,{size:"sm",variant:"filled",disabled:!!E,onClick:Ue,children:E?`Fix ${E} field${E===1?"":"s"}`:"Review"})]}),e(Ce,{open:!!o,onClose:()=>f(null),title:o?B(o.key):"",size:"sm",footer:o?e(_,{children:[e(O,{variant:"plain",href:o.key.startsWith("wf:")?ee("install"):ee("settings",`[${o.kind==="dates"?o.key:o.key.slice(0,o.key.lastIndexOf("."))}]`),onClick:()=>f(null),children:"Learn more"}),e(O,{variant:"filled",onClick:()=>f(null),children:"Done"})]}):null,children:o?e(_,{children:[e("p",{class:"info-body",children:o.help}),e("dl",{class:"facts",children:[e("div",{class:"fact",children:[e("dt",{children:"Default"}),e("dd",{children:W(o.default,o.kind,o.unit)})]}),e("div",{class:"fact",children:[e("dt",{children:"Now"}),e("dd",{children:W(ke(o,ie),o.kind,o.unit)})]}),e("div",{class:"fact fact-wide",children:[e("dt",{children:o.key.startsWith("wf:")?"Workflow input":"In the settings file"}),e("dd",{class:"mono",children:o.key.replace(/^wf:/,"")})]})]})]}):null}),x?e(x.ReviewSheet,{open:ae,onClose:()=>S(!1),app:t,defs:M,changes:R,values:z,wf:L,replays:ye,onSent:(a,p)=>{te.set(u=>{let h={...u[r.id]||{}};for(let j of a)delete h[j];return{...u,[r.id]:h}}),p&&F.set(u=>{let h={...u[r.id]||{}};for(let[j,G]of Object.entries(p))G===null?delete h[j]:h[j]=G;return{...u,[r.id]:h}})}}):null]})}export{st as default};
@@ -0,0 +1 @@
1
+ [data-design=sheet][data-page=setup] .card{border:1.5px solid var(--frame)}[data-design=sheet][data-page=setup] .setup-steps{counter-reset:svst;gap:0}[data-design=sheet][data-page=setup] .setup-step{counter-increment:svst;gap:14px;padding:14px 0}[data-design=sheet][data-page=setup] .setup-step+.setup-step{border-top:1px solid var(--line)}[data-design=sheet][data-page=setup] .setup-step:first-child{padding-top:2px}[data-design=sheet][data-page=setup] .setup-step:last-child{padding-bottom:2px}[data-design=sheet][data-page=setup] .setup-mark{width:30px;height:30px;border:1.5px solid var(--ink-2);border-radius:50%!important;background:var(--surface);color:var(--ink)}[data-design=sheet][data-page=setup] .setup-mark>*{display:none}[data-design=sheet][data-page=setup] .setup-mark:before{content:counter(svst);font:700 15px/1 var(--font);font-variant-numeric:tabular-nums}[data-design=sheet][data-page=setup] .setup-step.is-running .setup-mark{border-color:var(--sv-blue);color:var(--accent);background:var(--accent-soft);animation:svStepNow 1.2s var(--sv-ease) infinite alternate}@keyframes svStepNow{to{border-color:var(--line-strong)}}[data-design=sheet][data-page=setup] .setup-step.is-done .setup-mark{border-color:#000;background:var(--sv-mint);color:#000}[data-design=sheet][data-page=setup] .setup-step.is-failed .setup-mark{border-color:var(--sv-coral);background:var(--bad-soft);color:var(--bad)}[data-design=sheet][data-page=setup] .setup-step.is-waiting .setup-mark{border-color:var(--sv-amber);background:var(--watch-soft);color:var(--watch)}[data-design=sheet][data-page=setup] .setup-step:is(.is-pending,.is-skipped) .setup-mark{color:var(--ink-2);border-color:var(--line-strong)}[data-design=sheet][data-page=setup] .setup-step.is-skipped .setup-mark{border-style:dashed}[data-design=sheet][data-page=setup] .setup-body{padding-top:3px;gap:6px}[data-design=sheet][data-page=setup] .setup-body>b{font-weight:700;font-size:16.5px}[data-design=sheet][data-page=setup] .setup-step:is(.is-pending,.is-skipped) .setup-body>b{color:var(--ink-2);font-weight:600}[data-design=sheet][data-page=setup] .setup-step:is(.is-running,.is-done,.is-failed,.is-waiting,.is-skipped) .setup-body>b:after{display:inline-block;margin-left:12px;padding-left:19px;font:700 14.5px/1.5 var(--font);vertical-align:0;background:left center / 13px 13px no-repeat}[data-design=sheet][data-page=setup] .setup-step.is-running .setup-body>b:after{content:"running";content:"running" / "";color:var(--accent);background-image:none;padding-left:0}[data-design=sheet][data-page=setup] .setup-step.is-done .setup-body>b:after{content:"done";content:"done" / "";color:var(--good);background-image:var(--mark-good)}[data-design=sheet][data-page=setup] .setup-step.is-failed .setup-body>b:after{content:"failed";content:"failed" / "";color:var(--bad);background-image:var(--mark-bad)}[data-design=sheet][data-page=setup] .setup-step.is-waiting .setup-body>b:after{content:"waiting";content:"waiting" / "";color:var(--watch);background-image:var(--mark-watch)}[data-design=sheet][data-page=setup] .setup-step.is-skipped .setup-body>b:after{content:"skipped";content:"skipped" / "";color:var(--ink-2);padding-left:0}[data-design=sheet][data-page=setup] .setup-body p{font-size:15px;color:var(--ink-2)}[data-design=sheet][data-page=setup] .setup-fix{padding:8px 12px;background:var(--accent-soft);border-left:4px solid var(--sv-blue)}[data-design=sheet][data-page=setup] .setup-fix .ic{display:none}[data-design=sheet][data-page=setup] .setup-site,[data-design=sheet][data-page=setup] .jobs{font-size:15px}[data-design=sheet][data-page=setup] .jobs>li b{font-weight:600}[data-design=sheet][data-page=setup] .job-state{font-size:14px;color:var(--ink-2)}[data-design=sheet][data-page=setup] .job-dot{width:10px;height:10px;background:none;border:1.5px solid var(--ink-2)}[data-design=sheet][data-page=setup] .job-dot.is-in_progress{background:var(--sv-blue);border-color:var(--sv-blue)}[data-design=sheet][data-page=setup] .job-dot.is-success{width:13px;height:13px;border:0;background:var(--mark-good) center / contain no-repeat}[data-design=sheet][data-page=setup] .job-dot.is-failure{width:13px;height:13px;border:0;background:var(--mark-bad) center / contain no-repeat}[data-design=sheet][data-page=setup] .job-steps{border-left:1.5px solid var(--line-strong);padding-left:14px;margin-left:4px;font-size:14px}[data-design=sheet][data-page=setup] .job-steps .is-success .ic{color:var(--good)}[data-design=sheet][data-page=setup] .plan{padding:0}[data-design=sheet][data-page=setup] .plan-row{padding:14px 18px}[data-design=sheet][data-page=setup] .plan-text b{font-weight:700;font-size:16.5px}[data-design=sheet][data-page=setup] .plan-text small{font-size:15px}[data-design=sheet][data-page=setup] .wf-chip{padding:4px 11px;font-size:14px;font-weight:600;background:var(--surface);border:1.5px solid var(--line-strong);color:var(--ink)}[data-design=sheet][data-page=setup] .wf-chip:hover{border-color:var(--ink)}[data-design=sheet][data-page=setup] .wf-chip[aria-pressed=true]{background:var(--accent-soft);border-color:var(--sv-blue);color:var(--ink);font-weight:600}[data-design=sheet][data-page=setup] .wf-chip[aria-pressed=true] .ic{color:var(--accent)}[data-design=sheet][data-page=setup] .adv-row{font-size:15px}[data-design=sheet][data-page=setup] .yaml-peek summary{font-weight:600;font-size:15px;color:var(--accent)}[data-design=sheet][data-page=setup] .go-or{font-size:15px}[data-design=sheet][data-page=setup] .cmd-note{font-size:14px}[data-design=sheet][data-page=setup] .go-list{gap:0;counter-reset:go;font-size:15.5px}[data-design=sheet][data-page=setup] .go-list li{counter-increment:go;padding:9px 0;gap:12px;align-items:baseline}[data-design=sheet][data-page=setup] .go-list li+li{border-top:1px solid var(--line)}[data-design=sheet][data-page=setup] .go-list .ic{display:none}[data-design=sheet][data-page=setup] .go-list li:before{content:counter(go);font:700 15px var(--font);font-variant-numeric:tabular-nums;color:var(--ink-2);flex:none;width:18px;text-align:right}@media(prefers-reduced-motion:reduce){[data-design=sheet][data-page=setup] .setup-step.is-running .setup-mark{animation:none}}
@@ -0,0 +1,2 @@
1
+ import{a as Te,b as He,c as Oe,f as H,g as We}from"../chunks/chunk-RQZPSJ2Y.js";import{a as Me,f as De,g as se,h as ne}from"../chunks/chunk-3IXWEOIJ.js";import"../chunks/chunk-7TJCBOAY.js";import{a as Pe,b as $e,c as te,d as Re,e as _e,g as Be,h as Ae,i as Ie,j as ae,k as Le}from"../chunks/chunk-PABICGBL.js";import{b as S,c as j,e as q,f as xe,g as Se,h as Ce}from"../chunks/chunk-GQYFN4PE.js";import{b as ve,d as ke,e as we}from"../chunks/chunk-ASYNLVOP.js";import{c as be}from"../chunks/chunk-763NH7PP.js";import"../chunks/chunk-6BDBXA6V.js";import"../chunks/chunk-MAPYGK3P.js";import{e as he}from"../chunks/chunk-T7QVTNXF.js";import{a as N,e as ye}from"../chunks/chunk-RPXHAG6F.js";import{f as me}from"../chunks/chunk-4WKQTWUC.js";import{a as W,c as de,k as X,s as fe}from"../chunks/chunk-VQ5YXO54.js";import{b as Z,c as P,e as $}from"../chunks/chunk-76WAVKUG.js";import{a as E,b as G,c as ee}from"../chunks/chunk-VWKSMFWJ.js";import{G as ce,N as ue,O as J,P as ge,Q,S as z,a as B,c as v,d as T,g as K,i as Y,w as e,x as h,z as w}from"../chunks/chunk-GT4EAKAO.js";import{d as A}from"../chunks/chunk-G7NGB5UX.js";A();A();var Qe=/^(package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|uv\.lock|Pipfile\.lock|pdm\.lock|requirements[\w.-]*\.txt|pylock[\w.-]*\.toml|Cargo\.lock|go\.mod|go\.sum|Gemfile\.lock|gems\.locked|composer\.lock|pom\.xml|gradle\.lockfile|Package\.resolved|mix\.lock|pubspec\.lock|packages\.lock\.json)$/;async function ze(t,s){let i=de(s),n=await t.get(`/repos/${i}`);if(!n)return null;let a=n.default_branch||"main",[c,o,p,g,d]=await Promise.all([t.get(`/repos/${i}/actions/workflows?per_page=100`).catch(()=>null),t.get(`/repos/${i}/deployments?per_page=1`).catch(()=>null),t.get(`/repos/${i}/releases?per_page=1`).catch(()=>null),t.get(`/repos/${i}/contents/?ref=${encodeURIComponent(a)}`).catch(()=>null),t.call("GET",`/repos/${i}/branches/stackvitals-data`).then(u=>u.ok,()=>!1)]),r=c?.workflows||[],k=r.some(u=>u.path===S),[R,I]=await Promise.all([n.has_pages?t.get(`/repos/${i}/pages`).catch(()=>null):null,k?t.get(`/repos/${i}/contents/${S}?ref=${encodeURIComponent(a)}`).catch(()=>null):null]),L=r.filter(u=>u.path!==S&&!String(u.path).startsWith("dynamic/")),C=L.filter(u=>u.state==="active").map(u=>String(u.name)),y=L.filter(u=>u.state!=="active").map(u=>String(u.name));return{repo:n.full_name||s,private:!!n.private,branch:a,hasPages:!!n.has_pages,canPush:n.permissions?!!(n.permissions.push||n.permissions.admin):null,workflows:C,off:y,ciNames:Se(C),installed:k,dataBranch:!!d,deployments:!!o?.length,releases:!!p?.length,pages:n.has_pages?R?Re(R):{ours:!1,says:"another source"}:null,existing:I?.content?ye(I.content):null,lockfiles:Array.isArray(g)?g.filter(u=>u.type==="file"&&Qe.test(u.name)).map(u=>String(u.name)):[]}}function Ee(t){let s=["ci","flow"];return t.lockfiles.length&&s.push("deps"),t.private||s.push("community"),{modules:s,names:t.ciNames,days:90,budget:800,pages:t.private?"local":"public",everyCiRun:!1,pagesSwitch:!1,replace:!1}}A();function Ge(t,s){let i=t.split(/\r?\n/),n=s.split(/\r?\n/);if(i.length*n.length>4e6)return[...i.map(r=>({op:"-",text:r})),...n.map(r=>({op:"+",text:r}))];let a=i.length,c=n.length,o=Array.from({length:a+1},()=>new Uint32Array(c+1));for(let r=a-1;r>=0;r--)for(let k=c-1;k>=0;k--)o[r][k]=i[r]===n[k]?o[r+1][k+1]+1:Math.max(o[r+1][k],o[r][k+1]);let p=[],g=0,d=0;for(;g<a&&d<c;)i[g]===n[d]?(p.push({op:" ",text:i[g]}),g++,d++):o[g+1][d]>=o[g][d+1]?p.push({op:"-",text:i[g++]}):p.push({op:"+",text:n[d++]});for(;g<a;)p.push({op:"-",text:i[g++]});for(;d<c;)p.push({op:"+",text:n[d++]});return p}function Ne(t,s=2){let i=t.map((a,c)=>a.op!==" "||t.slice(Math.max(0,c-s),c+s+1).some(o=>o.op!==" ")),n=[];return t.forEach((a,c)=>{i[c]?n.push(`${a.op} ${a.text}`):(c===0||i[c-1])&&n.push(" \u2026")}),n.join(`
2
+ `)}A();var je=75e3,ie=15*6e4;async function qe(t,s,i=null){let n={...i?.exists?i:{exists:!1}},a=null;if(!n.exists){if(a=await t.get(`/repos/${s}`),!a)return{exists:!1};Object.assign(n,{exists:!0,public:!a.private,branch:a.default_branch||"main"})}if(!n.installed){let c=(await t.get(`/repos/${s}/actions/workflows?per_page=100`))?.workflows||[];if(n.installed=c.some(o=>o.path===S),!n.installed)return n}return!n.dataBranch&&(n.run=(await t.get(`/repos/${s}/actions/workflows/stackvitals.yml/runs?per_page=1`))?.workflow_runs?.[0]||null,n.dataBranch=n.run?.status==="completed"&&!!await t.get(`/repos/${s}/branches/stackvitals-data`),!n.dataBranch)||n.site||(n.site=!!(a||await t.get(`/repos/${s}`))?.has_pages),n}function Fe(t){let s=[!!t?.installed,!!t?.run,!!t?.dataBranch,!!t?.site],i=s.indexOf(!1);return["Workflow file committed","First run started","Data branch written","Web page on"].map((n,a)=>({title:n,state:s[a]?"done":a===i?"now":"later"}))}var Xe={ci:"CI health",flow:"Pull requests and delivery",deps:"Dependencies",community:"Community"},F=new Map,re=new Set,le=Math.random().toString(36).slice(2);function Ze(t){let s=fe.get().source,i=s.kind==="branch"?`${s.owner}/${s.repo}`:t?.repo||null;return i&&W(i)?i:null}function et({app:t,route:s}){let i=s.query.has("pick"),n=s.query.get("repo"),a=n?W(n)?n:null:i?null:Ze(t);return a&&t?.repo?.toLowerCase()===a.toLowerCase()&&me(t)&&!s.query.has("check")?e(at,{app:t}):a?e(it,{repo:a,app:t},a.toLowerCase()):e(tt,{app:t,bad:n&&!W(n)?n:null})}function tt({app:t,bad:s}){let i=Y(X),[n,a]=v(""),c=o=>{o.preventDefault();let p=Oe(n);p?be(`#/setup?repo=${encodeURIComponent(p)}`):z("Type it as owner/repo","bad")};return e(Z,{title:"Set up StackVitals",subtitle:"Pick a repo: StackVitals checks what it has and suggests a plan you can change.",children:[s?e("div",{class:"note note-bad",role:"alert",children:[e(h,{name:"warn"}),e("span",{children:["\u201C",s.slice(0,80),"\u201D isn't a repo name (owner/name), so nothing was opened."]})]}):null,i?e(P,{title:"Your repos",action:e(se,{compact:!0}),children:[e(De,{}),e(He,{onPick:(o,p)=>p==="data"?H(o.full_name,o.private):We(o.full_name,o.private)})]}):e(P,{title:"Connect GitHub",description:"To list your repos and set one up in one click.",children:e($,{children:e(ne,{app:t})})}),e(P,{title:"Or type a repo",children:e("form",{class:"byname-row",onSubmit:c,children:[e("input",{class:"input mono","aria-label":"Repository, as owner/repo",placeholder:"owner/repo",value:n,onInput:o=>a(o.currentTarget.value)}),e(w,{type:"submit",variant:"tinted",children:"Continue"})]})})]})}function at({app:t}){let[s,i]=v(null);return T(()=>{import("../chunks/SetupRunning-XWFQAKRZ.js").then(i)},[]),s?e(s.Running,{app:t}):e(Q,{lines:6})}var st={pending:"dot",running:"dot",done:"check",failed:"warn",skipped:"off",waiting:"clock"};function nt({run:t}){return e("ol",{class:"setup-steps","aria-label":"Setup steps",children:t.steps.map(s=>e("li",{class:`setup-step is-${s.status}`,"aria-current":s.status==="running"?"step":void 0,children:[e("span",{class:"setup-mark",children:s.status==="running"?e("span",{class:"spin","aria-label":"Running"}):e(h,{name:st[s.status]})}),e("div",{class:"setup-body",children:[e("b",{children:Pe[s.id]}),e("span",{class:"sr",children:[" (",s.status,")"]}),s.note?e("p",{children:[s.note,s.link?e(B,{children:[" ",e("a",{href:s.link,target:"_blank",rel:"noopener noreferrer",children:"Open on GitHub"})]}):null]}):null,s.fix?e("p",{class:"setup-fix",children:[e(h,{name:"about"}),e("span",{children:s.fix})]}):null,s.fixLink?e(w,{size:"sm",variant:"tinted",href:s.fixLink,external:!0,iconEnd:"external",children:s.fixLink.includes("personal-access-tokens")?"Make a new token":"Open on GitHub"}):null,s.id==="run"&&t.jobs?.length?e("ul",{class:"jobs",children:t.jobs.map(i=>e("li",{children:[e("span",{class:`job-dot is-${i.conclusion||i.status}`,"aria-hidden":"true"}),e("b",{children:i.name}),e("span",{class:"job-state",children:i.conclusion||i.status.replace("_"," ")}),i.status!=="completed"?e("ul",{class:"job-steps",children:i.steps.filter(n=>n.status!=="queued"||i.steps.indexOf(n)<3).map(n=>e("li",{class:`is-${n.conclusion||n.status}`,children:[n.status==="in_progress"?e("span",{class:"spin","aria-hidden":"true"}):e(h,{name:n.conclusion==="success"?"check":n.conclusion==="failure"?"warn":"dot"}),n.name]}))}):null]}))}):null]})]}))})}function ot(t,s,i){let[n,a]=v(void 0),[c,o]=v(null);return T(()=>{let p=!0,g=`${s}|${i}`;return F.has(g)||F.set(g,ze(t,s)),F.get(g).then(d=>p&&a(d),d=>{F.delete(g),p&&o(d instanceof Error?d.message:"The check failed.")}),()=>{p=!1}},[s,i]),{det:n,err:c}}function it({repo:t,app:s}){let i=Y(X),n=K(()=>N(i?.token),[i?.token]),{det:a,err:c}=ot(n,t,!!i),[o,p]=v(null),[g,d]=v(!1),[r,k]=v(()=>Ae(t)),[R,I]=v(!1),[L,C]=v(!1);T(()=>{a&&p(Ee(a))},[a]);let y=l=>o?xe(q(o.names,{compact:l,modules:o.modules}),{days:o.days,budget:o.budget,...o.pages==="artifact"?{pages:"artifact"}:{}}):"",u=async l=>{if(!i||re.has(t))return;if(!ae(t,le)){z("Setup for this repo is running in another tab.","neutral");return}re.add(t),I(!0);let f=l;try{let _=await he({app:s});_&&(f=await _e(l,k,{api:N(_.token),save:Je=>{Ie(Je),ae(t,le)},tokenPage:Me()}))}finally{re.delete(t),Le(t,le),I(!1)}f.finished&&f.steps.find(_=>_.id==="data")?.status==="done"&&(Te(t,"data"),z(`StackVitals is set up in ${t}`),H(t,f.target.private))},x=a&&o&&a.existing!==null&&a.existing!==y(!1),m=K(()=>x?Ne(Ge(a.existing,y(!1))):"",[x,a?.existing,o]),[b,U]=v(!1),[M,pe]=v(!1),V=!!x&&b&&M,O=!!a?.pages&&!a.pages.ours&&!a.private&&o?.pages==="public",Ve=()=>a&&o&&u($e({repo:a.repo,branch:a.branch,private:a.private,yaml:y(!1),everyCiRun:a.private&&o.everyCiRun,pages:o.pages,replace:V,pagesSwitch:O&&o.pagesSwitch}));T(()=>{i&&r&&!r.finished&&r.steps.some(l=>l.status==="running")&&u(r)},[!!i]);let D=l=>p(f=>f&&{...f,...l}),Ke=(l,f)=>D({modules:j.filter(_=>_===l?f:o.modules.includes(_))}),Ye=r&&!r.finished&&!R&&r.steps.some(l=>l.status==="failed"||l.status==="waiting");return e(Z,{title:`Set up ${t}`,subtitle:"StackVitals checked the repo and ticked what fits. Change anything, then set it up.",toolbar:e(w,{variant:"plain",href:"#/setup?pick=1",icon:"left",children:"Another repo"}),children:[c?e(ge,{icon:"warn",title:"Couldn't check this repo.",children:c}):null,a===void 0&&!c?e(Q,{lines:6}):null,a===null?e("div",{class:"note note-watch",role:"status",children:[e(h,{name:"lock"}),e("span",{children:["GitHub doesn't show ",e("b",{children:t}),i?" to this token":" to visitors",": the name is off, or it's private.",i?" Make sure the token can reach it.":" Connect GitHub to set up a private repo in one click."]})]}):null,r?e(P,{title:"Progress",description:r.finished?"Done.":R?"Working; keep this tab open.":"Stopped. Fix what's marked, then continue.",action:Ye?e(w,{variant:"filled",onClick:()=>u(Be(r)),children:"Continue"}):r.finished?e(w,{variant:"filled",onClick:()=>H(t,r.target.private),children:"Open the dashboard"}):null,children:[e($,{children:e(nt,{run:r})}),r.siteUrl?e("p",{class:"setup-site",children:["Web page: ",e("a",{href:r.siteUrl,target:"_blank",rel:"noopener noreferrer",children:r.siteUrl.replace("https://","")})]}):null]}):null,a&&o&&!R?e(B,{children:[a.dataBranch&&!r?e("div",{class:"note note-good",children:[e(h,{name:"check"}),e("span",{children:[t," already runs StackVitals.",e("span",{class:"note-act",children:e(w,{size:"sm",variant:"filled",onClick:()=>H(t,a.private),children:"Open the dashboard"})})]})]}):null,a.off.length?e("div",{class:"note",role:"status",children:[e(h,{name:"warn"}),e("span",{children:["Turned off on GitHub: ",a.off.join(", "),". StackVitals reads a workflow's runs only while it's on (Actions tab, the workflow, Enable)."]})]}):null,a.canPush===!1?e("div",{class:"note note-bad",role:"alert",children:[e(h,{name:"warn"}),e("span",{children:["Your account can't push to ",t,". Ask someone with write access, or send them this page."]})]}):null,e(P,{title:"The plan",description:e(B,{children:[a.private?"Private":"Public"," repo, default branch ",e("code",{children:a.branch}),a.workflows.length?`, ${a.workflows.length} workflow${a.workflows.length===1?"":"s"} found`:", no workflows yet","."]}),children:[e($,{pad:!1,children:e("ul",{class:"plan",children:[j.map(l=>e("li",{class:"plan-row",children:[e("div",{class:"plan-text",children:[e("b",{id:`m-${l}`,children:Xe[l]}),e("small",{children:rt(l,a)}),l==="ci"&&o.modules.includes("ci")&&a.workflows.length?e("div",{class:"wf-chips",role:"group","aria-label":"CI workflows to read",children:a.workflows.map(f=>e("button",{type:"button",class:"wf-chip press","aria-pressed":o.names.includes(f),onClick:()=>D({names:o.names.includes(f)?o.names.filter(_=>_!==f):[...o.names,f]}),children:[o.names.includes(f)?e(h,{name:"check"}):null,f]}))}):null]}),e(G,{checked:o.modules.includes(l),labelledBy:`m-${l}`,disabled:o.modules.length===1&&o.modules.includes(l),onChange:f=>Ke(l,f)})]})),e("li",{class:"plan-row",children:[e("div",{class:"plan-text",children:[e("b",{children:"Where you see it"}),e("small",{children:O?o.pagesSwitch?`GitHub Pages switches from ${a.pages.says} to the dashboard at ${te(t).replace("https://","")}.`:`Here in this app; the Pages site keeps serving ${a.pages.says}.`:o.pages==="public"?`A GitHub Pages site at ${te(t).replace("https://","")}, turned on after the first run.`:o.pages==="artifact"?"Each run uploads the app as a download (kept 7 days).":a.private?"Here in this app, read with your token. A Pages site would be public.":"Here in this app; no Pages site."})]}),e(w,{size:"sm",variant:"plain",onClick:()=>d(!g),expanded:g,children:g?"Hide advanced":"Advanced"})]})]})}),O?e($,{class:"advanced",children:[e("div",{class:"note note-watch",role:"status",children:[e(h,{name:"warn"}),e("span",{children:["Pages already serves ",e("b",{children:a.pages.says})," for ",t,". Switching replaces that site with the dashboard."]})]}),e("div",{class:"adv-row",children:[e("span",{children:"Pages site"}),e(E,{size:"sm",label:"Pages site",value:o.pagesSwitch?"switch":"keep",onChange:l=>D({pagesSwitch:l==="switch"}),options:[{value:"keep",label:"Keep it (dashboard in the app)"},{value:"switch",label:"Switch Pages to the dashboard"}]})]})]}):null,g?e($,{class:"advanced",children:[e("div",{class:"adv-row",children:[e("span",{id:"adv-days",children:"History to read on the first runs"}),e(ee,{label:"days",value:o.days,min:7,max:90,step:1,unit:"days",onChange:l=>D({days:l})})]}),e("div",{class:"adv-row",children:[e("span",{children:"Most API requests per run"}),e(ee,{label:"requests",value:o.budget,min:100,max:5e3,step:100,onChange:l=>D({budget:l})})]}),e("div",{class:"adv-row",children:[e("span",{children:"Web page"}),e(E,{size:"sm",label:"Web page",value:o.pages,onChange:l=>D({pages:l}),options:[{value:"public",label:"Pages site"},{value:"artifact",label:"Artifact"},{value:"local",label:"In this app"}]})]}),a.private&&o.pages==="public"?e("div",{class:"note note-watch",children:[e(h,{name:"warn"}),e("span",{children:"A Pages site is public on most plans, even for a private repo."})]}):null,a.private?e("div",{class:"adv-row",children:[e("span",{id:"adv-every",children:"Read every CI run (uses more Actions minutes; the pull request verdict needs it)"}),e(G,{checked:o.everyCiRun,labelledBy:"adv-every",onChange:l=>D({everyCiRun:l})})]}):null]}):null,e("details",{class:"yaml-peek",children:[e("summary",{children:["See the file (",S,")"]}),e(J,{code:y(!1),title:S})]})]}),x?e(P,{title:"The workflow file is already there",description:e(B,{children:[t," has a different ",e("code",{children:S}),". Lines with \u2212 go, lines with + come in."]}),children:e($,{children:[e("pre",{class:"diff","aria-label":"What would change",tabIndex:0,style:{overflow:"auto",maxHeight:"20rem",fontSize:"0.8125rem",margin:0},children:e("code",{children:m})}),e("div",{class:"adv-row",children:[e("span",{children:"How to change it"}),e(E,{size:"sm",label:"How to change it",value:b?"commit":"pr",onChange:l=>{U(l==="commit"),pe(!1)},options:[{value:"pr",label:"Open a pull request"},{value:"commit",label:`Commit to ${a.branch}`}]})]}),b?e("div",{class:"adv-row",children:[e("span",{id:"sure-l",children:["I've read the changes: replace the file on ",e("code",{children:a.branch})," in ",t]}),e(G,{checked:M,labelledBy:"sure-l",onChange:pe})]}):null]})}):null,i?e(P,{title:"Set it up",action:e(se,{compact:!0}),children:e($,{class:"go-card",children:[e("p",{class:"go-or",children:["Writes to ",e("b",{children:a.repo})," with ",i.login?`${i.login}'s`:"your"," GitHub access:"]}),e("ul",{class:"go-list",children:[e("li",{children:[e(h,{name:"check"}),x&&!V?e(B,{children:["Opens a pull request with the new file against ",e("code",{children:a.branch})]}):e(B,{children:["Commits the file to ",e("code",{children:a.branch})," (a pull request if the branch is protected)"]})]}),a.private&&o.everyCiRun?e("li",{children:[e(h,{name:"check"}),"Sets ",e("code",{children:"STACKVITALS_EVERY_CI_RUN"})]}):null,e("li",{children:[e(h,{name:"check"}),"Starts the first run and shows it here (2 to 5 minutes)"]}),!a.private&&o.pages==="public"&&(!O||o.pagesSwitch)?e("li",{children:[e(h,{name:"check"}),O?"Switches the Pages site to the dashboard":"Turns on the Pages site"]}):null,e("li",{children:[e(h,{name:"check"}),"Opens the dashboard"]})]}),e(w,{variant:"filled",size:"lg",wide:!0,onClick:Ve,disabled:a.canPush===!1||!!x&&b&&!M,children:x?V?`Replace the file on ${a.branch}`:"Open a pull request":r?"Set it up again":"Set it up"})]})}):e(Ue,{repo:t,branch:a.branch,yamlFull:y(!1),yamlCompact:y(!0),modules:o.modules,onConnect:()=>C(!0)})]}):null,a===null&&!i?e(Ue,{repo:t,branch:"main",yamlFull:q(null),yamlCompact:q(null,{compact:!0}),modules:[...j],onConnect:()=>C(!0)}):null,e(ce,{open:L,onClose:()=>C(!1),title:"Connect GitHub",description:"Then setup runs in one click.",children:e(ne,{app:s,onConnected:()=>C(!1)})})]})}function rt(t,s){return t==="ci"?s.workflows.length?"Flaky and slowing checks. Reads these when they finish (ticked: the ones that look like CI).":"No CI workflows yet: it starts reading once you add one.":t==="flow"?s.deployments||s.releases?`Review flow and cycle time; ${s.deployments?"deployments":"releases"} found, so delivery and DORA too.`:"Review flow and cycle time; delivery shows once you deploy or release.":t==="deps"?s.lockfiles.length?`Lockfiles found (${s.lockfiles.slice(0,3).join(", ")}): known vulnerabilities and a pull request check.`:"No lockfiles at the top of the repo.":s.private?"Newcomers and first answers; mostly useful for public repos.":"Newcomers, first answers, stars and traffic."}function Ue({repo:t,branch:s,yamlFull:i,yamlCompact:n,modules:a,onConnect:c}){let o=`sv:watch:${t}`,[p,g]=v(()=>{try{return Number(sessionStorage.getItem(o))||null}catch{return null}}),[d,r]=v(null),[k,R]=v(null),[I,L]=v(!1),C=()=>{let m=Date.now();g(m);try{sessionStorage.setItem(o,String(m))}catch{}},y=async m=>{L(!0);try{let b=await qe(N(),t,m);return r(b),R(null),b}catch(b){return R(b instanceof Error?b.message:"The check failed."),null}finally{L(!1)}};T(()=>{if(!p||Date.now()-p>ie)return;let m=!0,b=d;y(b).then(M=>{b=M||b});let U=setInterval(()=>{!m||document.hidden||Date.now()-p>ie||b?.site||y(b).then(M=>{b=M||b})},je);return()=>{m=!1,clearInterval(U)}},[p]);let u=Fe(d),x=ve(t,s,S,n,i);return e(B,{children:[e(P,{title:"Do it on GitHub",description:"No token needed: GitHub opens with the file ready; press Commit changes. That also starts the first run.",children:e($,{class:"go-card",children:[e("div",{class:"go-buttons",children:[e(w,{variant:"filled",href:x.url,external:!0,iconEnd:"external",onClick:()=>{ke(x,"GitHub opened with the file: press Commit changes there")(),C()},children:"Open GitHub with the file ready"}),e(ue,{text:i,label:"Copy the file"}),e(w,{variant:"tinted",icon:"link",onClick:c,children:"Connect GitHub for one click"})]}),e(we,{link:x}),e("p",{class:"go-or",children:"Or from a terminal:"}),e(J,{inline:!0,code:Ce(t,a),note:e(B,{children:["Then commit and push the file. ",e("code",{children:"pip install stackvitals"})," first."]})}),s==="main"?e("p",{class:"go-or",children:["Default branch isn't ",e("code",{children:"main"}),"? Change it in GitHub's editor before committing."]}):null]})}),e(P,{title:"Progress",description:p?"Checked about once a minute for 15 minutes (GitHub allows visitors 60 requests an hour).":"Starts when you open GitHub, or now:",action:e(w,{size:"sm",variant:"tinted",loading:I,onClick:()=>p?y(d):C(),children:p?"Check now":"Watch progress"}),children:e($,{children:[e("ol",{class:"setup-steps",children:u.map(m=>e("li",{class:`setup-step is-${m.state==="done"?"done":m.state==="now"&&p?"running":"pending"}`,children:[e("span",{class:"setup-mark",children:m.state==="done"?e(h,{name:"check"}):m.state==="now"&&p?e("span",{class:"spin","aria-label":"Waiting"}):e(h,{name:"dot"})}),e("div",{class:"setup-body",children:[e("b",{children:m.title}),m.title==="First run started"&&d?.run?e("p",{children:["Run ",e("a",{href:d.run.html_url,target:"_blank",rel:"noopener noreferrer",children:["#",d.run.run_number]}),": ",d.run.status==="completed"?d.run.conclusion:d.run.status,"."]}):null,m.title==="Web page on"&&m.state==="now"&&d?.public?e("p",{children:["In Settings, Pages: Deploy from a branch, ",e("code",{children:"stackvitals-data"}),", ",e("code",{children:"/docs"}),". ",e("a",{href:`https://github.com/${t}/settings/pages`,target:"_blank",rel:"noopener noreferrer",children:"Open Pages settings"})]}):null]})]}))}),k?e("div",{class:"note note-watch",role:"alert",children:[e(h,{name:"warn"}),e("span",{children:k})]}):null,d?.dataBranch?e(w,{variant:"filled",onClick:()=>H(t,!1),children:"Open the dashboard"}):null]})})]})}export{et as default};
@@ -0,0 +1 @@
1
+ [data-page=standing] td[data-label=Here]{font-weight:700}[data-page=standing] td[data-label=Typical]{color:var(--ink-2)}[data-design=sheet][data-page=standing] td[data-label=Measure]{font-size:15px;font-weight:600;color:var(--ink)}[data-design=sheet][data-page=standing] td[data-label=Here]{color:var(--ink);font-weight:700}[data-design=sheet][data-page=standing] td[data-label=Place]{font-weight:600;background:var(--accent-soft)}[data-design=sheet][data-page=standing] td[data-label="What it needs"]{font-size:15px;line-height:1.45;color:var(--ink-2)}[data-design=sheet][data-page=standing] .table-wrap.card,[data-design=sheet][data-page=standing] .stats.card{border:1.5px solid var(--frame)}[data-design=sheet][data-page=standing] .pn .table-wrap.card{border:0}.pn{min-width:0;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}.pn-strip{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:4px 12px;min-height:42px;padding:9px 16px;background:var(--surface-2);border-bottom:1px solid var(--line)}.pn-title{margin:0;font-size:15.5px;font-weight:700;line-height:1.35;overflow-wrap:anywhere;display:flex;align-items:center;gap:8px;flex-wrap:wrap}.pn-meta{font-size:14px;font-weight:600;color:var(--ink-2);display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap}.pn-body{padding:14px 16px;display:flex;flex-direction:column;gap:12px;min-width:0}.pn-body.is-flush{padding:0;gap:0}.pn-body>p{margin:0;font-size:15px;line-height:1.5}.pn-foot{display:flex;align-items:center;gap:8px 10px;flex-wrap:wrap;padding:10px 16px;border-top:1px solid var(--line)}.pn-foot .pn-hint{font-size:14px;color:var(--ink-2);flex-basis:100%}.pn .table-wrap.card{border:0;border-radius:0;box-shadow:none;background:transparent}.pn-good{border-top:4px solid var(--good)}.pn-watch{border-top:4px solid var(--watch)}.pn-bad{border-top:4px solid var(--bad)}.pn-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0;margin:0}.pn-facts.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.pn-fact{padding:8px 12px 8px 0;border-bottom:1px solid var(--line);min-width:0}.pn-fact dt{font-size:14px;font-weight:600;color:var(--ink-2)}.pn-fact dd{margin:2px 0 0;font-size:15.5px;font-weight:600;color:var(--ink);overflow-wrap:anywhere}.pn-steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.pn-steps>li{display:grid;grid-template-columns:32px minmax(0,1fr) auto;gap:4px 14px;align-items:start;padding:14px 16px;border-top:1px solid var(--line)}.pn-steps>li:first-child{border-top:0}.pn-step-n{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;background:var(--accent-soft);color:var(--accent);font-weight:700}.pn-step-h{margin:0;font-size:15.5px;font-weight:700}.pn-step-p{margin-top:3px;font-size:14.5px;line-height:1.5;color:var(--ink-2)}.pn-step-act{display:flex;gap:8px;flex-wrap:wrap;align-items:center;justify-content:flex-end}@media(max-width:640px){.pn-steps>li{grid-template-columns:28px minmax(0,1fr)}.pn-step-act{grid-column:2;justify-content:flex-start}.pn-facts.cols-2{grid-template-columns:minmax(0,1fr)}}[data-design=sheet] .pn{border:1.5px solid var(--frame);border-radius:2px}[data-design=sheet] .pn-strip{background:var(--strip);border-bottom:1px solid var(--line-strong);padding:9px 14px}[data-design=sheet] .pn-title{font-size:16px;font-weight:700;color:var(--ink)}[data-design=sheet] .pn-meta{font-size:14.5px;color:var(--ink-2)}[data-design=sheet] .pn-body{padding:14px}[data-design=sheet] .pn-body.is-flush{padding:0}[data-design=sheet] .pn-foot{padding:10px 14px;border-top:1px solid var(--line-strong)}[data-design=sheet] .pn-good{border-top:5px solid var(--sv-mint)}[data-design=sheet] .pn-watch{border-top:5px solid var(--sv-amber)}[data-design=sheet] .pn-bad{border-top:5px solid var(--sv-coral)}[data-design=sheet] .pn-fact dt{font-size:14px;font-weight:600;color:var(--ink-2)}[data-design=sheet] .pn-fact dd{font-size:16px;font-weight:600}[data-design=sheet] .pn-step-n{border-radius:2px;background:var(--ink);color:var(--bg);font-family:var(--display)}[data-design=sheet] .pn-steps>li.is-done .pn-step-n{background:var(--sv-mint);color:#000}
@@ -0,0 +1 @@
1
+ import{a as I}from"../chunks/chunk-TO4VVRZ7.js";import{a as y}from"../chunks/chunk-6RLVD2DT.js";import{d as A}from"../chunks/chunk-4WKQTWUC.js";import"../chunks/chunk-VQ5YXO54.js";import{b as C,c as l,e as E,h as B,i as f}from"../chunks/chunk-76WAVKUG.js";import"../chunks/chunk-VWKSMFWJ.js";import{L as v,P as $,R as P,a as b,k,m as c,n as R,w as r,z as m}from"../chunks/chunk-GT4EAKAO.js";import{d as _}from"../chunks/chunk-G7NGB5UX.js";_();function w(t,e){return typeof e!="number"?"\u2013":t.kind==="share"||/share|rate/.test(String(t.key||""))?c(e):t.kind==="time"?e>=3600?k(e/3600):`${Math.round(e/60)} min`:/hours/.test(String(t.key||""))||t.kind==="hours"?k(e):e.toLocaleString()}var h=t=>t?`${t.group||"similar repos"}${t.repos?`, ${Number(t.repos).toLocaleString()} repos`:""}`:null;function S(t){return!t||!Array.isArray(t.metrics)?[]:t.metrics.map((e,n)=>({id:String(e.key||n),name:String(e.name||e.key),you:w(e,e.you),typical:w(e,e.typical),place:String(e.place||"\u2013")}))}function T(t){let e=[];for(let s of t?.score?.facts||[])e.push({id:String(s.key),name:String(s.name||s.key),you:w(s,s.you),typical:w(s,s.typical),place:s.better_than!=null?`better than about ${s.better_than}%`:"\u2013"});let n=t?.dependency,u=(s,i)=>`${i(s.typical)} (middle half ${i(s.low)} to ${i(s.high)})`;n?.peers?.bus_factor&&e.push({id:"bus_factor",name:"Bus factor: fewest people behind half the merged PRs",you:String(n.bus_factor??"\u2013"),typical:u(n.peers.bus_factor,String),place:n.bus_factor==null?"\u2013":n.bus_factor<n.peers.bus_factor.low?"below the middle half":n.bus_factor>n.peers.bus_factor.high?"above the middle half":"within the middle half"}),n?.peers?.top_share&&e.push({id:"top_share",name:"Most active person's share of merged PRs",you:c(n.top_share),typical:u(n.peers.top_share,s=>c(s)),place:n.top_share==null?"\u2013":n.top_share>n.peers.top_share.high?"more concentrated than most":n.top_share<n.peers.top_share.low?"more spread than most":"within the middle half"});let o=t?.stars?.peers||t?.peers;return o?.place&&e.push({id:"stars",name:"Star growth, last 12 weeks",you:t?.stars?.gained_12w!=null?`+${t.stars.gained_12w}`:"\u2013",typical:o.typical_gain!=null?`+${o.typical_gain}`:"\u2013",place:String(o.place)}),e}var M=t=>t.charAt(0).toUpperCase()+t.slice(1);function j(t){let e=A({ci:"data.json",flow:"flow.json",dl:"delivery.json",com:"community.json"});if(!e.ready)return r(P,{});let n=e.com,u=n?.stars?.peers||n?.peers,o=[{key:"ci",area:"CI",href:"#/ci",group:h(e.ci?.benchmark),rows:S(e.ci?.benchmark),why:"needs about a week of CI history and the crawl's CI benchmark file"},{key:"flow",area:"Review flow",href:"#/prs",group:h(e.flow?.peers),rows:S(e.flow?.peers),why:"needs about ten merged pull requests and the crawl's review benchmark file"},{key:"delivery",area:"Delivery",href:"#/delivery",group:h(e.dl?.peers),rows:S(e.dl?.peers),why:"needs recorded deployments and the crawl's delivery benchmark file"},{key:"community",area:"Community",href:"#/community",group:h(n?.score)||h(u),rows:T(n),why:"needs two facts with a public comparison, or a few months of merged work"}],s=o.filter(a=>a.rows.length),i=o.filter(a=>!a.rows.length),d=e.dl?.ai?.leaderboard,g=d?Object.entries(d.agents||{}).map(([a,p])=>({id:a,k:M(String(a)),...p})).sort((a,p)=>(p.prs??0)-(a.prs??0)):[],O=s.reduce((a,p)=>a+p.rows.length,0);return r(C,{title:"Where you stand",subtitle:"This repo against similar public repos, measured the same way, in one place.",children:[r(l,{title:"Summary",description:"How many measures have a comparison, and against which groups.",info:r(v,{info:{title:"Where you stand",doc:"accuracy.md",body:r(b,{children:"The groups come from StackVitals' crawl of public repos, refreshed daily. Each comparison uses that benchmark's own definition, so it can differ from the number on the module's page, which follows your settings. A place is a share of the group's repos, not a grade."})}}),children:r(B,{children:[r(f,{label:"Measures compared",value:O}),r(f,{label:"Areas with a comparison",value:`${s.length} of ${o.length}`,note:s.map(a=>a.area).join(", ")||"none yet"}),r(f,{label:"Coding agents measured",value:g.length||"\u2013",note:g.length?"across the crawl's public repos":"no leaderboard file here"})]})}),s.length?s.map(a=>r(l,{title:a.area,description:`Compared with ${a.group||"similar repos"}: the closest group (same language and size, then wider) with enough repos.`,action:r(m,{size:"sm",variant:"plain",href:a.href,iconEnd:"right",children:["Open ",a.area]}),children:r(y,{name:`standing-${a.key}`,caption:`${a.area} against similar repos`,search:!1,rows:a.rows,columns:[{key:"name",label:"Measure",primary:!0},{key:"you",label:"Here",num:!0},{key:"typical",label:"Typical",num:!0},{key:"place",label:"Place"}]})})):r(l,{title:"Against similar repos",description:"Each number is placed in the closest group with enough repos.",children:r(E,{children:r($,{icon:"insights",title:"No comparison yet.",children:"Comparisons appear once the crawl's benchmark files are available to this repo and each module has enough of its own history (about ten merged pull requests, a week of CI)."})})}),i.length?r(l,{title:"Not compared yet",description:"The areas without a comparison, and what each needs.",children:r(y,{name:"standing-missing",caption:"Areas not compared yet",search:!1,rows:i.map(a=>({id:a.key,area:a.area,why:M(a.why),href:a.href})),columns:[{key:"area",label:"Area",primary:!0},{key:"why",label:"What it needs"},{key:"href",label:"Open",raw:()=>"",render:a=>r(m,{variant:"plain",size:"sm",href:a.href,iconEnd:"right",children:["Open ",a.area]})}]})}):null,d?r(l,{title:"Coding agents",description:"How each agent's pull requests fare across public repos.",children:r(I,{title:"Agent leaderboard",meta:r(b,{children:[R(g.length,"agent"),d.window_days?`, last ${d.window_days} days`:""]}),foot:r(m,{variant:"tinted",href:"#/delivery?tab=ai",iconEnd:"right",children:"Open the full leaderboard"}),flush:!0,children:r(y,{name:"standing-agents",search:!1,limit:8,rows:g,columns:[{key:"k",label:"Agent",primary:!0},{key:"repos",label:"Repos",num:!0},{key:"prs",label:"Decided PRs",num:!0},{key:"merged",label:"Merged",num:!0,render:a=>c(a.merged)}]})})}):null]})}export{j as default};
@@ -0,0 +1 @@
1
+ import{a}from"../chunks/chunk-THFUOCPC.js";import"../chunks/chunk-RQZPSJ2Y.js";import"../chunks/chunk-3IXWEOIJ.js";import"../chunks/chunk-Y6LUXDM6.js";import"../chunks/chunk-7TJCBOAY.js";import"../chunks/chunk-PABICGBL.js";import"../chunks/chunk-GQYFN4PE.js";import"../chunks/chunk-763NH7PP.js";import"../chunks/chunk-6BDBXA6V.js";import"../chunks/chunk-MAPYGK3P.js";import"../chunks/chunk-T7QVTNXF.js";import"../chunks/chunk-RPXHAG6F.js";import"../chunks/chunk-4WKQTWUC.js";import"../chunks/chunk-VQ5YXO54.js";import"../chunks/chunk-76WAVKUG.js";import"../chunks/chunk-VWKSMFWJ.js";import"../chunks/chunk-GT4EAKAO.js";import"../chunks/chunk-G7NGB5UX.js";export{a as default};
@@ -0,0 +1 @@
1
+ import{b as a,c as b,d as c}from"../chunks/chunk-THFUOCPC.js";import"../chunks/chunk-RQZPSJ2Y.js";import"../chunks/chunk-3IXWEOIJ.js";import"../chunks/chunk-Y6LUXDM6.js";import"../chunks/chunk-7TJCBOAY.js";import"../chunks/chunk-PABICGBL.js";import"../chunks/chunk-GQYFN4PE.js";import"../chunks/chunk-763NH7PP.js";import"../chunks/chunk-6BDBXA6V.js";import"../chunks/chunk-MAPYGK3P.js";import"../chunks/chunk-T7QVTNXF.js";import"../chunks/chunk-RPXHAG6F.js";import"../chunks/chunk-4WKQTWUC.js";import"../chunks/chunk-VQ5YXO54.js";import"../chunks/chunk-76WAVKUG.js";import"../chunks/chunk-VWKSMFWJ.js";import"../chunks/chunk-GT4EAKAO.js";import"../chunks/chunk-G7NGB5UX.js";export{c as default,b as pickRepo,a as useByName};
@@ -0,0 +1 @@
1
+ [{"name":"modules","help":"Modules to run, comma separated. Available now - ci (CI health), flow (Team Flow, on schedule and manual runs), deps (dependency check on pull requests that change a lockfile), community (newcomers, first answers, stars and traffic, on schedule and manual runs), portal (the org catalog, run from the org's private portal repo)","default":"ci,flow,deps,community","kind":"choices","choices":["ci","flow","deps","community","portal"]},{"name":"token","help":"Token that can read Actions and write the stackvitals-data branch","default":"${{ github.token }}","kind":"text","secret":true},{"name":"portal-token","help":"Optional token from an org-owned read-only GitHub App, so Portal reads the org's private repos (without it, public repos only)","default":"","kind":"text","secret":true},{"name":"portal-org","help":"The org Portal catalogs (default - the owner of the repo it runs in)","default":"","kind":"text"},{"name":"traffic-token","help":"Optional token from your own GitHub App with Administration read, so Community keeps traffic past GitHub's 14 days (the built-in token can't read traffic)","default":"","kind":"text","secret":true},{"name":"days","help":"Days of history to fill in on the first runs (GitHub keeps at most 90)","default":"90","kind":"int"},{"name":"budget","help":"Most API requests per run (the built-in token allows 1,000 an hour)","default":"800","kind":"int"},{"name":"tests","help":"Read test reports (JUnit XML or CTRF JSON) from your run artifacts to find single flaky tests","default":"true","kind":"bool"},{"name":"test-artifacts","help":"Regex for the artifact names that hold test reports (empty = names with junit, test-results, ctrf...)","default":"","kind":"text"},{"name":"pr-comments","help":"One comment on failed PR runs saying which failures are known flakes (needs pull-requests write)","default":"true","kind":"bool"},{"name":"rerun-flaky","help":"Re-run failed jobs once when every failure is a known flake (needs actions write)","default":"false","kind":"bool"},{"name":"quarantine","help":"Keep a list of flaky tests for the stackvitals ci quarantine command","default":"false","kind":"bool"},{"name":"preflight-comments","help":"Team Flow - one note on new outside PRs that miss what merged PRs here usually include (needs pull-requests write)","default":"false","kind":"bool"},{"name":"deps-comments","help":"Dependency check - one comment on same-repo PRs listing changed packages and their verdicts (needs pull-requests write)","default":"false","kind":"bool"},{"name":"issues","help":"Keep one issue per flaky test or job, closed once fixed (needs issues write)","default":"false","kind":"bool"},{"name":"mention-owners","help":"@-mention a flaky test's code owners in the issues StackVitals opens (off: owners are named without a notification)","default":"false","kind":"bool"},{"name":"webhook","help":"Slack, Discord, Microsoft Teams (Workflows) or any JSON webhook URL (pass a secret) to hear when something newly turns flaky and when a delivery number crosses its threshold","default":"","kind":"text","secret":true},{"name":"team-webhooks","help":"One \"@org/team = https://...\" line per team (pass a secret); a team's newly flaky tests go to its own chat, the rest to webhook","default":"","kind":"text","secret":true},{"name":"jira-email","help":"The Jira Cloud account's email (pass a secret); with jira-token and [connectors.jira] url, issues, sprints and incidents are read","default":"","kind":"text","secret":true},{"name":"jira-token","help":"A Jira Cloud API token for that account (pass a secret; it expires within a year, so set key_expires to be warned)","default":"","kind":"text","secret":true},{"name":"linear-token","help":"A Linear personal API key (pass a secret); issues and cycles of the teams under [connectors.linear] are read","default":"","kind":"text","secret":true},{"name":"pagerduty-token","help":"A PagerDuty REST API key, read-only (pass a secret); its incidents then count in DORA instead of labels, reverts and hotfixes","default":"","kind":"text","secret":true},{"name":"incident-io-token","help":"An incident.io API key with read access (pass a secret); its incidents then count in DORA instead of labels, reverts and hotfixes","default":"","kind":"text","secret":true},{"name":"sonar-token","help":"A SonarQube or SonarCloud token (pass a secret), only for a private project or your own server; public SonarCloud projects need none","default":"","kind":"text","secret":true},{"name":"copilot-token","help":"A token that can read the org's Copilot usage reports (an org App with \"Organization Copilot metrics\" read, or a fine-grained token); kept day by day","default":"","kind":"text","secret":true},{"name":"anthropic-admin-key","help":"An Anthropic Admin API key (sk-ant-admin..., pass a secret); the organisation's daily Claude API cost is set beside AI-involved pull requests","default":"","kind":"text","secret":true},{"name":"openai-admin-key","help":"An OpenAI admin key (pass a secret); the organisation's daily API cost is set beside AI-involved pull requests","default":"","kind":"text","secret":true},{"name":"cursor-admin-key","help":"A Cursor admin API key (pass a secret); the team's billing-cycle spend and daily agent use are set beside AI-involved pull requests","default":"","kind":"text","secret":true},{"name":"slack-token","help":"A Slack bot token (channels:history) that reads the support channels under [connectors.slack]; only times and flags are kept","default":"","kind":"text","secret":true},{"name":"discord-token","help":"A Discord bot token (View Channel, Read Message History) that reads the support channels under [connectors.discord]; only times and flags are kept","default":"","kind":"text","secret":true},{"name":"imports-json","help":"Path to the list of packages your code imports (`stackvitals deps imports --out imports.json` in an earlier step, after checkout) for Python, JavaScript and Rust repos; known vulnerabilities then say whether your code imports the package (an import, not a call path)","default":"","kind":"text"},{"name":"govulncheck-json","help":"Path to govulncheck's JSON output (`govulncheck -format json ./... > govulncheck.json` in an earlier step) for Go repos; the supply page then says which advisories the code really calls","default":"","kind":"text"},{"name":"triage-key","help":"A model API key (pass a secret, e.g. a free Gemini key from Google AI Studio) for [ci.triage]; up to 3 undecided failures per run get a model's view beside the verdict","default":"","kind":"text","secret":true},{"name":"label-stuck","help":"Label pull requests whose asked-for review has not started after 3 days (\"stackvitals: waiting for review\"), and take the label off once one has (needs pull-requests or issues write)","default":"false","kind":"bool"},{"name":"retention-days","help":"Days of pull request, issue and Portal history kept in the data branch","default":"400","kind":"int"},{"name":"ci-retention-days","help":"Days of CI run and test history kept in the data branch","default":"180","kind":"int"},{"name":"size-cap-mb","help":"Most history kept in the data branch, in MB; the oldest days go first","default":"250","kind":"int"},{"name":"squash-history","help":"Every 1,000 commits, rewrite the data branch to one commit (files unchanged; the branch is force-pushed)","default":"false","kind":"bool"},{"name":"pages","help":"\"branch\" (default): GitHub Pages serves the stackvitals-data branch. \"deploy\": this job publishes the monitor itself (Pages source \"GitHub Actions\"; the job needs pages and id-token write and the github-pages environment), for busy repos past 10 Pages builds an hour. \"artifact\": no Pages; each run that changed the app uploads it as a workflow artifact (kept 7 days, or less if your org sets a shorter limit) to download and open locally, for private repos; anyone who can read the repo can download it","default":"branch","kind":"choice","choices":["branch","deploy","artifact"]},{"name":"storage","help":"Where history is kept: \"git\" (default, the stackvitals-data branch) or an S3-compatible bucket as s3://bucket/prefix (AWS S3, Cloudflare R2, MinIO: the service must support replace-only-if-unchanged writes, If-Match), for very busy repos and big orgs. Switching starts a fresh history (the branch is not copied). With a bucket, publish the app with pages \"deploy\" or \"artifact\"; the tools that read the stackvitals-data branch (stackvitals ui and sql, Explore, the MCP server, the Portal org view, quarantine in your CI) do not read a bucket yet","default":"git","kind":"text"},{"name":"s3-endpoint","help":"The bucket service's endpoint, like https://s3.us-east-1.amazonaws.com or https://<account>.r2.cloudflarestorage.com","default":"","kind":"text"},{"name":"s3-region","help":"The bucket's region (\"auto\" for R2)","default":"auto","kind":"text"},{"name":"s3-key-id","help":"An access key id that can read, write, delete and list that prefix (pass a secret)","default":"","kind":"text","secret":true},{"name":"s3-secret","help":"Its secret (pass a secret)","default":"","kind":"text","secret":true}]
@@ -0,0 +1,34 @@
1
+ <!doctype html>
2
+ <html lang="en" data-design="sheet">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://avatars.githubusercontent.com; font-src 'self'; connect-src 'self' https://api.github.com https://raw.githubusercontent.com https://*.github.io https://api.linear.app; object-src 'none'; base-uri 'none'; form-action 'none'">
7
+ <meta name="referrer" content="no-referrer">
8
+ <meta name="color-scheme" content="light">
9
+ <meta name="sv-page-css" content="about,activity,agents,ci,community,connections,delivery,deps,explore,health,help,insights,investment,overview,portal,prs,settings,setup,standing">
10
+ <title>StackVitals</title>
11
+ <link rel="icon" id="favicon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%232160C4'/%3E%3C/svg%3E">
12
+ <link rel="stylesheet" href="app/main.css">
13
+ <script src="app/boot.js"></script>
14
+ <script type="module" src="app/main.js"></script>
15
+ <link rel="modulepreload" href="app/chunks/chunk-Y6LUXDM6.js">
16
+ <link rel="modulepreload" href="app/chunks/chunk-7TJCBOAY.js">
17
+ <link rel="modulepreload" href="app/chunks/chunk-4SQPQ5TB.js">
18
+ <link rel="modulepreload" href="app/chunks/chunk-763NH7PP.js">
19
+ <link rel="modulepreload" href="app/chunks/chunk-6BDBXA6V.js">
20
+ <link rel="modulepreload" href="app/chunks/chunk-MAPYGK3P.js">
21
+ <link rel="modulepreload" href="app/chunks/chunk-4WKQTWUC.js">
22
+ <link rel="modulepreload" href="app/chunks/chunk-VQ5YXO54.js">
23
+ <link rel="modulepreload" href="app/chunks/chunk-76WAVKUG.js">
24
+ <link rel="modulepreload" href="app/chunks/chunk-VWKSMFWJ.js">
25
+ <link rel="modulepreload" href="app/chunks/chunk-GT4EAKAO.js">
26
+ <link rel="modulepreload" href="app/chunks/chunk-G7NGB5UX.js">
27
+ </head>
28
+ <body>
29
+ <div id="splash" class="splash" aria-hidden="true"><span id="splash-mark" class="splash-mark"></span></div>
30
+ <script src="app/boot.js"></script>
31
+ <div id="root"></div>
32
+ <noscript><p style="padding:16px">The StackVitals app needs JavaScript. The printable pages (ci.html, flow.html, delivery.html) show the same numbers.</p></noscript>
33
+ </body>
34
+ </html>
@@ -0,0 +1,108 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'none'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'">
7
+ <meta name="referrer" content="no-referrer">
8
+ <meta name="color-scheme" content="light dark">
9
+ <title>StackVitals: your repo's vital signs, free</title>
10
+ <meta name="description" content="A free GitHub Action that watches flaky tests, pull-request flow, DORA, dependencies and community health, keeps the history in your own repo, and shows what needs a decision.">
11
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%232160C4'/%3E%3C/svg%3E">
12
+ <link rel="stylesheet" href="site/site.css">
13
+ </head>
14
+ <body>
15
+ <header class="site-top"><nav class="wrap" aria-label="StackVitals">
16
+ <a class="mark" href="./"><svg width="30" height="30" viewBox="0 0 32 32" aria-hidden="true"><rect width="32" height="32" rx="8" fill="var(--logo-tile)"/><path d="M6.5 20.5 16 25.3l9.5-4.8M6.5 15.6 16 20.4l9.5-4.8" fill="none" stroke="var(--logo-fg)" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 5.8 25.5 10.6 16 15.4 6.5 10.6Z" fill="var(--logo-acc)"/></svg>StackVitals</a>
17
+ <span class="links"><a href="#watch">What it watches</a><a href="#how">How it works</a><a href="#compare">Compare</a><a href="#questions">Questions</a></span>
18
+ <a class="btn" href="app.html?demo=1">Live demo</a>
19
+ <a class="btn primary" href="app.html#/setup">Set it up</a>
20
+ </nav></header>
21
+ <main class="wrap">
22
+ <section class="hero" aria-labelledby="hero-title">
23
+ <h1 id="hero-title">Flaky tests, stuck reviews, slow releases and risky updates, in one place.</h1>
24
+ <p class="lede">StackVitals is a free GitHub Action. Every few hours it reads your CI runs, pull requests and releases, keeps the
25
+ history in a branch of your own repo, and shows what needs a decision. No hosted backend, no account, nothing to host.</p>
26
+ <div class="cta-row"><a class="btn primary big" href="app.html#/setup">Set it up in five minutes</a><a class="btn big" href="app.html?demo=1">See the live demo</a><!--REAL-DEMO--></div>
27
+ </section>
28
+
29
+ <section id="watch" class="band" aria-labelledby="watch-title">
30
+ <h2 id="watch-title">Six modules, one app</h2>
31
+ <p class="lede">Each module keeps its own history and raises its own alerts. Turn on the ones you need.</p>
32
+ <div class="grid">
33
+ <article class="card"><h3>CI health</h3><p>Flaky and failing tests and jobs from every run, failure groups, the minutes they cost; quarantine, one re-run of known flakes, one issue per flaky test, and a verdict check you can require.</p><p class="covers">Covers the core workflows of Trunk Flaky Tests, BuildPulse.</p></article>
34
+ <article class="card"><h3>Pull requests</h3><p>Who holds the next move on each pull request, reviews that never started, working agreements your team sets, and a weekly digest.</p><p class="covers">Covers the core workflows of Swarmia, LinearB.</p></article>
35
+ <article class="card"><h3>Delivery</h3><p>DORA's five delivery metrics, the first four counted the way Apache DevLake's dashboards count them, and cycle time in LinearB's phases from first commit to production.</p><p class="covers">Covers the core workflows of Apache DevLake, Sleuth.</p></article>
36
+ <article class="card"><h3>Dependencies</h3><p>Update pull requests by age, security updates past 48 hours, how fast updates merge, and a verdict on each package from public evidence.</p><p class="covers">Covers the core workflows of Renovate's dashboard, Socket.</p></article>
37
+ <article class="card"><h3>Community</h3><p>Newcomers waiting for a first answer, how fast maintainers answer, stars, and traffic kept past GitHub's 14 days with your own GitHub App.</p><p class="covers">Covers the core workflows of LFX Insights and the CHAOSS tools.</p></article>
38
+ <article class="card"><h3>Portal</h3><p>Every repo in an org with its owners checked, bronze, silver and gold scorecards against peer repos, and campaigns with reminders.</p><p class="covers">Covers the core workflows of Cortex, OpsLevel, Port.</p></article>
39
+ </div>
40
+ </section>
41
+
42
+ <section class="band" aria-labelledby="receipts-title">
43
+ <h2 id="receipts-title">Receipts, not claims</h2>
44
+ <div class="grid">
45
+ <div class="card receipt"><b>90,000</b><span>active public repos with 100+ stars sampled for peer comparisons</span><span class="source">the daily crawl, each repo read every 4 weeks</span></div>
46
+ <div class="card receipt"><b>1,000</b><span>most-used npm and PyPI packages each, watched for update verdicts</span><span class="source">ranked by repos that depend on them</span></div>
47
+ <div class="card receipt"><b>1 year</b><span>of pull-request history in the first run; 90 days of CI</span><span class="source">GitHub's own API, read by your workflow</span></div>
48
+ <div class="card receipt"><b>0</b><span>servers to run, accounts to make or bills to pay</span><span class="source">everything lives in your repo's stackvitals-data branch</span></div>
49
+ </div>
50
+ </section>
51
+
52
+ <section id="how" class="band" aria-labelledby="how-title">
53
+ <h2 id="how-title">From GitHub to your app</h2>
54
+ <div class="grid">
55
+ <div class="card"><h3>GitHub</h3><p>Your CI runs, pull requests, issues and deployments.</p></div>
56
+ <div class="card"><h3>Your workflow</h3><p>After every CI run and every 3 hours, it reads with the workflow's own token, about a minute a run.</p></div>
57
+ <div class="card"><h3>stackvitals-data</h3><p>A branch in your repo: every number with its history, every decision with who and why.</p></div>
58
+ <div class="card"><h3>Your app</h3><p>A static page on your GitHub Pages, or on your machine for private repos.</p></div>
59
+ </div>
60
+ <p class="lede after">Decisions happen where you already work: type <code>/stackvitals quarantine</code> in any issue or pull
61
+ request, or press Decide in the app. Every decision is logged with who made it, why and until when.</p>
62
+ </section>
63
+
64
+ <section class="band" aria-labelledby="setup-title">
65
+ <h2 id="setup-title">Five minutes, five steps</h2>
66
+ <ol class="steps">
67
+ <li><span class="n">1</span><b>Find your repo</b><span class="time">10 s</span></li>
68
+ <li><span class="n">2</span><b>Add the workflow</b><span class="time">1 min</span></li>
69
+ <li><span class="n">3</span><b>The first run</b><span class="time">2 to 5 min</span></li>
70
+ <li><span class="n">4</span><b>Turn on the page</b><span class="time">1 min</span></li>
71
+ <li><span class="n">5</span><b>Open your app</b><span class="time">now</span></li>
72
+ </ol>
73
+ <p><a class="btn primary big" href="app.html#/setup">Start the setup</a></p>
74
+ </section>
75
+
76
+ <section id="compare" class="band" aria-labelledby="compare-title">
77
+ <h2 id="compare-title">What one free install covers</h2>
78
+ <div class="tbl" tabindex="0" role="region" aria-label="Comparison"><table>
79
+ <thead><tr><th>What you get</th><th>Usually bought from</th><th>Their list price</th></tr></thead>
80
+ <tbody>
81
+ <tr><td>Flaky tests: detection, quarantine, re-runs, a required check</td><td>Trunk Flaky Tests, BuildPulse</td><td class="mute">Trunk free up to 5 committers; BuildPulse from $99 a month</td></tr>
82
+ <tr><td>Pull-request flow, review waits, working agreements, weekly digest</td><td>Swarmia, LinearB</td><td class="mute">Swarmia $45 to $55 per developer a month (free under 10); LinearB $29 to $59 per contributor a month, 50-seat minimum</td></tr>
83
+ <tr><td>DORA metrics and cycle-time phases</td><td>Apache DevLake</td><td class="mute">Free, on servers you run (Docker)</td></tr>
84
+ <tr><td>Org catalog, owners, scorecards, campaigns</td><td>Cortex, OpsLevel, Port</td><td class="mute">Port from $30 a seat a month (free up to 15); Cortex and OpsLevel by quote</td></tr>
85
+ <tr><td>Update-bot hygiene and package verdicts</td><td>Renovate's dashboard, Socket</td><td class="mute">Socket from $25 a seat a month</td></tr>
86
+ <tr><td>Open-source community health</td><td>LFX Insights, CHAOSS tools</td><td class="mute">LFX for Linux Foundation projects; CHAOSS tools self-hosted</td></tr>
87
+ </tbody>
88
+ </table></div>
89
+ <p class="mute small">Public list prices as of October 2026. StackVitals covers the core workflows of these tools for GitHub-first teams.</p>
90
+ </section>
91
+
92
+ <section id="questions" class="band faq" aria-labelledby="questions-title">
93
+ <h2 id="questions-title">Questions</h2>
94
+ <details><summary>Is it really free?</summary><p>Yes. It runs in your own GitHub Actions minutes (about a minute a run) and keeps everything in your repo. There is no StackVitals service to pay for or sign up to.</p></details>
95
+ <details><summary>Does it work for private repos?</summary><p>Yes. The workflow is the same. GitHub Pages sites are public, so a private repo's app opens on your machine with <code>stackvitals ui owner/repo</code>, or in the app here with a token that can read the repo.</p></details>
96
+ <details><summary>Where does my data go?</summary><p>Into a branch called stackvitals-data in your own repo, and nowhere else, unless you add a chat webhook yourself.</p></details>
97
+ <details><summary>What can it change in my repo?</summary><p>Only what someone with access asks for: a /stackvitals command or a request from the app is checked against that person's GitHub access before anything is recorded or changed.</p></details>
98
+ <details><summary>Does it replace the paid tools?</summary><p>It covers the core workflows of the tools in the table for GitHub-first teams. It doesn't do investment allocation, surveys, hosted runners or on-call.</p></details>
99
+ <details><summary>How do I remove it?</summary><p>Delete the workflow file, delete the stackvitals-data branch and turn GitHub Pages off. Nothing is left anywhere else.</p></details>
100
+ </section>
101
+ </main>
102
+ <footer class="site-foot"><div class="wrap">
103
+ <span class="mark">StackVitals</span>
104
+ <span class="mute">Free and open source (MIT). It runs in your repo's GitHub Actions and keeps everything in your repo.</span>
105
+ <span class="links"><a href="app.html#/setup">Set it up</a><a href="app.html?demo=1#/connections">Connections</a><a href="app.html?demo=1">Live demo</a><a href="#questions">Questions</a></span>
106
+ </div></footer>
107
+ </body>
108
+ </html>
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'none'; style-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'">
7
+ <meta http-equiv="refresh" content="0; url=app.html?demo=1#/connections">
8
+ <meta name="referrer" content="no-referrer">
9
+ <title>Connections · StackVitals</title>
10
+ <link rel="stylesheet" href="site/site.css">
11
+ </head>
12
+ <body>
13
+ <main class="wrap hero"><h1>Integrations are now Connections</h1><p class="lede"><a href="app.html?demo=1#/connections">Open Connections in the StackVitals app</a>.</p></main>
14
+ </body>
15
+ </html>
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'none'; style-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'">
7
+ <meta http-equiv="refresh" content="0; url=app.html#/setup">
8
+ <meta name="referrer" content="no-referrer">
9
+ <title>Setup · StackVitals</title>
10
+ <link rel="stylesheet" href="site/site.css">
11
+ </head>
12
+ <body>
13
+ <main class="wrap hero"><h1>Setup moved into the app</h1><p class="lede"><a href="app.html#/setup">Open Setup in the StackVitals app</a>.</p></main>
14
+ </body>
15
+ </html>