@openagentsy/hooks 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +32 -2
  3. package/dist/accountability.d.ts +29 -0
  4. package/dist/accountability.d.ts.map +1 -0
  5. package/dist/accountability.js +21 -0
  6. package/dist/accountability.js.map +1 -0
  7. package/dist/accountability.test.d.ts +2 -0
  8. package/dist/accountability.test.d.ts.map +1 -0
  9. package/dist/accountability.test.js +42 -0
  10. package/dist/accountability.test.js.map +1 -0
  11. package/dist/approvals.d.ts +110 -0
  12. package/dist/approvals.d.ts.map +1 -0
  13. package/dist/approvals.js +464 -0
  14. package/dist/approvals.js.map +1 -0
  15. package/dist/approvals.test.d.ts +2 -0
  16. package/dist/approvals.test.d.ts.map +1 -0
  17. package/dist/approvals.test.js +307 -0
  18. package/dist/approvals.test.js.map +1 -0
  19. package/dist/base-tool.d.ts +26 -0
  20. package/dist/base-tool.d.ts.map +1 -0
  21. package/dist/base-tool.js +37 -0
  22. package/dist/base-tool.js.map +1 -0
  23. package/dist/base-tool.test.d.ts +2 -0
  24. package/dist/base-tool.test.d.ts.map +1 -0
  25. package/dist/base-tool.test.js +34 -0
  26. package/dist/base-tool.test.js.map +1 -0
  27. package/dist/eval/index.d.ts +3 -0
  28. package/dist/eval/index.d.ts.map +1 -0
  29. package/dist/eval/index.js +3 -0
  30. package/dist/eval/index.js.map +1 -0
  31. package/dist/eval/runner.d.ts +179 -0
  32. package/dist/eval/runner.d.ts.map +1 -0
  33. package/dist/eval/runner.js +616 -0
  34. package/dist/eval/runner.js.map +1 -0
  35. package/dist/eval/runner.test.d.ts +2 -0
  36. package/dist/eval/runner.test.d.ts.map +1 -0
  37. package/dist/eval/runner.test.js +431 -0
  38. package/dist/eval/runner.test.js.map +1 -0
  39. package/dist/eval/types.d.ts +173 -0
  40. package/dist/eval/types.d.ts.map +1 -0
  41. package/dist/eval/types.js +104 -0
  42. package/dist/eval/types.js.map +1 -0
  43. package/dist/event.d.ts +59 -0
  44. package/dist/event.d.ts.map +1 -0
  45. package/dist/event.js +178 -0
  46. package/dist/event.js.map +1 -0
  47. package/dist/event.test.d.ts +2 -0
  48. package/dist/event.test.d.ts.map +1 -0
  49. package/dist/event.test.js +49 -0
  50. package/dist/event.test.js.map +1 -0
  51. package/dist/index.d.ts +30 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +29 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lessons/capture.d.ts +66 -0
  56. package/dist/lessons/capture.d.ts.map +1 -0
  57. package/dist/lessons/capture.js +166 -0
  58. package/dist/lessons/capture.js.map +1 -0
  59. package/dist/lessons/capture.test.d.ts +2 -0
  60. package/dist/lessons/capture.test.d.ts.map +1 -0
  61. package/dist/lessons/capture.test.js +200 -0
  62. package/dist/lessons/capture.test.js.map +1 -0
  63. package/dist/lessons/decide.d.ts +90 -0
  64. package/dist/lessons/decide.d.ts.map +1 -0
  65. package/dist/lessons/decide.js +334 -0
  66. package/dist/lessons/decide.js.map +1 -0
  67. package/dist/lessons/decide.test.d.ts +2 -0
  68. package/dist/lessons/decide.test.d.ts.map +1 -0
  69. package/dist/lessons/decide.test.js +527 -0
  70. package/dist/lessons/decide.test.js.map +1 -0
  71. package/dist/lessons/id.d.ts +5 -0
  72. package/dist/lessons/id.d.ts.map +1 -0
  73. package/dist/lessons/id.js +20 -0
  74. package/dist/lessons/id.js.map +1 -0
  75. package/dist/lessons/index.d.ts +5 -0
  76. package/dist/lessons/index.d.ts.map +1 -0
  77. package/dist/lessons/index.js +5 -0
  78. package/dist/lessons/index.js.map +1 -0
  79. package/dist/lessons/model.d.ts +163 -0
  80. package/dist/lessons/model.d.ts.map +1 -0
  81. package/dist/lessons/model.js +181 -0
  82. package/dist/lessons/model.js.map +1 -0
  83. package/dist/lessons/model.test.d.ts +2 -0
  84. package/dist/lessons/model.test.d.ts.map +1 -0
  85. package/dist/lessons/model.test.js +178 -0
  86. package/dist/lessons/model.test.js.map +1 -0
  87. package/dist/lessons/permissions.test.d.ts +2 -0
  88. package/dist/lessons/permissions.test.d.ts.map +1 -0
  89. package/dist/lessons/permissions.test.js +88 -0
  90. package/dist/lessons/permissions.test.js.map +1 -0
  91. package/dist/lessons/store.d.ts +74 -0
  92. package/dist/lessons/store.d.ts.map +1 -0
  93. package/dist/lessons/store.js +231 -0
  94. package/dist/lessons/store.js.map +1 -0
  95. package/dist/output-checks.d.ts +64 -0
  96. package/dist/output-checks.d.ts.map +1 -0
  97. package/dist/output-checks.js +248 -0
  98. package/dist/output-checks.js.map +1 -0
  99. package/dist/output-checks.test.d.ts +2 -0
  100. package/dist/output-checks.test.d.ts.map +1 -0
  101. package/dist/output-checks.test.js +58 -0
  102. package/dist/output-checks.test.js.map +1 -0
  103. package/dist/paths.d.ts +37 -0
  104. package/dist/paths.d.ts.map +1 -0
  105. package/dist/paths.js +70 -0
  106. package/dist/paths.js.map +1 -0
  107. package/dist/paths.test.d.ts +2 -0
  108. package/dist/paths.test.d.ts.map +1 -0
  109. package/dist/paths.test.js +36 -0
  110. package/dist/paths.test.js.map +1 -0
  111. package/dist/policies/agi-framing.d.ts +12 -0
  112. package/dist/policies/agi-framing.d.ts.map +1 -0
  113. package/dist/policies/agi-framing.js +33 -0
  114. package/dist/policies/agi-framing.js.map +1 -0
  115. package/dist/policies/anti-anthropomorphism.d.ts +13 -0
  116. package/dist/policies/anti-anthropomorphism.d.ts.map +1 -0
  117. package/dist/policies/anti-anthropomorphism.js +34 -0
  118. package/dist/policies/anti-anthropomorphism.js.map +1 -0
  119. package/dist/policies/anti-dependence.d.ts +12 -0
  120. package/dist/policies/anti-dependence.d.ts.map +1 -0
  121. package/dist/policies/anti-dependence.js +33 -0
  122. package/dist/policies/anti-dependence.js.map +1 -0
  123. package/dist/policies/anti-sycophancy.d.ts +13 -0
  124. package/dist/policies/anti-sycophancy.d.ts.map +1 -0
  125. package/dist/policies/anti-sycophancy.js +34 -0
  126. package/dist/policies/anti-sycophancy.js.map +1 -0
  127. package/dist/policies/dark-pattern.d.ts +14 -0
  128. package/dist/policies/dark-pattern.d.ts.map +1 -0
  129. package/dist/policies/dark-pattern.js +44 -0
  130. package/dist/policies/dark-pattern.js.map +1 -0
  131. package/dist/policies/destructive-needs-approval.d.ts +14 -0
  132. package/dist/policies/destructive-needs-approval.d.ts.map +1 -0
  133. package/dist/policies/destructive-needs-approval.js +31 -0
  134. package/dist/policies/destructive-needs-approval.js.map +1 -0
  135. package/dist/policies/discovery.d.ts +12 -0
  136. package/dist/policies/discovery.d.ts.map +1 -0
  137. package/dist/policies/discovery.js +130 -0
  138. package/dist/policies/discovery.js.map +1 -0
  139. package/dist/policies/high-risk.d.ts +25 -0
  140. package/dist/policies/high-risk.d.ts.map +1 -0
  141. package/dist/policies/high-risk.js +105 -0
  142. package/dist/policies/high-risk.js.map +1 -0
  143. package/dist/policies/human-only-decisions.d.ts +14 -0
  144. package/dist/policies/human-only-decisions.d.ts.map +1 -0
  145. package/dist/policies/human-only-decisions.js +33 -0
  146. package/dist/policies/human-only-decisions.js.map +1 -0
  147. package/dist/policies/index.d.ts +29 -0
  148. package/dist/policies/index.d.ts.map +1 -0
  149. package/dist/policies/index.js +82 -0
  150. package/dist/policies/index.js.map +1 -0
  151. package/dist/policies/no-skip-git-hooks.d.ts +14 -0
  152. package/dist/policies/no-skip-git-hooks.d.ts.map +1 -0
  153. package/dist/policies/no-skip-git-hooks.js +31 -0
  154. package/dist/policies/no-skip-git-hooks.js.map +1 -0
  155. package/dist/policies/package-manager.d.ts +12 -0
  156. package/dist/policies/package-manager.d.ts.map +1 -0
  157. package/dist/policies/package-manager.js +29 -0
  158. package/dist/policies/package-manager.js.map +1 -0
  159. package/dist/policies/patterns.d.ts +17 -0
  160. package/dist/policies/patterns.d.ts.map +1 -0
  161. package/dist/policies/patterns.js +30 -0
  162. package/dist/policies/patterns.js.map +1 -0
  163. package/dist/policies/policies.test.d.ts +2 -0
  164. package/dist/policies/policies.test.d.ts.map +1 -0
  165. package/dist/policies/policies.test.js +210 -0
  166. package/dist/policies/policies.test.js.map +1 -0
  167. package/dist/policies/privacy-transparency.d.ts +14 -0
  168. package/dist/policies/privacy-transparency.d.ts.map +1 -0
  169. package/dist/policies/privacy-transparency.js +50 -0
  170. package/dist/policies/privacy-transparency.js.map +1 -0
  171. package/dist/policies/professional-displacement.d.ts +15 -0
  172. package/dist/policies/professional-displacement.d.ts.map +1 -0
  173. package/dist/policies/professional-displacement.js +45 -0
  174. package/dist/policies/professional-displacement.js.map +1 -0
  175. package/dist/policies/protect-policy.d.ts +14 -0
  176. package/dist/policies/protect-policy.d.ts.map +1 -0
  177. package/dist/policies/protect-policy.js +35 -0
  178. package/dist/policies/protect-policy.js.map +1 -0
  179. package/dist/policies/scope-enforcement.d.ts +14 -0
  180. package/dist/policies/scope-enforcement.d.ts.map +1 -0
  181. package/dist/policies/scope-enforcement.js +34 -0
  182. package/dist/policies/scope-enforcement.js.map +1 -0
  183. package/dist/policies/secret-scan-writes.d.ts +13 -0
  184. package/dist/policies/secret-scan-writes.d.ts.map +1 -0
  185. package/dist/policies/secret-scan-writes.js +38 -0
  186. package/dist/policies/secret-scan-writes.js.map +1 -0
  187. package/dist/policies/selection.d.ts +20 -0
  188. package/dist/policies/selection.d.ts.map +1 -0
  189. package/dist/policies/selection.js +93 -0
  190. package/dist/policies/selection.js.map +1 -0
  191. package/dist/policies/structural-bias.d.ts +14 -0
  192. package/dist/policies/structural-bias.d.ts.map +1 -0
  193. package/dist/policies/structural-bias.js +41 -0
  194. package/dist/policies/structural-bias.js.map +1 -0
  195. package/dist/policies/third-party-impact.d.ts +13 -0
  196. package/dist/policies/third-party-impact.d.ts.map +1 -0
  197. package/dist/policies/third-party-impact.js +38 -0
  198. package/dist/policies/third-party-impact.js.map +1 -0
  199. package/dist/policies/tool-call.d.ts +38 -0
  200. package/dist/policies/tool-call.d.ts.map +1 -0
  201. package/dist/policies/tool-call.js +53 -0
  202. package/dist/policies/tool-call.js.map +1 -0
  203. package/dist/policies/truthfulness-uncertainty.d.ts +13 -0
  204. package/dist/policies/truthfulness-uncertainty.d.ts.map +1 -0
  205. package/dist/policies/truthfulness-uncertainty.js +45 -0
  206. package/dist/policies/truthfulness-uncertainty.js.map +1 -0
  207. package/dist/policies/workspace-writes-only.d.ts +25 -0
  208. package/dist/policies/workspace-writes-only.d.ts.map +1 -0
  209. package/dist/policies/workspace-writes-only.js +54 -0
  210. package/dist/policies/workspace-writes-only.js.map +1 -0
  211. package/dist/policy-engine.d.ts +69 -0
  212. package/dist/policy-engine.d.ts.map +1 -0
  213. package/dist/policy-engine.js +145 -0
  214. package/dist/policy-engine.js.map +1 -0
  215. package/dist/policy-registry.d.ts +62 -0
  216. package/dist/policy-registry.d.ts.map +1 -0
  217. package/dist/policy-registry.js +63 -0
  218. package/dist/policy-registry.js.map +1 -0
  219. package/dist/policy-registry.test.d.ts +2 -0
  220. package/dist/policy-registry.test.d.ts.map +1 -0
  221. package/dist/policy-registry.test.js +79 -0
  222. package/dist/policy-registry.test.js.map +1 -0
  223. package/dist/policy-release.d.ts +44 -0
  224. package/dist/policy-release.d.ts.map +1 -0
  225. package/dist/policy-release.js +65 -0
  226. package/dist/policy-release.js.map +1 -0
  227. package/dist/policy.d.ts +141 -0
  228. package/dist/policy.d.ts.map +1 -0
  229. package/dist/policy.js +22 -0
  230. package/dist/policy.js.map +1 -0
  231. package/dist/quality/audit.d.ts +56 -0
  232. package/dist/quality/audit.d.ts.map +1 -0
  233. package/dist/quality/audit.js +52 -0
  234. package/dist/quality/audit.js.map +1 -0
  235. package/dist/quality/findings.d.ts +34 -0
  236. package/dist/quality/findings.d.ts.map +1 -0
  237. package/dist/quality/findings.js +121 -0
  238. package/dist/quality/findings.js.map +1 -0
  239. package/dist/quality/findings.test.d.ts +2 -0
  240. package/dist/quality/findings.test.d.ts.map +1 -0
  241. package/dist/quality/findings.test.js +79 -0
  242. package/dist/quality/findings.test.js.map +1 -0
  243. package/dist/quality/index.d.ts +20 -0
  244. package/dist/quality/index.d.ts.map +1 -0
  245. package/dist/quality/index.js +20 -0
  246. package/dist/quality/index.js.map +1 -0
  247. package/dist/quality/rule.d.ts +43 -0
  248. package/dist/quality/rule.d.ts.map +1 -0
  249. package/dist/quality/rule.js +162 -0
  250. package/dist/quality/rule.js.map +1 -0
  251. package/dist/quality/rule.test.d.ts +2 -0
  252. package/dist/quality/rule.test.d.ts.map +1 -0
  253. package/dist/quality/rule.test.js +187 -0
  254. package/dist/quality/rule.test.js.map +1 -0
  255. package/dist/quality/tools.d.ts +30 -0
  256. package/dist/quality/tools.d.ts.map +1 -0
  257. package/dist/quality/tools.js +33 -0
  258. package/dist/quality/tools.js.map +1 -0
  259. package/dist/quality/tools.test.d.ts +2 -0
  260. package/dist/quality/tools.test.d.ts.map +1 -0
  261. package/dist/quality/tools.test.js +41 -0
  262. package/dist/quality/tools.test.js.map +1 -0
  263. package/dist/quality/waive.d.ts +37 -0
  264. package/dist/quality/waive.d.ts.map +1 -0
  265. package/dist/quality/waive.js +39 -0
  266. package/dist/quality/waive.js.map +1 -0
  267. package/dist/quality/waivers.d.ts +63 -0
  268. package/dist/quality/waivers.d.ts.map +1 -0
  269. package/dist/quality/waivers.js +132 -0
  270. package/dist/quality/waivers.js.map +1 -0
  271. package/dist/quality/waivers.test.d.ts +2 -0
  272. package/dist/quality/waivers.test.d.ts.map +1 -0
  273. package/dist/quality/waivers.test.js +138 -0
  274. package/dist/quality/waivers.test.js.map +1 -0
  275. package/dist/registry.d.ts +86 -0
  276. package/dist/registry.d.ts.map +1 -0
  277. package/dist/registry.js +92 -0
  278. package/dist/registry.js.map +1 -0
  279. package/dist/registry.test.d.ts +2 -0
  280. package/dist/registry.test.d.ts.map +1 -0
  281. package/dist/registry.test.js +117 -0
  282. package/dist/registry.test.js.map +1 -0
  283. package/dist/rules.d.ts +107 -0
  284. package/dist/rules.d.ts.map +1 -0
  285. package/dist/rules.js +632 -0
  286. package/dist/rules.js.map +1 -0
  287. package/dist/rules.test.d.ts +2 -0
  288. package/dist/rules.test.d.ts.map +1 -0
  289. package/dist/rules.test.js +488 -0
  290. package/dist/rules.test.js.map +1 -0
  291. package/dist/secrets.d.ts +17 -0
  292. package/dist/secrets.d.ts.map +1 -0
  293. package/dist/secrets.js +17 -0
  294. package/dist/secrets.js.map +1 -0
  295. package/dist/secrets.test.d.ts +2 -0
  296. package/dist/secrets.test.d.ts.map +1 -0
  297. package/dist/secrets.test.js +20 -0
  298. package/dist/secrets.test.js.map +1 -0
  299. package/dist/shell-env.d.ts +23 -0
  300. package/dist/shell-env.d.ts.map +1 -0
  301. package/dist/shell-env.js +34 -0
  302. package/dist/shell-env.js.map +1 -0
  303. package/dist/shell-env.test.d.ts +2 -0
  304. package/dist/shell-env.test.d.ts.map +1 -0
  305. package/dist/shell-env.test.js +45 -0
  306. package/dist/shell-env.test.js.map +1 -0
  307. package/package.json +49 -4
