pm-slack 2026.5.31 → 2026.6.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.6.3 - 2026-06-02
4
+
5
+ ### Added
6
+
7
+ - Deep feature enhancement 2026-06-03 ([pm-slack-l3ux](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/features/pm-slack-l3ux.toon))
8
+ - Digest reads pm store toon/json files directly \(no new SDK service\) ([pm-slack-06ti](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/decisions/pm-slack-06ti.toon))
9
+
10
+ ### Other
11
+
12
+ - Best-effort hook policy unchanged; strict creds only in test/digest real-post ([pm-slack-b08f](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/decisions/pm-slack-b08f.toon))
13
+ - Routing model: PM\_SLACK\_ROUTES JSON map + per-event channel override ([pm-slack-i3ir](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/decisions/pm-slack-i3ir.toon))
14
+ - Unit tests + README + functional test + release 2026.6.3 ([pm-slack-ffs4](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-ffs4.toon))
15
+ - Strict missing-creds CommandError for real posts; keep best-effort hook ([pm-slack-7fk4](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-7fk4.toon))
16
+ - slack digest command: activity summary over --since/--days ([pm-slack-nga4](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-nga4.toon))
17
+ - slack test command: offline preview, no network, --json ([pm-slack-36xw](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-36xw.toon))
18
+ - Event/type routing to multiple webhooks/channels \(PM\_SLACK\_ROUTES\) ([pm-slack-747x](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-747x.toon))
19
+ - Format toggle: --format text\|blockkit for hook + commands ([pm-slack-1fbz](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/tasks/pm-slack-1fbz.toon))
20
+
21
+ ## 2026.06.02 - 2026-06-02
22
+
23
+ ### Added
24
+
25
+ - Add afterCommand notification hook + slack notify command with Block Kit ([pm-slack-b3y5](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/features/pm-slack-b3y5.toon))
26
+
3
27
  ## 2026.05.29 - 2026-05-29
4
28
 
5
29
  ### Fixed
package/README.md CHANGED
@@ -33,10 +33,12 @@ pm install github.com/unbraind/pm-slack --project
33
33
 
34
34
  | Variable | Required | Default | Description |
35
35
  |---|---|---|---|
36
- | `PM_SLACK_WEBHOOK` | **Yes** | — | Slack incoming webhook URL |
37
- | `PM_SLACK_CHANNEL` | No | — | Channel hint appended to messages (e.g. `#pm-alerts`) |
36
+ | `PM_SLACK_WEBHOOK` | Usually | — | Slack incoming webhook URL (optional if every routing rule carries its own `webhook`) |
37
+ | `PM_SLACK_CHANNEL` | No | — | Default channel hint appended to messages (e.g. `#pm-alerts`) |
38
38
  | `PM_SLACK_MIN_PRIORITY` | No | `1` | Minimum priority to notify (1=critical, 2=high, 3=medium, 4=low) |
39
39
  | `PM_SLACK_EVENTS` | No | `create,close,block` | Comma-separated list of events to notify on |
