openpitstop 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +512 -0
  3. package/demo-repo/README.md +24 -0
  4. package/demo-repo/package-lock.json +4483 -0
  5. package/demo-repo/package.json +17 -0
  6. package/demo-repo/src/config.js +5 -0
  7. package/demo-repo/src/db.js +31 -0
  8. package/demo-repo/src/server.js +13 -0
  9. package/demo-repo/src/userController.js +22 -0
  10. package/demo-repo/src/userRepo.js +18 -0
  11. package/demo-repo/src/userService.js +59 -0
  12. package/demo-repo/test/user.test.js +12 -0
  13. package/demo-repo-fintech/README.md +27 -0
  14. package/demo-repo-fintech/package-lock.json +1023 -0
  15. package/demo-repo-fintech/package.json +14 -0
  16. package/demo-repo-fintech/pitstop-repro-ledger-order-ord-conc-1-charged-2.test.mjs +175 -0
  17. package/demo-repo-fintech/pitstop-repro-ledger-order-ord-retry-2-charged-2.test.mjs +175 -0
  18. package/demo-repo-fintech/pitstop-repro-ledger-order-ord-webhook-3-charged-2.test.mjs +175 -0
  19. package/demo-repo-fintech/src/gateway.js +26 -0
  20. package/demo-repo-fintech/src/server.js +61 -0
  21. package/demo-repo-generators/package-lock.json +1508 -0
  22. package/demo-repo-generators/package.json +17 -0
  23. package/demo-repo-generators/public/index.html +10 -0
  24. package/demo-repo-generators/scripts/build.js +17 -0
  25. package/demo-repo-generators/src/counter.js +16 -0
  26. package/demo-repo-integrity/README.md +49 -0
  27. package/demo-repo-integrity/package.json +12 -0
  28. package/demo-repo-integrity/src/money.js +19 -0
  29. package/demo-repo-integrity/test/money.test.js +17 -0
  30. package/dist/analyzers/accessibility.d.ts +18 -0
  31. package/dist/analyzers/accessibility.js +248 -0
  32. package/dist/analyzers/accessibility.js.map +1 -0
  33. package/dist/analyzers/dependencyGraph.d.ts +14 -0
  34. package/dist/analyzers/dependencyGraph.js +206 -0
  35. package/dist/analyzers/dependencyGraph.js.map +1 -0
  36. package/dist/analyzers/devex.d.ts +19 -0
  37. package/dist/analyzers/devex.js +301 -0
  38. package/dist/analyzers/devex.js.map +1 -0
  39. package/dist/analyzers/duplication.d.ts +2 -0
  40. package/dist/analyzers/duplication.js +47 -0
  41. package/dist/analyzers/duplication.js.map +1 -0
  42. package/dist/analyzers/index.d.ts +12 -0
  43. package/dist/analyzers/index.js +38 -0
  44. package/dist/analyzers/index.js.map +1 -0
  45. package/dist/analyzers/integrity/assertionLiteralTamper.d.ts +2 -0
  46. package/dist/analyzers/integrity/assertionLiteralTamper.js +164 -0
  47. package/dist/analyzers/integrity/assertionLiteralTamper.js.map +1 -0
  48. package/dist/analyzers/integrity/exceptionSwallow.d.ts +2 -0
  49. package/dist/analyzers/integrity/exceptionSwallow.js +198 -0
  50. package/dist/analyzers/integrity/exceptionSwallow.js.map +1 -0
  51. package/dist/analyzers/integrity/exitCheat.d.ts +2 -0
  52. package/dist/analyzers/integrity/exitCheat.js +31 -0
  53. package/dist/analyzers/integrity/exitCheat.js.map +1 -0
  54. package/dist/analyzers/integrity/git.d.ts +10 -0
  55. package/dist/analyzers/integrity/git.js +181 -0
  56. package/dist/analyzers/integrity/git.js.map +1 -0
  57. package/dist/analyzers/integrity/hardcodedMatch.d.ts +2 -0
  58. package/dist/analyzers/integrity/hardcodedMatch.js +93 -0
  59. package/dist/analyzers/integrity/hardcodedMatch.js.map +1 -0
  60. package/dist/analyzers/integrity/helpers.d.ts +21 -0
  61. package/dist/analyzers/integrity/helpers.js +66 -0
  62. package/dist/analyzers/integrity/helpers.js.map +1 -0
  63. package/dist/analyzers/integrity/index.d.ts +10 -0
  64. package/dist/analyzers/integrity/index.js +27 -0
  65. package/dist/analyzers/integrity/index.js.map +1 -0
  66. package/dist/analyzers/integrity/mockOverreach.d.ts +2 -0
  67. package/dist/analyzers/integrity/mockOverreach.js +72 -0
  68. package/dist/analyzers/integrity/mockOverreach.js.map +1 -0
  69. package/dist/analyzers/integrity/suppressionCreep.d.ts +2 -0
  70. package/dist/analyzers/integrity/suppressionCreep.js +27 -0
  71. package/dist/analyzers/integrity/suppressionCreep.js.map +1 -0
  72. package/dist/analyzers/integrity/testTamper.d.ts +2 -0
  73. package/dist/analyzers/integrity/testTamper.js +153 -0
  74. package/dist/analyzers/integrity/testTamper.js.map +1 -0
  75. package/dist/analyzers/integrity/types.d.ts +63 -0
  76. package/dist/analyzers/integrity/types.js +13 -0
  77. package/dist/analyzers/integrity/types.js.map +1 -0
  78. package/dist/analyzers/ledger/attacks.d.ts +17 -0
  79. package/dist/analyzers/ledger/attacks.js +135 -0
  80. package/dist/analyzers/ledger/attacks.js.map +1 -0
  81. package/dist/analyzers/ledger/discover.d.ts +15 -0
  82. package/dist/analyzers/ledger/discover.js +122 -0
  83. package/dist/analyzers/ledger/discover.js.map +1 -0
  84. package/dist/analyzers/ledger/evidence.d.ts +22 -0
  85. package/dist/analyzers/ledger/evidence.js +127 -0
  86. package/dist/analyzers/ledger/evidence.js.map +1 -0
  87. package/dist/analyzers/ledger/harness.d.ts +4 -0
  88. package/dist/analyzers/ledger/harness.js +270 -0
  89. package/dist/analyzers/ledger/harness.js.map +1 -0
  90. package/dist/analyzers/ledger/index.d.ts +14 -0
  91. package/dist/analyzers/ledger/index.js +116 -0
  92. package/dist/analyzers/ledger/index.js.map +1 -0
  93. package/dist/analyzers/ledger/types.d.ts +31 -0
  94. package/dist/analyzers/ledger/types.js +2 -0
  95. package/dist/analyzers/ledger/types.js.map +1 -0
  96. package/dist/analyzers/perf.d.ts +2 -0
  97. package/dist/analyzers/perf.js +106 -0
  98. package/dist/analyzers/perf.js.map +1 -0
  99. package/dist/analyzers/reliability.d.ts +22 -0
  100. package/dist/analyzers/reliability.js +339 -0
  101. package/dist/analyzers/reliability.js.map +1 -0
  102. package/dist/analyzers/routes.d.ts +17 -0
  103. package/dist/analyzers/routes.js +115 -0
  104. package/dist/analyzers/routes.js.map +1 -0
  105. package/dist/analyzers/security.d.ts +2 -0
  106. package/dist/analyzers/security.js +302 -0
  107. package/dist/analyzers/security.js.map +1 -0
  108. package/dist/analyzers/suiteRunner.d.ts +64 -0
  109. package/dist/analyzers/suiteRunner.js +381 -0
  110. package/dist/analyzers/suiteRunner.js.map +1 -0
  111. package/dist/analyzers/tests.d.ts +2 -0
  112. package/dist/analyzers/tests.js +215 -0
  113. package/dist/analyzers/tests.js.map +1 -0
  114. package/dist/analyzers/types.d.ts +203 -0
  115. package/dist/analyzers/types.js +2 -0
  116. package/dist/analyzers/types.js.map +1 -0
  117. package/dist/analyzers/util.d.ts +35 -0
  118. package/dist/analyzers/util.js +209 -0
  119. package/dist/analyzers/util.js.map +1 -0
  120. package/dist/ciCheckA.d.ts +2 -0
  121. package/dist/ciCheckA.js +5 -0
  122. package/dist/ciCheckA.js.map +1 -0
  123. package/dist/ciCheckB.d.ts +2 -0
  124. package/dist/ciCheckB.js +6 -0
  125. package/dist/ciCheckB.js.map +1 -0
  126. package/dist/cli.d.ts +2 -0
  127. package/dist/cli.js +65 -0
  128. package/dist/cli.js.map +1 -0
  129. package/dist/commands/budget.d.ts +33 -0
  130. package/dist/commands/budget.js +108 -0
  131. package/dist/commands/budget.js.map +1 -0
  132. package/dist/commands/ci.d.ts +14 -0
  133. package/dist/commands/ci.js +157 -0
  134. package/dist/commands/ci.js.map +1 -0
  135. package/dist/commands/demo.d.ts +2 -0
  136. package/dist/commands/demo.js +163 -0
  137. package/dist/commands/demo.js.map +1 -0
  138. package/dist/commands/digest.d.ts +8 -0
  139. package/dist/commands/digest.js +189 -0
  140. package/dist/commands/digest.js.map +1 -0
  141. package/dist/commands/doctor.d.ts +2 -0
  142. package/dist/commands/doctor.js +98 -0
  143. package/dist/commands/doctor.js.map +1 -0
  144. package/dist/commands/drive.d.ts +3 -0
  145. package/dist/commands/drive.js +170 -0
  146. package/dist/commands/drive.js.map +1 -0
  147. package/dist/commands/gate.d.ts +2 -0
  148. package/dist/commands/gate.js +136 -0
  149. package/dist/commands/gate.js.map +1 -0
  150. package/dist/commands/honesty.d.ts +2 -0
  151. package/dist/commands/honesty.js +182 -0
  152. package/dist/commands/honesty.js.map +1 -0
  153. package/dist/commands/inspect.d.ts +2 -0
  154. package/dist/commands/inspect.js +244 -0
  155. package/dist/commands/inspect.js.map +1 -0
  156. package/dist/commands/install.d.ts +2 -0
  157. package/dist/commands/install.js +81 -0
  158. package/dist/commands/install.js.map +1 -0
  159. package/dist/commands/integrity.d.ts +2 -0
  160. package/dist/commands/integrity.js +74 -0
  161. package/dist/commands/integrity.js.map +1 -0
  162. package/dist/commands/memory.d.ts +6 -0
  163. package/dist/commands/memory.js +90 -0
  164. package/dist/commands/memory.js.map +1 -0
  165. package/dist/commands/pen.d.ts +17 -0
  166. package/dist/commands/pen.js +158 -0
  167. package/dist/commands/pen.js.map +1 -0
  168. package/dist/commands/prompt.d.ts +2 -0
  169. package/dist/commands/prompt.js +37 -0
  170. package/dist/commands/prompt.js.map +1 -0
  171. package/dist/commands/readyCheck.d.ts +21 -0
  172. package/dist/commands/readyCheck.js +68 -0
  173. package/dist/commands/readyCheck.js.map +1 -0
  174. package/dist/commands/report.d.ts +2 -0
  175. package/dist/commands/report.js +48 -0
  176. package/dist/commands/report.js.map +1 -0
  177. package/dist/commands/repro.d.ts +3 -0
  178. package/dist/commands/repro.js +61 -0
  179. package/dist/commands/repro.js.map +1 -0
  180. package/dist/commands/scan.d.ts +27 -0
  181. package/dist/commands/scan.js +348 -0
  182. package/dist/commands/scan.js.map +1 -0
  183. package/dist/commands/share.d.ts +2 -0
  184. package/dist/commands/share.js +163 -0
  185. package/dist/commands/share.js.map +1 -0
  186. package/dist/commands/trends.d.ts +2 -0
  187. package/dist/commands/trends.js +103 -0
  188. package/dist/commands/trends.js.map +1 -0
  189. package/dist/commands/try.d.ts +12 -0
  190. package/dist/commands/try.js +208 -0
  191. package/dist/commands/try.js.map +1 -0
  192. package/dist/commands/verify.d.ts +44 -0
  193. package/dist/commands/verify.js +381 -0
  194. package/dist/commands/verify.js.map +1 -0
  195. package/dist/commands/watch.d.ts +10 -0
  196. package/dist/commands/watch.js +70 -0
  197. package/dist/commands/watch.js.map +1 -0
  198. package/dist/evidence.d.ts +37 -0
  199. package/dist/evidence.js +61 -0
  200. package/dist/evidence.js.map +1 -0
  201. package/dist/graph/correlate.d.ts +7 -0
  202. package/dist/graph/correlate.js +246 -0
  203. package/dist/graph/correlate.js.map +1 -0
  204. package/dist/graph/integrity.d.ts +22 -0
  205. package/dist/graph/integrity.js +39 -0
  206. package/dist/graph/integrity.js.map +1 -0
  207. package/dist/installer/targets.d.ts +23 -0
  208. package/dist/installer/targets.js +162 -0
  209. package/dist/installer/targets.js.map +1 -0
  210. package/dist/memory/store.d.ts +33 -0
  211. package/dist/memory/store.js +131 -0
  212. package/dist/memory/store.js.map +1 -0
  213. package/dist/pen/dynamic.d.ts +36 -0
  214. package/dist/pen/dynamic.js +622 -0
  215. package/dist/pen/dynamic.js.map +1 -0
  216. package/dist/pen/fix.d.ts +35 -0
  217. package/dist/pen/fix.js +239 -0
  218. package/dist/pen/fix.js.map +1 -0
  219. package/dist/pen/proof.d.ts +46 -0
  220. package/dist/pen/proof.js +112 -0
  221. package/dist/pen/proof.js.map +1 -0
  222. package/dist/pen/report.d.ts +11 -0
  223. package/dist/pen/report.js +258 -0
  224. package/dist/pen/report.js.map +1 -0
  225. package/dist/pen/static.d.ts +17 -0
  226. package/dist/pen/static.js +565 -0
  227. package/dist/pen/static.js.map +1 -0
  228. package/dist/pen/store.d.ts +11 -0
  229. package/dist/pen/store.js +36 -0
  230. package/dist/pen/store.js.map +1 -0
  231. package/dist/pen/types.d.ts +112 -0
  232. package/dist/pen/types.js +53 -0
  233. package/dist/pen/types.js.map +1 -0
  234. package/dist/report/format.d.ts +126 -0
  235. package/dist/report/format.js +706 -0
  236. package/dist/report/format.js.map +1 -0
  237. package/dist/report/score.d.ts +47 -0
  238. package/dist/report/score.js +164 -0
  239. package/dist/report/score.js.map +1 -0
  240. package/dist/repro/framework.d.ts +26 -0
  241. package/dist/repro/framework.js +224 -0
  242. package/dist/repro/framework.js.map +1 -0
  243. package/dist/repro/generate.d.ts +14 -0
  244. package/dist/repro/generate.js +669 -0
  245. package/dist/repro/generate.js.map +1 -0
  246. package/dist/repro/ids.d.ts +32 -0
  247. package/dist/repro/ids.js +175 -0
  248. package/dist/repro/ids.js.map +1 -0
  249. package/dist/repro/index.d.ts +24 -0
  250. package/dist/repro/index.js +69 -0
  251. package/dist/repro/index.js.map +1 -0
  252. package/dist/repro/pen.d.ts +26 -0
  253. package/dist/repro/pen.js +321 -0
  254. package/dist/repro/pen.js.map +1 -0
  255. package/dist/repro/run.d.ts +18 -0
  256. package/dist/repro/run.js +36 -0
  257. package/dist/repro/run.js.map +1 -0
  258. package/dist/sandbox/proxy.d.ts +41 -0
  259. package/dist/sandbox/proxy.js +231 -0
  260. package/dist/sandbox/proxy.js.map +1 -0
  261. package/dist/sandbox/startCmd.d.ts +24 -0
  262. package/dist/sandbox/startCmd.js +71 -0
  263. package/dist/sandbox/startCmd.js.map +1 -0
  264. package/dist/ui/spinner.d.ts +18 -0
  265. package/dist/ui/spinner.js +26 -0
  266. package/dist/ui/spinner.js.map +1 -0
  267. package/dist/verify/metrics.d.ts +13 -0
  268. package/dist/verify/metrics.js +72 -0
  269. package/dist/verify/metrics.js.map +1 -0
  270. package/package.json +68 -0
  271. package/scripts/cheat-demo.cjs +102 -0
  272. package/templates/ledger/preload.cjs +331 -0
  273. package/templates/pen/preload.cjs +196 -0
  274. package/templates/pitstop.prompt.md +371 -0
