pm-slack 2026.6.2 → 2026.6.4

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,6 +1,30 @@
1
1
  # Changelog
2
2
 
3
- ## 2026.6.2 - 2026-06-02
3
+ ## 2026.6.4 - 2026-06-04
4
+
5
+ ### Added
6
+
7
+ - Lifecycle event taxonomy + assignee mentions + action buttons ([pm-slack-c3q7](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/features/pm-slack-c3q7.toon))
8
+
9
+ ## 2026.06.03 - 2026-06-02
10
+
11
+ ### Added
12
+
13
+ - Deep feature enhancement 2026-06-03 ([pm-slack-l3ux](https://github.com/unbraind/pm-slack/blob/main/.agents/pm/features/pm-slack-l3ux.toon))
14
+ - 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))
15
+
16
+ ### Other
17
+
18
+ - 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))
19
+ - 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))
20
+ - 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))
21
+ - 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))
22
+ - 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))
23
+ - 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))
24
+ - 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))
25
+ - 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))
26
+
27
+ ## 2026.06.02 - 2026-06-02
4
28
 
5
29
  ### Added
6
30
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Slack notifications for [pm-cli](https://github.com/unbraind/pm-cli) item lifecycle events.
4
4
 
5
- Fires after `create`, `close`, and `block` operations and posts a formatted message to a Slack incoming webhook.
5
+ Fires after `create`, `close`, `block`, `cancel`, `open`, `start`, `unblock`, and `reopen` lifecycle transitions and posts a formatted message to a Slack incoming webhook. Optionally maps assignees to Slack `@mentions` and adds Block Kit action buttons linking to the item / GitHub URL.
6
6
 
7
7
  ---
8
8
 
@@ -33,10 +33,14 @@ 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
- | `PM_SLACK_EVENTS` | No | `create,close,block` | Comma-separated list of events to notify on |
39
+ | `PM_SLACK_EVENTS` | No | all events | Comma-separated list of events to notify on. Status-name aliases (`canceled`, `in_progress`, …) accepted |
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)) |
42
+ | `PM_SLACK_ASSIGNEE_MAP` | No | — | Comma list of `name=slackId` pairs mapping assignees to Slack `@mentions`, e.g. `alice=U123,bob=U456` |
43
+ | `PM_SLACK_MENTION_ASSIGNEE` | No | auto | Set `0`/`false` to disable assignee mentions even when a map is set (auto-enabled when `PM_SLACK_ASSIGNEE_MAP` is non-empty) |
40
44
 
41
45
  Export them in your shell profile or `.env`:
42
46
 
@@ -45,6 +49,7 @@ export PM_SLACK_WEBHOOK="<slack-webhook-url>"
45
49
  export PM_SLACK_CHANNEL="#pm-alerts"
46
50
  export PM_SLACK_MIN_PRIORITY=2 # only critical + high
47
51
  export PM_SLACK_EVENTS="create,close" # skip block notifications
