prismalens 0.0.2 → 0.1.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 (75) hide show
  1. package/README.md +12 -2
  2. package/dist/bin/prismalens.js +13 -0
  3. package/dist/bin/prismalens.js.map +1 -1
  4. package/dist/src/cli/doctor.d.ts +15 -1
  5. package/dist/src/cli/doctor.d.ts.map +1 -1
  6. package/dist/src/cli/doctor.js +107 -56
  7. package/dist/src/cli/doctor.js.map +1 -1
  8. package/dist/src/cli/flags.d.ts +2 -0
  9. package/dist/src/cli/flags.d.ts.map +1 -0
  10. package/dist/src/cli/flags.js +25 -0
  11. package/dist/src/cli/flags.js.map +1 -0
  12. package/dist/src/cli/grouping.d.ts +18 -0
  13. package/dist/src/cli/grouping.d.ts.map +1 -0
  14. package/dist/src/cli/grouping.js +169 -0
  15. package/dist/src/cli/grouping.js.map +1 -0
  16. package/dist/src/cli/init.d.ts.map +1 -1
  17. package/dist/src/cli/init.js +26 -11
  18. package/dist/src/cli/init.js.map +1 -1
  19. package/dist/src/cli/investigate.d.ts +12 -0
  20. package/dist/src/cli/investigate.d.ts.map +1 -1
  21. package/dist/src/cli/investigate.js +142 -140
  22. package/dist/src/cli/investigate.js.map +1 -1
  23. package/dist/src/cli/listen.d.ts +50 -0
  24. package/dist/src/cli/listen.d.ts.map +1 -0
  25. package/dist/src/cli/listen.js +249 -0
  26. package/dist/src/cli/listen.js.map +1 -0
  27. package/dist/src/cli/report.d.ts +19 -0
  28. package/dist/src/cli/report.d.ts.map +1 -0
  29. package/dist/src/cli/report.js +60 -0
  30. package/dist/src/cli/report.js.map +1 -0
  31. package/dist/src/cli/serve.d.ts.map +1 -1
  32. package/dist/src/cli/serve.js +11 -2
  33. package/dist/src/cli/serve.js.map +1 -1
  34. package/dist/src/cli/status.d.ts +14 -0
  35. package/dist/src/cli/status.d.ts.map +1 -0
  36. package/dist/src/cli/status.js +83 -0
  37. package/dist/src/cli/status.js.map +1 -0
  38. package/dist/src/config/loader.d.ts.map +1 -1
  39. package/dist/src/config/loader.js +28 -2
  40. package/dist/src/config/loader.js.map +1 -1
  41. package/dist/src/config/schema.d.ts +121 -0
  42. package/dist/src/config/schema.d.ts.map +1 -1
  43. package/dist/src/config/schema.js +47 -1
  44. package/dist/src/config/schema.js.map +1 -1
  45. package/dist/src/core/caps.d.ts +36 -0
  46. package/dist/src/core/caps.d.ts.map +1 -0
  47. package/dist/src/core/caps.js +36 -0
  48. package/dist/src/core/caps.js.map +1 -0
  49. package/dist/src/core/db.d.ts +3 -0
  50. package/dist/src/core/db.d.ts.map +1 -0
  51. package/dist/src/core/db.js +71 -0
  52. package/dist/src/core/db.js.map +1 -0
  53. package/dist/src/core/file-session-store.js +2 -2
  54. package/dist/src/core/file-session-store.js.map +1 -1
  55. package/dist/src/core/run-investigation.d.ts +10 -0
  56. package/dist/src/core/run-investigation.d.ts.map +1 -1
  57. package/dist/src/core/run-investigation.js +85 -30
  58. package/dist/src/core/run-investigation.js.map +1 -1
  59. package/dist/src/core/session.d.ts +22 -1
  60. package/dist/src/core/session.d.ts.map +1 -1
  61. package/dist/src/core/session.js +6 -129
  62. package/dist/src/core/session.js.map +1 -1
  63. package/dist/src/core/slack-notify.d.ts +9 -0
  64. package/dist/src/core/slack-notify.d.ts.map +1 -0
  65. package/dist/src/core/slack-notify.js +57 -0
  66. package/dist/src/core/slack-notify.js.map +1 -0
  67. package/dist/src/core/sqlite-session-store.d.ts +39 -0
  68. package/dist/src/core/sqlite-session-store.d.ts.map +1 -0
  69. package/dist/src/core/sqlite-session-store.js +239 -0
  70. package/dist/src/core/sqlite-session-store.js.map +1 -0
  71. package/dist/src/http/server.d.ts +26 -0
  72. package/dist/src/http/server.d.ts.map +1 -0
  73. package/dist/src/http/server.js +151 -0
  74. package/dist/src/http/server.js.map +1 -0
  75. package/package.json +6 -5