@@ -0,0 +1,108 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import boxen from "boxen";
4
+ import path from "node:path";
5
+ import fs from "node:fs";
6
+ import { readyCheck } from "./readyCheck.js";
7
+ function history(repo, glob) {
8
+ const dir = path.join(repo, ".pitstop");
9
+ if (!fs.existsSync(dir))
10
+ return [];
11
+ const re = new RegExp(`^${glob}$`);
12
+ const out = [];
13
+ for (const f of fs.readdirSync(dir)) {
14
+ if (!re.test(f))
15
+ continue;
16
+ try {
17
+ const data = JSON.parse(fs.readFileSync(path.join(dir, f), "utf8"));
18
+ const at = data.timestamp ?? f;
19
+ out.push({ at, data });
20
+ }
21
+ catch {
22
+ /* skip */
23
+ }
24
+ }
25
+ return out.sort((a, b) => a.at.localeCompare(b.at));
26
+ }
27
+ export function budget(repo) {
28
+ const scans = history(repo, "scan-.*\\.json");
29
+ const verifies = history(repo, "verify-.*\\.json");
30
+ const pens = history(repo, "pen-.*\\.json");
31
+ const ledgerRuns = fs.existsSync(path.join(repo, ".pitstop"))
32
+ ? fs.readdirSync(path.join(repo, ".pitstop")).filter((f) => /^ledger-evidence-.*\.json$/.test(f)).length
33
+ : 0;
34
+ const cacheDir = path.join(repo, ".pitstop", "cache");
35
+ const auditCacheHits = fs.existsSync(cacheDir)
36
+ ? fs.readdirSync(cacheDir).filter((f) => /^npm-audit-.*\.json$/.test(f)).length
37
+ : 0;
38
+ let reliabilityRuns = 0;
39
+ let testMs = 0;
40
+ let buildMs = 0;
41
+ for (const s of scans) {
42
+ const d = s.data;
43
+ reliabilityRuns += d.reliability?.runs ?? 0;
44
+ testMs += d.tests?.durationMs ?? 0;
45
+ buildMs += d.perf?.buildTimeMs ?? 0;
46
+ }
47
+ const totalComputeSeconds = Math.round((testMs + buildMs) / 1000);
48
+ return {
49
+ scans: {
50
+ count: scans.length,
51
+ reliabilityRuns,
52
+ testMs,
53
+ buildMs,
54
+ last: scans[scans.length - 1]?.at ?? "—",
55
+ },
56
+ verifies: { count: verifies.length, last: verifies[verifies.length - 1]?.at ?? "—" },
57
+ pens: { count: pens.length, last: pens[pens.length - 1]?.at ?? "—" },
58
+ ledgerRuns,
59
+ auditCacheHits,
60
+ totalComputeSeconds,
61
+ loopRuns: verifies.length,
62
+ };
63
+ }
64
+ export const budgetCmd = new Command("budget")
65
+ .description("Token-economy ledger: what the autonomous loop actually ran (scans, reliability runs, verifies, pen tests), " +
66
+ "how much wall-clock compute that cost, and what ready-check/--reuse would have saved. Honest proxy: the CLI " +
67
+ "cannot see model token counts.")
68
+ .argument("[repo]", "path to the repo", ".")
69
+ .option("--json", "print machine-readable JSON")
70
+ .action((repoArg, options) => {
71
+ const repo = path.resolve(repoArg);
72
+ const b = budget(repo);
73
+ const rc = readyCheck(repo);
74
+ if (options.json) {
75
+ console.log(JSON.stringify({ repo, ...b, readyCheck: rc }, null, 2));
76
+ return;
77
+ }
78
+ const fmtMs = (ms) => (ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`);
79
+ const lines = [];
80
+ lines.push(`${chalk.bold("Full scans")}: ${b.scans.count} (reliability runs: ${b.scans.reliabilityRuns} · tests: ${fmtMs(b.scans.testMs)} · builds: ${fmtMs(b.scans.buildMs)})`);
81
+ lines.push(`${chalk.bold("Verify runs")}: ${b.verifies.count} (last ${b.verifies.last})`);
82
+ lines.push(`${chalk.bold("Pen tests")}: ${b.pens.count} (last ${b.pens.last})`);
83
+ lines.push(`${chalk.bold("Ledger boots")}: ${b.ledgerRuns}`);
84
+ lines.push(`${chalk.bold("Audit cache files")}: ${b.auditCacheHits} (each = one npm-audit network round-trip saved)`);
85
+ lines.push("");
86
+ lines.push(`${chalk.bold("Wall-clock compute")}: ${fmtMs((b.scans.testMs + b.scans.buildMs))} spent on test/build runs (models cost tokens; machines cost seconds — this is the honest meter).`);
87
+ lines.push("");
88
+ if (rc.ready) {
89
+ lines.push(chalk.green("The tree is unchanged since the last scan — the next loop iteration should have used `scan --reuse`."));
90
+ }
91
+ else {
92
+ lines.push(chalk.yellow("The tree HAS changed since the last scan — a re-scan is legitimate spend."));
93
+ }
94
+ lines.push("");
95
+ lines.push(chalk.cyan("Cut the burn:"));
96
+ lines.push(` ready-check before every re-scan (exit 0 = reuse the baseline)`);
97
+ lines.push(` scan --reuse inside the loop; full scan only at the end`);
98
+ lines.push(` verify during iteration, full reliability runs only on the final pass`);
99
+ console.log(boxen(lines.join("\n"), {
100
+ title: " PITSTOP — Budget ",
101
+ titleAlignment: "center",
102
+ borderStyle: "round",
103
+ padding: 1,
104
+ borderColor: "cyan",
105
+ }));
106
+ });
107
+ export default budgetCmd;
108
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/commands/budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * `pitstop ci` — CI-mode, diagnostic-only analysis.
4
+ *
5
+ * Runs the same scan pipeline as `pitstop scan`, then (inside a PR, detected
6
+ * via GITHUB_BASE_REF) diffs the current branch's metrics against the base
7
+ * branch's snapshot, and prints ONE GitHub-flavored markdown block meant to be
8
+ * posted as a PR comment.
9
+ *
10
+ * It is deliberately READ-ONLY: it never commits, never creates branches, never
11
+ * edits files. Autonomous fixing only ever happens through the /pitstop slash
12
+ * command in an interactive coding agent, never here.
13
+ */
14
+ export declare const ci: Command;
@@ -0,0 +1,157 @@
1
+ import { Command } from "commander";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import { runAllAnalyzers } from "../analyzers/index.js";
6
+ import { correlate } from "../graph/correlate.js";
7
+ import { runScan } from "./scan.js";
8
+ import { safeExec } from "../analyzers/util.js";
9
+ import { buildModel, renderMarkdown, } from "../report/format.js";
10
+ import { classifyRisk, deltasOf, metricsOf } from "../verify/metrics.js";
11
+ /**
12
+ * `pitstop ci` — CI-mode, diagnostic-only analysis.
13
+ *
14
+ * Runs the same scan pipeline as `pitstop scan`, then (inside a PR, detected
15
+ * via GITHUB_BASE_REF) diffs the current branch's metrics against the base
16
+ * branch's snapshot, and prints ONE GitHub-flavored markdown block meant to be
17
+ * posted as a PR comment.
18
+ *
19
+ * It is deliberately READ-ONLY: it never commits, never creates branches, never
20
+ * edits files. Autonomous fixing only ever happens through the /pitstop slash
21
+ * command in an interactive coding agent, never here.
22
+ */
23
+ export const ci = new Command("ci")
24
+ .description("CI-mode scan: run scan + verify vs the base branch (PR) and print a markdown report for PR comments. " +
25
+ "pitstop ci is diagnostic-only; use the /pitstop slash command locally for autonomous fixes.")
26
+ .argument("[repo]", "path to the repo to analyze (defaults to cwd)", ".")
27
+ .action(async (repoArg) => {
28
+ const repo = path.resolve(repoArg);
29
+ const baseRef = process.env.GITHUB_BASE_REF?.trim() || "";
30
+ console.error(`[pitstop ci] scanning ${repo}${baseRef ? ` vs base \`${baseRef}\`` : ""}`);
31
+ let headResult;
32
+ let baseResult = null;
33
+ let baseSnapshot = null;
34
+ try {
35
+ const run = await runScan(repo);
36
+ headResult = run.result;
37
+ }
38
+ catch (err) {
39
+ console.error(`[pitstop ci] scan failed: ${err?.message ?? err}`);
40
+ process.exitCode = 1;
41
+ return;
42
+ }
43
+ // Verify against the base branch in a PR context (read-only, via a temp snapshot).
44
+ if (baseRef) {
45
+ baseSnapshot = fetchBaseSnapshot(repo, baseRef);
46
+ if (baseSnapshot) {
47
+ try {
48
+ baseResult = await analyzeDir(baseSnapshot);
49
+ }
50
+ catch (err) {
51
+ console.error(`[pitstop ci] base-branch analysis failed: ${err?.message ?? err}`);
52
+ baseResult = null;
53
+ }
54
+ finally {
55
+ try {
56
+ fs.rmSync(baseSnapshot, { recursive: true, force: true });
57
+ }
58
+ catch {
59
+ /* best-effort cleanup */
60
+ }
61
+ }
62
+ }
63
+ }
64
+ const model = buildModel(repo);
65
+ if (baseResult) {
66
+ const baseline = metricsOf(baseResult);
67
+ const current = metricsOf(headResult);
68
+ const deltas = deltasOf(baseline, current);
69
+ const risk = classifyRisk(baseline, current, deltas);
70
+ const verify = {
71
+ timestamp: new Date().toISOString(),
72
+ repo,
73
+ baselineTimestamp: baseResult.timestamp,
74
+ risk,
75
+ exitCode: risk === "High" ? 1 : 0,
76
+ deltas,
77
+ baseline,
78
+ current,
79
+ };
80
+ model.latestVerify = verify;
81
+ model.hasVerify = true;
82
+ model.verifiesCount = Math.max(model.verifiesCount, 1);
83
+ }
84
+ const headerNote = buildHeaderNote(baseRef, baseResult !== null);
85
+ const markdown = renderMarkdown(model, {
86
+ clustersFirst: true,
87
+ headerNote,
88
+ title: "CI Report",
89
+ });
90
+ console.log(markdown);
91
+ });
92
+ function buildHeaderNote(baseRef, hasBase) {
93
+ const repo = process.env.GITHUB_REPOSITORY ?? "";
94
+ const head = process.env.GITHUB_HEAD_REF ?? "";
95
+ const ref = process.env.GITHUB_REF ?? "";
96
+ const bits = [];
97
+ if (repo)
98
+ bits.push(`repo \`${repo}\``);
99
+ if (head)
100
+ bits.push(`head \`${head}\``);
101
+ if (ref && !head)
102
+ bits.push(`ref \`${ref}\``);
103
+ if (baseRef) {
104
+ bits.push(`base \`${baseRef}\``);
105
+ bits.push(hasBase ? "verify: diff vs base branch" : "base snapshot unavailable — no diff");
106
+ }
107
+ else {
108
+ bits.push("no GITHUB_BASE_REF — not a PR; scan only");
109
+ }
110
+ bits.push("diagnostic-only, read-only");
111
+ return bits.join(" · ");
112
+ }
113
+ async function analyzeDir(dir) {
114
+ const result = await runAllAnalyzers(dir);
115
+ const { clusters } = correlate(dir, result);
116
+ result.clusters = clusters;
117
+ return result;
118
+ }
119
+ /**
120
+ * Fetch a clean read-only snapshot of the base branch into a temp dir using
121
+ * only `git` (never touches the working tree, never creates branches, and no
122
+ * shell pipeline — `tar` is not guaranteed on Windows). The base commit is
123
+ * fetched into a fresh repo from the already-fetched local clone, so no
124
+ * network round trip is needed. Returns null on any failure so CI degrades to
125
+ * a scan-only report.
126
+ */
127
+ function fetchBaseSnapshot(repo, baseRef) {
128
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "pitstop-ci-base-"));
129
+ const fetch = safeExec("git", ["fetch", "--depth=1", "origin", baseRef], repo, 180000);
130
+ if (fetch.code !== 0) {
131
+ console.error(`[pitstop ci] could not fetch origin/${baseRef}: ${fetch.stderr.trim() || fetch.stdout.trim()}`);
132
+ return null;
133
+ }
134
+ const rev = safeExec("git", ["rev-parse", `origin/${baseRef}`], repo, 30000);
135
+ const commit = rev.stdout.trim();
136
+ if (!commit) {
137
+ console.error(`[pitstop ci] could not resolve origin/${baseRef}`);
138
+ return null;
139
+ }
140
+ const init = safeExec("git", ["init", "-q"], tmp, 30000);
141
+ if (init.code !== 0)
142
+ return null;
143
+ // Fetch the exact base commit from the local repo (local transport can fetch
144
+ // an arbitrary object id), then check it out detached — a pure-git snapshot.
145
+ const pull = safeExec("git", ["fetch", "--depth=1", repo, commit], tmp, 180000);
146
+ if (pull.code !== 0) {
147
+ console.error(`[pitstop ci] could not extract base snapshot: ${pull.stderr.trim() || pull.stdout.trim()}`);
148
+ return null;
149
+ }
150
+ const co = safeExec("git", ["checkout", "-q", "FETCH_HEAD"], tmp, 60000);
151
+ if (co.code !== 0) {
152
+ console.error(`[pitstop ci] could not check out base snapshot: ${co.stderr.trim()}`);
153
+ return null;
154
+ }
155
+ return tmp;
156
+ }
157
+ //# sourceMappingURL=ci.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/commands/ci.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const demo: Command;
@@ -0,0 +1,163 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import { fileURLToPath } from "node:url";
7
+ import { safeExec, safeExecAsync } from "../analyzers/util.js";
8
+ import { runScan, renderBox } from "./scan.js";
9
+ import { createSpinner } from "../ui/spinner.js";
10
+ /**
11
+ * `pitstop demo` — the first-touch wow, kept self-contained on purpose:
12
+ *
13
+ * - NO writes outside the OS temp dir (+ a node_modules cache under
14
+ * ~/.pitstop/cache so repeat demos skip the registry entirely). It never
15
+ * installs slash commands into the user's tool configs — that stays an
16
+ * explicit, user-invoked `pitstop install` — so a demo cannot surprise you
17
+ * with files in ~/.claude etc.
18
+ * - NO npm install in the hot path. node_modules is linked from (1) the
19
+ * fixture's own checkout, (2) the user-level cache, and only as a last
20
+ * resort (3) a one-time cached install with --no-audit --no-fund. A directory
21
+ * junction/symlink is used where the platform allows it, because physically
22
+ * copying ~25MB of jest on Windows costs ~15s of Defender scanning.
23
+ */
24
+ function repoRoot() {
25
+ return path.resolve(fileURLToPath(new URL("../..", import.meta.url)));
26
+ }
27
+ /** Link (junction on Windows, symlink elsewhere) `candidate` -> `dest`; never throws. */
28
+ function linkModules(candidate, destPath) {
29
+ if (!fs.existsSync(candidate))
30
+ return false;
31
+ try {
32
+ if (process.platform === "win32") {
33
+ fs.symlinkSync(candidate, destPath, "junction");
34
+ }
35
+ else {
36
+ fs.symlinkSync(candidate, destPath, "dir");
37
+ }
38
+ return true;
39
+ }
40
+ catch {
41
+ /* platform/permission — fall back to a physical copy */
42
+ }
43
+ try {
44
+ fs.cpSync(candidate, destPath, { recursive: true });
45
+ return fs.existsSync(destPath);
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ /** Resolve node_modules for the temp demo: cache → fixture → one-time cached install. */
52
+ async function ensureDeps(demoName, src, tmp) {
53
+ const cacheRoot = path.join(os.homedir(), ".pitstop", "cache", demoName);
54
+ const cacheModules = path.join(cacheRoot, "node_modules");
55
+ const target = path.join(tmp, "node_modules");
56
+ // 1) A ready copy — user cache first (stable), then the fixture's own checkout.
57
+ for (const candidate of [cacheModules, path.join(src, "node_modules")]) {
58
+ if (fs.existsSync(candidate) && linkModules(candidate, target))
59
+ return true;
60
+ }
61
+ // 2) One-time install INTO the cache (never the repo's fixture, so the
62
+ // checkout stays pristine), then link. --no-audit/--no-fund: it is a
63
+ // manually-triggered demo, and every repeat run hits the cache instead.
64
+ try {
65
+ fs.mkdirSync(cacheRoot, { recursive: true });
66
+ fs.copyFileSync(path.join(src, "package.json"), path.join(cacheRoot, "package.json"));
67
+ const lock = path.join(src, "package-lock.json");
68
+ if (fs.existsSync(lock))
69
+ fs.copyFileSync(lock, path.join(cacheRoot, "package-lock.json"));
70
+ }
71
+ catch {
72
+ /* ignore copy errors — the install will fail loudly if the manifest is missing */
73
+ }
74
+ const install = await safeExecAsync("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], cacheRoot, 240000);
75
+ if (install.code !== 0)
76
+ return false;
77
+ return linkModules(cacheModules, target);
78
+ }
79
+ export const demo = new Command("demo")
80
+ .description("Recreate an intentionally-broken OpenPitStop demo repo in a fresh temp dir (default: " +
81
+ "demo-repo, or pass demo-repo-integrity / demo-repo-fintech / demo-repo-generators), " +
82
+ "initialize git, and scan it RIGHT NOW so you see the boxed report without any setup. " +
83
+ "Self-contained: nothing is written outside the OS temp dir (slash-command install is " +
84
+ "a separate, explicit step).")
85
+ .argument("[demo]", "demo fixture directory name (default: demo-repo)", "demo-repo")
86
+ .action(async (demoArg) => {
87
+ const repoRootDir = repoRoot();
88
+ const demoName = path.basename(demoArg);
89
+ const src = path.join(repoRootDir, demoName);
90
+ if (!fs.existsSync(src)) {
91
+ console.log(`demo repo ${demoName} not found at ${src}`);
92
+ return;
93
+ }
94
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "pitstop-demo-"));
95
+ fs.cpSync(src, tmp, { recursive: true, filter: (p) => !/node_modules$/.test(p) });
96
+ // A fixture's checked-in .pitstop records a previous repo path and stale
97
+ // baselines — wipe those so the temp repo starts clean, but KEEP the cache
98
+ // dir (npm-audit JSON + jest cache) so the first demo scan is fast.
99
+ const pitstopDir = path.join(tmp, ".pitstop");
100
+ if (fs.existsSync(pitstopDir)) {
101
+ for (const f of fs.readdirSync(pitstopDir)) {
102
+ if (f === "cache")
103
+ continue;
104
+ try {
105
+ fs.rmSync(path.join(pitstopDir, f), { recursive: true, force: true });
106
+ }
107
+ catch {
108
+ /* best-effort */
109
+ }
110
+ }
111
+ }
112
+ // Deps: source → cache → one-time cached install. If we get here without
113
+ // node_modules, tests/reliability/perf print "skipped" and the box still
114
+ // ships the other analyzers — the demo degrades, it doesn't hang.
115
+ const ready = await ensureDeps(demoName, src, tmp);
116
+ if (ready) {
117
+ console.log(chalk.dim("demo deps ready (cached — no registry hit)."));
118
+ }
119
+ else {
120
+ console.log(chalk.yellow("npm install did not complete — tests/reliability/perf will print `skipped`; " +
121
+ "the rest of the box still runs."));
122
+ }
123
+ // The autonomous loop (branch, revert, commit) and the verify integrity gate
124
+ // both need a git repo. Initialize one and commit a clean baseline so the
125
+ // fix loop diffs against it.
126
+ const init = safeExec("git", ["init"], tmp);
127
+ if (init.code !== 0) {
128
+ console.log(chalk.yellow("git init failed — the integrity gate will not be able to diff fixes."));
129
+ }
130
+ else {
131
+ safeExec("git", ["config", "user.email", "pitstop@demo.local"], tmp);
132
+ safeExec("git", ["config", "user.name", "OpenPitStop Demo"], tmp);
133
+ const add = safeExec("git", ["add", "-A"], tmp);
134
+ if (add.code !== 0) {
135
+ console.log(chalk.yellow("git add failed — baseline commit skipped."));
136
+ }
137
+ else {
138
+ const commit = safeExec("git", ["commit", "-m", "demo baseline"], tmp);
139
+ console.log(commit.code === 0
140
+ ? chalk.dim("git baseline committed (integrity gate will diff fixes against it).")
141
+ : chalk.yellow("git commit failed — verify's integrity gate will not see a baseline."));
142
+ }
143
+ }
144
+ // The wow moment: scan the seeded-broken demo repo RIGHT NOW and show the
145
+ // boxed report, so a first-time user sees the whole product without needing
146
+ // an AI tool, a browser tab, or any setup. Flaky detection is trimmed to 1
147
+ // suite run so the demo lands fast.
148
+ const spin = createSpinner("Scanning the demo repo (this is the report your agent will see)");
149
+ try {
150
+ const { result } = await runScan(tmp, { reliabilityRuns: 1 });
151
+ spin.succeed("Demo scan complete");
152
+ console.log("\n" + renderBox(result));
153
+ }
154
+ catch (err) {
155
+ spin.fail("Demo scan failed");
156
+ console.log(chalk.yellow(`could not scan the demo repo: ${err?.message ?? err}`));
157
+ }
158
+ console.log(`\n${chalk.bold("Next:")} cd ${tmp}, open it in Claude Code/Cursor/OpenCode, type /pitstop, hit enter.\n` +
159
+ `The agent will fix the findings above, cluster by cluster, and loop until the score is clean.` +
160
+ `\n(To register the /pitstop slash command in your tools, run \`pitstop install\` in that repo — ` +
161
+ `it writes into your tool configs, so it is never done silently by the demo.)`);
162
+ });
163
+ //# sourceMappingURL=demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo.js","sourceRoot":"","sources":["../../src/commands/demo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * `pitstop digest` — the shareable progress story. Reads the `.pitstop`
4
+ * history and answers "what happened to this repo since <window>?" for humans:
5
+ * score movement, what got fixed, verifies/gates run, cheat attempts caught,
6
+ * flakiest tests, and what's still open.
7
+ */
8
+ export declare const digest: Command;