standup-mr 0.6.1 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to standup-mr are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.0] - 2026-10-10
8
+
9
+ ### Added
10
+
11
+ - **Tool annotations.** Every MCP tool now declares `readOnlyHint`,
12
+ `destructiveHint`, `idempotentHint` and `openWorldHint`, so a host can tell
13
+ the read-only `get_standup_data` and `get_note_instructions` apart from
14
+ `post_standup_note`, which sends a message other people will see, and warn
15
+ before invoking it.
16
+
17
+ ### Changed
18
+
19
+ - The MCP server registers its tools with `registerTool`, which needs
20
+ `@modelcontextprotocol/sdk` 1.30.0 or later.
21
+
7
22
  ## [0.6.1] - 2026-09-02
8
23
 
9
24
  ### Fixed
package/README.md CHANGED
@@ -12,13 +12,13 @@ pipeline is red, it opens the job log and tells you **why**.
12
12
 
13
13
  ## What makes it different
14
14
 
15
- | | commit-log tools | standup-mr |
16
- |---|---|---|
17
- | Source | local `git log` | GitLab or GitHub API |
18
- | Merge request state | ✗ | ready / blocked / draft / stale |
19
- | Review queue | ✗ | pending only, approvals filtered out |
20
- | Failed pipeline | ✗ | error lines from the job trace or the Actions job log |
21
- | Self-hosted (GitLab CE/EE, GitHub Enterprise) | varies | first class |
15
+ | | commit-log tools | standup-mr |
16
+ | --------------------------------------------- | ---------------- | ----------------------------------------------------- |
17
+ | Source | local `git log` | GitLab or GitHub API |
18
+ | Merge request state | ✗ | ready / blocked / draft / stale |
19
+ | Review queue | ✗ | pending only, approvals filtered out |
20
+ | Failed pipeline | ✗ | error lines from the job trace or the Actions job log |
21
+ | Self-hosted (GitLab CE/EE, GitHub Enterprise) | varies | first class |
22
22
 
23
23
  ## Use
24
24
 
@@ -36,10 +36,10 @@ npx standup-mr fetch --markdown | npx standup-mr post --google-chat "$URL"
36
36
 
37
37
  ### Identity
38
38
 