52
+ export PM_SLACK_FORMAT="text" # plain text instead of Block Kit
48
53
  ```
49
54
 
50
55
  ---
@@ -55,7 +60,17 @@ export PM_SLACK_EVENTS="create,close" # skip block notifications
55
60
  |---|---|---|
56
61
  | `create` | `pm add`, `pm create`, `pm new` | Fires when a new item is created |
57
62
  | `close` | `pm close`, `pm done`, `pm complete` | Fires when an item is closed/resolved |
58
- | `block` | `pm update --status blocked`, `pm set status blocked` | Fires when an item's status changes to blocked |
63
+ | `block` | `pm update --status blocked` | Fires when an item's status changes to blocked |
64
+ | `cancel` | `pm update --status canceled` | Fires when an item is canceled (reason read from `close_reason`) |
65
+ | `open` | `pm update --status open` (e.g. `draft → open`) | Fires when an item is published/opened |
66
+ | `start` | `pm claim`, `pm start-task`, `pm update --status in_progress` | Fires when work begins on an item |
67
+ | `unblock` | `pm update --status open` from a `blocked` state | Distinguished when the result carries the prior status |
68
+ | `reopen` | `pm update --status open` from a `closed`/`canceled` state | Distinguished when the result carries the prior status |
69
+
70
+ `unblock` / `reopen` are refinements of an `open` transition: when pm's hook
71
+ result exposes the previous status, the more specific event is used; otherwise
72
+ the transition surfaces as `open`. Status-name aliases (`canceled`,
73
+ `in_progress`, `reopened`, …) are accepted anywhere an event name is.
59
74
 
60
75
  ---
61
76
 
@@ -115,12 +130,141 @@ PM_SLACK_EVENTS="create,close"
115
130
 
116
131
  ---
117
132
 
133
+ ## Message Formats
134
+
135
+ Notifications render as rich Slack **Block Kit** by default (header, a fields
136
+ grid with item id / type / event / priority / status / author, an optional
137
+ reason section, and a context footer). Set the format to plain `text` for
138
+ minimal/legacy channels:
139
+
140
+ ```bash
141
+ export PM_SLACK_FORMAT="text" # plain mrkdwn, no blocks
142
+ ```
143
+
144
+ Per-command, the `--format blockkit|text` flag overrides the env var for
145
+ `slack notify`, `slack test`, and `slack digest`.
146
+
147
+ ---
148
+
149
+ ## Routing (by event, type, or status)
150
+
151
+ `PM_SLACK_ROUTES` is an optional JSON array of rules that send specific events,
152
+ item types, or statuses to a different webhook and/or channel. Routing is purely
153
+ additive — with no rules configured, behavior is unchanged.
154
+
155
+ Each rule is `{ "match": "<selector>", "webhook"?: "...", "channel"?: "..." }`.
156
+ Selectors:
157
+
158
+ | Selector | Matches |
159
+ |---|---|
160
+ | `create` / `close` / `block` | that lifecycle event |
161
+ | `type:<itemType>` | items of that type (case-insensitive) |
162
+ | `status:<status>` | items in that status (case-insensitive) |
163
+ | `*` / `all` | everything (use as a catch-all) |
164
+
165
+ The **first matching rule wins**; any field a rule omits falls back to the
166
+ default `PM_SLACK_WEBHOOK` / `PM_SLACK_CHANNEL`.
167
+
168
+ ```bash
169
+ export PM_SLACK_ROUTES='[
170
+ { "match": "block", "channel": "#urgent" },
171
+ { "match": "type:Bug", "webhook": "https://hooks.slack.com/services/AAA/BBB/CCC" }
172
+ ]'
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Assignee @mentions
178
+
179
+ Map a pm item's `assignee` to a Slack user (or group) id so notifications
180
+ @-mention the responsible person. Set `PM_SLACK_ASSIGNEE_MAP` to a comma list of
181
+ `name=id` pairs:
182
+
183
+ ```bash
184
+ export PM_SLACK_ASSIGNEE_MAP="alice=U0123ABC,bob=U0456DEF,team=<!subteam^S0789GHI>"
185
+ ```
186
+
187
+ - A raw id (`U0123ABC`) is wrapped as `<@U0123ABC>`.
188
+ - A pre-wrapped token (e.g. `<!subteam^S0789GHI>` for a group) is used verbatim.
189
+ - Mentions auto-enable in the hook whenever the map is non-empty; set
190
+ `PM_SLACK_MENTION_ASSIGNEE=0` to force them off.
191
+ - For ad-hoc posts, `pm slack notify --assignee alice --mention-assignee` resolves
192
+ the mention from the same map. When no mapping exists, the raw assignee name is
193
+ still shown (blockkit) — output is byte-identical to before when no map is set.
194
+
195
+ ---
196
+
197
+ ## Action buttons (item / GitHub links)
198
+
199
+ When a pm item carries a URL, the Block Kit notification adds an action button
200
+ linking to it (`View on GitHub` for github.com URLs, otherwise `Open item`). The
201
+ URL is read from the first present of these item fields: `github_url`,
202
+ `html_url`, `url`, `source_url`, `link` (camelCase variants accepted). The
203
+ plain-`text` format is unchanged. For ad-hoc posts:
204
+
205
+ ```bash
206
+ pm slack notify --title 'Deploy' --on close --url 'https://github.com/unbraind/pm-slack/pull/3' --dry-run
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Commands
212
+
213
+ ### `pm slack notify`
214
+
215
+ Manually post a Block Kit (or text) message for an ad-hoc note.
216
+
217
+ ```bash
218
+ pm slack notify --text 'Release shipped :rocket:' --dry-run
219
+ pm slack notify --title 'Deploy done' --on close --format text --channel '#releases'
220
+ ```
221
+
222
+ ### `pm slack test`
223
+
224
+ Build and **print** a sample notification in the chosen format **without
225
+ posting** — fully offline, no webhook required. Great for previewing formatting.
226
+
227
+ ```bash
228
+ pm slack test --format blockkit # rich preview
229
+ pm slack test --format text --on close # plain-text preview of a close event
230
+ pm slack test --on block --json # machine-readable payload (with global --json)
231
+ ```
232
+
233
+ Flags: `--format blockkit|text`, `--on create|close|block`, `--title`,
234
+ `--channel`, `--json`.
235
+
236
+ ### `pm slack digest`
237
+
238
+ Produce a single summary of recent activity (created / closed / blocked /
239
+ in-progress) over a time window, as Block Kit or text. Reads the pm store
240
+ directly. Use `--dry-run` to preview without posting.
241
+
242
+ ```bash
243
+ pm slack digest --days 7 --dry-run
244
+ pm slack digest --since 2026-06-01 --format text --dry-run
245
+ pm slack digest --days 1 --format blockkit # real post (needs a webhook)
246
+ ```
247
+
248
+ Flags: `--since <date>`, `--days <n>` (default 7), `--format blockkit|text`,
249
+ `--channel`, `--webhook`, `--dry-run`, `--json`.
250
+
251
+ A real (non-`--dry-run`) `slack digest` post without a configured webhook fails
252
+ with a clear error (exit 1) rather than crashing.
253
+
254
+ ---
255
+
118
256
  ## Error Handling
119
257
 
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.
258
+ The **lifecycle hook is best-effort** and never breaks your pm command:
259
+
260
+ - If `PM_SLACK_WEBHOOK` is not set, the hook silently skips all notifications and logs a debug message.
261
+ - If the webhook URL is invalid, the hook logs an error and continues without crashing pm-cli.
262
+ - HTTP errors from Slack (non-2xx responses), network failures, and timeouts (10s) are logged but never fail the underlying `pm` command.
263
+
264
+ The **`slack digest` command is strict** when actually posting:
265
+
266
+ - A real (non-`--dry-run`) `slack digest` post without a webhook fails with a clear `CommandError` (exit 1).
267
+ - Use `--dry-run` to build and preview a digest with no webhook and no network call.
124
268
 
125
269
  ---
126
270
 
@@ -141,12 +285,11 @@ The extension uses only Node.js built-ins (`node:https`) — no external runtime
141
285
  ```json
