@tangle-network/browser-agent-driver 0.30.0 → 0.32.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 (252) hide show
  1. package/dist/brain/index.d.ts +12 -0
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +36 -8
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-ack-patch.d.ts +39 -0
  6. package/dist/cli-ack-patch.d.ts.map +1 -0
  7. package/dist/cli-ack-patch.js +47 -0
  8. package/dist/cli-ack-patch.js.map +1 -0
  9. package/dist/cli-design-audit.d.ts +12 -0
  10. package/dist/cli-design-audit.d.ts.map +1 -1
  11. package/dist/cli-design-audit.js +78 -0
  12. package/dist/cli-design-audit.js.map +1 -1
  13. package/dist/cli-jobs.d.ts +13 -0
  14. package/dist/cli-jobs.d.ts.map +1 -0
  15. package/dist/cli-jobs.js +253 -0
  16. package/dist/cli-jobs.js.map +1 -0
  17. package/dist/cli-patterns.d.ts +26 -0
  18. package/dist/cli-patterns.d.ts.map +1 -0
  19. package/dist/cli-patterns.js +49 -0
  20. package/dist/cli-patterns.js.map +1 -0
  21. package/dist/cli-reports.d.ts +12 -0
  22. package/dist/cli-reports.d.ts.map +1 -0
  23. package/dist/cli-reports.js +97 -0
  24. package/dist/cli-reports.js.map +1 -0
  25. package/dist/cli.js +29 -1
  26. package/dist/cli.js.map +1 -1
  27. package/dist/design/audit/attribution/aggregate.d.ts +16 -0
  28. package/dist/design/audit/attribution/aggregate.d.ts.map +1 -0
  29. package/dist/design/audit/attribution/aggregate.js +81 -0
  30. package/dist/design/audit/attribution/aggregate.js.map +1 -0
  31. package/dist/design/audit/attribution/store.d.ts +36 -0
  32. package/dist/design/audit/attribution/store.d.ts.map +1 -0
  33. package/dist/design/audit/attribution/store.js +108 -0
  34. package/dist/design/audit/attribution/store.js.map +1 -0
  35. package/dist/design/audit/attribution/types.d.ts +13 -0
  36. package/dist/design/audit/attribution/types.d.ts.map +1 -0
  37. package/dist/design/audit/attribution/types.js +10 -0
  38. package/dist/design/audit/attribution/types.js.map +1 -0
  39. package/dist/design/audit/build-result.d.ts +68 -0
  40. package/dist/design/audit/build-result.d.ts.map +1 -0
  41. package/dist/design/audit/build-result.js +243 -0
  42. package/dist/design/audit/build-result.js.map +1 -0
  43. package/dist/design/audit/classify-ensemble.d.ts +46 -0
  44. package/dist/design/audit/classify-ensemble.d.ts.map +1 -0
  45. package/dist/design/audit/classify-ensemble.js +207 -0
  46. package/dist/design/audit/classify-ensemble.js.map +1 -0
  47. package/dist/design/audit/ethics/check.d.ts +59 -0
  48. package/dist/design/audit/ethics/check.d.ts.map +1 -0
  49. package/dist/design/audit/ethics/check.js +137 -0
  50. package/dist/design/audit/ethics/check.js.map +1 -0
  51. package/dist/design/audit/ethics/loader.d.ts +21 -0
  52. package/dist/design/audit/ethics/loader.d.ts.map +1 -0
  53. package/dist/design/audit/ethics/loader.js +207 -0
  54. package/dist/design/audit/ethics/loader.js.map +1 -0
  55. package/dist/design/audit/ethics/rules/finance.yaml +37 -0
  56. package/dist/design/audit/ethics/rules/kids.yaml +37 -0
  57. package/dist/design/audit/ethics/rules/legal.yaml +35 -0
  58. package/dist/design/audit/ethics/rules/medical.yaml +36 -0
  59. package/dist/design/audit/evaluate.d.ts.map +1 -1
  60. package/dist/design/audit/evaluate.js +4 -1
  61. package/dist/design/audit/evaluate.js.map +1 -1
  62. package/dist/design/audit/first-principles-mode.d.ts +42 -0
  63. package/dist/design/audit/first-principles-mode.d.ts.map +1 -0
  64. package/dist/design/audit/first-principles-mode.js +77 -0
  65. package/dist/design/audit/first-principles-mode.js.map +1 -0
  66. package/dist/design/audit/modality/android.d.ts +14 -0
  67. package/dist/design/audit/modality/android.d.ts.map +1 -0
  68. package/dist/design/audit/modality/android.js +18 -0
  69. package/dist/design/audit/modality/android.js.map +1 -0
  70. package/dist/design/audit/modality/html.d.ts +22 -0
  71. package/dist/design/audit/modality/html.d.ts.map +1 -0
  72. package/dist/design/audit/modality/html.js +51 -0
  73. package/dist/design/audit/modality/html.js.map +1 -0
  74. package/dist/design/audit/modality/index.d.ts +8 -0
  75. package/dist/design/audit/modality/index.d.ts.map +1 -0
  76. package/dist/design/audit/modality/index.js +15 -0
  77. package/dist/design/audit/modality/index.js.map +1 -0
  78. package/dist/design/audit/modality/ios.d.ts +16 -0
  79. package/dist/design/audit/modality/ios.d.ts.map +1 -0
  80. package/dist/design/audit/modality/ios.js +19 -0
  81. package/dist/design/audit/modality/ios.js.map +1 -0
  82. package/dist/design/audit/modality/types.d.ts +9 -0
  83. package/dist/design/audit/modality/types.d.ts.map +1 -0
  84. package/dist/design/audit/modality/types.js +9 -0
  85. package/dist/design/audit/modality/types.js.map +1 -0
  86. package/dist/design/audit/patches/generate.d.ts +45 -0
  87. package/dist/design/audit/patches/generate.d.ts.map +1 -0
  88. package/dist/design/audit/patches/generate.js +161 -0
  89. package/dist/design/audit/patches/generate.js.map +1 -0
  90. package/dist/design/audit/patches/index.d.ts +8 -0
  91. package/dist/design/audit/patches/index.d.ts.map +1 -0
  92. package/dist/design/audit/patches/index.js +5 -0
  93. package/dist/design/audit/patches/index.js.map +1 -0
  94. package/dist/design/audit/patches/parse.d.ts +29 -0
  95. package/dist/design/audit/patches/parse.d.ts.map +1 -0
  96. package/dist/design/audit/patches/parse.js +153 -0
  97. package/dist/design/audit/patches/parse.js.map +1 -0
  98. package/dist/design/audit/patches/render.d.ts +20 -0
  99. package/dist/design/audit/patches/render.d.ts.map +1 -0
  100. package/dist/design/audit/patches/render.js +55 -0
  101. package/dist/design/audit/patches/render.js.map +1 -0
  102. package/dist/design/audit/patches/severity-enforcement.d.ts +23 -0
  103. package/dist/design/audit/patches/severity-enforcement.d.ts.map +1 -0
  104. package/dist/design/audit/patches/severity-enforcement.js +42 -0
  105. package/dist/design/audit/patches/severity-enforcement.js.map +1 -0
  106. package/dist/design/audit/patches/validate.d.ts +40 -0
  107. package/dist/design/audit/patches/validate.d.ts.map +1 -0
  108. package/dist/design/audit/patches/validate.js +60 -0
  109. package/dist/design/audit/patches/validate.js.map +1 -0
  110. package/dist/design/audit/patterns/match.d.ts +24 -0
  111. package/dist/design/audit/patterns/match.d.ts.map +1 -0
  112. package/dist/design/audit/patterns/match.js +48 -0
  113. package/dist/design/audit/patterns/match.js.map +1 -0
  114. package/dist/design/audit/patterns/mine.d.ts +31 -0
  115. package/dist/design/audit/patterns/mine.d.ts.map +1 -0
  116. package/dist/design/audit/patterns/mine.js +35 -0
  117. package/dist/design/audit/patterns/mine.js.map +1 -0
  118. package/dist/design/audit/patterns/store.d.ts +14 -0
  119. package/dist/design/audit/patterns/store.d.ts.map +1 -0
  120. package/dist/design/audit/patterns/store.js +53 -0
  121. package/dist/design/audit/patterns/store.js.map +1 -0
  122. package/dist/design/audit/patterns/types.d.ts +53 -0
  123. package/dist/design/audit/patterns/types.d.ts.map +1 -0
  124. package/dist/design/audit/patterns/types.js +13 -0
  125. package/dist/design/audit/patterns/types.js.map +1 -0
  126. package/dist/design/audit/pipeline.d.ts +12 -0
  127. package/dist/design/audit/pipeline.d.ts.map +1 -1
  128. package/dist/design/audit/pipeline.js +81 -5
  129. package/dist/design/audit/pipeline.js.map +1 -1
  130. package/dist/design/audit/rubric/anchor-loader.d.ts +44 -0
  131. package/dist/design/audit/rubric/anchor-loader.d.ts.map +1 -0
  132. package/dist/design/audit/rubric/anchor-loader.js +210 -0
  133. package/dist/design/audit/rubric/anchor-loader.js.map +1 -0
  134. package/dist/design/audit/rubric/anchors/blog.yaml +33 -0
  135. package/dist/design/audit/rubric/anchors/dashboard.yaml +35 -0
  136. package/dist/design/audit/rubric/anchors/docs.yaml +35 -0
  137. package/dist/design/audit/rubric/anchors/ecommerce.yaml +33 -0
  138. package/dist/design/audit/rubric/anchors/marketing.yaml +34 -0
  139. package/dist/design/audit/rubric/anchors/saas-app.yaml +38 -0
  140. package/dist/design/audit/rubric/anchors/social.yaml +33 -0
  141. package/dist/design/audit/rubric/anchors/tool.yaml +33 -0
  142. package/dist/design/audit/rubric/anchors/utility.yaml +33 -0
  143. package/dist/design/audit/rubric/fragments/audience-clinician.md +42 -0
  144. package/dist/design/audit/rubric/fragments/audience-developer.md +40 -0
  145. package/dist/design/audit/rubric/fragments/audience-kids.md +35 -0
  146. package/dist/design/audit/rubric/fragments/audience-vulnerability-minor-facing.md +37 -0
  147. package/dist/design/audit/rubric/fragments/first-principles.md +65 -0
  148. package/dist/design/audit/rubric/fragments/modality-mobile.md +39 -0
  149. package/dist/design/audit/rubric/fragments/modality-tablet.md +35 -0
  150. package/dist/design/audit/rubric/fragments/regulatory-coppa.md +32 -0
  151. package/dist/design/audit/rubric/fragments/regulatory-gdpr.md +33 -0
  152. package/dist/design/audit/rubric/fragments/regulatory-hipaa.md +36 -0
  153. package/dist/design/audit/rubric/loader.d.ts +26 -6
  154. package/dist/design/audit/rubric/loader.d.ts.map +1 -1
  155. package/dist/design/audit/rubric/loader.js +45 -26
  156. package/dist/design/audit/rubric/loader.js.map +1 -1
  157. package/dist/design/audit/rubric/rollup-weights.d.ts +25 -0
  158. package/dist/design/audit/rubric/rollup-weights.d.ts.map +1 -0
  159. package/dist/design/audit/rubric/rollup-weights.js +51 -0
  160. package/dist/design/audit/rubric/rollup-weights.js.map +1 -0
  161. package/dist/design/audit/score-types.d.ts +431 -0
  162. package/dist/design/audit/score-types.d.ts.map +1 -0
  163. package/dist/design/audit/score-types.js +26 -0
  164. package/dist/design/audit/score-types.js.map +1 -0
  165. package/dist/design/audit/score.d.ts +49 -0
  166. package/dist/design/audit/score.d.ts.map +1 -0
  167. package/dist/design/audit/score.js +211 -0
  168. package/dist/design/audit/score.js.map +1 -0
  169. package/dist/design/audit/types.d.ts +28 -0
  170. package/dist/design/audit/types.d.ts.map +1 -1
  171. package/dist/discover/index.d.ts +16 -0
  172. package/dist/discover/index.d.ts.map +1 -0
  173. package/dist/discover/index.js +25 -0
  174. package/dist/discover/index.js.map +1 -0
  175. package/dist/discover/wayback.d.ts +49 -0
  176. package/dist/discover/wayback.d.ts.map +1 -0
  177. package/dist/discover/wayback.js +123 -0
  178. package/dist/discover/wayback.js.map +1 -0
  179. package/dist/jobs/anti-bot.d.ts +19 -0
  180. package/dist/jobs/anti-bot.d.ts.map +1 -0
  181. package/dist/jobs/anti-bot.js +64 -0
  182. package/dist/jobs/anti-bot.js.map +1 -0
  183. package/dist/jobs/cost-estimate.d.ts +12 -0
  184. package/dist/jobs/cost-estimate.d.ts.map +1 -0
  185. package/dist/jobs/cost-estimate.js +21 -0
  186. package/dist/jobs/cost-estimate.js.map +1 -0
  187. package/dist/jobs/cost-history.d.ts +19 -0
  188. package/dist/jobs/cost-history.d.ts.map +1 -0
  189. package/dist/jobs/cost-history.js +42 -0
  190. package/dist/jobs/cost-history.js.map +1 -0
  191. package/dist/jobs/index.d.ts +31 -0
  192. package/dist/jobs/index.d.ts.map +1 -0
  193. package/dist/jobs/index.js +37 -0
  194. package/dist/jobs/index.js.map +1 -0
  195. package/dist/jobs/orchestrator.d.ts +42 -0
  196. package/dist/jobs/orchestrator.d.ts.map +1 -0
  197. package/dist/jobs/orchestrator.js +282 -0
  198. package/dist/jobs/orchestrator.js.map +1 -0
  199. package/dist/jobs/queue.d.ts +45 -0
  200. package/dist/jobs/queue.d.ts.map +1 -0
  201. package/dist/jobs/queue.js +114 -0
  202. package/dist/jobs/queue.js.map +1 -0
  203. package/dist/jobs/retry.d.ts +36 -0
  204. package/dist/jobs/retry.d.ts.map +1 -0
  205. package/dist/jobs/retry.js +77 -0
  206. package/dist/jobs/retry.js.map +1 -0
  207. package/dist/jobs/store.d.ts +31 -0
  208. package/dist/jobs/store.d.ts.map +1 -0
  209. package/dist/jobs/store.js +92 -0
  210. package/dist/jobs/store.js.map +1 -0
  211. package/dist/jobs/types.d.ts +106 -0
  212. package/dist/jobs/types.d.ts.map +1 -0
  213. package/dist/jobs/types.js +13 -0
  214. package/dist/jobs/types.js.map +1 -0
  215. package/dist/reports/aggregate.d.ts +38 -0
  216. package/dist/reports/aggregate.d.ts.map +1 -0
  217. package/dist/reports/aggregate.js +145 -0
  218. package/dist/reports/aggregate.js.map +1 -0
  219. package/dist/reports/index.d.ts +21 -0
  220. package/dist/reports/index.d.ts.map +1 -0
  221. package/dist/reports/index.js +15 -0
  222. package/dist/reports/index.js.map +1 -0
  223. package/dist/reports/narrate.d.ts +19 -0
  224. package/dist/reports/narrate.d.ts.map +1 -0
  225. package/dist/reports/narrate.js +40 -0
  226. package/dist/reports/narrate.js.map +1 -0
  227. package/dist/reports/templates.d.ts +43 -0
  228. package/dist/reports/templates.d.ts.map +1 -0
  229. package/dist/reports/templates.js +200 -0
  230. package/dist/reports/templates.js.map +1 -0
  231. package/dist/reports/tokens.d.ts +69 -0
  232. package/dist/reports/tokens.d.ts.map +1 -0
  233. package/dist/reports/tokens.js +74 -0
  234. package/dist/reports/tokens.js.map +1 -0
  235. package/dist/reports/tools.d.ts +76 -0
  236. package/dist/reports/tools.d.ts.map +1 -0
  237. package/dist/reports/tools.js +205 -0
  238. package/dist/reports/tools.js.map +1 -0
  239. package/dist/reports/types.d.ts +51 -0
  240. package/dist/reports/types.d.ts.map +1 -0
  241. package/dist/reports/types.js +9 -0
  242. package/dist/reports/types.js.map +1 -0
  243. package/dist/run-state.d.ts +36 -1
  244. package/dist/run-state.d.ts.map +1 -1
  245. package/dist/run-state.js +36 -1
  246. package/dist/run-state.js.map +1 -1
  247. package/dist/runner/runner.d.ts.map +1 -1
  248. package/dist/runner/runner.js +73 -3
  249. package/dist/runner/runner.js.map +1 -1
  250. package/dist/types.d.ts +7 -0
  251. package/dist/types.d.ts.map +1 -1
  252. package/package.json +5 -1
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Pre-flight cost estimate — refuses to silently spend $1k.
3
+ *
4
+ * The numbers here are deliberately conservative and based on observed
5
+ * production telemetry for `claude-code` provider with sonnet at the time of
6
+ * writing. If the assumptions drift, only one constant changes.
7
+ */
8
+ /** Average USD per single-page audit. Tuned for sonnet via claude-code provider, 1 audit pass. */
9
+ export const DEFAULT_PER_AUDIT_USD = 0.4;
10
+ export function estimateCost(spec, targetCount, perAuditUSD = DEFAULT_PER_AUDIT_USD) {
11
+ const pages = Math.max(spec.audit?.pages ?? 1, 1);
12
+ const estimatedTotalUSD = targetCount * pages * perAuditUSD;
13
+ const exceedsCap = typeof spec.maxCostUSD === 'number' && estimatedTotalUSD > spec.maxCostUSD;
14
+ return {
15
+ targetCount,
16
+ perAuditUSD: perAuditUSD * pages,
17
+ estimatedTotalUSD,
18
+ exceedsCap,
19
+ };
20
+ }
21
+ //# sourceMappingURL=cost-estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-estimate.js","sourceRoot":"","sources":["../../src/jobs/cost-estimate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,kGAAkG;AAClG,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAA;AAExC,MAAM,UAAU,YAAY,CAAC,IAAa,EAAE,WAAmB,EAAE,WAAW,GAAG,qBAAqB;IAClG,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IACjD,MAAM,iBAAiB,GAAG,WAAW,GAAG,KAAK,GAAG,WAAW,CAAA;IAC3D,MAAM,UAAU,GAAG,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAA;IAC7F,OAAO;QACL,WAAW;QACX,WAAW,EAAE,WAAW,GAAG,KAAK;QAChC,iBAAiB;QACjB,UAAU;KACX,CAAA;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Adaptive cost estimate from historical jobs. The default flat
3
+ * `DEFAULT_PER_AUDIT_USD` is still a fine starting point for a fresh user,
4
+ * but once 3+ jobs have completed we can do better: averaging the actual
5
+ * per-target cost across recent jobs is closer to ground truth, especially
6
+ * once ethics / first-principles modes start firing differently per target.
7
+ *
8
+ * Pure function of `~/.bad/jobs/` records — no telemetry endpoint required.
9
+ */
10
+ export interface AdaptiveCostStats {
11
+ perAuditUSD: number;
12
+ source: 'history' | 'default';
13
+ /** Number of historical job records the estimate was averaged over. */
14
+ jobsObserved: number;
15
+ /** Number of audited targets the estimate was averaged over. */
16
+ targetsObserved: number;
17
+ }
18
+ export declare function computePerAuditFromHistory(dir?: string): AdaptiveCostStats;
19
+ //# sourceMappingURL=cost-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-history.d.ts","sourceRoot":"","sources":["../../src/jobs/cost-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAyB1E"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Adaptive cost estimate from historical jobs. The default flat
3
+ * `DEFAULT_PER_AUDIT_USD` is still a fine starting point for a fresh user,
4
+ * but once 3+ jobs have completed we can do better: averaging the actual
5
+ * per-target cost across recent jobs is closer to ground truth, especially
6
+ * once ethics / first-principles modes start firing differently per target.
7
+ *
8
+ * Pure function of `~/.bad/jobs/` records — no telemetry endpoint required.
9
+ */
10
+ import { listJobs, loadJob } from './store.js';
11
+ import { DEFAULT_PER_AUDIT_USD } from './cost-estimate.js';
12
+ /** Min number of completed jobs before we trust history over the static default. */
13
+ const MIN_HISTORY = 3;
14
+ export function computePerAuditFromHistory(dir) {
15
+ const entries = listJobs(dir);
16
+ // Only count completed/partial jobs — failed ones have skewed cost.
17
+ const usable = entries.filter((e) => e.status === 'completed' || e.status === 'partial').slice(0, 20);
18
+ if (usable.length < MIN_HISTORY) {
19
+ return { perAuditUSD: DEFAULT_PER_AUDIT_USD, source: 'default', jobsObserved: usable.length, targetsObserved: 0 };
20
+ }
21
+ let totalCost = 0;
22
+ let totalTargets = 0;
23
+ for (const entry of usable) {
24
+ const job = loadJob(entry.jobId, dir);
25
+ if (!job)
26
+ continue;
27
+ const okCount = job.results.filter(r => r.status === 'ok' && typeof r.costUSD === 'number').length;
28
+ if (okCount === 0)
29
+ continue;
30
+ totalCost += job.totalCostUSD;
31
+ totalTargets += okCount;
32
+ }
33
+ if (totalTargets === 0) {
34
+ return { perAuditUSD: DEFAULT_PER_AUDIT_USD, source: 'default', jobsObserved: usable.length, targetsObserved: 0 };
35
+ }
36
+ const perAudit = totalCost / totalTargets;
37
+ // Floor at half the static default to prevent runaway optimism on a stretch
38
+ // of zero-cost jobs (which can happen with the claude-code provider).
39
+ const floored = Math.max(perAudit, DEFAULT_PER_AUDIT_USD * 0.5);
40
+ return { perAuditUSD: floored, source: 'history', jobsObserved: usable.length, targetsObserved: totalTargets };
41
+ }
42
+ //# sourceMappingURL=cost-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-history.js","sourceRoot":"","sources":["../../src/jobs/cost-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,oFAAoF;AACpF,MAAM,WAAW,GAAG,CAAC,CAAA;AAWrB,MAAM,UAAU,0BAA0B,CAAC,GAAY;IACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC7B,oEAAoE;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACpH,IAAI,MAAM,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QAChC,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,EAAE,CAAA;IACnH,CAAC;IACD,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACrC,IAAI,CAAC,GAAG;YAAE,SAAQ;QAClB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAA;QAClG,IAAI,OAAO,KAAK,CAAC;YAAE,SAAQ;QAC3B,SAAS,IAAI,GAAG,CAAC,YAAY,CAAA;QAC7B,YAAY,IAAI,OAAO,CAAA;IACzB,CAAC;IACD,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,EAAE,CAAA;IACnH,CAAC;IACD,MAAM,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAA;IACzC,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,qBAAqB,GAAG,GAAG,CAAC,CAAA;IAC/D,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,CAAA;AAChH,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Jobs — declarative comparative-audit jobs.
3
+ *
4
+ * Public surface:
5
+ * createJob(spec) → Job (queued, persisted, ready to run)
6
+ * runJob(job, opts) → Job (executes the fan-out, returns final state)
7
+ * loadJob / listJobs / saveJob — store accessors
8
+ * estimateCost — pre-flight cost guard
9
+ */
10
+ export type { Job, JobSpec, JobStatus, JobKind, JobTarget, JobResultEntry, JobResultStatus, DiscoverSpec, DiscoverSource, AuditOptions, CostEstimate, } from './types.js';
11
+ export { newJobId, saveJob, loadJob, listJobs, appendIndexEntry, jobsDir, jobPath, updateJobStatus } from './store.js';
12
+ export type { JobIndexEntry } from './store.js';
13
+ export { estimateCost, DEFAULT_PER_AUDIT_USD } from './cost-estimate.js';
14
+ export { runJob } from './queue.js';
15
+ export type { AuditFn, RunJobOptions } from './queue.js';
16
+ export { withRetry, isRetryableDefault, DEFAULT_RETRY_POLICY } from './retry.js';
17
+ export type { RetryPolicy } from './retry.js';
18
+ export { detectBlock, reasonFor } from './anti-bot.js';
19
+ export type { BlockSignals } from './anti-bot.js';
20
+ export { computePerAuditFromHistory } from './cost-history.js';
21
+ export type { AdaptiveCostStats } from './cost-history.js';
22
+ export { orchestrateJob, needsIntervention } from './orchestrator.js';
23
+ export type { OrchestrateJobOptions } from './orchestrator.js';
24
+ import type { Job, JobSpec, JobTarget } from './types.js';
25
+ /**
26
+ * Mint a fresh `queued` job from a spec. Targets are seeded from the spec
27
+ * (snapshot expansion, if any, must be done by the caller via the
28
+ * `discover` module before runJob).
29
+ */
30
+ export declare function createJob(spec: JobSpec, targets: JobTarget[], dir?: string): Job;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,GAAG,EACH,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,cAAc,EACd,eAAe,EACf,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtH,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAChF,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAE9D,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAGzD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAahF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Jobs — declarative comparative-audit jobs.
3
+ *
4
+ * Public surface:
5
+ * createJob(spec) → Job (queued, persisted, ready to run)
6
+ * runJob(job, opts) → Job (executes the fan-out, returns final state)
7
+ * loadJob / listJobs / saveJob — store accessors
8
+ * estimateCost — pre-flight cost guard
9
+ */
10
+ export { newJobId, saveJob, loadJob, listJobs, appendIndexEntry, jobsDir, jobPath, updateJobStatus } from './store.js';
11
+ export { estimateCost, DEFAULT_PER_AUDIT_USD } from './cost-estimate.js';
12
+ export { runJob } from './queue.js';
13
+ export { withRetry, isRetryableDefault, DEFAULT_RETRY_POLICY } from './retry.js';
14
+ export { detectBlock, reasonFor } from './anti-bot.js';
15
+ export { computePerAuditFromHistory } from './cost-history.js';
16
+ export { orchestrateJob, needsIntervention } from './orchestrator.js';
17
+ import { newJobId, saveJob, appendIndexEntry } from './store.js';
18
+ /**
19
+ * Mint a fresh `queued` job from a spec. Targets are seeded from the spec
20
+ * (snapshot expansion, if any, must be done by the caller via the
21
+ * `discover` module before runJob).
22
+ */
23
+ export function createJob(spec, targets, dir) {
24
+ const job = {
25
+ jobId: newJobId(),
26
+ spec,
27
+ status: 'queued',
28
+ createdAt: new Date().toISOString(),
29
+ targets,
30
+ results: [],
31
+ totalCostUSD: 0,
32
+ };
33
+ saveJob(job, dir);
34
+ appendIndexEntry(job, dir);
35
+ return job;
36
+ }
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEtH,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEhF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAE9D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAIrE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAEhE;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa,EAAE,OAAoB,EAAE,GAAY;IACzE,MAAM,GAAG,GAAQ;QACf,KAAK,EAAE,QAAQ,EAAE;QACjB,IAAI;QACJ,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO;QACP,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,CAAC;KAChB,CAAA;IACD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACjB,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IAC1B,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Agentic orchestrator — wraps `runJob` with a control loop that handles
3
+ * strategic decisions (re-sample broken wayback snapshots, retry vs skip,
4
+ * widen the window when too many fail, conclude) via LLM tool calls.
5
+ *
6
+ * Design: protocols are deterministic (retry/backoff lives in `retry.ts`,
7
+ * anti-bot detection lives in `anti-bot.ts`). The orchestrator only steps
8
+ * in for *judgment* calls where a hand-tuned heuristic would break the
9
+ * moment the world changes. Cost ceiling: hard-capped at spec.maxCostUSD,
10
+ * and each control-loop iteration is a single LLM call (~1.5s, ~$0.005).
11
+ *
12
+ * Tool surface (LLM-callable):
13
+ * getJobState() — what's done, what failed, current cost
14
+ * resampleWayback(...) — replace targets for a URL with a new sample
15
+ * retryTarget(...) — re-attempt a single failed/skipped target
16
+ * markSkipped(...) — terminal skip with reason
17
+ * concludeJob() — exit the loop
18
+ *
19
+ * The orchestrator runs the initial fan-out via `runJob` first (so the
20
+ * deterministic happy path doesn't pay LLM tax), then enters the loop only
21
+ * if the result needs intervention.
22
+ */
23
+ import { Brain } from '../brain/index.js';
24
+ import { type AuditFn } from './queue.js';
25
+ import type { Job } from './types.js';
26
+ export interface OrchestrateJobOptions {
27
+ auditFn: AuditFn;
28
+ /** Persistence dir override (tests). */
29
+ dir?: string;
30
+ /** Cap on agent control-loop iterations. Default 8. */
31
+ maxIterations?: number;
32
+ /** Override the LLM provider (tests). Defaults to the default Brain. */
33
+ brain?: Brain;
34
+ /** When true, log every tool call. */
35
+ verbose?: boolean;
36
+ }
37
+ export declare function orchestrateJob(job: Job, opts: OrchestrateJobOptions): Promise<Job>;
38
+ /** Cheap deterministic check: did the fan-out leave anything worth fixing? */
39
+ declare function needsIntervention(job: Job): boolean;
40
+ /** Re-export for tests / callers that want to inspect what would have run. */
41
+ export { needsIntervention };
42
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/jobs/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzC,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,YAAY,CAAA;AAGjD,OAAO,KAAK,EAAE,GAAG,EAA6B,MAAM,YAAY,CAAA;AAEhE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAkCD,wBAAsB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAmDxF;AAED,8EAA8E;AAC9E,iBAAS,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAa5C;AA+JD,8EAA8E;AAC9E,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Agentic orchestrator — wraps `runJob` with a control loop that handles
3
+ * strategic decisions (re-sample broken wayback snapshots, retry vs skip,
4
+ * widen the window when too many fail, conclude) via LLM tool calls.
5
+ *
6
+ * Design: protocols are deterministic (retry/backoff lives in `retry.ts`,
7
+ * anti-bot detection lives in `anti-bot.ts`). The orchestrator only steps
8
+ * in for *judgment* calls where a hand-tuned heuristic would break the
9
+ * moment the world changes. Cost ceiling: hard-capped at spec.maxCostUSD,
10
+ * and each control-loop iteration is a single LLM call (~1.5s, ~$0.005).
11
+ *
12
+ * Tool surface (LLM-callable):
13
+ * getJobState() — what's done, what failed, current cost
14
+ * resampleWayback(...) — replace targets for a URL with a new sample
15
+ * retryTarget(...) — re-attempt a single failed/skipped target
16
+ * markSkipped(...) — terminal skip with reason
17
+ * concludeJob() — exit the loop
18
+ *
19
+ * The orchestrator runs the initial fan-out via `runJob` first (so the
20
+ * deterministic happy path doesn't pay LLM tax), then enters the loop only
21
+ * if the result needs intervention.
22
+ */
23
+ import { generateText, tool, jsonSchema, stepCountIs } from 'ai';
24
+ import { Brain } from '../brain/index.js';
25
+ import { resolveProviderApiKey, resolveProviderModelName } from '../provider-defaults.js';
26
+ import { runJob } from './queue.js';
27
+ import { saveJob, appendIndexEntry } from './store.js';
28
+ import { discoverWaybackSnapshots } from '../discover/wayback.js';
29
+ const SYSTEM_PROMPT = `You are an audit-job orchestrator.
30
+
31
+ Your job: bring this audit job to a high-quality completion. After the initial fan-out has run, decide whether and how to fix gaps:
32
+ - If multiple wayback snapshots for the same URL came back blocked or scored 0, the snapshots are likely broken archive captures. Re-sample more snapshots in the same window using the resampleWayback tool.
33
+ - If a single target failed with a transient error, retry it.
34
+ - If a target is structurally unfixable (anti-bot, persistent 4xx, total content failure), mark it skipped with a clear reason.
35
+ - When the job is in good shape OR you've hit diminishing returns OR cost is approaching the cap, call concludeJob.
36
+
37
+ Rules:
38
+ - You MUST stay under spec.maxCostUSD when set.
39
+ - Do not retry the same target more than twice.
40
+ - Do not resample the same URL more than once.
41
+ - When in doubt, conclude. A clean partial job is better than an over-fitted one.
42
+ - Reply only with tool calls until you call concludeJob.
43
+ `;
44
+ export async function orchestrateJob(job, opts) {
45
+ const verbose = opts.verbose ?? false;
46
+ // Phase 1: deterministic fan-out (no LLM in the loop).
47
+ await runJob(job, { auditFn: opts.auditFn, dir: opts.dir });
48
+ const state = {
49
+ job,
50
+ resamples: new Map(),
51
+ retries: new Map(),
52
+ concluded: false,
53
+ reason: '',
54
+ };
55
+ // Phase 2: only invoke the agent if the run needs intervention.
56
+ if (!needsIntervention(job)) {
57
+ if (verbose)
58
+ console.log(' [orchestrator] no intervention needed');
59
+ return job;
60
+ }
61
+ if (verbose) {
62
+ const failed = job.results.filter(r => r.status === 'failed').length;
63
+ const skipped = job.results.filter(r => r.status === 'skipped').length;
64
+ console.log(` [orchestrator] entering loop · failed=${failed} · skipped=${skipped} · cost=$${job.totalCostUSD.toFixed(2)}`);
65
+ }
66
+ // Default to the same provider as the audit pipeline (claude-code via
67
+ // subscription, no API key required). If the operator already supplied a
68
+ // brain, respect that.
69
+ const brain = opts.brain ?? defaultBrain();
70
+ const tools = buildTools(state, opts, verbose);
71
+ const model = await brain.getLanguageModel({ provider: 'claude-code' });
72
+ const result = await generateText({
73
+ model,
74
+ system: SYSTEM_PROMPT,
75
+ prompt: 'The fan-out has completed. Call getJobState first to see what happened, then take corrective actions, then call concludeJob.',
76
+ tools,
77
+ stopWhen: stepCountIs(opts.maxIterations ?? 8),
78
+ });
79
+ if (verbose) {
80
+ console.log(` [orchestrator] finishReason=${result.finishReason} steps=${result.steps.length} toolCalls=${result.steps.reduce((acc, s) => acc + s.toolCalls.length, 0)}`);
81
+ if (result.text)
82
+ console.log(` [orchestrator] final-text: ${result.text.slice(0, 200)}`);
83
+ }
84
+ if (!state.concluded) {
85
+ state.reason = 'orchestrator: max iterations reached without explicit conclude';
86
+ }
87
+ // Persist final state.
88
+ saveJob(state.job, opts.dir);
89
+ appendIndexEntry(state.job, opts.dir);
90
+ return state.job;
91
+ }
92
+ /** Cheap deterministic check: did the fan-out leave anything worth fixing? */
93
+ function needsIntervention(job) {
94
+ const failed = job.results.filter(r => r.status === 'failed').length;
95
+ const ok = job.results.filter(r => r.status === 'ok');
96
+ const skipped = job.results.filter(r => r.status === 'skipped').length;
97
+ // Coverage: anything missing or failed is an intervention candidate.
98
+ if (failed > 0)
99
+ return true;
100
+ if (ok.length + skipped < job.targets.length)
101
+ return true;
102
+ // Quality: zero-scored ok results from wayback snapshots almost always
103
+ // indicate a broken archive capture (anti-bot got past detection, or the
104
+ // archived page is truncated). Treat as intervention-worthy.
105
+ const zeroScored = ok.filter(r => r.snapshotUrl && (r.rollupScore ?? -1) === 0).length;
106
+ if (zeroScored > 0)
107
+ return true;
108
+ return false;
109
+ }
110
+ function buildTools(state, opts, verbose) {
111
+ return {
112
+ getJobState: tool({
113
+ description: 'Return the current job state — targets, results, totalCostUSD, maxCostUSD, recent failures, and which URLs already have re-sampled targets.',
114
+ inputSchema: jsonSchema({ type: 'object', properties: {} }),
115
+ execute: async () => {
116
+ const j = state.job;
117
+ const groupedByUrl = new Map();
118
+ for (const r of j.results) {
119
+ const k = r.url;
120
+ if (!groupedByUrl.has(k))
121
+ groupedByUrl.set(k, []);
122
+ groupedByUrl.get(k).push(r);
123
+ }
124
+ const summary = {
125
+ jobId: j.jobId,
126
+ status: j.status,
127
+ totalCostUSD: j.totalCostUSD,
128
+ maxCostUSD: j.spec.maxCostUSD ?? null,
129
+ targets: j.targets.length,
130
+ ok: j.results.filter(r => r.status === 'ok').length,
131
+ failed: j.results.filter(r => r.status === 'failed').length,
132
+ skipped: j.results.filter(r => r.status === 'skipped').length,
133
+ retriesUsed: Array.from(state.retries.entries()).map(([k, n]) => ({ key: k, retries: n })),
134
+ resamplesUsed: Array.from(state.resamples.values()).filter(r => r.attempted).map(r => r.url),
135
+ byUrl: Array.from(groupedByUrl.entries()).map(([url, rows]) => ({
136
+ url,
137
+ snapshots: rows.length,
138
+ ok: rows.filter(r => r.status === 'ok').length,
139
+ failed: rows.filter(r => r.status === 'failed').length,
140
+ skipped: rows.filter(r => r.status === 'skipped').length,
141
+ zeroScored: rows.filter(r => r.status === 'ok' && (r.rollupScore ?? 0) === 0).length,
142
+ })),
143
+ failureSamples: j.results.filter(r => r.status === 'failed').slice(0, 5).map(r => ({
144
+ url: r.url, snapshotUrl: r.snapshotUrl, error: r.error,
145
+ })),
146
+ skippedSamples: j.results.filter(r => r.status === 'skipped').slice(0, 5).map(r => ({
147
+ url: r.url, snapshotUrl: r.snapshotUrl, reason: r.error,
148
+ })),
149
+ };
150
+ if (verbose)
151
+ console.log(' [orchestrator] getJobState');
152
+ return summary;
153
+ },
154
+ }),
155
+ resampleWayback: tool({
156
+ description: 'Discover N additional wayback snapshots for a URL and audit them. Use when several existing snapshots for that URL came back blocked or zero-scored — broken archive captures cluster, so re-sampling a different month often produces good ones. Each URL can only be resampled once per orchestrator run.',
157
+ inputSchema: jsonSchema({
158
+ type: 'object',
159
+ properties: {
160
+ url: { type: 'string' },
161
+ count: { type: 'integer', minimum: 1, maximum: 8 },
162
+ since: { type: 'string', description: 'ISO date lower bound' },
163
+ until: { type: 'string', description: 'ISO date upper bound' },
164
+ },
165
+ required: ['url', 'count'],
166
+ }),
167
+ execute: async ({ url, count, since, until }) => {
168
+ if (state.resamples.has(url)) {
169
+ return { error: `already resampled ${url} — skip and conclude or retry individual targets instead` };
170
+ }
171
+ if (overBudget(state))
172
+ return { error: 'cost cap reached — conclude job' };
173
+ const action = { url, count, since, until, attempted: true };
174
+ state.resamples.set(url, action);
175
+ if (verbose)
176
+ console.log(` [orchestrator] resampleWayback ${url} count=${count}`);
177
+ try {
178
+ const targets = await discoverWaybackSnapshots(url, { count, since, until });
179
+ if (targets.length === 0)
180
+ return { added: 0, error: 'CDX returned zero captures for that window' };
181
+ // De-dupe against snapshots we already audited.
182
+ const existing = new Set(state.job.results.map(r => r.snapshotUrl ?? r.url));
183
+ const fresh = targets.filter(t => !existing.has(t.snapshotUrl ?? t.url));
184
+ if (fresh.length === 0)
185
+ return { added: 0, note: 'all sampled snapshots were already audited; widen the window or pick a different URL' };
186
+ state.job.targets.push(...fresh);
187
+ // Run only the new targets through the queue with resume=true.
188
+ await runJob(state.job, { auditFn: opts.auditFn, dir: opts.dir, resume: true });
189
+ const newOk = fresh.filter(t => state.job.results.some(r => (r.snapshotUrl ?? r.url) === (t.snapshotUrl ?? t.url) && r.status === 'ok')).length;
190
+ return { added: fresh.length, newlyOk: newOk, totalCostUSD: state.job.totalCostUSD };
191
+ }
192
+ catch (err) {
193
+ return { error: err.message };
194
+ }
195
+ },
196
+ }),
197
+ retryTarget: tool({
198
+ description: 'Re-attempt a single failed or skipped target. Use only for transient failures. Hard cap: 2 retries per target per orchestrator run.',
199
+ inputSchema: jsonSchema({
200
+ type: 'object',
201
+ properties: {
202
+ url: { type: 'string' },
203
+ snapshotUrl: { type: 'string' },
204
+ },
205
+ required: ['url'],
206
+ }),
207
+ execute: async ({ url, snapshotUrl }) => {
208
+ const key = snapshotUrl ?? url;
209
+ const used = state.retries.get(key) ?? 0;
210
+ if (used >= 2)
211
+ return { error: `retry budget for ${key} exhausted (2 used)` };
212
+ if (overBudget(state))
213
+ return { error: 'cost cap reached — conclude job' };
214
+ state.retries.set(key, used + 1);
215
+ if (verbose)
216
+ console.log(` [orchestrator] retryTarget ${key} attempt=${used + 1}`);
217
+ // Drop the existing failed/skipped entry, then resume — the queue will pick the missing target up.
218
+ state.job.results = state.job.results.filter(r => (r.snapshotUrl ?? r.url) !== key);
219
+ await runJob(state.job, { auditFn: opts.auditFn, dir: opts.dir, resume: true });
220
+ const newEntry = state.job.results.find(r => (r.snapshotUrl ?? r.url) === key);
221
+ return { status: newEntry?.status ?? 'unknown', error: newEntry?.error, totalCostUSD: state.job.totalCostUSD };
222
+ },
223
+ }),
224
+ markSkipped: tool({
225
+ description: 'Terminally mark a target as skipped (no further retries). Use for structurally unfixable failures — persistent 4xx, anti-bot, dead URL.',
226
+ inputSchema: jsonSchema({
227
+ type: 'object',
228
+ properties: {
229
+ url: { type: 'string' },
230
+ snapshotUrl: { type: 'string' },
231
+ reason: { type: 'string' },
232
+ },
233
+ required: ['url', 'reason'],
234
+ }),
235
+ execute: async ({ url, snapshotUrl, reason }) => {
236
+ const key = snapshotUrl ?? url;
237
+ const idx = state.job.results.findIndex(r => (r.snapshotUrl ?? r.url) === key);
238
+ if (idx >= 0) {
239
+ state.job.results[idx] = { ...state.job.results[idx], status: 'skipped', error: reason };
240
+ }
241
+ else {
242
+ state.job.results.push({ url, snapshotUrl, status: 'skipped', error: reason });
243
+ }
244
+ saveJob(state.job, opts.dir);
245
+ if (verbose)
246
+ console.log(` [orchestrator] markSkipped ${key}: ${reason}`);
247
+ return { ok: true };
248
+ },
249
+ }),
250
+ concludeJob: tool({
251
+ description: 'End the orchestrator loop. Provide a one-sentence reason summarizing the final state.',
252
+ inputSchema: jsonSchema({
253
+ type: 'object',
254
+ properties: { reason: { type: 'string' } },
255
+ required: ['reason'],
256
+ }),
257
+ execute: async ({ reason }) => {
258
+ state.concluded = true;
259
+ state.reason = reason;
260
+ if (verbose)
261
+ console.log(` [orchestrator] concludeJob: ${reason}`);
262
+ return { concluded: true };
263
+ },
264
+ }),
265
+ };
266
+ }
267
+ function overBudget(state) {
268
+ const cap = state.job.spec.maxCostUSD;
269
+ if (typeof cap !== 'number')
270
+ return false;
271
+ // Leave 10% headroom so the next single audit doesn't push us over.
272
+ return state.job.totalCostUSD >= cap * 0.9;
273
+ }
274
+ /** Re-export for tests / callers that want to inspect what would have run. */
275
+ export { needsIntervention };
276
+ function defaultBrain() {
277
+ const provider = 'claude-code';
278
+ const model = resolveProviderModelName(provider);
279
+ const apiKey = resolveProviderApiKey(provider);
280
+ return new Brain({ provider, model, apiKey, vision: false, llmTimeoutMs: 60_000 });
281
+ }
282
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/jobs/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Job runner — bounded-concurrency fan-out over the audit pipeline.
3
+ *
4
+ * Synchronous in the sense that `runJob()` returns when every target has been
5
+ * processed (ok, failed, or skipped). Crash safety: every individual result
6
+ * is persisted to disk as soon as it lands, so killing the process leaves a
7
+ * resumable record (resume is a future addition; today the partial state
8
+ * is just observable).
9
+ *
10
+ * `auditFn` is injected so tests can run the queue without touching
11
+ * Playwright/LLMs.
12
+ */
13
+ import type { Job, JobTarget } from './types.js';
14
+ import { type RetryPolicy } from './retry.js';
15
+ export interface AuditFn {
16
+ (target: JobTarget, opts: Job['spec']['audit']): Promise<{
17
+ runId: string;
18
+ resultPath: string;
19
+ rollupScore?: number;
20
+ pageType?: string;
21
+ costUSD?: number;
22
+ tokensPath?: string;
23
+ /**
24
+ * When set, the result was deterministically classified as blocked /
25
+ * anti-bot — the queue records `status: 'skipped'` with this reason
26
+ * instead of `'ok'`, so leaderboards don't include a misleading score.
27
+ */
28
+ blockedReason?: string;
29
+ }>;
30
+ }
31
+ export interface RunJobOptions {
32
+ auditFn: AuditFn;
33
+ /** Persistence dir override (tests). */
34
+ dir?: string;
35
+ /** Concurrency override; falls back to spec.concurrency, then 2. */
36
+ concurrency?: number;
37
+ /** Per-target failure swallower — defaults to recording the error and continuing. */
38
+ onError?: (target: JobTarget, error: Error) => 'continue' | 'abort';
39
+ /** Retry policy applied around each `auditFn` call. Pass `null` to disable retry. */
40
+ retryPolicy?: RetryPolicy | null;
41
+ /** When true, skip targets that already have a non-failed result on the job (used by `bad jobs resume`). */
42
+ resume?: boolean;
43
+ }
44
+ export declare function runJob(job: Job, opts: RunJobOptions): Promise<Job>;
45
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/jobs/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAA;AAChE,OAAO,EAAmC,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAE9E,MAAM,WAAW,OAAO;IACtB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;QACvD,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB;;;;WAIG;QACH,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAC,CAAA;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,OAAO,CAAA;IACnE,qFAAqF;IACrF,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAChC,4GAA4G;IAC5G,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAID,wBAAsB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAwCxE"}