@@ -84,6 +84,7 @@ export declare const AgentConfigSchema: z.ZodObject<{
84
84
  * default (3). A single-alert run always uses one branch regardless.
85
85
  */
86
86
  max_branches: z.ZodOptional<z.ZodNumber>;
87
+ max_turns: z.ZodOptional<z.ZodNumber>;
87
88
  }, "strip", z.ZodTypeAny, {
88
89
  default: "deepagents" | "claude-code" | "codex";
89
90
  permissions: {
@@ -97,6 +98,7 @@ export declare const AgentConfigSchema: z.ZodObject<{
97
98
  };
98
99
  model?: string | undefined;
99
100
  max_branches?: number | undefined;
101
+ max_turns?: number | undefined;
100
102
  }, {
101
103
  default?: "deepagents" | "claude-code" | "codex" | undefined;
102
104
  model?: string | undefined;
@@ -104,6 +106,7 @@ export declare const AgentConfigSchema: z.ZodObject<{
104
106
  sandbox?: "auto" | "process" | "srt" | "e2b" | undefined;
105
107
  limits?: Record<string, unknown> | undefined;
106
108
  max_branches?: number | undefined;
109
+ max_turns?: number | undefined;
107
110
  }>;
108
111
  export declare const WorkspaceConfigSchema: z.ZodObject<{
109
112
  base_dir: z.ZodDefault<z.ZodString>;
@@ -112,6 +115,73 @@ export declare const WorkspaceConfigSchema: z.ZodObject<{
112
115
  }, {
113
116
  base_dir?: string | undefined;
114
117
  }>;
118
+ /**
119
+ * Run-budget guardrails for `pl listen` (issue #62): non-dollar caps only.
120
+ * `max_concurrent`/`max_per_hour` gate dispatch; `max_turns` is threaded into the
121
+ * default harness as a per-run runaway guard (no default ⇒ the harness's own default).
122
+ */
123
+ export declare const ListenCapsConfigSchema: z.ZodObject<{
124
+ /** Max investigations running at once. Default 2. */
125
+ max_concurrent: z.ZodDefault<z.ZodNumber>;
126
+ /** Max investigations started per trailing hour. Default 10. */
127
+ max_per_hour: z.ZodDefault<z.ZodNumber>;
128
+ /** Per-run turn ceiling for the default harness. Unset ⇒ the harness default. */
129
+ max_turns: z.ZodOptional<z.ZodNumber>;
130
+ }, "strip", z.ZodTypeAny, {
131
+ max_concurrent: number;
132
+ max_per_hour: number;
133
+ max_turns?: number | undefined;
134
+ }, {
135
+ max_turns?: number | undefined;
136
+ max_concurrent?: number | undefined;
137
+ max_per_hour?: number | undefined;
138
+ }>;
139
+ /**
140
+ * `pl listen` webhook intake (issue #58, Phase 1 R1). `token` is REQUIRED to
141
+ * start listening but optional here so every other command parses a config
142
+ * without it; set it via env interpolation (`token: "${PRISMALENS_LISTEN_TOKEN}"`)
143
+ * rather than a literal. The grouping_window_ms configures the debounce window.
144
+ */
145
+ export declare const ListenConfigSchema: z.ZodObject<{
146
+ /** Local intake port (4181: clear of 9090/9093/3000/8080 defaults). 0 = ephemeral. */
147
+ port: z.ZodDefault<z.ZodNumber>;
148
+ /** Shared bearer token Alertmanager presents; unset ⇒ `pl listen` refuses to start. */
149
+ token: z.ZodOptional<z.ZodString>;
150
+ /** Max alerts waiting or running at once; default 8. */
151
+ max_pending: z.ZodDefault<z.ZodNumber>;
152
+ /** Grouping window in milliseconds to debounce alerts into one investigation. */
153
+ grouping_window_ms: z.ZodDefault<z.ZodNumber>;
154
+ /**
155
+ * Slack incoming-webhook URL for report delivery (issue #61). Optional — unset ⇒
156
+ * delivery disabled. Set via env interpolation (slack_webhook_url:
157
+ * "${PRISMALENS_SLACK_WEBHOOK_URL}") so the secret stays in env (ADR-0006).
158
+ */
159
+ slack_webhook_url: z.ZodOptional<z.ZodString>;
160
+ /** Run-budget guardrails (issue #62). Always present with defaults after parse. */
161
+ caps: z.ZodEffects<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>, {
162
+ max_concurrent: number;
163
+ max_per_hour: number;
164
+ max_turns?: number | undefined;
165
+ }, Record<string, unknown> | undefined>;
166
+ }, "strip", z.ZodTypeAny, {
167
+ port: number;
168
+ max_pending: number;
169
+ grouping_window_ms: number;
170
+ caps: {
171
+ max_concurrent: number;
172
+ max_per_hour: number;
173
+ max_turns?: number | undefined;
174
+ };
175
+ token?: string | undefined;
176
+ slack_webhook_url?: string | undefined;
177
+ }, {
178
+ port?: number | undefined;
179
+ token?: string | undefined;
180
+ max_pending?: number | undefined;
181
+ grouping_window_ms?: number | undefined;
182
+ slack_webhook_url?: string | undefined;
183
+ caps?: Record<string, unknown> | undefined;
184
+ }>;
115
185
  /**
116
186
  * Read-only telemetry + app endpoints the harness may query. Mirrors the engine's
117
187
  * TelemetryEndpoints (camelCase) so a loaded config can be handed straight to
@@ -176,6 +246,19 @@ export declare const RepoConfigSchema: z.ZodObject<{
176
246
  local_path?: string | null | undefined;
177
247
  alert_sources?: Record<string, Record<string, string>> | undefined;
178
248
  }>;
249
+ export declare const SynthConfigSchema: z.ZodObject<{
250
+ provider: z.ZodOptional<z.ZodEnum<["custom" | "anthropic" | "openai" | "google" | "ollama" | "groq", ...("custom" | "anthropic" | "openai" | "google" | "ollama" | "groq")[]]>>;
251
+ model: z.ZodOptional<z.ZodString>;
252
+ base_url: z.ZodOptional<z.ZodString>;
253
+ }, "strip", z.ZodTypeAny, {
254
+ model?: string | undefined;
255
+ provider?: "custom" | "anthropic" | "openai" | "google" | "ollama" | "groq" | undefined;
256
+ base_url?: string | undefined;
257
+ }, {
258
+ model?: string | undefined;
259
+ provider?: "custom" | "anthropic" | "openai" | "google" | "ollama" | "groq" | undefined;
260
+ base_url?: string | undefined;
261
+ }>;
179
262
  export declare const PlConfigSchema: z.ZodObject<{
180
263
  $schema: z.ZodOptional<z.ZodString>;
181
264
  /** Convenience single-repo default (owner/name); `repos` is the multi-repo map. */
@@ -243,10 +326,28 @@ export declare const PlConfigSchema: z.ZodObject<{
243
326
  };
244
327
  model?: string | undefined;
245
328
  max_branches?: number | undefined;
329
+ max_turns?: number | undefined;
330
+ }, Record<string, unknown> | undefined>;
331
+ synth: z.ZodEffects<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>, {
332
+ model?: string | undefined;
333
+ provider?: "custom" | "anthropic" | "openai" | "google" | "ollama" | "groq" | undefined;
334
+ base_url?: string | undefined;
246
335
  }, Record<string, unknown> | undefined>;
247
336
  workspace: z.ZodEffects<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>, {
248
337
  base_dir: string;
249
338
  }, Record<string, unknown> | undefined>;
339
+ listen: z.ZodEffects<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>, {
340
+ port: number;
341
+ max_pending: number;
342
+ grouping_window_ms: number;
343
+ caps: {
344
+ max_concurrent: number;
345
+ max_per_hour: number;
346
+ max_turns?: number | undefined;
347
+ };
348
+ token?: string | undefined;
349
+ slack_webhook_url?: string | undefined;
350
+ }, Record<string, unknown> | undefined>;
250
351
  telemetry: z.ZodEffects<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>, {
251
352
  prometheusUrl?: string | undefined;
252
353
  alertmanagerUrl?: string | undefined;
@@ -266,6 +367,18 @@ export declare const PlConfigSchema: z.ZodObject<{
266
367
  native?: Record<string, unknown> | undefined;
267
368
  }> | undefined>;
268
369
  }, "strip", z.ZodTypeAny, {
370
+ listen: {
371
+ port: number;
372
+ max_pending: number;
373
+ grouping_window_ms: number;
374
+ caps: {
375
+ max_concurrent: number;
376
+ max_per_hour: number;
377
+ max_turns?: number | undefined;
378
+ };
379
+ token?: string | undefined;
380
+ slack_webhook_url?: string | undefined;
381
+ };
269
382
  alert_sources: Record<string, Record<string, string>>;
270
383
  repos: Record<string, {
271
384
  repo: string;
@@ -294,6 +407,12 @@ export declare const PlConfigSchema: z.ZodObject<{
294
407
  };
295
408
  model?: string | undefined;
296
409
  max_branches?: number | undefined;
410
+ max_turns?: number | undefined;
411
+ };
412
+ synth: {
413
+ model?: string | undefined;
414
+ provider?: "custom" | "anthropic" | "openai" | "google" | "ollama" | "groq" | undefined;
415
+ base_url?: string | undefined;
297
416
  };
298
417
  workspace: {
299
418
  base_dir: string;
@@ -309,6 +428,7 @@ export declare const PlConfigSchema: z.ZodObject<{
309
428
  repo?: string | undefined;
310
429
  $schema?: string | undefined;
311
430
  }, {
431
+ listen?: Record<string, unknown> | undefined;
312
432
  repo?: string | undefined;
313
433
  alert_sources?: Record<string, Record<string, string>> | undefined;
314
434
  $schema?: string | undefined;
@@ -324,6 +444,7 @@ export declare const PlConfigSchema: z.ZodObject<{
324
444
  }> | undefined;
325
445
  logs?: Record<string, unknown> | undefined;
326
446
  agent?: Record<string, unknown> | undefined;
447
+ synth?: Record<string, unknown> | undefined;
327
448
  workspace?: Record<string, unknown> | undefined;
328
449
  telemetry?: Record<string, unknown> | undefined;
329
450
  harnesses?: Record<string, {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;EAEjC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;;EAEpC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB;IACnC,qEAAqE;;IAErE,gEAAgE;;IAEhE,+EAA+E;;;;;;;;;;EAE9E,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB;;IAE7B;;;;;OAKG;;IAEH,4DAA4D;;;;IAE5D;;;;;;OAMG;;IAEH;;;OAGG;;;;;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;EAEF,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;EAEhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAIhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;IAE/B,yDAAyD;;IAEzD,2DAA2D;;;;;;;;;;EAE1D,CAAC;AAEH,gFAAgF;AAChF,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AAEH,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,iEAGnC,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AAcH,eAAO,MAAM,cAAc;;IAE1B,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;IAMnF,iFAAiF;;;QA5CjF,yDAAyD;;QAEzD,2DAA2D;;;;;;;;;;;;;;;;;;;IA+C3D,wDAAwD;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQxD,sEAAsE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKrE,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAC3D,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;EAEjC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;;EAEpC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB;IACnC,qEAAqE;;IAErE,gEAAgE;;IAEhE,+EAA+E;;;;;;;;;;EAE9E,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB;;IAE7B;;;;;OAKG;;IAEH,4DAA4D;;;;IAE5D;;;;;;OAMG;;IAEH;;;OAGG;;;;;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;EAGF,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;EAEhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;IAClC,qDAAqD;;IAErD,gEAAgE;;IAEhE,iFAAiF;;;;;;;;;;EAEhF,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;IAC9B,sFAAsF;;IAEtF,uFAAuF;;IAEvF,wDAAwD;;IAExD,iFAAiF;;IAEjF;;;;OAIG;;IAEH,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;EAElF,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAIhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;IAE/B,yDAAyD;;IAEzD,2DAA2D;;;;;;;;;;EAE1D,CAAC;AAEH,gFAAgF;AAChF,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AAEH,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,iEAGnC,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AAcH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;EAI5B,CAAC;AAEH,eAAO,MAAM,cAAc;;IAE1B,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;IAMnF,iFAAiF;;;QAlDjF,yDAAyD;;QAEzD,2DAA2D;;;;;;;;;;;;;;;;;;;IAqD3D,wDAAwD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAUxD,sEAAsE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKrE,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAC3D,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -18,6 +18,7 @@
18
18
  * the role machinery is gone.
19
19
  */
20
20
  import { HARNESS_IDS, PERMISSION_MODES } from "@prismalens/config/harness";
21
+ import { llmProviderIdSchema } from "@prismalens/config/llm";
21
22
  import { SANDBOX_MODES } from "@prismalens/engine";
22
23
  import { z } from "zod";
23
24
  /**
@@ -54,7 +55,7 @@ export const AgentLimitsConfigSchema = z.object({
54
55
  });
55
56
  /** Tier-2 harness backend the supervisor rents (ADR-0008). */
56
57
  export const AgentConfigSchema = z.object({
57
- default: z.enum(HARNESS_IDS).default("deepagents"),
58
+ default: z.enum(HARNESS_IDS).default("claude-code"),
58
59
  /**
59
60
  * BARE model id (e.g. "gpt-oss:120b") — the chosen harness applies its own
60
61
  * provider prefix (ADR-0017: deepagents prepends "openai:"; Claude Code takes it
@@ -83,10 +84,48 @@ export const AgentConfigSchema = z.object({
83
84
  * default (3). A single-alert run always uses one branch regardless.
84
85
  */
85
86
  max_branches: z.number().int().positive().optional(),
87
+ max_turns: z.number().int().positive().optional(),
86
88
  });
87
89
  export const WorkspaceConfigSchema = z.object({
88
90
  base_dir: z.string().default("~/.prismalens"),
89
91
  });
92
+ /**
93
+ * Run-budget guardrails for `pl listen` (issue #62): non-dollar caps only.
94
+ * `max_concurrent`/`max_per_hour` gate dispatch; `max_turns` is threaded into the
95
+ * default harness as a per-run runaway guard (no default ⇒ the harness's own default).
96
+ */
97
+ export const ListenCapsConfigSchema = z.object({
98
+ /** Max investigations running at once. Default 2. */
99
+ max_concurrent: z.number().int().positive().default(2),
100
+ /** Max investigations started per trailing hour. Default 10. */
101
+ max_per_hour: z.number().int().positive().default(10),
102
+ /** Per-run turn ceiling for the default harness. Unset ⇒ the harness default. */
103
+ max_turns: z.number().int().positive().optional(),
104
+ });
105
+ /**
106
+ * `pl listen` webhook intake (issue #58, Phase 1 R1). `token` is REQUIRED to
107
+ * start listening but optional here so every other command parses a config
108
+ * without it; set it via env interpolation (`token: "${PRISMALENS_LISTEN_TOKEN}"`)
109
+ * rather than a literal. The grouping_window_ms configures the debounce window.
110
+ */
111
+ export const ListenConfigSchema = z.object({
112
+ /** Local intake port (4181: clear of 9090/9093/3000/8080 defaults). 0 = ephemeral. */
113
+ port: z.number().int().min(0).max(65535).default(4181),
114
+ /** Shared bearer token Alertmanager presents; unset ⇒ `pl listen` refuses to start. */
115
+ token: z.string().optional(),
116
+ /** Max alerts waiting or running at once; default 8. */
117
+ max_pending: z.number().int().positive().default(8),
118
+ /** Grouping window in milliseconds to debounce alerts into one investigation. */
119
+ grouping_window_ms: z.number().int().min(1000).max(120000).default(60000),
120
+ /**
121
+ * Slack incoming-webhook URL for report delivery (issue #61). Optional — unset ⇒
122
+ * delivery disabled. Set via env interpolation (slack_webhook_url:
123
+ * "${PRISMALENS_SLACK_WEBHOOK_URL}") so the secret stays in env (ADR-0006).
124
+ */
125
+ slack_webhook_url: z.string().url().optional(),
126
+ /** Run-budget guardrails (issue #62). Always present with defaults after parse. */
127
+ caps: optionalWithDefaults(ListenCapsConfigSchema),
128
+ });
90
129
  /**
91
130
  * Read-only telemetry + app endpoints the harness may query. Mirrors the engine's
92
131
  * TelemetryEndpoints (camelCase) so a loaded config can be handed straight to
@@ -132,6 +171,11 @@ function optionalWithDefaults(schema) {
132
171
  .optional(z.record(z.string(), z.unknown()))
133
172
  .transform((val) => schema.parse(val ?? {}));
134
173
  }
174
+ export const SynthConfigSchema = z.object({
175
+ provider: llmProviderIdSchema.optional(),
176
+ model: z.string().optional(),
177
+ base_url: z.string().url().optional(),
178
+ });
135
179
  export const PlConfigSchema = z.object({
136
180
  $schema: z.string().optional(),
137
181
  /** Convenience single-repo default (owner/name); `repos` is the multi-repo map. */
@@ -148,7 +192,9 @@ export const PlConfigSchema = z.object({
148
192
  /** Read-only log-query system the harness may query. */
149
193
  logs: optionalWithDefaults(LogSourceConfigSchema),
150
194
  agent: optionalWithDefaults(AgentConfigSchema),
195
+ synth: optionalWithDefaults(SynthConfigSchema),
151
196
  workspace: optionalWithDefaults(WorkspaceConfigSchema),
197
+ listen: optionalWithDefaults(ListenConfigSchema),
152
198
  telemetry: optionalWithDefaults(TelemetryConfigSchema),
153
199
  alert_sources: AlertSourceConfigSchema.optional().transform((val) => val ?? {}),
154
200
  /** Per-harness native passthrough (ADR-0017), keyed by harness id. */
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The dispatch-time run-budget gate for `pl listen` (issue #62). Concurrency +
3
+ * per-hour ONLY gate dispatch here; `max_turns` is threaded to the engine harness
4
+ * (not a dispatch decision) and is deliberately absent from {@link DispatchCaps}.
5
+ * Pure and clock-injected: state lives in the closure, the clock is a caller arg, so
6
+ * the per-hour window is deterministically testable with a fake clock.
7
+ */
8
+ export interface DispatchCaps {
9
+ /** Max investigations running at once. Unset ⇒ concurrency unbounded. */
10
+ maxConcurrent?: number;
11
+ /** Max investigations STARTED in the trailing hour. Unset ⇒ rate unbounded. */
12
+ maxPerHour?: number;
13
+ }
14
+ export type CapReason = "concurrency" | "per_hour";
15
+ export type CapDecision = {
16
+ allow: true;
17
+ } | {
18
+ allow: false;
19
+ reason: CapReason;
20
+ };
21
+ export interface CapsGate {
22
+ /**
23
+ * Evaluate the caps and, on allow, ATOMICALLY record the start (active++ and push
24
+ * `nowMs` into the hourly window). The caller MUST invoke this with NO `await`
25
+ * between reading the caps and this call — the single-threaded event loop then
26
+ * makes check-and-commit atomic, so two window timers cannot both pass a
27
+ * concurrency=1 gate (the dispatch race the scout flagged).
28
+ */
29
+ tryDispatch(caps: DispatchCaps, nowMs: number): CapDecision;
30
+ /** Release one active slot when a dispatched run finishes. Call exactly once per `allow`. */
31
+ release(): void;
32
+ /** Live active count (inspection/tests). */
33
+ readonly activeCount: number;
34
+ }
35
+ export declare function createCapsGate(): CapsGate;
36
+ //# sourceMappingURL=caps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caps.d.ts","sourceRoot":"","sources":["../../../src/core/caps.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC5B,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;AACnD,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,QAAQ;IACxB;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5D,6FAA6F;IAC7F,OAAO,IAAI,IAAI,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAID,wBAAgB,cAAc,IAAI,QAAQ,CA+BzC"}
@@ -0,0 +1,36 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 Sumit Patel
3
+ const HOUR_MS = 3_600_000;
4
+ export function createCapsGate() {
5
+ let active = 0;
6
+ // Rolling window of dispatched-run START times (ms). Per-hour is a rate on
7
+ // STARTS, so entries are pruned by age, never by release.
8
+ const startsMs = [];
9
+ return {
10
+ get activeCount() {
11
+ return active;
12
+ },
13
+ tryDispatch(caps, nowMs) {
14
+ // Concurrency FIRST (cheapest, trips most often), then per-hour. The FIRST
15
+ // cap that trips is the recorded reason.
16
+ if (caps.maxConcurrent !== undefined && active >= caps.maxConcurrent) {
17
+ return { allow: false, reason: "concurrency" };
18
+ }
19
+ const cutoff = nowMs - HOUR_MS;
20
+ while (startsMs.length > 0 && startsMs[0] <= cutoff) {
21
+ startsMs.shift();
22
+ }
23
+ if (caps.maxPerHour !== undefined && startsMs.length >= caps.maxPerHour) {
24
+ return { allow: false, reason: "per_hour" };
25
+ }
26
+ active++;
27
+ startsMs.push(nowMs);
28
+ return { allow: true };
29
+ },
30
+ release() {
31
+ if (active > 0)
32
+ active--;
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=caps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caps.js","sourceRoot":"","sources":["../../../src/core/caps.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AAkC7B,MAAM,OAAO,GAAG,SAAS,CAAC;AAE1B,MAAM,UAAU,cAAc;IAC7B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,2EAA2E;IAC3E,0DAA0D;IAC1D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,OAAO;QACN,IAAI,WAAW;YACd,OAAO,MAAM,CAAC;QACf,CAAC;QACD,WAAW,CAAC,IAAI,EAAE,KAAK;YACtB,2EAA2E;YAC3E,yCAAyC;YACzC,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBACtE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;YAChD,CAAC;YACD,MAAM,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;YAC/B,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAK,QAAQ,CAAC,CAAC,CAAY,IAAI,MAAM,EAAE,CAAC;gBACjE,QAAQ,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;YACD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACzE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;YAC7C,CAAC;YACD,MAAM,EAAE,CAAC;YACT,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QACD,OAAO;YACN,IAAI,MAAM,GAAG,CAAC;gBAAE,MAAM,EAAE,CAAC;QAC1B,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DatabaseSync as DatabaseSyncType } from "node:sqlite";
2
+ export declare function openDatabase(baseDir: string): DatabaseSyncType;
3
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/core/db.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAYpE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CA0D9D"}
@@ -0,0 +1,71 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 Sumit Patel
3
+ import { mkdirSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ let DatabaseSync;
6
+ try {
7
+ const mod = await import("node:sqlite");
8
+ DatabaseSync = mod.DatabaseSync;
9
+ }
10
+ catch {
11
+ console.error("PrismaLens requires Node >= 22.13.");
12
+ process.exit(1);
13
+ }
14
+ export function openDatabase(baseDir) {
15
+ mkdirSync(baseDir, { recursive: true });
16
+ const db = new DatabaseSync(join(baseDir, "prismalens.db"));
17
+ db.exec(`
18
+ PRAGMA journal_mode = WAL;
19
+ PRAGMA busy_timeout = 5000;
20
+ PRAGMA foreign_keys = ON;
21
+
22
+ CREATE TABLE IF NOT EXISTS groups (
23
+ id TEXT PRIMARY KEY,
24
+ group_key TEXT,
25
+ formed_by TEXT NOT NULL DEFAULT 'window',
26
+ created_at TEXT NOT NULL
27
+ );
28
+
29
+ CREATE TABLE IF NOT EXISTS runs (
30
+ run_id TEXT PRIMARY KEY,
31
+ group_id TEXT REFERENCES groups(id),
32
+ status TEXT NOT NULL CHECK (status IN ('running','done','errored','suppressed')),
33
+ alertname TEXT,
34
+ agent TEXT,
35
+ repo TEXT,
36
+ workspace_path TEXT NOT NULL,
37
+ error TEXT,
38
+ suppression_reason TEXT,
39
+ created_at TEXT NOT NULL,
40
+ updated_at TEXT NOT NULL,
41
+ completed_at TEXT
42
+ );
43
+ CREATE INDEX IF NOT EXISTS idx_runs_created_at ON runs(created_at DESC);
44
+ CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(status);
45
+
46
+ CREATE TABLE IF NOT EXISTS events (
47
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
48
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
49
+ payload TEXT NOT NULL
50
+ );
51
+ CREATE INDEX IF NOT EXISTS idx_events_run ON events(run_id, id);
52
+
53
+ CREATE TABLE IF NOT EXISTS reports (
54
+ run_id TEXT PRIMARY KEY REFERENCES runs(run_id),
55
+ payload TEXT NOT NULL
56
+ );
57
+
58
+ -- One row per alert attached to a group, in insertion order (rowid).
59
+ -- late = 0 for the alerts that formed the window, 1 for alerts that
60
+ -- attached while the group's run was already in flight.
61
+ CREATE TABLE IF NOT EXISTS group_alerts (
62
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
63
+ group_id TEXT NOT NULL REFERENCES groups(id),
64
+ late INTEGER NOT NULL,
65
+ payload TEXT NOT NULL
66
+ );
67
+ CREATE INDEX IF NOT EXISTS idx_group_alerts ON group_alerts(group_id, id);
68
+ `);
69
+ return db;
70
+ }
71
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/core/db.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,IAAI,YAAqC,CAAC;AAE1C,IAAI,CAAC;IACJ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACxC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;AACjC,CAAC;AAAC,MAAM,CAAC;IACR,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC3C,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;IAE5D,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDP,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC;AACX,CAAC"}
@@ -17,8 +17,8 @@ export function createFileSessionStore(sessions, meta) {
17
17
  completedAt: new Date().toISOString(),
18
18
  });
19
19
  },
20
- async fail() {
21
- await sessions.update(meta.runId, { status: "errored" });
20
+ async fail(error) {
21
+ await sessions.update(meta.runId, { status: "errored", error });
22
22
  },
23
23
  };
24
24
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"file-session-store.js","sourceRoot":"","sources":["../../../src/core/file-session-store.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AA4B7B,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CACrC,QAAwB,EACxB,IAAwB;IAExB,IAAI,OAAkC,CAAC;IAEvC,MAAM,KAAK,GAAuB;QACjC,KAAK,CAAC,MAAM;YACX,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAqB;YACjC,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAA2B;YACvC,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;gBACjC,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI;YACT,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC1D,CAAC;KACD,CAAC;IAEF,OAAO;QACN,KAAK;QACL,aAAa;YACZ,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACd,uDAAuD,CACvD,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,aAAa,CAAC;QAC9B,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"file-session-store.js","sourceRoot":"","sources":["../../../src/core/file-session-store.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AA4B7B,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CACrC,QAAwB,EACxB,IAAwB;IAExB,IAAI,OAAkC,CAAC;IAEvC,MAAM,KAAK,GAAuB;QACjC,KAAK,CAAC,MAAM;YACX,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAqB;YACjC,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAA2B;YACvC,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;gBACjC,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAa;YACvB,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,CAAC;KACD,CAAC;IAEF,OAAO;QACN,KAAK;QACL,aAAa;YACZ,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACd,uDAAuD,CACvD,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,aAAa,CAAC;QAC9B,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -4,6 +4,8 @@ export type { ResolvedInvestigation };
4
4
  export interface ResolveInvestigationArgs {
5
5
  /** Raw alert payload (piped JSON / RPC param) coerced into a FiringAlert. */
6
6
  alert?: Record<string, unknown>;
7
+ /** Multiple raw alerts (storm grouping). When present, supersedes `alert`. */
8
+ alerts?: Record<string, unknown>[];
7
9
  /** Free-text fallback → a synthesized alert when no alert payload is supplied. */
8
10
  query?: string;
9
11
  /** Repository the harness investigates (its cwd). Defaults to `process.cwd()`. */
@@ -31,6 +33,8 @@ export interface ResolveInvestigationArgs {
31
33
  * console warning.
32
34
  */
33
35
  requestedSandbox?: string;
36
+ /** Per-run turn ceiling for the default harness (issue #62). Forwarded to the engine. */
37
+ maxTurns?: number;
34
38
  }
35
39
  /**
36
40
  * Resolve a seed alert + merged `pl.config.yaml` into the inputs
@@ -38,5 +42,11 @@ export interface ResolveInvestigationArgs {
38
42
  * the BYO-key secrets from env, and delegates the actual build to the engine
39
43
  * resolver. Throws (via the engine) on a hard input error.
40
44
  */
45
+ export declare function isSynthConfigured(config: PlConfig): boolean;
41
46
  export declare function resolveInvestigation(args: ResolveInvestigationArgs, config: PlConfig): ResolvedInvestigation;
47
+ /**
48
+ * The alert's service identity label — `service`, else `namespace`, else `job`.
49
+ * Exported for the `listen` path's per-payload repo resolution (issue #58 AC5).
50
+ */
51
+ export declare function pickServiceLabel(alert: Record<string, unknown> | undefined): string | undefined;
42
52
  //# sourceMappingURL=run-investigation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-investigation.d.ts","sourceRoot":"","sources":["../../../src/core/run-investigation.ts"],"names":[],"mappings":"AAmBA,OAAO,EAGN,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EAEZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,MAAM,WAAW,wBAAwB;IACxC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,wBAAwB,EAC9B,MAAM,EAAE,QAAQ,GACd,qBAAqB,CA4FvB"}
1
+ {"version":3,"file":"run-investigation.d.ts","sourceRoot":"","sources":["../../../src/core/run-investigation.ts"],"names":[],"mappings":"AAyBA,OAAO,EAIN,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EAEZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,MAAM,WAAW,wBAAwB;IACxC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACnC,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAa3D;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,wBAAwB,EAC9B,MAAM,EAAE,QAAQ,GACd,qBAAqB,CAwIvB;AAwCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,MAAM,GAAG,SAAS,CAIpB"}