39
- | | GitHub | GitLab |
40
- |---|---|---|
41
- | Flags | `--host` / `--token` | `--host` / `--token` |
42
- | Env | `GITHUB_HOST` / `GITHUB_TOKEN` | `GITLAB_HOST` / `GITLAB_TOKEN` |
39
+ | | GitHub | GitLab |
40
+ | ----------- | ------------------------------------------- | ------------------------------------------------------- |
41
+ | Flags | `--host` / `--token` | `--host` / `--token` |
42
+ | Env | `GITHUB_HOST` / `GITHUB_TOKEN` | `GITLAB_HOST` / `GITLAB_TOKEN` |
43
43
  | CLI session | [`gh`](https://cli.github.com/) auth config | [`glab`](https://gitlab.com/gitlab-org/cli) auth config |
44
44
 
45
45
  GitHub defaults to `github.com` when no host is given. GitLab has no default —
@@ -93,15 +93,15 @@ paste in the note-writing rules separately.
93
93
 
94
94
  ```json
95
95
  {
96
- "mcpServers": {
97
- "standup": {
98
- "command": "npx",
99
- "args": ["-y", "standup-mr", "mcp"],
100
- "env": {
101
- "GITHUB_TOKEN": "ghp_..."
102
- }
96
+ "mcpServers": {
97
+ "standup": {
98
+ "command": "npx",
99
+ "args": ["-y", "standup-mr", "mcp"],
100
+ "env": {
101
+ "GITHUB_TOKEN": "ghp_..."
102
+ }
103
+ }
103
104
  }
104
- }
105
105
  }
106
106
  ```
107
107
 
@@ -123,11 +123,11 @@ documentation for the current format rather than trusting this file blindly.
123
123
 
124
124
  The server exposes three tools:
125
125
 
126
- | Tool | What it does |
127
- |---|---|
128
- | `get_standup_data` | Reads the provider and returns the report as JSON. Optional `provider`, `host`, `lang`. |
126
+ | Tool | What it does |
127
+ | ----------------------- | -------------------------------------------------------------------------------------------- |
128
+ | `get_standup_data` | Reads the provider and returns the report as JSON. Optional `provider`, `host`, `lang`. |
129
129
  | `get_note_instructions` | Returns the note-writing rules, so the assistant can write the note the way the skill would. |
130
- | `post_standup_note` | Posts a finished note to a Slack, Discord or Google Chat webhook. |
130
+ | `post_standup_note` | Posts a finished note to a Slack, Discord or Google Chat webhook. |
131
131
 
132
132
  `post_standup_note` reads the webhook URL from `STANDUP_WEBHOOK_URL` and never
133
133
  takes it as an argument — anyone holding that URL can post to the channel, so
@@ -196,8 +196,8 @@ _Structured digest — not a written note._
196
196
  ## Blockers
197
197
 
198
198
  - `acme/mobile` !6 — job `quality`
199
- - `npm ERR! code E404`
200
- - `npm ERR! 404 Not Found - GET https://registry.example.com/@acme%2fui`
199
+ - `npm ERR! code E404`
200
+ - `npm ERR! 404 Not Found - GET https://registry.example.com/@acme%2fui`
201
201
  ```
202
202
 
203
203
  The last section is the point of the tool. Every other standup tool can tell you
@@ -232,7 +232,7 @@ pipe `standup fetch` into anything, or import the package, read
232
232
  returns `null` with no error.
233
233
  - `MergeRequest`, `Review` and `Blocker` carry a required `provider` field, and
234
234
  `Provider.getReviews` takes an `Identity` rather than a numeric id.
235
- - The MCP `CollectOptions.provider` is now a provider *name*; inject a
235
+ - The MCP `CollectOptions.provider` is now a provider _name_; inject a
236
236
  `Provider` instance through `providerImpl`.
237
237
 
238
238
  Claude Code plugin users should run `/plugin marketplace update standup-mr` —
@@ -1,12 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/buckets/buckets.constants.ts
4
- var STALE_DAYS = 14;
5
-
6
3
  // src/dates/dates.constants.ts
7
4
  var DAYS = {
8
- en: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
9
- tr: ["Pazar", "Pazartesi", "Sal\u0131", "\xC7ar\u015Famba", "Per\u015Fembe", "Cuma", "Cumartesi"]
5
+ en: [
6
+ "Sunday",
7
+ "Monday",
8
+ "Tuesday",
9
+ "Wednesday",
10
+ "Thursday",
11
+ "Friday",
12
+ "Saturday"
13
+ ],
14
+ tr: [
15
+ "Pazar",
16
+ "Pazartesi",
17
+ "Sal\u0131",
18
+ "\xC7ar\u015Famba",
19
+ "Per\u015Fembe",
20
+ "Cuma",
21
+ "Cumartesi"
22
+ ]
10
23
  };
11
24
  var MONTHS = {
12
25
  en: [
@@ -77,10 +90,14 @@ function previousActiveDays(eventDates, today) {
77
90
  }));
78
91
  }
79
92
 
93
+ // src/buckets/buckets.constants.ts
94
+ var STALE_DAYS = 14;
95
+
80
96
  // src/buckets/buckets.ts
81
97
  function classify(mr, today, staleDays = STALE_DAYS) {
82
98
  if (mr.draft) return "draft";
83
- if (mr.pipeline === "failed" || mr.pipeline === "canceled" || mr.unresolved > 0) return "blocked";
99
+ if (mr.pipeline === "failed" || mr.pipeline === "canceled" || mr.unresolved > 0)
100
+ return "blocked";
84
101
  const age = Math.round(
85
102
  (Date.parse(`${isoDay(today)}T00:00:00Z`) - Date.parse(`${mr.updated}T00:00:00Z`)) / MS_PER_DAY
86
103
  );
@@ -169,7 +186,9 @@ function cliStatus(cli) {
169
186
  }
170
187
  }
171
188
  function parseLoggedInHosts(statusOutput) {
172
- const hosts = [...statusOutput.matchAll(/Logged in to (\S+)/g)].map((match) => match[1]);
189
+ const hosts = [...statusOutput.matchAll(/Logged in to (\S+)/g)].map(
190
+ (match) => match[1]
191
+ );
173
192
  return [...new Set(hosts)].sort();
174
193
  }
175
194
  var parseGlabHosts = parseLoggedInHosts;
@@ -186,14 +205,6 @@ function ghToken(host) {
186
205
  return cliCapture("gh", ["auth", "token", "--hostname", host]);
187
206
  }
188
207
 
189
- // src/notify/notify.constants.ts
190
- var PAYLOAD_FIELD = {
191
- slack: "text",
192
- discord: "content",
193
- "google-chat": "text"
194
- };
195
- var WEBHOOK_KINDS = Object.keys(PAYLOAD_FIELD);
196
-
197
208
  // src/render/chat.ts
198
209
  var MARKDOWN_NATIVE = ["discord"];
199
210
  var FENCE = /^```/;
@@ -214,6 +225,14 @@ function toChatText(markdown, kind) {
214
225
  }).join("\n");