142
286
  {
143
287
  "name": "pm-slack",
144
- "version": "0.1.0",
145
288
  "description": "Slack notifications for pm item lifecycle events",
146
289
  "author": "@unbraind",
147
- "entry": "index.js",
290
+ "entry": "./dist/index.js",
148
291
  "priority": 50,
149
- "capabilities": ["hooks", "services"]
292
+ "capabilities": ["commands", "hooks", "schema"]
150
293
  }
151
294
  ```
152
295
 
package/dist/index.d.ts CHANGED
@@ -13,7 +13,20 @@
13
13
  * PM_SLACK_WEBHOOK (required) Slack incoming webhook URL
14
14
  * PM_SLACK_CHANNEL (optional) Override channel, e.g. #pm-alerts
15
15
  * PM_SLACK_MIN_PRIORITY (optional) Minimum priority to notify (1=critical … 4=low), default 1 (critical only; set 4 for all)
16
- * PM_SLACK_EVENTS (optional) Comma-separated subset of hook events: create,close,block (default: all)
16
+ * PM_SLACK_EVENTS (optional) Comma-separated subset of hook events:
17
+ * create,close,block,cancel,open,start,unblock,reopen (default: all).
18
+ * Status-name aliases (e.g. "canceled","in_progress") are accepted.
19
+ * PM_SLACK_FORMAT (optional) Default notification format: "blockkit" (default) or "text"
20
+ * PM_SLACK_ASSIGNEE_MAP (optional) Comma list of "name=slackId" pairs mapping a pm item's
21
+ * assignee to a Slack @mention, e.g. "alice=U123,bob=U456".
22
+ * PM_SLACK_MENTION_ASSIGNEE (optional) Set to 0/false to disable assignee @mentions even when a map is set
23
+ * (mentions auto-enable in the hook whenever PM_SLACK_ASSIGNEE_MAP is non-empty).
24
+ * PM_SLACK_ROUTES (optional) JSON array of routing rules to send specific
25
+ * events/types/statuses to different webhooks/channels.
26
+ * Each rule: { "match": "<selector>", "webhook"?: "...", "channel"?: "..." }
27
+ * Selector forms: an event ("create"|"close"|"block"),
28
+ * "type:<itemType>" (case-insensitive), or "status:<status>".
29
+ * First matching rule wins; unset fields fall back to the defaults.
17
30
  */
18
31
  import type { AfterCommandHookContext } from "@unbrained/pm-cli/sdk";
19
32
  declare class CommandError extends Error {
@@ -31,25 +44,162 @@ interface PmItem {
31
44
  blocked_reason?: string;
32
45
  closedReason?: string;
33
46
  blockedReason?: string;
47
+ cancel_reason?: string;
48
+ cancelReason?: string;
34
49
  author?: string;
50
+ assignee?: string;
51
+ url?: string;
52
+ github_url?: string;
53
+ githubUrl?: string;
54
+ html_url?: string;
55
+ htmlUrl?: string;
56
+ source_url?: string;
57
+ sourceUrl?: string;
58
+ link?: string;
59
+ }
60
+ type EventKind = "create" | "close" | "block" | "cancel" | "open" | "start" | "unblock" | "reopen";
61
+ type MessageFormat = "blockkit" | "text";
62
+ /** A single routing rule parsed from PM_SLACK_ROUTES. */
63
+ interface RouteRule {
64
+ /** Raw selector string, e.g. "block", "type:Bug", "status:blocked". */
65
+ match: string;
66
+ webhook?: string;
67
+ channel?: string;
68
+ }
69
+ /** Resolved destination for a notification after applying routing rules. */
70
+ interface RouteTarget {
71
+ webhookUrl: string;
72
+ channel?: string;
35
73
  }
36
- type EventKind = "create" | "close" | "block";
37
74
  interface SlackBlock {
38
75
  type: string;
39
76
  [key: string]: unknown;
40
77
  }
78
+ interface SlackPayload {
79
+ text: string;
80
+ blocks?: SlackBlock[];
81
+ mrkdwn?: boolean;
82
+ channel?: string;
83
+ thread_ts?: string;
84
+ }
85
+ declare function normalizeEvent(token: string): EventKind | null;
41
86
  declare function parseEvents(spec: string | undefined): Set<EventKind>;
87
+ /**
88
+ * Normalize a format spec to a known MessageFormat. Accepts a few friendly
89
+ * aliases ("block"/"blocks" → blockkit, "plain"/"txt" → text). Falls back to
90
+ * the supplied default when the spec is empty or unrecognized.
91
+ */
92
+ declare function parseFormat(spec: string | undefined, fallback?: MessageFormat): MessageFormat;
93
+ declare function parseRoutes(spec: string | undefined): RouteRule[];
94
+ /**
95
+ * Does a single route rule match this event/item? Selector forms:
96
+ * - bare event name: "create" | "close" | "block"
97
+ * - "type:<itemType>" (case-insensitive on item.type)
98
+ * - "status:<status>" (case-insensitive on item.status)
99
+ * - "*" / "all" (matches everything — useful as a catch-all)
100
+ */
101
+ declare function ruleMatches(rule: RouteRule, event: EventKind, item: PmItem): boolean;
102
+ /**
103
+ * Resolve the destination (webhook + channel) for an event/item given the
104
+ * configured routes and the default webhook/channel. First matching rule wins;
105
+ * any field a rule omits falls back to the default. Returns null only when no
106
+ * webhook can be resolved at all.
107
+ */
108
+ declare function selectRoute(event: EventKind, item: PmItem, routes: RouteRule[], defaultWebhook: string, defaultChannel?: string): RouteTarget | null;
42
109
  declare function meetsMinPriority(item: PmItem, minPriority: Priority): boolean;
43
- declare function buildTextMessage(item: PmItem, event: EventKind, channel?: string): string;
110
+ /** Parse PM_SLACK_ASSIGNEE_MAP into a case-insensitive name→id lookup. */
111
+ declare function parseAssigneeMap(spec: string | undefined): Map<string, string>;
112
+ /**
113
+ * Resolve an item's assignee to a Slack mention token using the map. Returns a
114
+ * ready-to-embed mention string (e.g. `<@U123>`) or undefined when there's no
115
+ * assignee or no mapping. A raw id is wrapped as `<@id>`; a token already
116
+ * containing `<` is passed through unchanged (supports `<!subteam^S123>` etc).
117
+ */
118
+ declare function resolveAssigneeMention(item: PmItem, map: Map<string, string>): string | undefined;
119
+ declare function isHttpUrl(value: unknown): value is string;
120
+ /** Resolve a primary URL for the item, plus whether it points at GitHub. */
121
+ declare function resolveItemUrl(item: PmItem, override?: string): {
122
+ url: string;
123
+ isGithub: boolean;
124
+ } | undefined;
125
+ declare function buildTextMessage(item: PmItem, event: EventKind, channel?: string, mention?: string): string;
44
126
  interface BlockKitOptions {
45
127
  channel?: string;
46
128
  /** Extra free-form body appended as a section (e.g. from `--text`). */
47
129
  note?: string;
130
+ /** Pre-resolved Slack mention token for the assignee (e.g. `<@U123>`). */
131
+ mention?: string;
132
+ /** Resolved item/GitHub URL for an action button. */
133
+ link?: {
134
+ url: string;
135
+ isGithub: boolean;
136
+ };
48
137
  }
49
138
  declare function buildItemBlockKit(item: PmItem, event: EventKind, opts?: BlockKitOptions): {
50
139
  blocks: SlackBlock[];
51
140
  fallback: string;
52
141
  };
142
+ /**
143
+ * Build a ready-to-post SlackPayload for an item event in the requested format.
144
+ * - "blockkit": rich Block Kit blocks + plain-text fallback in `text`.
145
+ * - "text": plain mrkdwn only (no `blocks`), for minimal/legacy channels.
146
+ */
147
+ declare function buildItemPayload(item: PmItem, event: EventKind, format: MessageFormat, opts?: BlockKitOptions): SlackPayload;
148
+ /** Fields we read off each stored item for digest purposes. */
149
+ interface DigestItem extends PmItem {
150
+ created_at?: string;
151
+ updated_at?: string;
152
+ }
153
+ /**
154
+ * Minimal parser for a stored pm item file. Handles the toon scalar form
155
+ * (`key: value`, optionally quoted) and JSON. Only top-level scalar fields are
156
+ * extracted; nested/array sections are ignored. Returns null when no id found.
157
+ */
158
+ declare function parseStoredItem(content: string, ext: string): DigestItem | null;
159
+ /**
160
+ * Resolve a `--since <date>` / `--days <n>` window into an epoch-ms cutoff.
161
+ * `since` (ISO date or datetime) wins when both are given; otherwise `days`
162
+ * back from `now`. Defaults to 7 days. Returns the cutoff in ms.
163
+ */
164
+ declare function resolveWindow(since: string | undefined, days: number | undefined, now?: number): {
165
+ cutoffMs: number;
166
+ label: string;
167
+ };
168
+ type DigestBucket = "created" | "closed" | "blocked" | "in_progress";
169
+ interface DigestSummary {
170
+ windowLabel: string;
171
+ cutoffMs: number;
172
+ counts: Record<DigestBucket, number>;
173
+ buckets: Record<DigestBucket, DigestItem[]>;
174
+ total: number;
175
+ }
176
+ /**
177
+ * Aggregate store items into digest buckets for the window. An item counts as:
178
+ * - created if created_at >= cutoff
179
+ * - closed if it is in a closed/done status AND updated_at >= cutoff
180
+ * - blocked if status === blocked AND updated_at >= cutoff
181
+ * - in_progress if status === in_progress AND updated_at >= cutoff
182
+ * An item may appear in multiple buckets (e.g. created and blocked).
183
+ */
184
+ declare function aggregateDigest(items: DigestItem[], cutoffMs: number, windowLabel: string): DigestSummary;
185
+ declare function buildDigestText(summary: DigestSummary, channel?: string): string;
186
+ declare function buildDigestBlockKit(summary: DigestSummary, channel?: string): {
187
+ blocks: SlackBlock[];
188
+ fallback: string;
189
+ };
190
+ declare function buildDigestPayload(summary: DigestSummary, format: MessageFormat, channel?: string): SlackPayload;
191
+ /** Map a (normalized) status string to the EventKind for a transition into it. */
192
+ declare function statusToEvent(status: string | undefined): EventKind | null;
193
+ /**
194
+ * Detect the lifecycle event for a completed command. Strategy:
195
+ * 1. Create/close commands map directly.
196
+ * 2. Status-changing commands (update/set/lifecycle aliases) derive the event
197
+ * from the *resulting* status (preferring the explicit --status option,
198
+ * falling back to the result item's status).
199
+ * 3. When the result carries the prior status (`previousStatus`), refine
200
+ * open→reopen (from a closed/canceled state) and open→unblock (from
201
+ * blocked) so terminal-recovery transitions are distinguishable.
202
+ */
53
203
  declare function detectEvent(ctx: AfterCommandHookContext): EventKind | null;
54
204
  declare function extractItem(ctx: AfterCommandHookContext): PmItem | null;
55
205
  declare const _default: {
@@ -60,11 +210,32 @@ declare const _default: {
60
210
  export default _default;
61
211
  export declare const __test__: {
62
212
  buildItemBlockKit: typeof buildItemBlockKit;
213
+ buildItemPayload: typeof buildItemPayload;
63
214
  buildTextMessage: typeof buildTextMessage;
64
215
  parseEvents: typeof parseEvents;
216
+ normalizeEvent: typeof normalizeEvent;
217
+ parseFormat: typeof parseFormat;
218
+ parseRoutes: typeof parseRoutes;
219
+ ruleMatches: typeof ruleMatches;
220
+ selectRoute: typeof selectRoute;
65
221
  detectEvent: typeof detectEvent;
222
+ statusToEvent: typeof statusToEvent;
66
223
  extractItem: typeof extractItem;
67
224
  meetsMinPriority: typeof meetsMinPriority;
225
+ parseAssigneeMap: typeof parseAssigneeMap;
226
+ resolveAssigneeMention: typeof resolveAssigneeMention;
227
+ resolveItemUrl: typeof resolveItemUrl;
228
+ isHttpUrl: typeof isHttpUrl;
229
+ EVENT_META: Record<EventKind, {
230
+ verb: string;
231
+ emoji: string;
232
+ }>;
233
+ parseStoredItem: typeof parseStoredItem;
234
+ resolveWindow: typeof resolveWindow;
235
+ aggregateDigest: typeof aggregateDigest;
236
+ buildDigestText: typeof buildDigestText;
237
+ buildDigestBlockKit: typeof buildDigestBlockKit;
238
+ buildDigestPayload: typeof buildDigestPayload;
68
239
  EXIT_CODE: {
69
240
  readonly GENERIC_FAILURE: 1;
70
241
  readonly USAGE: 2;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,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,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAmDD,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,CAO7D;AAsDD,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;AA+DD,iBAAS,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI,CAkBnE;AAED,iBAAS,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,GAAG,IAAI,CAehE;;;;;;AAMD,wBAoLG;AAGH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;CASpB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}