40
+ | `PM_SLACK_FORMAT` | No | `blockkit` | Default message format: `blockkit` (rich) or `text` (plain mrkdwn) |
41
+ | `PM_SLACK_ROUTES` | No | — | JSON array of routing rules (see [Routing](#routing-by-event-type-or-status)) |
40
42
 
41
43
  Export them in your shell profile or `.env`:
42
44
 
@@ -45,6 +47,7 @@ export PM_SLACK_WEBHOOK="<slack-webhook-url>"
45
47
  export PM_SLACK_CHANNEL="#pm-alerts"
46
48
  export PM_SLACK_MIN_PRIORITY=2 # only critical + high
47
49
  export PM_SLACK_EVENTS="create,close" # skip block notifications
50
+ export PM_SLACK_FORMAT="text" # plain text instead of Block Kit
48
51
  ```
49
52
 
50
53
  ---
@@ -115,12 +118,107 @@ PM_SLACK_EVENTS="create,close"
115
118
 
116
119
  ---
117
120
 
121
+ ## Message Formats
122
+
123
+ Notifications render as rich Slack **Block Kit** by default (header, a fields
124
+ grid with item id / type / event / priority / status / author, an optional
125
+ reason section, and a context footer). Set the format to plain `text` for
126
+ minimal/legacy channels:
127
+
128
+ ```bash
129
+ export PM_SLACK_FORMAT="text" # plain mrkdwn, no blocks
130
+ ```
131
+
132
+ Per-command, the `--format blockkit|text` flag overrides the env var for
133
+ `slack notify`, `slack test`, and `slack digest`.
134
+
135
+ ---
136
+
137
+ ## Routing (by event, type, or status)
138
+
139
+ `PM_SLACK_ROUTES` is an optional JSON array of rules that send specific events,
140
+ item types, or statuses to a different webhook and/or channel. Routing is purely
141
+ additive — with no rules configured, behavior is unchanged.
142
+
143
+ Each rule is `{ "match": "<selector>", "webhook"?: "...", "channel"?: "..." }`.
144
+ Selectors:
145
+
146
+ | Selector | Matches |
147
+ |---|---|
148
+ | `create` / `close` / `block` | that lifecycle event |
149
+ | `type:<itemType>` | items of that type (case-insensitive) |
150
+ | `status:<status>` | items in that status (case-insensitive) |
151
+ | `*` / `all` | everything (use as a catch-all) |
152
+
153
+ The **first matching rule wins**; any field a rule omits falls back to the
154
+ default `PM_SLACK_WEBHOOK` / `PM_SLACK_CHANNEL`.
155
+
156
+ ```bash
157
+ export PM_SLACK_ROUTES='[
158
+ { "match": "block", "channel": "#urgent" },
159
+ { "match": "type:Bug", "webhook": "https://hooks.slack.com/services/AAA/BBB/CCC" }
160
+ ]'
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Commands
166
+
167
+ ### `pm slack notify`
168
+
169
+ Manually post a Block Kit (or text) message for an ad-hoc note.
170
+
171
+ ```bash
172
+ pm slack notify --text 'Release shipped :rocket:' --dry-run
173
+ pm slack notify --title 'Deploy done' --on close --format text --channel '#releases'
174
+ ```
175
+
176
+ ### `pm slack test`
177
+
178
+ Build and **print** a sample notification in the chosen format **without
179
+ posting** — fully offline, no webhook required. Great for previewing formatting.
180
+
181
+ ```bash
182
+ pm slack test --format blockkit # rich preview
183
+ pm slack test --format text --on close # plain-text preview of a close event
184
+ pm slack test --on block --json # machine-readable payload (with global --json)
185
+ ```
186
+
187
+ Flags: `--format blockkit|text`, `--on create|close|block`, `--title`,
188
+ `--channel`, `--json`.
189
+
190
+ ### `pm slack digest`
191
+
192
+ Produce a single summary of recent activity (created / closed / blocked /
193
+ in-progress) over a time window, as Block Kit or text. Reads the pm store
194
+ directly. Use `--dry-run` to preview without posting.
195
+
196
+ ```bash
197
+ pm slack digest --days 7 --dry-run
198
+ pm slack digest --since 2026-06-01 --format text --dry-run
199
+ pm slack digest --days 1 --format blockkit # real post (needs a webhook)
200
+ ```
201
+
202
+ Flags: `--since <date>`, `--days <n>` (default 7), `--format blockkit|text`,
203
+ `--channel`, `--webhook`, `--dry-run`, `--json`.
204
+
205
+ A real (non-`--dry-run`) `slack digest` post without a configured webhook fails
206
+ with a clear error (exit 1) rather than crashing.
207
+
208
+ ---
209
+
118
210
  ## Error Handling
119
211
 
120
- - If `PM_SLACK_WEBHOOK` is not set, the extension silently skips all notifications and logs a debug message.
121
- - If the webhook URL is invalid, the extension logs an error and continues without crashing pm-cli.
122
- - HTTP errors from Slack (non-2xx responses) are logged but do not fail the pm-cli command.
123
- - Network timeouts are set to 10 seconds.
212
+ The **lifecycle hook is best-effort** and never breaks your pm command:
213
+
214
+ - If `PM_SLACK_WEBHOOK` is not set, the hook silently skips all notifications and logs a debug message.
215
+ - If the webhook URL is invalid, the hook logs an error and continues without crashing pm-cli.
216
+ - HTTP errors from Slack (non-2xx responses), network failures, and timeouts (10s) are logged but never fail the underlying `pm` command.
217
+
218
+ The **`slack digest` command is strict** when actually posting:
219
+
220
+ - A real (non-`--dry-run`) `slack digest` post without a webhook fails with a clear `CommandError` (exit 1).
221
+ - Use `--dry-run` to build and preview a digest with no webhook and no network call.
124
222
 
125
223
  ---
126
224
 
@@ -141,12 +239,11 @@ The extension uses only Node.js built-ins (`node:https`) — no external runtime
141
239
  ```json
142
240
  {
143
241
  "name": "pm-slack",
144
- "version": "0.1.0",
145
242
  "description": "Slack notifications for pm item lifecycle events",
146
243
  "author": "@unbraind",
147
- "entry": "index.js",
244
+ "entry": "./dist/index.js",
148
245
  "priority": 50,
149
- "capabilities": ["hooks", "services"]
246
+ "capabilities": ["commands", "hooks", "schema"]
150
247
  }
151
248
  ```
152
249
 
package/dist/index.d.ts CHANGED
@@ -1,16 +1,184 @@
1
1
  /**
2
2
  * pm-slack — Slack notifications for pm-cli item lifecycle events
3
3
  *
4
+ * Two surfaces:
5
+ * 1. afterCommand hook — posts a Slack notification when an item is created,
6
+ * closed, or blocked (only if PM_SLACK_WEBHOOK is set; otherwise a silent
7
+ * no-op). The hook NEVER throws and NEVER blocks the command: all work is
8
+ * wrapped in try/catch and Slack posting is fire-and-forget.
9
+ * 2. `pm slack notify` command — manual posting of a rich Slack Block Kit
10
+ * message (sections, fields, context) with a plain-text fallback.
11
+ *
4
12
  * Env vars:
5
13
  * PM_SLACK_WEBHOOK (required) Slack incoming webhook URL
6
14
  * PM_SLACK_CHANNEL (optional) Override channel, e.g. #pm-alerts
7
15
  * PM_SLACK_MIN_PRIORITY (optional) Minimum priority to notify (1=critical … 4=low), default 1 (critical only; set 4 for all)
8
- * PM_SLACK_EVENTS (optional) Comma-separated subset: create,close,block (default: all)
16
+ * PM_SLACK_EVENTS (optional) Comma-separated subset of hook events: create,close,block (default: all)
17
+ * PM_SLACK_FORMAT (optional) Default notification format: "blockkit" (default) or "text"
18
+ * PM_SLACK_ROUTES (optional) JSON array of routing rules to send specific
19
+ * events/types/statuses to different webhooks/channels.
20
+ * Each rule: { "match": "<selector>", "webhook"?: "...", "channel"?: "..." }
21
+ * Selector forms: an event ("create"|"close"|"block"),
22
+ * "type:<itemType>" (case-insensitive), or "status:<status>".
23
+ * First matching rule wins; unset fields fall back to the defaults.
24
+ */
25
+ import type { AfterCommandHookContext } from "@unbrained/pm-cli/sdk";
26
+ declare class CommandError extends Error {
27
+ exitCode: number;
28
+ constructor(message: string, exitCode?: number);
29
+ }
30
+ type Priority = 1 | 2 | 3 | 4;
31
+ interface PmItem {
32
+ id: string;
33
+ title: string;
34
+ type?: string;
35
+ priority?: Priority;
36
+ status?: string;
37
+ close_reason?: string;
38
+ blocked_reason?: string;
39
+ closedReason?: string;
40
+ blockedReason?: string;
41
+ author?: string;
42
+ }
43
+ type EventKind = "create" | "close" | "block";
44
+ type MessageFormat = "blockkit" | "text";
45
+ /** A single routing rule parsed from PM_SLACK_ROUTES. */
46
+ interface RouteRule {
47
+ /** Raw selector string, e.g. "block", "type:Bug", "status:blocked". */
48
+ match: string;
49
+ webhook?: string;
50
+ channel?: string;
51
+ }
52
+ /** Resolved destination for a notification after applying routing rules. */
53
+ interface RouteTarget {
54
+ webhookUrl: string;
55
+ channel?: string;
56
+ }
57
+ interface SlackBlock {
58
+ type: string;
59
+ [key: string]: unknown;
60
+ }
61
+ interface SlackPayload {
62
+ text: string;
63
+ blocks?: SlackBlock[];
64
+ mrkdwn?: boolean;
65
+ channel?: string;
66
+ thread_ts?: string;
67
+ }
68
+ declare function parseEvents(spec: string | undefined): Set<EventKind>;
69
+ /**
70
+ * Normalize a format spec to a known MessageFormat. Accepts a few friendly
71
+ * aliases ("block"/"blocks" → blockkit, "plain"/"txt" → text). Falls back to
72
+ * the supplied default when the spec is empty or unrecognized.
73
+ */
74
+ declare function parseFormat(spec: string | undefined, fallback?: MessageFormat): MessageFormat;
75
+ declare function parseRoutes(spec: string | undefined): RouteRule[];
76
+ /**
77
+ * Does a single route rule match this event/item? Selector forms:
78
+ * - bare event name: "create" | "close" | "block"
79
+ * - "type:<itemType>" (case-insensitive on item.type)
80
+ * - "status:<status>" (case-insensitive on item.status)
81
+ * - "*" / "all" (matches everything — useful as a catch-all)
82
+ */
83
+ declare function ruleMatches(rule: RouteRule, event: EventKind, item: PmItem): boolean;
84
+ /**
85
+ * Resolve the destination (webhook + channel) for an event/item given the
86
+ * configured routes and the default webhook/channel. First matching rule wins;
87
+ * any field a rule omits falls back to the default. Returns null only when no
88
+ * webhook can be resolved at all.
89
+ */
90
+ declare function selectRoute(event: EventKind, item: PmItem, routes: RouteRule[], defaultWebhook: string, defaultChannel?: string): RouteTarget | null;
91
+ declare function meetsMinPriority(item: PmItem, minPriority: Priority): boolean;
92
+ declare function buildTextMessage(item: PmItem, event: EventKind, channel?: string): string;
93
+ interface BlockKitOptions {
94
+ channel?: string;
95
+ /** Extra free-form body appended as a section (e.g. from `--text`). */
96
+ note?: string;
97
+ }
98
+ declare function buildItemBlockKit(item: PmItem, event: EventKind, opts?: BlockKitOptions): {
99
+ blocks: SlackBlock[];
100
+ fallback: string;
101
+ };
102
+ /**
103
+ * Build a ready-to-post SlackPayload for an item event in the requested format.
104
+ * - "blockkit": rich Block Kit blocks + plain-text fallback in `text`.
105
+ * - "text": plain mrkdwn only (no `blocks`), for minimal/legacy channels.
9
106
  */
107
+ declare function buildItemPayload(item: PmItem, event: EventKind, format: MessageFormat, opts?: BlockKitOptions): SlackPayload;
108
+ /** Fields we read off each stored item for digest purposes. */
109
+ interface DigestItem extends PmItem {
110
+ created_at?: string;
111
+ updated_at?: string;
112
+ }
113
+ /**
114
+ * Minimal parser for a stored pm item file. Handles the toon scalar form
115
+ * (`key: value`, optionally quoted) and JSON. Only top-level scalar fields are
116
+ * extracted; nested/array sections are ignored. Returns null when no id found.
117
+ */
118
+ declare function parseStoredItem(content: string, ext: string): DigestItem | null;
119
+ /**
120
+ * Resolve a `--since <date>` / `--days <n>` window into an epoch-ms cutoff.
121
+ * `since` (ISO date or datetime) wins when both are given; otherwise `days`
122
+ * back from `now`. Defaults to 7 days. Returns the cutoff in ms.
123
+ */
124
+ declare function resolveWindow(since: string | undefined, days: number | undefined, now?: number): {
125
+ cutoffMs: number;
126
+ label: string;
127
+ };
128
+ type DigestBucket = "created" | "closed" | "blocked" | "in_progress";
129
+ interface DigestSummary {
130
+ windowLabel: string;
131
+ cutoffMs: number;
132
+ counts: Record<DigestBucket, number>;
133
+ buckets: Record<DigestBucket, DigestItem[]>;
134
+ total: number;
135
+ }
136
+ /**
137
+ * Aggregate store items into digest buckets for the window. An item counts as:
138
+ * - created if created_at >= cutoff
139
+ * - closed if it is in a closed/done status AND updated_at >= cutoff
140
+ * - blocked if status === blocked AND updated_at >= cutoff
141
+ * - in_progress if status === in_progress AND updated_at >= cutoff
142
+ * An item may appear in multiple buckets (e.g. created and blocked).
143
+ */
144
+ declare function aggregateDigest(items: DigestItem[], cutoffMs: number, windowLabel: string): DigestSummary;
145
+ declare function buildDigestText(summary: DigestSummary, channel?: string): string;
146
+ declare function buildDigestBlockKit(summary: DigestSummary, channel?: string): {
147
+ blocks: SlackBlock[];
148
+ fallback: string;
149
+ };
150
+ declare function buildDigestPayload(summary: DigestSummary, format: MessageFormat, channel?: string): SlackPayload;
151
+ declare function detectEvent(ctx: AfterCommandHookContext): EventKind | null;
152
+ declare function extractItem(ctx: AfterCommandHookContext): PmItem | null;
10
153
  declare const _default: {
11
154
  name: string;
12
155
  version: string;
13
156
  activate(api: import("@unbrained/pm-cli/sdk").ExtensionApi): void;
14
157
  };
15
158
  export default _default;
159
+ export declare const __test__: {
160
+ buildItemBlockKit: typeof buildItemBlockKit;
161
+ buildItemPayload: typeof buildItemPayload;
162
+ buildTextMessage: typeof buildTextMessage;
163
+ parseEvents: typeof parseEvents;
164
+ parseFormat: typeof parseFormat;
165
+ parseRoutes: typeof parseRoutes;
166
+ ruleMatches: typeof ruleMatches;
167
+ selectRoute: typeof selectRoute;
168
+ detectEvent: typeof detectEvent;
169
+ extractItem: typeof extractItem;
170
+ meetsMinPriority: typeof meetsMinPriority;
171
+ parseStoredItem: typeof parseStoredItem;
172
+ resolveWindow: typeof resolveWindow;
173
+ aggregateDigest: typeof aggregateDigest;
174
+ buildDigestText: typeof buildDigestText;
175
+ buildDigestBlockKit: typeof buildDigestBlockKit;
176
+ buildDigestPayload: typeof buildDigestPayload;
177
+ EXIT_CODE: {
178
+ readonly GENERIC_FAILURE: 1;
179
+ readonly USAGE: 2;
180
+ readonly NOT_FOUND: 3;
181
+ };
182
+ CommandError: typeof CommandError;
183
+ };
16
184
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;;;;;AAkQH,wBAqFG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAEV,uBAAuB,EAExB,MAAM,uBAAuB,CAAC;AAqB/B,cAAM,YAAa,SAAQ,KAAK;IAC9B,QAAQ,EAAE,MAAM,CAAC;gBACL,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAkC;CAK1E;AAMD,KAAK,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE9B,UAAU,MAAM;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,KAAK,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzC,yDAAyD;AACzD,UAAU,SAAS;IACjB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4EAA4E;AAC5E,UAAU,WAAW;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2CD,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,CAO7D;AAQD;;;;GAIG;AACH,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAE,aAA0B,GAAG,aAAa,CAMlG;AAUD,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,EAAE,CAyB1D;AAED;;;;;;GAMG;AACH,iBAAS,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAU7E;AAED;;;;;GAKG;AACH,iBAAS,WAAW,CAClB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,EAAE,EACnB,cAAc,EAAE,MAAM,EACtB,cAAc,CAAC,EAAE,MAAM,GACtB,WAAW,GAAG,IAAI,CAUpB;AAgED,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAItE;AA0BD,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAalF;AAUD,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iBAAS,iBAAiB,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,EAChB,IAAI,GAAE,eAAoB,GACzB;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA+C5C;AAED;;;;GAIG;AACH,iBAAS,gBAAgB,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,eAAoB,GACzB,YAAY,CAiBd;AA+DD,+DAA+D;AAC/D,UAAU,UAAW,SAAQ,MAAM;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAoCxE;AA4BD;;;;GAIG;AACH,iBAAS,aAAa,CACpB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,GAAE,MAAmB,GACvB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASrC;AAED,KAAK,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;AAErE,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf;AAOD;;;;;;;GAOG;AACH,iBAAS,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,CAyBlG;AAkBD,iBAAS,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAazE;AAED,iBAAS,mBAAmB,CAC1B,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAsD5C;AAED,iBAAS,kBAAkB,CACzB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,MAAM,GACf,YAAY,CAed;AAeD,iBAAS,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI,CAkBnE;AAED,iBAAS,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,GAAG,IAAI,CAehE;;;;;;AAMD,wBAmUG;AAGH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;CAoBpB,CAAC"}