pm-slack-standup 2026.6.2 → 2026.6.4-1
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 +30 -1
- package/README.md +96 -14
- package/dist/index.d.ts +268 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +678 -125
- package/dist/index.js.map +1 -1
- package/manifest.json +3 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 2026.6.
|
|
3
|
+
## 2026.6.4-1 - 2026-06-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- preflight: fail-fast Slack-credential gate for standup post path ([pm-slack-standup-qnkp](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/features/pm-slack-standup-qnkp.toon))
|
|
8
|
+
|
|
9
|
+
## 2026.06.04 - 2026-06-04
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Blocker inference, yesterday/today split, multi-channel, fallback-to-stdout, custom section labels ([pm-slack-standup-8s6b](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/features/pm-slack-standup-8s6b.toon))
|
|
14
|
+
|
|
15
|
+
## 2026.06.03 - 2026-06-02
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Deep feature expansion: multi-format output, grouping, sections, date windows ([pm-slack-standup-h64p](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/features/pm-slack-standup-h64p.toon))
|
|
20
|
+
- Add --days relative date window alongside --since ([pm-slack-standup-5sow](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-5sow.toon))
|
|
21
|
+
- Add --sections selection/ordering with dedicated Blocked section ([pm-slack-standup-jimx](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-jimx.toon))
|
|
22
|
+
- Add --group-by sprint and type \(extend assignee/status\) ([pm-slack-standup-f4m6](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-f4m6.toon))
|
|
23
|
+
- Add --format slack\|blockkit\|markdown\|plain unified output ([pm-slack-standup-dgyy](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-dgyy.toon))
|
|
24
|
+
|
|
25
|
+
### Other
|
|
26
|
+
|
|
27
|
+
- Keep slack message text byte-identical; --format governs printed output only \(blockkit JSON no longer always dumped in dry-run\) ([pm-slack-standup-rttw](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/decisions/pm-slack-standup-rttw.toon))
|
|
28
|
+
- Block Kit schema: single header \(150ch\), one mrkdwn section per bucket \(3000ch truncation\), divider + context footer ([pm-slack-standup-rpty](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/decisions/pm-slack-standup-rpty.toon))
|
|
29
|
+
- Export pure helpers + node:test unit suite \(formatters/grouping/window\) ([pm-slack-standup-uf4j](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-uf4j.toon))
|
|
30
|
+
- Missing-creds real post -\> CommandError \(exit 1\); no network in dry-run ([pm-slack-standup-m9ze](https://github.com/unbraind/pm-slack-standup/blob/main/.agents/pm/tasks/pm-slack-standup-m9ze.toon))
|
|
31
|
+
|
|
32
|
+
## 2026.06.02 - 2026-06-02
|
|
4
33
|
|
|
5
34
|
### Added
|
|
6
35
|
|
package/README.md
CHANGED
|
@@ -5,12 +5,20 @@ A [pm-cli](https://github.com/unbraind/pm-cli) extension that posts your current
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- Posts WIP, Blocked, Up Next (and optional Done) items to Slack as a rich **Block Kit** message (header, one section per bucket, context footer) with an automatic plain-text fallback
|
|
8
|
-
-
|
|
9
|
-
-
|
|
8
|
+
- **Four output formats** (`--format`): `slack` (Slack mrkdwn, the default), `blockkit` (the raw Block Kit `blocks` JSON), `markdown` (GitHub/CommonMark), and `plain` text
|
|
9
|
+
- **`--dry-run`** — build and print the message in the chosen format **without** posting to Slack (no network call is made)
|
|
10
|
+
- Group section items by `status` (default), `assignee`, `sprint`, or `type` (`--group-by`)
|
|
11
|
+
- Choose which sections to render and in what order with `--sections` (`in_progress`, `blocked`, `done`, `up_next`); a dedicated **Blocked** section always surfaces blocked items
|
|
12
|
+
- **Impediment inference** — the Blocked section surfaces not only `status=blocked` items but any open/in-progress item carrying a `blocked_by` dependency (top-level or in `dependencies[]`), so dependency-blocked work is never hidden
|
|
13
|
+
- **Yesterday/Today split** (`--yesterday`) — split the Done section into **Done Yesterday** / **Done Today** by the local-day boundary (implies `--include-done`)
|
|
14
|
+
- **Multi-channel posting** (`--channels #a,#b`) — post the same standup to several channel names and/or webhook URLs in one run, each message labelled with its own channel
|
|
15
|
+
- **`--fallback-to-stdout`** — if a Slack post fails, print the rendered standup to stdout (exit 0) instead of erroring out, so the work isn't lost on a transport failure
|
|
16
|
+
- **Custom section labels** (`--section-labels`) — override any section's title and/or emoji, e.g. `in_progress=Rolling,blocked=🔥 On Fire`
|
|
17
|
+
- Scope the "recently closed / Done" window with `--since <iso>` **or** `--days <n>` (relative)
|
|
10
18
|
- Map pm authors to Slack handles so they get mentioned (`--mention-map`)
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
19
|
+
- `pm standup export` — write the standup to a file as Markdown or JSON (the JSON form includes the full Block Kit payload for archiving or re-posting)
|
|
20
|
+
- `--channel` override; webhook URL configurable via flag or environment variable
|
|
21
|
+
- **Fail-fast credential preflight** — when you actually request a Slack post (anything other than `--dry-run`) but no webhook is configured, the command aborts **immediately** with a clear, actionable, non-zero error (exit 2) **before** reading any pm data or rendering anything — no half-built message, no crash. The non-posting `--dry-run` preview path is never gated, so previewing without credentials keeps working. See [Credential preflight](#credential-preflight).
|
|
14
22
|
|
|
15
23
|
## Installation
|
|
16
24
|
|
|
@@ -58,12 +66,35 @@ pm standup [flags]
|
|
|
58
66
|
|------|------|---------|-------------|
|
|
59
67
|
| `--webhook <url>` | string | — | Slack incoming webhook URL (overrides `PM_SLACK_WEBHOOK`) |
|
|
60
68
|
| `--channel <name>` | string | — | Channel name shown in the message (e.g. `#team-eng`) |
|
|
61
|
-
| `--dry-run` | boolean | `false` |
|
|
69
|
+
| `--dry-run` | boolean | `false` | Build and print the message in the chosen format **without** posting |
|
|
70
|
+
| `--format <fmt>` | string | `slack` | Output format: `slack` (mrkdwn) \| `blockkit` (JSON) \| `markdown` \| `plain` |
|
|
62
71
|
| `--include-done` | boolean | `false` | Include recently-closed items in a Done section |
|
|
63
|
-
| `--since <iso>` | string | — | ISO date/time window;
|
|
64
|
-
| `--
|
|
72
|
+
| `--since <iso>` | string | — | ISO date/time window; scopes the Done section to items updated since then |
|
|
73
|
+
| `--days <n>` | number | — | Relative window: scope Done to items updated in the last N days (combines with `--since`, more restrictive bound wins) |
|
|
74
|
+
| `--group-by <field>` | string | `status` | Group section items by `status` \| `assignee` \| `sprint` \| `type` |
|
|
75
|
+
| `--sections <list>` | string | all | Comma list of sections to render/order: `in_progress`, `blocked`, `done`, `up_next` |
|
|
65
76
|
| `--mention-map <map>` | string | — | Map pm authors to Slack handles, e.g. `alice=@alice,bob=@bob` |
|
|
66
|
-
| `--
|
|
77
|
+
| `--yesterday` | boolean | `false` | Split Done into **Done Yesterday** / **Done Today** by local day (implies `--include-done`) |
|
|
78
|
+
| `--channels <list>` | string | — | Post the same standup to multiple targets: comma list of `#channel` names and/or full webhook URLs |
|
|
79
|
+
| `--fallback-to-stdout` | boolean | `false` | If the Slack post fails, print the rendered standup to stdout (exit 0) instead of erroring |
|
|
80
|
+
| `--section-labels <map>` | string | — | Override section titles/emoji, e.g. `in_progress=Rolling,blocked=🔥 On Fire` |
|
|
81
|
+
|
|
82
|
+
> **Note on `text`:** the legacy `--format text` value is still accepted as an alias for `plain`.
|
|
83
|
+
|
|
84
|
+
### Output formats
|
|
85
|
+
|
|
86
|
+
`--format` selects what the command prints (in `--dry-run`) and how it renders the Slack message text:
|
|
87
|
+
|
|
88
|
+
- **`slack`** (default) — Slack mrkdwn (`*bold*`, `_italic_`). The message posted to Slack is unchanged from previous versions.
|
|
89
|
+
- **`blockkit`** — the raw Slack Block Kit `{ "blocks": [...] }` JSON, ready to POST to `chat.postMessage` or paste into Block Kit Builder.
|
|
90
|
+
- **`markdown`** — GitHub/CommonMark with `#`/`##` headings and `-` bullets, for issues, wikis, or PR comments.
|
|
91
|
+
- **`plain`** — emphasis-free plain text for email or terminals.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pm standup --dry-run --format blockkit # raw Block Kit JSON
|
|
95
|
+
pm standup --dry-run --format markdown --include-done # CommonMark
|
|
96
|
+
pm standup --dry-run --format plain --days 7 # plain text, last 7 days
|
|
97
|
+
```
|
|
67
98
|
|
|
68
99
|
## Export
|
|
69
100
|
|
|
@@ -96,7 +127,33 @@ pm standup --channel '#team-eng' --dry-run
|
|
|
96
127
|
|
|
97
128
|
**Include done items and use plain text format:**
|
|
98
129
|
```bash
|
|
99
|
-
pm standup --include-done --format
|
|
130
|
+
pm standup --include-done --format plain
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Group by sprint, only In Progress + Blocked:**
|
|
134
|
+
```bash
|
|
135
|
+
pm standup --dry-run --group-by sprint --sections in_progress,blocked
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Split Done by yesterday/today:**
|
|
139
|
+
```bash
|
|
140
|
+
pm standup --dry-run --yesterday --format plain
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Post to multiple channels at once:**
|
|
144
|
+
```bash
|
|
145
|
+
pm standup --channels '#team-eng,#standups'
|
|
146
|
+
pm standup --channels 'https://hooks.slack.com/services/AAA,https://hooks.slack.com/services/BBB'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Never lose the standup if Slack is down:**
|
|
150
|
+
```bash
|
|
151
|
+
pm standup --fallback-to-stdout # prints the message to stdout (exit 0) if the post fails
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Rename sections / change emoji:**
|
|
155
|
+
```bash
|
|
156
|
+
pm standup --dry-run --section-labels 'in_progress=Rolling,blocked=🔥 On Fire'
|
|
100
157
|
```
|
|
101
158
|
|
|
102
159
|
**Full explicit invocation:**
|
|
@@ -132,7 +189,7 @@ pm standup \
|
|
|
132
189
|
• [Chore] Update dependencies (priority 3)
|
|
133
190
|
```
|
|
134
191
|
|
|
135
|
-
### Plain Text (`--format
|
|
192
|
+
### Plain Text (`--format plain`)
|
|
136
193
|
|
|
137
194
|
```
|
|
138
195
|
📊 pm standup — 2026-05-09
|
|
@@ -150,6 +207,31 @@ pm standup \
|
|
|
150
207
|
• [Chore] Update dependencies (priority 3)
|
|
151
208
|
```
|
|
152
209
|
|
|
210
|
+
## Credential preflight
|
|
211
|
+
|
|
212
|
+
Before any post is attempted, `pm standup` runs a **fail-fast credential gate**:
|
|
213
|
+
|
|
214
|
+
- **A post is "requested"** whenever you do *not* pass `--dry-run`. (`--fallback-to-stdout` still counts as a post — it only changes how a *transport* failure is handled; it still needs a webhook to attempt delivery.)
|
|
215
|
+
- **The gate fires only when** a post is requested **and** no usable webhook is configured. A webhook is "configured" if `--webhook` or `PM_SLACK_WEBHOOK` is set, **or** every `--channels` target is a full webhook URL (bare `#name` channels still need the base webhook).
|
|
216
|
+
- **When it fires**, the command aborts **immediately** — before reading any pm items or rendering anything — with a clear, actionable error and a **non-zero exit (2 / usage)**. Nothing is posted.
|
|
217
|
+
- **When it does not fire** (a webhook is present, *or* you used `--dry-run`), the command proceeds exactly as before.
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Post requested, no webhook → immediate abort (exit 2), nothing posted:
|
|
221
|
+
pm standup --channel '#team-eng'
|
|
222
|
+
# Slack post requested but no webhook is configured. Set PM_SLACK_WEBHOOK or
|
|
223
|
+
# pass --webhook <url> (or provide full webhook URLs via --channels).
|
|
224
|
+
# To preview without posting, use --dry-run.
|
|
225
|
+
|
|
226
|
+
# Preview without credentials → always allowed (exit 0):
|
|
227
|
+
pm standup --dry-run
|
|
228
|
+
|
|
229
|
+
# With a webhook → preflight passes, the post proceeds:
|
|
230
|
+
PM_SLACK_WEBHOOK=https://hooks.slack.com/services/... pm standup --channel '#team-eng'
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This is implemented in the `standup` command handler (where a thrown error reliably aborts with a non-zero exit); the package also declares the `preflight` capability and registers a scoped pass-through preflight hook for the standup command.
|
|
234
|
+
|
|
153
235
|
## Environment Variables
|
|
154
236
|
|
|
155
237
|
| Variable | Description |
|
|
@@ -173,10 +255,10 @@ npm run dev # watch mode
|
|
|
173
255
|
|
|
174
256
|
## How It Works
|
|
175
257
|
|
|
176
|
-
1. Reads every item once via `pm --path <root> list-all --json --include-body` and buckets them locally into In Progress, Blocked, open (Up Next) and optionally Done.
|
|
258
|
+
1. Reads every item once via `pm --path <root> list-all --json --include-body` and buckets them locally into In Progress, Blocked, open (Up Next) and optionally Done. Any open/in-progress item with a `blocked_by` dependency (top-level or in `dependencies[]`) is re-bucketed into Blocked; closed items are never re-surfaced as blocked.
|
|
177
259
|
2. Sorts open items by priority (ascending) and takes the top 3 as "Up Next".
|
|
178
|
-
3. Builds a Slack Block Kit `blocks` array (header + a section per bucket + context footer) plus a plain-text `fallback`, optionally grouped by assignee and annotated with Slack mentions.
|
|
179
|
-
4.
|
|
260
|
+
3. Builds a Slack Block Kit `blocks` array (header + a section per bucket + context footer) plus a plain-text `fallback`, optionally grouped by assignee and annotated with Slack mentions. Section titles/emoji can be overridden with `--section-labels`, and `--yesterday` expands Done into Done Yesterday / Done Today.
|
|
261
|
+
4. In `--dry-run`, prints the message in the chosen `--format` and exits without any network call. Otherwise posts `{ text, blocks }` to each target (the base webhook plus any `--channels`) using Node.js native `https`. A missing webhook (on a real post) raises a structured `CommandError`; a failed post does too **unless** `--fallback-to-stdout` is set, in which case the rendered standup is printed to stdout and the command exits 0.
|
|
180
262
|
|
|
181
263
|
## License
|
|
182
264
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,271 @@
|
|
|
1
|
+
export declare class CommandError extends Error {
|
|
2
|
+
exitCode: number;
|
|
3
|
+
constructor(message: string, exitCode?: number);
|
|
4
|
+
}
|
|
5
|
+
export interface PmDependency {
|
|
6
|
+
id?: string;
|
|
7
|
+
kind?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface PmItem {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
status: string;
|
|
14
|
+
type?: string;
|
|
15
|
+
priority?: number;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
milestone?: string;
|
|
18
|
+
release?: string;
|
|
19
|
+
sprint?: string;
|
|
20
|
+
assignee?: string;
|
|
21
|
+
author?: string;
|
|
22
|
+
body?: string;
|
|
23
|
+
created_at?: string;
|
|
24
|
+
updated_at?: string;
|
|
25
|
+
blocked_by?: string;
|
|
26
|
+
dependencies?: PmDependency[];
|
|
27
|
+
}
|
|
28
|
+
export type Format = "slack" | "blockkit" | "markdown" | "plain";
|
|
29
|
+
export type GroupBy = "status" | "assignee" | "sprint" | "type";
|
|
30
|
+
export type SectionKey = "in_progress" | "blocked" | "done" | "up_next";
|
|
31
|
+
export declare const ALL_SECTIONS: readonly SectionKey[];
|
|
32
|
+
export interface StandupData {
|
|
33
|
+
wip: PmItem[];
|
|
34
|
+
blocked: PmItem[];
|
|
35
|
+
done: PmItem[];
|
|
36
|
+
upNext: PmItem[];
|
|
37
|
+
total: number;
|
|
38
|
+
doneYesterday?: PmItem[];
|
|
39
|
+
doneToday?: PmItem[];
|
|
40
|
+
}
|
|
41
|
+
export interface StandupOptions {
|
|
42
|
+
channel?: string;
|
|
43
|
+
format: Format;
|
|
44
|
+
includeDone: boolean;
|
|
45
|
+
since?: string;
|
|
46
|
+
groupBy: GroupBy;
|
|
47
|
+
sections: SectionKey[];
|
|
48
|
+
mentionMap: Record<string, string>;
|
|
49
|
+
splitYesterday: boolean;
|
|
50
|
+
sectionLabels: Partial<Record<SectionKey, SectionLabelOverride>>;
|
|
51
|
+
}
|
|
52
|
+
export interface SectionLabelOverride {
|
|
53
|
+
emoji?: string;
|
|
54
|
+
title?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function readBoolOption(options: Record<string, unknown>, key: string): boolean;
|
|
57
|
+
export declare function readStrOption(options: Record<string, unknown>, key: string): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Parse a `--mention-map` spec mapping pm authors to Slack handles.
|
|
60
|
+
* Accepts `author=@handle,other=@h2` (commas) or semicolon separators.
|
|
61
|
+
* A leading `@` on the handle is optional and normalized on.
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseMentionMap(spec: string | undefined): Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* Normalize a `--format` value. Accepts the four public formats plus the
|
|
66
|
+
* legacy `text` alias (== `plain`). Unknown values raise a USAGE CommandError.
|
|
67
|
+
*/
|
|
68
|
+
export declare function parseFormat(raw: string | undefined): Format;
|
|
69
|
+
export declare function parseGroupBy(raw: string | undefined): GroupBy;
|
|
70
|
+
/**
|
|
71
|
+
* Parse a `--sections` spec (comma/semicolon list) into an ordered, de-duped
|
|
72
|
+
* list of section keys. Empty spec → all sections in default order. An
|
|
73
|
+
* unknown token is a USAGE error rather than a silent drop.
|
|
74
|
+
*/
|
|
75
|
+
export declare function parseSections(spec: string | undefined): SectionKey[];
|
|
76
|
+
/**
|
|
77
|
+
* Parse a `--section-labels` spec overriding section titles (and optionally
|
|
78
|
+
* an emoji). Accepts `key=Label,other=Label2` (comma/semicolon separated).
|
|
79
|
+
* The label value may itself lead with an emoji + space, e.g.
|
|
80
|
+
* `blocked=🔥 On Fire` sets emoji "🔥" and title "On Fire"; a label with no
|
|
81
|
+
* leading emoji keeps the section's default emoji and only changes the title.
|
|
82
|
+
* Keys use the same aliases as `--sections` (wip→in_progress, etc.).
|
|
83
|
+
* Unknown keys are a USAGE error rather than a silent drop.
|
|
84
|
+
*/
|
|
85
|
+
export declare function parseSectionLabels(spec: string | undefined): Partial<Record<SectionKey, SectionLabelOverride>>;
|
|
86
|
+
/**
|
|
87
|
+
* Parse a `--channels` spec (comma/semicolon list) into an ordered, de-duped
|
|
88
|
+
* list of channel targets. Each target is either a Slack channel name
|
|
89
|
+
* (e.g. `#team-eng`) or a full webhook URL — multi-channel posting accepts
|
|
90
|
+
* both (a name is shown in the message; a URL is POSTed to). Empty → [].
|
|
91
|
+
*/
|
|
92
|
+
export declare function parseChannels(spec: string | undefined): string[];
|
|
93
|
+
/** True when a channel token is a full webhook URL rather than a name. */
|
|
94
|
+
export declare function isWebhookUrl(token: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the "recently closed" window start (ms epoch) from `--since` and/or
|
|
97
|
+
* `--days`. `--since` is an explicit ISO date/time; `--days <n>` is N days
|
|
98
|
+
* before now. If both are given the *later* (more restrictive) bound wins.
|
|
99
|
+
* Returns NaN when neither is set (no windowing). Invalid input → USAGE error.
|
|
100
|
+
*/
|
|
101
|
+
export declare function resolveSinceMs(since: string | undefined, days: number | undefined, now?: number): number;
|
|
102
|
+
export declare function parseDays(raw: string | undefined): number | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Read every item once via `list-all --json --include-body`, then bucket by
|
|
105
|
+
* status locally. This is a single pm invocation (vs. four list-by-status
|
|
106
|
+
* calls) and gives us bodies + assignee + timestamps for grouping/windowing.
|
|
107
|
+
*/
|
|
108
|
+
export declare function fetchAllItems(pmRoot: string): PmItem[];
|
|
109
|
+
/**
|
|
110
|
+
* True when an item's last activity falls within the [sinceMs, now] window.
|
|
111
|
+
* NaN sinceMs means "no window" → always true.
|
|
112
|
+
*/
|
|
113
|
+
export declare function withinWindow(item: PmItem, sinceMs: number): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* True when an item carries a `blocked_by` dependency, regardless of its
|
|
116
|
+
* status. pm surfaces this either as a top-level `blocked_by` string (item ID
|
|
117
|
+
* or free-text reason) or as one/more `dependencies` entries with
|
|
118
|
+
* `kind: "blocked_by"`. Used to surface impediments that are NOT explicitly
|
|
119
|
+
* status=blocked under the Blocked section.
|
|
120
|
+
*/
|
|
121
|
+
export declare function hasBlockedByDep(item: PmItem): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Local-day key (YYYY-MM-DD in the host's local timezone) for an item's last
|
|
124
|
+
* activity. Used by the `--yesterday` split. Falls back to created_at, then
|
|
125
|
+
* to the empty string when no timestamp is parseable.
|
|
126
|
+
*/
|
|
127
|
+
export declare function localDayKey(item: PmItem): string;
|
|
128
|
+
/** Local-day key (YYYY-MM-DD) for a given epoch-ms instant. */
|
|
129
|
+
export declare function localDayKeyOf(ms: number): string;
|
|
130
|
+
/**
|
|
131
|
+
* Bucket items into standup sections.
|
|
132
|
+
* `sinceMs` (epoch ms, NaN = no window) filters the Done section to items
|
|
133
|
+
* updated within the window; WIP/blocked/up-next always reflect current state.
|
|
134
|
+
*/
|
|
135
|
+
export declare function buildStandupData(items: PmItem[], opts: StandupOptions, sinceMs?: number, now?: number): StandupData;
|
|
136
|
+
interface SectionDef {
|
|
137
|
+
key: SectionKey;
|
|
138
|
+
emoji: string;
|
|
139
|
+
title: string;
|
|
140
|
+
items: PmItem[];
|
|
141
|
+
emptyNote: string | null;
|
|
142
|
+
withPriority: boolean;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Resolve the ordered, selected section definitions for the given data.
|
|
146
|
+
* `in_progress` and `blocked` always render (even empty, with their note);
|
|
147
|
+
* `done` and `up_next` only render when they hold items — preserving the
|
|
148
|
+
* historical message shape. `--sections` filters which keys are eligible.
|
|
149
|
+
*
|
|
150
|
+
* When `--yesterday` is active and Done has items, the single Done section is
|
|
151
|
+
* expanded into "Done Yesterday" + "Done Today" (only the non-empty subsets
|
|
152
|
+
* render), preserving the section's position in the ordering.
|
|
153
|
+
*/
|
|
154
|
+
export declare function resolveSections(data: StandupData, opts: StandupOptions): SectionDef[];
|
|
155
|
+
export declare function itemText(item: PmItem, mentionMap: Record<string, string>, withPriority?: boolean): string;
|
|
156
|
+
/**
|
|
157
|
+
* Group a list of items by the configured field (assignee, sprint or type).
|
|
158
|
+
* Items missing the field bucket under a synthetic "_none" key (rendered as a
|
|
159
|
+
* friendly label). Returns entries sorted by group key for stable output.
|
|
160
|
+
*/
|
|
161
|
+
export declare function groupItems(items: PmItem[], groupBy: GroupBy): Array<[string, PmItem[]]>;
|
|
162
|
+
/**
|
|
163
|
+
* Render the standup as a single text blob for the chosen non-Block-Kit
|
|
164
|
+
* format. `slack` is byte-identical to the historical output (mrkdwn);
|
|
165
|
+
* `plain` drops emphasis punctuation; `markdown` uses `#`/`**`/`-`.
|
|
166
|
+
*/
|
|
167
|
+
export declare function buildTextMessage(data: StandupData, opts: StandupOptions): string;
|
|
168
|
+
export interface SlackBlock {
|
|
169
|
+
type: string;
|
|
170
|
+
[key: string]: unknown;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Build a Slack Block Kit `blocks` array: a header, a section per selected
|
|
174
|
+
* standup bucket and a context footer. Returns the blocks plus a plain-text
|
|
175
|
+
* `fallback` Slack renders in notifications and old clients.
|
|
176
|
+
*
|
|
177
|
+
* Block Kit schema choices: a single `header` block (plain_text, capped at
|
|
178
|
+
* Slack's 150-char limit), one `section`/`mrkdwn` block per bucket (Slack
|
|
179
|
+
* caps section text at 3000 chars — long buckets are truncated with an
|
|
180
|
+
* ellipsis to stay valid), a `divider`, then a `context` footer summarizing
|
|
181
|
+
* counts / window / grouping.
|
|
182
|
+
*/
|
|
183
|
+
export declare function buildBlockKit(data: StandupData, opts: StandupOptions): {
|
|
184
|
+
blocks: SlackBlock[];
|
|
185
|
+
fallback: string;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Render the standup in whichever `--format` was selected, as the string the
|
|
189
|
+
* command prints (dry-run) or the exporter writes. `blockkit` returns the
|
|
190
|
+
* pretty-printed `{ blocks }` JSON; everything else returns text.
|
|
191
|
+
*/
|
|
192
|
+
export declare function renderStandup(data: StandupData, opts: StandupOptions): string;
|
|
193
|
+
/** One resolved post target: the webhook URL to POST to + the channel name. */
|
|
194
|
+
export interface PostTarget {
|
|
195
|
+
webhookUrl: string;
|
|
196
|
+
/** Channel name shown in the message (may differ per target). */
|
|
197
|
+
channel?: string;
|
|
198
|
+
}
|
|
199
|
+
export interface PostResultEntry {
|
|
200
|
+
channel?: string;
|
|
201
|
+
ok: boolean;
|
|
202
|
+
error?: string;
|
|
203
|
+
}
|
|
204
|
+
/** A poster sends one payload to one webhook. Injectable for testing. */
|
|
205
|
+
export type Poster = (webhookUrl: string, payload: Record<string, unknown>) => Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* Resolve the ordered list of post targets from `--webhook`/env + `--channel`
|
|
208
|
+
* + `--channels`. Each `--channels` token is either a `#name` (posted to the
|
|
209
|
+
* base webhook, just changing the displayed channel) or a full webhook URL
|
|
210
|
+
* (posted to that URL). When no `--channels` is given, a single target using
|
|
211
|
+
* the base webhook + `--channel` is returned. De-dupes (webhook,channel) pairs.
|
|
212
|
+
*/
|
|
213
|
+
export declare function resolvePostTargets(baseWebhook: string, baseChannel: string | undefined, channels: string[]): PostTarget[];
|
|
214
|
+
/**
|
|
215
|
+
* Post the standup to every resolved target, re-rendering per target so each
|
|
216
|
+
* channel's message shows its own channel name. Returns a per-target result;
|
|
217
|
+
* never throws — the caller decides how to treat failures (e.g. fallback to
|
|
218
|
+
* stdout). The `poster` is injectable so this is testable without a network.
|
|
219
|
+
*/
|
|
220
|
+
export declare function postStandupTargets(targets: PostTarget[], data: StandupData, baseOpts: StandupOptions, poster: Poster): Promise<PostResultEntry[]>;
|
|
221
|
+
/**
|
|
222
|
+
* Decide whether the `standup` invocation is actually going to *post* to Slack.
|
|
223
|
+
*
|
|
224
|
+
* The command has two non-posting shapes that must NOT be gated:
|
|
225
|
+
* - `--dry-run` : build + print the message, never touches Slack.
|
|
226
|
+
* Every other shape is a real post attempt (the default), including
|
|
227
|
+
* `--fallback-to-stdout` — that flag only means "print instead of erroring *if
|
|
228
|
+
* the network post fails*", it still REQUIRES a webhook to attempt the post.
|
|
229
|
+
*/
|
|
230
|
+
export declare function isPostRequested(options: Record<string, unknown>): boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Resolve whether a *base* Slack webhook is required for this post. `--channels`
|
|
233
|
+
* may carry full webhook URLs that are self-sufficient targets; but if there is
|
|
234
|
+
* no `--channels` at all, or any `--channels` entry is a bare `#name`, the base
|
|
235
|
+
* webhook (`--webhook` / `PM_SLACK_WEBHOOK`) is needed to actually deliver.
|
|
236
|
+
*/
|
|
237
|
+
export declare function needsBaseWebhook(channels: string[]): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Fail-fast credential preflight for the standup *post* path.
|
|
240
|
+
*
|
|
241
|
+
* Fires ONLY when a Slack post is actually requested (not `--dry-run`) AND the
|
|
242
|
+
* credentials needed to deliver it are missing. In that case it throws a
|
|
243
|
+
* structured {@link CommandError} (USAGE / exit 2) BEFORE any pm data is read
|
|
244
|
+
* or any message is rendered — a clean, actionable, non-zero abort.
|
|
245
|
+
*
|
|
246
|
+
* It deliberately does NOT block the legitimate non-posting shapes:
|
|
247
|
+
* - `--dry-run` (preview to stdout) is never gated.
|
|
248
|
+
* This keeps the existing stdout-fallback behaviour intact while turning a
|
|
249
|
+
* "we got all the way to the transport layer and then discovered there's no
|
|
250
|
+
* webhook" failure into an immediate, obvious one.
|
|
251
|
+
*
|
|
252
|
+
* NOTE: this is invoked from the command HANDLER (not from `registerPreflight`)
|
|
253
|
+
* on purpose. pm's runtime wraps `registerPreflight` overrides in a try/catch
|
|
254
|
+
* and downgrades any thrown error to a non-fatal warning, so a throw there does
|
|
255
|
+
* NOT abort the command. Throwing from the handler is the only reliable way to
|
|
256
|
+
* fail-fast with a non-zero exit. The `registerPreflight` registration below is
|
|
257
|
+
* a scoped pass-through that exists to surface the `preflight` capability.
|
|
258
|
+
*/
|
|
259
|
+
export declare function preflightSlackCredentials(options: Record<string, unknown>): void;
|
|
260
|
+
/**
|
|
261
|
+
* Resolve every standup option except the render `format`, which differs
|
|
262
|
+
* between the command (slack|blockkit|markdown|plain) and the exporter
|
|
263
|
+
* (md|json file format). Callers supply the format they want.
|
|
264
|
+
*/
|
|
265
|
+
export declare function resolveStandupOptions(options: Record<string, unknown>, format: Format): {
|
|
266
|
+
opts: StandupOptions;
|
|
267
|
+
sinceMs: number;
|
|
268
|
+
};
|
|
1
269
|
declare const _default: {
|
|
2
270
|
name: string;
|
|
3
271
|
version: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|