215
226
  }
216
227
 
228
+ // src/notify/notify.constants.ts
229
+ var PAYLOAD_FIELD = {
230
+ "slack": "text",
231
+ "discord": "content",
232
+ "google-chat": "text"
233
+ };
234
+ var WEBHOOK_KINDS = Object.keys(PAYLOAD_FIELD);
235
+
217
236
  // src/notify/notify.ts
218
237
  async function postWebhook(url, text, kind = "slack", fetchImpl = fetch) {
219
238
  const field = PAYLOAD_FIELD[kind];
@@ -228,7 +247,9 @@ async function postWebhook(url, text, kind = "slack", fetchImpl = fetch) {
228
247
  body: JSON.stringify({ [field]: toChatText(text, kind) })
229
248
  });
230
249
  if (!response.ok) {
231
- throw new Error(`Webhook rejected the message: HTTP ${response.status}.`);
250
+ throw new Error(
251
+ `Webhook rejected the message: HTTP ${response.status}.`
252
+ );
232
253
  }
233
254
  }
234
255
  var WEBHOOK_HOSTS = {
@@ -279,17 +300,25 @@ function retryAfter(response) {
279
300
  const value = response.headers.get("retry-after");
280
301
  if (!value) return "";
281
302
  const seconds = Number(value);
282
- if (!Number.isFinite(seconds) || seconds <= 0) return `; retry after ${value}`;
303
+ if (!Number.isFinite(seconds) || seconds <= 0)
304
+ return `; retry after ${value}`;
283
305
  return `; retry after ${seconds}s`;
284
306
  }
285
307
  function assertUsable(response, host) {
286
308
  if (response.ok || response.status === 404) return;
287
309
  if (response.status === 403 || response.status === 429) {
288
310
  if (remaining(response) === "0") {
289
- throw new ApiError(`${host} rate limit reached${resetAt(response)}.`, response.status);
311
+ throw new ApiError(
312
+ `${host} rate limit reached${resetAt(response)}.`,
313
+ response.status
314
+ );
290
315
  }
291
316
  const retry = retryAfter(response);
292
- if (retry) throw new ApiError(`${host} rate limit reached${retry}.`, response.status);
317
+ if (retry)
318
+ throw new ApiError(
319
+ `${host} rate limit reached${retry}.`,
320
+ response.status
321
+ );
293
322
  }
294
323
  if (response.status === 401) {
295
324
  throw new ApiError(
@@ -490,8 +519,8 @@ var GitHubProvider = class {
490
519
  }
491
520
  headers() {
492
521
  return {
493
- authorization: `Bearer ${this.token}`,
494
- accept: "application/vnd.github+json",
522
+ "authorization": `Bearer ${this.token}`,
523
+ "accept": "application/vnd.github+json",
495
524
  "x-github-api-version": API_VERSION
496
525
  };
497
526
  }
@@ -543,11 +572,14 @@ var GitHubProvider = class {
543
572
  return rows;
544
573
  }
545
574
  async getLogText(path) {
546
- const first = await this.send(buildUrl(this.api, path), { redirect: "manual" });
575
+ const first = await this.send(buildUrl(this.api, path), {
576
+ redirect: "manual"
577
+ });
547
578
  if (first.status === 404) return "";
548
579
  const location = first.headers.get("location");
549
580
  if (!location) {
550
- if (first.status === 0 || first.status >= 300 && first.status < 400) return "";
581
+ if (first.status === 0 || first.status >= 300 && first.status < 400)
582
+ return "";
551
583
  assertUsable(first, this.host);
552
584
  return first.ok ? await first.text() : "";
553
585
  }
@@ -590,7 +622,9 @@ var GitHubProvider = class {
590
622
  async shapePr(item) {
591
623
  const project = repoFromUrl(item.repository_url);
592
624
  const iid = item.number;
593
- const pull = await this.getJson(`repos/${project}/pulls/${iid}`);
625
+ const pull = await this.getJson(
626
+ `repos/${project}/pulls/${iid}`
627
+ );
594
628
  if (!pull) return null;
595
629
  const sha = pull.head?.sha ?? "";
596
630
  const [checks, reviews] = await Promise.all([
@@ -598,9 +632,15 @@ var GitHubProvider = class {
598
632
  `repos/${project}/commits/${sha}/check-runs`,
599
633
  { per_page: PAGE_SIZE }
600
634
  ) : Promise.resolve(null),
601
- this.getPaged(`repos/${project}/pulls/${iid}/reviews`, {}, 2)
635
+ this.getPaged(
636
+ `repos/${project}/pulls/${iid}/reviews`,
637
+ {},
638
+ 2
639
+ )
602
640
  ]);
603
- const { pipeline, pipelineId } = normalizeChecks(checks?.check_runs ?? []);
641
+ const { pipeline, pipelineId } = normalizeChecks(
642
+ checks?.check_runs ?? []
643
+ );
604
644
  return {
605
645
  provider: "github",
606
646
  project,
@@ -639,7 +679,9 @@ var GitHubProvider = class {
639
679
  `is:pr is:open review-requested:${identity.username}`,
640
680
  SEARCH_CAP
641
681
  );
642
- const cutoff = isoDay(new Date(today.getTime() - FRESH_REVIEW_DAYS * MS_PER_DAY));
682
+ const cutoff = isoDay(
683
+ new Date(today.getTime() - FRESH_REVIEW_DAYS * MS_PER_DAY)
684
+ );
643
685
  const rows = await Promise.all(
644
686
  items.map(async (item) => {
645
687
  const project = repoFromUrl(item.repository_url);
@@ -705,7 +747,10 @@ var GitHubProvider = class {
705
747
  (run) => run.conclusion !== null && FAILED_CONCLUSIONS.has(run.conclusion)
706
748
  );
707
749
  if (!failed) return null;
708
- const summary = [failed.output?.summary ?? "", failed.output?.text ?? ""].filter(Boolean).join("\n");
750
+ const summary = [
751
+ failed.output?.summary ?? "",
752
+ failed.output?.text ?? ""
753
+ ].filter(Boolean).join("\n");
709
754
  const errors = extractErrors(summary);
710
755
  if (errors.length === 0) return null;
711
756
  return {
@@ -818,7 +863,9 @@ var GitLabProvider = class {
818
863
  const raw = await this.getPaged("events", {
819
864
  after: isoDay(since)
820
865
  });
821
- const ids = [...new Set(raw.map((e) => e.project_id).filter(Boolean))];
866
+ const ids = [
867
+ ...new Set(raw.map((e) => e.project_id).filter(Boolean))
868
+ ];
822
869
  const paths = new Map(
823
870
  await Promise.all(
824
871
  ids.map(async (id) => [id, await this.projectPath(id)])
@@ -829,7 +876,7 @@ var GitLabProvider = class {
829
876
  return {
830
877
  at: String(event.created_at).slice(0, 16),
831
878
  action: event.action_name,
832
- project: paths.get(event.project_id) ?? "",
879
+ project: paths.get(event.project_id ?? -1) ?? "",
833
880
  targetType: event.target_type ?? "",
834
881
  title: event.target_title ?? "",
835
882
  branch: push.ref ?? "",
@@ -841,7 +888,9 @@ var GitLabProvider = class {
841
888
  async countUnresolved(projectId, iid) {
842
889
  const discussions = await this.getJson(
843
890
  `projects/${projectId}/merge_requests/${iid}/discussions`,
844
- { per_page: PAGE_SIZE2 }
891
+ {
892
+ per_page: PAGE_SIZE2
893
+ }
845
894
  );
846
895
  if (!discussions) return 0;
847
896
  return discussions.filter((discussion) => {
@@ -894,7 +943,9 @@ var GitLabProvider = class {
894
943
  async approvedByMe(projectId, iid, uid) {
895
944
  const approvals = await this.getJson(`projects/${projectId}/merge_requests/${iid}/approvals`);
896
945
  if (!approvals) return false;
897
- return (approvals.approved_by ?? []).some((entry) => entry.user?.id === uid);
946
+ return (approvals.approved_by ?? []).some(
947
+ (entry) => entry.user?.id === uid
948
+ );
898
949
  }
899
950
  async getReviews(identity, today) {
900
951
  const raw = await this.getPaged("merge_requests", {
@@ -902,7 +953,9 @@ var GitLabProvider = class {
902
953
  state: "opened",
903
954
  reviewer_id: identity.id
904
955
  });
905
- const cutoff = isoDay(new Date(today.getTime() - FRESH_REVIEW_DAYS2 * MS_PER_DAY));
956
+ const cutoff = isoDay(
957
+ new Date(today.getTime() - FRESH_REVIEW_DAYS2 * MS_PER_DAY)
958
+ );
906
959
  const rows = await Promise.all(
907
960
  raw.map(async (mr) => ({
908
961
  provider: "gitlab",
@@ -914,7 +967,11 @@ var GitLabProvider = class {
914
967
  draft: mr.draft,
915
968
  url: mr.web_url,
916
969
  fresh: String(mr.updated_at).slice(0, 10) >= cutoff,
917
- approvedByMe: await this.approvedByMe(mr.project_id, mr.iid, identity.id)
970
+ approvedByMe: await this.approvedByMe(
971
+ mr.project_id,
972
+ mr.iid,
973
+ identity.id
974
+ )
918
975
  }))
919
976
  );
920
977
  return rows.sort((a, b) => b.updated.localeCompare(a.updated));
@@ -926,7 +983,9 @@ var GitLabProvider = class {
926
983
  ) ?? [];
927
984
  const job = jobs.find((j) => j.status === "failed");
928
985
  if (!job) return null;
929
- const trace = await this.getText(`projects/${mr.projectId}/jobs/${job.id}/trace`);
986
+ const trace = await this.getText(
987
+ `projects/${mr.projectId}/jobs/${job.id}/trace`
988
+ );
930
989
  return {
931
990
  provider: "gitlab",
932
991
  project: mr.project,
@@ -959,7 +1018,12 @@ function hostFrom(cliHost, envHost, probe, fallback, labels) {
959
1018
  if (cliHost) return cliHost;
960
1019
  if (envHost) return envHost;
961
1020
  const found = probe();
962
- return resolveHost(void 0, void 0, found.length > 0 ? found : fallback, labels);
1021
+ return resolveHost(
1022
+ void 0,
1023
+ void 0,
1024
+ found.length > 0 ? found : fallback,
1025
+ labels
1026
+ );
963
1027
  }
964
1028
  function chooseKind(options = {}) {
965
1029
  const env = options.env ?? process.env;
@@ -1012,7 +1076,13 @@ function connect(options = {}) {
1012
1076
  const env = options.env ?? process.env;
1013
1077
  const probe = options.probe ?? DEFAULT_PROBE;
1014
1078
  if (chooseKind(options) === "github") {
1015
- const host2 = hostFrom(options.host, env.GITHUB_HOST, probe.github, [DOT_COM], GITHUB_LABELS);
1079
+ const host2 = hostFrom(
1080
+ options.host,
1081
+ env.GITHUB_HOST,
1082
+ probe.github,
1083
+ [DOT_COM],
1084
+ GITHUB_LABELS
1085
+ );
1016
1086
  const token2 = resolveToken(
1017
1087
  host2,
1018
1088
  options.token,
@@ -1022,7 +1092,13 @@ function connect(options = {}) {
1022
1092
  );
1023
1093
  return new GitHubProvider(host2, token2);
1024
1094
  }
1025
- const host = hostFrom(options.host, env.GITLAB_HOST, probe.gitlab, [], GITLAB_LABELS);
1095
+ const host = hostFrom(
1096
+ options.host,
1097
+ env.GITLAB_HOST,
1098
+ probe.gitlab,
1099
+ [],
1100
+ GITLAB_LABELS
1101
+ );
1026
1102
  const token = resolveToken(
1027
1103
  host,
1028
1104
  options.token,
@@ -1086,10 +1162,18 @@ function eventLine(event) {
1086
1162
  }
1087
1163
  function toMarkdown(report, lang = "en") {
1088
1164
  const base = STRINGS[lang] ?? STRINGS.en;
1089
- const t = { ...base, ...PROVIDER_STRINGS[report.provider][lang] ?? {} };
1165
+ const t = {
1166
+ ...base,
1167
+ ...PROVIDER_STRINGS[report.provider][lang] ?? {}
1168
+ };
1090
1169
  const ref = REF_PREFIX[report.provider];
1091
1170
  const out = [];
1092
- out.push(`# ${report.today.label} \u2014 ${report.user}`, "", `_${t.digest}_`, "");
1171
+ out.push(
1172
+ `# ${report.today.label} \u2014 ${report.user}`,
1173
+ "",
1174
+ `_${t.digest}_`,
1175
+ ""
1176
+ );
1093
1177
  if (report.previousDays.length === 0) {
1094
1178
  out.push(`## ${t.previous}`, "", `_${t.nothing}_`, "");
1095
1179
  }
@@ -1116,7 +1200,10 @@ function toMarkdown(report, lang = "en") {
1116
1200
  }
1117
1201
  const pending = report.reviews.filter((r) => !r.approvedByMe);
1118
1202
  if (pending.length > 0) {
1119
- out.push(`## ${t.reviews} (${report.reviewPendingCount} ${t.pending})`, "");
1203
+ out.push(
1204
+ `## ${t.reviews} (${report.reviewPendingCount} ${t.pending})`,
1205
+ ""
1206
+ );
1120
1207
  for (const review of pending) {
1121
1208
  out.push(
1122
1209
  `- \`${review.project}\` ${ref}${review.iid} ${review.title} \u2014 ${review.author}`
@@ -1127,7 +1214,9 @@ function toMarkdown(report, lang = "en") {
1127
1214
  if (report.blockers.length > 0) {
1128
1215
  out.push(`## ${t.blockers}`, "");
1129
1216
  for (const blocker of report.blockers) {
1130
- out.push(`- \`${blocker.project}\` ${ref}${blocker.mr} \u2014 job \`${blocker.job}\``);
1217
+ out.push(
1218
+ `- \`${blocker.project}\` ${ref}${blocker.mr} \u2014 job \`${blocker.job}\``
1219
+ );
1131
1220
  out.push(...blocker.errors.map((line) => ` - \`${line}\``));
1132
1221
  }
1133
1222
  out.push("");
@@ -1195,21 +1284,29 @@ import { dirname as dirname2, join as join2 } from "path";
1195
1284
  import { fileURLToPath as fileURLToPath2 } from "url";
1196
1285
  function readStandupSkillBody() {
1197
1286
  const moduleDir = dirname2(fileURLToPath2(import.meta.url));
1198
- const skillPath = join2(findPackageRoot(moduleDir), "skills", "standup", "SKILL.md");
1287
+ const skillPath = join2(
1288
+ findPackageRoot(moduleDir),
1289
+ "skills",
1290
+ "standup",
1291
+ "SKILL.md"
1292
+ );
1199
1293
  if (!existsSync2(skillPath)) {
1200
1294
  throw new Error(`Cannot find the standup skill file at ${skillPath}`);
1201
1295
  }
1202
1296
  const content = readFileSync2(skillPath, "utf8");
1203
- const withoutFrontmatter = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, "");
1297
+ const withoutFrontmatter = content.replace(
1298
+ /^---\r?\n[\s\S]*?\r?\n---\r?\n/,
1299
+ ""
1300
+ );
1204
1301
  return withoutFrontmatter.replace(/^\n+/, "");
1205
1302
  }
1206
1303
 
1207
1304
  export {
1208
- STALE_DAYS,
1209
1305
  isoDay,
1210
1306
  localAt,
1211
1307
  label,
1212
1308
  previousActiveDays,
1309
+ STALE_DAYS,
1213
1310
  classify,
1214
1311
  markMissingPipelines,
1215
1312
  ConfigError,
@@ -1223,8 +1320,8 @@ export {
1223
1320
  glabToken,
1224
1321
  ghHosts,
1225
1322
  ghToken,
1226
- WEBHOOK_KINDS,
1227
1323
  toChatText,
1324
+ WEBHOOK_KINDS,
1228
1325
  postWebhook,
1229
1326
  inferWebhookKind,
1230
1327
  buildUrl,
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  postWebhook,
9
9
  readStandupSkillBody,
10
10
  toMarkdown
11
- } from "./chunk-NJO6LFYN.js";
11
+ } from "./chunk-J5LAGA3U.js";
12
12
 
13
13
  // src/cli/cli.ts
14
14
  import { realpathSync } from "fs";
@@ -64,7 +64,11 @@ async function main(argv) {
64
64
  markdown: { type: "boolean", default: false }
65
65
  }
66
66
  });
67
- const report = await buildReport(connect(values), /* @__PURE__ */ new Date(), values.lang);
67
+ const report = await buildReport(
68
+ connect(values),
69
+ /* @__PURE__ */ new Date(),
70
+ values.lang
71
+ );
68
72
  const output = values.markdown ? toMarkdown(report, values.lang) : JSON.stringify(report, null, 1);
69
73
  process.stdout.write(`${output}
70
74
  `);
@@ -75,7 +79,10 @@ async function main(argv) {
75
79
  args: rest,
76
80
  options: {
77
81
  ...Object.fromEntries(
78
- WEBHOOK_KINDS.map((kind2) => [kind2, { type: "string" }])
82
+ WEBHOOK_KINDS.map((kind2) => [
83
+ kind2,
84
+ { type: "string" }
85
+ ])
79
86
  ),
80
87
  text: { type: "string", default: "-" }
81
88
  }
@@ -83,7 +90,9 @@ async function main(argv) {
83
90
  const urls = values;
84
91
  const kind = WEBHOOK_KINDS.find((candidate) => urls[candidate]);
85
92
  if (!kind) {
86
- const flags = WEBHOOK_KINDS.map((candidate) => `--${candidate} URL`).join(" | ");
93
+ const flags = WEBHOOK_KINDS.map(
94
+ (candidate) => `--${candidate} URL`
95
+ ).join(" | ");
87
96
  process.stderr.write(`Pass one of: ${flags}.
88
97
  `);
89
98
  return 1;
@@ -99,7 +108,12 @@ async function main(argv) {
99
108
  }
100
109
  if (command === "mcp") {
101
110
  const moduleDir = dirname(fileURLToPath(import.meta.url));
102
- const serverPath = join(findPackageRoot(moduleDir), "dist", "mcp", "server.js");
111
+ const serverPath = join(
112
+ findPackageRoot(moduleDir),
113
+ "dist",
114
+ "mcp",
115
+ "server.js"
116
+ );
103
117
  const serverUrl = pathToFileURL(serverPath).href;
104
118
  const { main: startMcpServer } = await import(serverUrl);
105
119
  await startMcpServer();