package/dist/policy.js ADDED
@@ -0,0 +1,22 @@
1
+ /** The result of a policy that let the thing through. */
2
+ export function allow() {
3
+ return { action: 'allow' };
4
+ }
5
+ /** The result of a policy that noted something. */
6
+ export function flag(findings, severity = 'warn') {
7
+ return { action: 'flag', findings, severity };
8
+ }
9
+ /** The result of a policy that stopped the thing. */
10
+ export function block(reason, finding) {
11
+ return finding === undefined ? { action: 'block', reason } : { action: 'block', reason, finding };
12
+ }
13
+ /**
14
+ * The findings of a set of matches.
15
+ *
16
+ * The policy id is on every finding, so a finding that travels on its own
17
+ * still says which policy produced it.
18
+ */
19
+ export function findingsOf(policyId, type, matches) {
20
+ return matches.map((match) => ({ policyId, type, match }));
21
+ }
22
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AA0GA,yDAAyD;AACzD,MAAM,UAAU,KAAK;IACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,IAAI,CAAC,QAAyB,EAAE,WAA2B,MAAM;IAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAChD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,KAAK,CAAC,MAAc,EAAE,OAAuB;IAC3D,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACpG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,QAAgB,EAChB,IAAY,EACZ,OAA0B;IAE1B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { type Finding, type SloplintDegradation, type SloplintPath } from '@openagentsy/quality';
2
+ import { type WaiverLookup } from './waivers.js';
3
+ export type { Finding, SloplintDegradation, SloplintPath };
4
+ /**
5
+ * The audit.
6
+ *
7
+ * The hook reports the findings of a write to the agent that made it, and
8
+ * in the `after` mode the hook does nothing at all: the audit is the report
9
+ * then. The audit runs the whole rule set over a scope of files, runs the
10
+ * optional linter over the pages and the stylesheets in it, and marks the
11
+ * findings a person waived.
12
+ *
13
+ * The whole rule set is the one the audit runs, the comment rules
14
+ * included: the comment lint needs a TypeScript parse, and the audit is a
15
+ * call a person made on purpose, so the parse is paid for on demand here
16
+ * and not at all on the write path.
17
+ *
18
+ * The module is not exported from the package barrel: the whole rule set
19
+ * carries the TypeScript compiler, and the plugin must not pay for it. The
20
+ * callers reach it by its own path, `@openagentsy/hooks/quality/audit`.
21
+ */
22
+ /** What the audit looks at. */
23
+ export interface QualityAuditOptions {
24
+ /** The project root. The files are relative to it. */
25
+ root: string;
26
+ /** The files to audit. */
27
+ files: readonly string[];
28
+ /** The waivers that cover a finding. */
29
+ waivers?: WaiverLookup | undefined;
30
+ }
31
+ /** What the audit found. */
32
+ export interface QualityAuditResult {
33
+ /** The files the check read. */
34
+ files: string[];
35
+ /** Every finding, the waived ones included. */
36
+ findings: Finding[];
37
+ /** The findings no waiver covers. */
38
+ open: Finding[];
39
+ /** The findings a waiver covers. */
40
+ waived: Finding[];
41
+ /** Which path ran. */
42
+ path: SloplintPath;
43
+ /** Why the linter did not deliver, when it did not. */
44
+ degraded?: SloplintDegradation | undefined;
45
+ /** The script the linter ran, when one ran. */
46
+ script?: string | undefined;
47
+ }
48
+ /**
49
+ * The audit of a scope of files.
50
+ *
51
+ * The static findings stand in every case: a linter that is absent, that
52
+ * crashes or that says something the bridge cannot read leaves the static
53
+ * findings exactly as they were, and the report says which path ran.
54
+ */
55
+ export declare function runQualityAudit(options: QualityAuditOptions): Promise<QualityAuditResult>;
56
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/quality/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EAEZ,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE,YAAY,EAAE,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AAE3D;;;;;;;;;;;;;;;;;GAiBG;AAEH,+BAA+B;AAC/B,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,wCAAwC;IACxC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACpC;AAED,4BAA4B;AAC5B,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,qCAAqC;IACrC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,oCAAoC;IACpC,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,sBAAsB;IACtB,IAAI,EAAE,YAAY,CAAC;IACnB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC3C,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiB/F"}
@@ -0,0 +1,52 @@
1
+ import { allRegistry, check, runSloplint, } from '@openagentsy/quality';
2
+ import { readDesignMd } from './rule.js';
3
+ import { loadWaiverLookup } from './waivers.js';
4
+ /**
5
+ * The audit of a scope of files.
6
+ *
7
+ * The static findings stand in every case: a linter that is absent, that
8
+ * crashes or that says something the bridge cannot read leaves the static
9
+ * findings exactly as they were, and the report says which path ran.
10
+ */
11
+ export async function runQualityAudit(options) {
12
+ const files = auditedFiles(options.files);
13
+ const findings = await findingsOf(files, options.root);
14
+ const linter = await runSloplint({ root: options.root, files });
15
+ const all = [...findings, ...linter.findings];
16
+ const waivers = options.waivers ?? (await loadWaiverLookup(options.root));
17
+ const waived = all.filter((finding) => waivers.covers(finding));
18
+ const open = all.filter((finding) => !waivers.covers(finding));
19
+ return {
20
+ files,
21
+ findings: all,
22
+ open,
23
+ waived,
24
+ path: linter.path,
25
+ ...(linter.degraded !== undefined ? { degraded: linter.degraded } : {}),
26
+ ...(linter.script !== undefined ? { script: linter.script } : {}),
27
+ };
28
+ }
29
+ /**
30
+ * The files a rule applies to.
31
+ *
32
+ * A file no rule reads is not read: the check reads every file it is given,
33
+ * and a scope of a whole project holds a thousand files that no rule has an
34
+ * opinion about.
35
+ */
36
+ function auditedFiles(files) {
37
+ return files.filter((path) => allRegistry.forFile(path).length > 0);
38
+ }
39
+ /**
40
+ * The findings of the check, when there is a file to check.
41
+ *
42
+ * The design file is read as data: it can name a taste rule and turn it
43
+ * off, and nothing else.
44
+ */
45
+ async function findingsOf(files, root) {
46
+ if (files.length === 0)
47
+ return [];
48
+ const design = await readDesignMd(root);
49
+ const ctx = design === undefined ? {} : { design };
50
+ return await check(files, ctx, { root, registry: allRegistry });
51
+ }
52
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/quality/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,EAEL,WAAW,GAGZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAqB,MAAM,cAAc,CAAC;AAmDnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA4B;IAChE,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,OAAO;QACL,KAAK;QACL,QAAQ,EAAE,GAAG;QACb,IAAI;QACJ,MAAM;QACN,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,KAAwB;IAC5C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,UAAU,CAAC,KAAwB,EAAE,IAAY;IAC9D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;IACnD,OAAO,MAAM,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { Finding } from '@openagentsy/quality';
2
+ /**
3
+ * The findings store.
4
+ *
5
+ * The findings a check produced have to outlive the session that produced
6
+ * them: the task store reads them when a task is completed, and that is
7
+ * another process, hours later. So they live in a file under the state
8
+ * root, beside the waivers the next bean writes, and the file is the only
9
+ * truth.
10
+ *
11
+ * A record replaces the findings of the files it checked and keeps the
12
+ * findings of the other files. So a finding that has been fixed goes away
13
+ * when the file is written again, and a finding of another file is not
14
+ * lost by the write.
15
+ */
16
+ /** The file the findings live in. */
17
+ export declare function findingsPath(stateRoot: string): string;
18
+ /** What the store can do. */
19
+ export interface FindingsStore {
20
+ /** Record what a check found, for the files the check looked at. */
21
+ record(taskId: string, files: readonly string[], findings: readonly Finding[]): Promise<void>;
22
+ /** Every finding recorded for a task. */
23
+ forTask(taskId: string): Promise<Finding[]>;
24
+ /** The floor findings that are open for a task. */
25
+ openFloor(taskId: string): Promise<Finding[]>;
26
+ }
27
+ /**
28
+ * The store of a project.
29
+ *
30
+ * The state root is the root of the project, and the file is under it, so
31
+ * two projects never read each other's findings.
32
+ */
33
+ export declare function createFindingsStore(stateRoot: string): FindingsStore;
34
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../src/quality/findings.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGpD;;;;;;;;;;;;;GAaG;AAEH,qCAAqC;AACrC,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,6BAA6B;AAC7B,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,yCAAyC;IACzC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5C,mDAAmD;IACnD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CAC/C;AAmDD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAgBpE"}
@@ -0,0 +1,121 @@
1
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { normalizePath } from '@openagentsy/core';
4
+ import { z } from 'zod';
5
+ /**
6
+ * The findings store.
7
+ *
8
+ * The findings a check produced have to outlive the session that produced
9
+ * them: the task store reads them when a task is completed, and that is
10
+ * another process, hours later. So they live in a file under the state
11
+ * root, beside the waivers the next bean writes, and the file is the only
12
+ * truth.
13
+ *
14
+ * A record replaces the findings of the files it checked and keeps the
15
+ * findings of the other files. So a finding that has been fixed goes away
16
+ * when the file is written again, and a finding of another file is not
17
+ * lost by the write.
18
+ */
19
+ /** The file the findings live in. */
20
+ export function findingsPath(stateRoot) {
21
+ return join(stateRoot, '.openagentsy', 'quality', 'findings.json');
22
+ }
23
+ /** A finding, as the file holds it. */
24
+ const FindingSchema = z.object({
25
+ ruleId: z.string(),
26
+ source: z.string(),
27
+ tier: z.enum(['floor', 'reflex', 'finish']),
28
+ file: z.string(),
29
+ line: z.number(),
30
+ message: z.string(),
31
+ fix: z.string(),
32
+ kind: z.enum(['claim']).optional(),
33
+ });
34
+ /** The file, as it holds the findings. */
35
+ const FindingsFileSchema = z.object({
36
+ version: z.number(),
37
+ tasks: z.record(z.string(), z.array(FindingSchema)),
38
+ });
39
+ /**
40
+ * A finding, as the quality package says it.
41
+ *
42
+ * The schema knows an absent kind and an undefined kind alike, and the
43
+ * package says the kind is there or not there, so the absent one is
44
+ * dropped on the way out.
45
+ */
46
+ function toFinding(entry) {
47
+ const base = {
48
+ ruleId: entry.ruleId,
49
+ source: entry.source,
50
+ tier: entry.tier,
51
+ file: entry.file,
52
+ line: entry.line,
53
+ message: entry.message,
54
+ fix: entry.fix,
55
+ };
56
+ return entry.kind === undefined ? base : { ...base, kind: entry.kind };
57
+ }
58
+ /** The state of a project that has no findings yet. */
59
+ function emptyState() {
60
+ return {};
61
+ }
62
+ /**
63
+ * The store of a project.
64
+ *
65
+ * The state root is the root of the project, and the file is under it, so
66
+ * two projects never read each other's findings.
67
+ */
68
+ export function createFindingsStore(stateRoot) {
69
+ const path = findingsPath(stateRoot);
70
+ return {
71
+ record: async (taskId, files, findings) => {
72
+ const state = await readState(path);
73
+ const checked = new Set(files.map((file) => normalizePath(file)));
74
+ const kept = (state[taskId] ?? []).filter((finding) => !checked.has(normalizePath(finding.file)));
75
+ state[taskId] = [...kept, ...findings];
76
+ await writeState(path, state);
77
+ },
78
+ forTask: async (taskId) => (await readState(path))[taskId] ?? [],
79
+ openFloor: async (taskId) => ((await readState(path))[taskId] ?? []).filter((finding) => finding.tier === 'floor'),
80
+ };
81
+ }
82
+ /** What the file holds, when it holds something a store can read. */
83
+ async function readState(path) {
84
+ let text;
85
+ try {
86
+ text = await readFile(path, 'utf8');
87
+ }
88
+ catch {
89
+ return emptyState();
90
+ }
91
+ let parsed;
92
+ try {
93
+ parsed = JSON.parse(text);
94
+ }
95
+ catch {
96
+ return emptyState();
97
+ }
98
+ const result = FindingsFileSchema.safeParse(parsed);
99
+ if (!result.success)
100
+ return emptyState();
101
+ const tasks = {};
102
+ for (const [taskId, entries] of Object.entries(result.data.tasks)) {
103
+ tasks[taskId] = entries.map(toFinding);
104
+ }
105
+ return tasks;
106
+ }
107
+ /**
108
+ * Write the state.
109
+ *
110
+ * The write goes to a temporary file that is renamed over the old one, so
111
+ * a reader never sees half a file: the task store reads this file while
112
+ * the plugin writes it.
113
+ */
114
+ async function writeState(path, state) {
115
+ await mkdir(dirname(path), { recursive: true });
116
+ const temporary = `${path}.tmp`;
117
+ const file = { version: 1, tasks: state };
118
+ await writeFile(temporary, `${JSON.stringify(file, null, 2)}\n`, 'utf8');
119
+ await rename(temporary, path);
120
+ }
121
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/quality/findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=findings.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.test.d.ts","sourceRoot":"","sources":["../../src/quality/findings.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,79 @@
1
+ import { mkdtemp, readFile } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { describe, expect, it } from 'vitest';
5
+ import { createFindingsStore, findingsPath } from './findings.js';
6
+ /** A state root the test writes into. */
7
+ async function scratch() {
8
+ return await mkdtemp(join(tmpdir(), 'openagentsy-findings-'));
9
+ }
10
+ /** A finding, for the store to hold. */
11
+ function finding(over = {}) {
12
+ return {
13
+ ruleId: 'css/no-transition-all',
14
+ source: 'hallmark:floor-2',
15
+ tier: 'reflex',
16
+ file: 'src/app.css',
17
+ line: 12,
18
+ message: 'A transition of all moves every property.',
19
+ fix: 'Name the properties to transition instead of all',
20
+ ...over,
21
+ };
22
+ }
23
+ describe('the findings store', () => {
24
+ it('writes the findings under the state root', async () => {
25
+ const root = await scratch();
26
+ const store = createFindingsStore(root);
27
+ await store.record('oa-1', ['src/app.css'], [finding()]);
28
+ const written = await readFile(findingsPath(root), 'utf8');
29
+ expect(written).toContain('css/no-transition-all');
30
+ expect(findingsPath(root)).toBe(join(root, '.openagentsy', 'quality', 'findings.json'));
31
+ });
32
+ it('reads the findings back in a store that was made later', async () => {
33
+ const root = await scratch();
34
+ await createFindingsStore(root).record('oa-1', ['src/app.css'], [finding()]);
35
+ const found = await createFindingsStore(root).forTask('oa-1');
36
+ expect(found).toHaveLength(1);
37
+ expect(found[0]?.ruleId).toBe('css/no-transition-all');
38
+ });
39
+ it('keeps the findings of one task apart from the findings of another', async () => {
40
+ const root = await scratch();
41
+ const store = createFindingsStore(root);
42
+ await store.record('oa-1', ['src/app.css'], [finding()]);
43
+ await store.record('oa-2', ['src/other.css'], [finding({ file: 'src/other.css' })]);
44
+ expect(await store.forTask('oa-1')).toHaveLength(1);
45
+ expect((await store.forTask('oa-2'))[0]?.file).toBe('src/other.css');
46
+ });
47
+ it('holds the floor findings apart from the rest', async () => {
48
+ const root = await scratch();
49
+ const store = createFindingsStore(root);
50
+ await store.record('oa-1', ['src/app.css'], [
51
+ finding({ tier: 'floor' }),
52
+ finding({ tier: 'reflex', ruleId: 'copy/buzzwords' }),
53
+ finding({ tier: 'finish', ruleId: 'copy/em-dash' }),
54
+ ]);
55
+ const floor = await store.openFloor('oa-1');
56
+ expect(floor).toHaveLength(1);
57
+ expect(floor[0]?.tier).toBe('floor');
58
+ });
59
+ it('drops the findings of a file that was checked again', async () => {
60
+ const root = await scratch();
61
+ const store = createFindingsStore(root);
62
+ await store.record('oa-1', ['src/app.css'], [finding()]);
63
+ await store.record('oa-1', ['src/app.css'], []);
64
+ expect(await store.forTask('oa-1')).toEqual([]);
65
+ });
66
+ it('keeps the findings of the files that were not checked', async () => {
67
+ const root = await scratch();
68
+ const store = createFindingsStore(root);
69
+ await store.record('oa-1', ['src/app.css'], [finding()]);
70
+ await store.record('oa-1', ['src/other.css'], [finding({ file: 'src/other.css' })]);
71
+ const found = await store.forTask('oa-1');
72
+ expect(found.map((entry) => entry.file).sort()).toEqual(['src/app.css', 'src/other.css']);
73
+ });
74
+ it('starts empty for a project that has no findings yet', async () => {
75
+ const root = await scratch();
76
+ expect(await createFindingsStore(root).forTask('oa-1')).toEqual([]);
77
+ });
78
+ });
79
+ //# sourceMappingURL=findings.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.test.js","sourceRoot":"","sources":["../../src/quality/findings.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The quality check in the harness.
3
+ *
4
+ * The store holds the findings of the checks, and the rule runs a check
5
+ * after every write. The waivers are the decisions of people about those
6
+ * findings: a waiver a person recorded covers a finding, and a covered
7
+ * finding is not open.
8
+ *
9
+ * The tools are not here: they carry the whole rule set, and the whole
10
+ * rule set carries the TypeScript compiler. The plugin bundles this
11
+ * package, so the tools are reached by their own path,
12
+ * `@openagentsy/hooks/quality/tools`, and the board server imports them
13
+ * from there. The recording of a waiver is reached the same way,
14
+ * `@openagentsy/hooks/quality/waive`, because it asks the whole rule set
15
+ * whether a rule may be waived.
16
+ */
17
+ export * from './findings.js';
18
+ export * from './rule.js';
19
+ export * from './waivers.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quality/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The quality check in the harness.
3
+ *
4
+ * The store holds the findings of the checks, and the rule runs a check
5
+ * after every write. The waivers are the decisions of people about those
6
+ * findings: a waiver a person recorded covers a finding, and a covered
7
+ * finding is not open.
8
+ *
9
+ * The tools are not here: they carry the whole rule set, and the whole
10
+ * rule set carries the TypeScript compiler. The plugin bundles this
11
+ * package, so the tools are reached by their own path,
12
+ * `@openagentsy/hooks/quality/tools`, and the board server imports them
13
+ * from there. The recording of a waiver is reached the same way,
14
+ * `@openagentsy/hooks/quality/waive`, because it asks the whole rule set
15
+ * whether a rule may be waived.
16
+ */
17
+ export * from './findings.js';
18
+ export * from './rule.js';
19
+ export * from './waivers.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/quality/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { check } from '@openagentsy/quality/check';
2
+ import type { Rule } from '../registry.js';
3
+ import { type FindingsStore } from './findings.js';
4
+ import { type WaiverLookup } from './waivers.js';
5
+ /** When the check runs. */
6
+ export type QualityMode = 'during' | 'after';
7
+ /** What the rule needs to know. */
8
+ export interface QualityRuleOptions {
9
+ /** The project the agent works in. */
10
+ workspace: string;
11
+ /** Where the `.openagentsy/` directory lives. */
12
+ stateRoot: string;
13
+ /** When the check runs. */
14
+ mode: QualityMode;
15
+ /** The task the findings belong to, when there is one. */
16
+ taskId?: string | undefined;
17
+ /** The task of a session, when the session has one. */
18
+ taskIdForSession?: (sessionID: string) => string | undefined | Promise<string | undefined>;
19
+ /** The design file, read as data. */
20
+ design?: string | undefined;
21
+ /** The waivers that cover a finding. */
22
+ waivers?: WaiverLookup;
23
+ /** The store the findings go into. */
24
+ store?: FindingsStore;
25
+ /** How the check runs. */
26
+ check?: typeof check;
27
+ }
28
+ /**
29
+ * The rule.
30
+ *
31
+ * The mode decides what the rule does: `during` runs the check after every
32
+ * write, and `after` does nothing here — the findings are reported by the
33
+ * audit command instead.
34
+ */
35
+ export declare function qualityAfterWrite(options: QualityRuleOptions): Rule;
36
+ /**
37
+ * The design file of a project, read as data.
38
+ *
39
+ * The file is optional, and it is never read as instructions: it can name
40
+ * a taste rule and turn it off, and nothing else.
41
+ */
42
+ export declare function readDesignMd(workspace: string): Promise<string | undefined>;
43
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../src/quality/rule.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAKnD,OAAO,KAAK,EAAiB,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAqBnE,2BAA2B;AAC3B,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C,mCAAmC;AACnC,MAAM,WAAW,kBAAkB;IACjC,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3F,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,wCAAwC;IACxC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,sCAAsC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAyBnE;AAwFD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAMjF"}