@cesar-richard/git-connector-sdk 1.67.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +108 -1
  2. package/dist/schema.d.ts +501 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -443,7 +443,10 @@ Query params:
443
443
  | `author` | no | CSV of author login aliases (case-insensitive). When set, only issues attributable to one of the aliases are returned and `attribution` is populated. When **absent**, every window deliverable is returned with `attribution: null`. |
444
444
  | `source` | no | `github` or `gitlab`. |
445
445
 
446
- Each `DeliverableIssue` carries `deliveryState`, `deliveredAt`, `deliveryLabel`,
446
+ Each `DeliverableIssue` carries `deliveryState`, `deliveredAt`,
447
+ `deliveryReason` (a typed `{ kind, ruleLabel, transitionAt, transitionBy }`
448
+ explaining WHY the classification fired — read `deliveryReason.ruleLabel`
449
+ to get the scoped label that triggered it),
447
450
  `attribution` (`{ isAssignee, hasOwnCommit, isMergedPRAuthor, result }` with
448
451
  `result` precedence `assigned > committer > pr_author > none`), `linkedActivities`,
449
452
  and an `evidence` blob (`deliveryTransitions`, `consideredCommits`, `consideredPRs`)
@@ -626,6 +629,110 @@ The server runs a nightly cron (3 AM UTC) + a post-sync event hook that:
626
629
  Identities created via `POST /v1/identities` or whose `displayName` was set
627
630
  via `PATCH` keep `display_name_source = "manual"` automatically.
628
631
 
632
+ ## Rendering deliverable narratives
633
+
634
+ `/v1/deliverables` now ships every field needed to render a rich per-topic
635
+ summary without a second API call. Each `DeliverableIssue` exposes:
636
+
637
+ - The full topic context: `body`, `state`, `assignees` + `assigneesResolved`,
638
+ `iteration`, `milestone`, `labels`, `statusHistory`, `createdAt`, `updatedAt`.
639
+ - A typed `deliveryReason: { kind, ruleLabel, transitionAt, transitionBy }`
640
+ digest explaining WHY the classification fired. `kind` is one of
641
+ `rule_label_added`, `closed_in_window`, `in_progress_opened_label_active`,
642
+ `in_progress_delivered_after_window`, `in_progress_fallback_open`. Use
643
+ `deliveryReason.ruleLabel` to display the scoped label that triggered the
644
+ state (replaces the legacy `deliveryLabel` field).
645
+ - A typed array of linked PR/MRs with stable cross-endpoint ids and the names
646
+ of requested reviewers:
647
+
648
+ ```ts
649
+ LinkedActivity {
650
+ id: string; // "gitlab:org/proj:mr:42"
651
+ source: "github" | "gitlab";
652
+ externalId: string; // "42"
653
+ number: number; // 42
654
+ type: "pr" | "mr";
655
+ title: string;
656
+ url: string;
657
+ state: "open" | "closed" | "merged" | "draft" | "unknown";
658
+ isMerged: boolean;
659
+ isDraft: boolean;
660
+ awaitingReview: boolean;
661
+ requestedReviewers: string[]; // logins
662
+ requestedReviewersResolved?: ResolvedUser[]; // with name/email
663
+ // ...mergedAt, reviews, volume, etc.
664
+ }
665
+ ```
666
+
667
+ ### Deduplicating activities
668
+
669
+ `LinkedActivity.id` is stable across endpoints — the **same** id format is
670
+ used by `Activity.id` from `/v1/activities`. Dedupe by id, **never** by URL:
671
+
672
+ ```ts
673
+ const linkedIds = new Set(
674
+ deliverables.issues.flatMap(i => i.linkedActivities.map(la => la.id)),
675
+ );
676
+ const orphans = rawActivities.filter(a => !linkedIds.has(a.id));
677
+ ```
678
+
679
+ ### Rendering a topic narrative
680
+
681
+ ```ts
682
+ function renderLinkedActivity(la: LinkedActivity): string {
683
+ const num = `#${la.number}`;
684
+ if (la.isMerged) {
685
+ const when = la.mergedAt
686
+ ? `mergée le ${new Date(la.mergedAt).toLocaleDateString()}`
687
+ : "mergée";
688
+ return `${num} '${la.title}' ${when}`;
689
+ }
690
+ if (la.isDraft) return `${num} '${la.title}' en draft`;
691
+ if (la.awaitingReview && la.requestedReviewers.length > 0) {
692
+ const named = (la.requestedReviewersResolved ?? []).map(
693
+ r => r.name ?? r.login,
694
+ );
695
+ const unnamed = la.requestedReviewers.filter(
696
+ l => !(la.requestedReviewersResolved ?? []).some(r => r.login === l),
697
+ );
698
+ const all = [...named, ...unnamed].slice(0, 3).join(", ");
699
+ return `${num} '${la.title}' en attente de review de ${all}`;
700
+ }
701
+ return `${num} '${la.title}' ${la.state}`;
702
+ }
703
+
704
+ function renderTopic(issue: DeliverableIssue): string {
705
+ const num = `#${issue.number}`;
706
+ const owner =
707
+ issue.assigneesResolved?.[0]?.name ?? issue.assignees[0] ?? "personne";
708
+ const iter = issue.iteration?.title ?? "hors itération";
709
+ const linked = issue.linkedActivities;
710
+ const merged = linked.filter(la => la.isMerged).length;
711
+ const open = linked.filter(la => la.state === "open").length;
712
+ // Use deliveryReason.ruleLabel + kind to phrase the classification.
713
+ const reason = issue.deliveryReason.ruleLabel
714
+ ? ` (via label '${issue.deliveryReason.ruleLabel}')`
715
+ : issue.deliveryReason.kind === "closed_in_window"
716
+ ? " (fermée dans la fenêtre)"
717
+ : "";
718
+ const head =
719
+ `Le sujet '${issue.title}' (${num}), assigné à ${owner}, ` +
720
+ `dans ${iter}, est ${issue.deliveryState}${reason} ` +
721
+ `avec ${linked.length} PR liées (${merged} mergées, ${open} en cours)`;
722
+ const details = linked.map(renderLinkedActivity).join("\n - ");
723
+ return `${head}:\n - ${details}`;
724
+ }
725
+ ```
726
+
727
+ Sample output:
728
+
729
+ ```
730
+ Le sujet 'Refactor auth' (#42), assigné à Bob Smith, dans Sprint-25, est in_progress (via label '=::En cours') avec 3 PR liées (2 mergées, 1 en cours):
731
+ - #18 'Initial refactor' mergée le 2026-05-15
732
+ - #21 'Tests' mergée le 2026-05-20
733
+ - #24 'Polish' en attente de review de Alice Doe, Carol Roe
734
+ ```
735
+
629
736
  ## Related
630
737
 
631
738
  - **Server / control UI:** [git-connector](https://github.com/cesar-richard-ei/git-connector)
package/dist/schema.d.ts CHANGED
@@ -301,7 +301,16 @@ export interface components {
301
301
  url: string;
302
302
  deliveryState: "delivered" | "in_progress" | "not_delivered";
303
303
  deliveredAt: string | null;
304
- deliveryLabel: string | null;
304
+ deliveryReason: {
305
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
306
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
307
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
308
+ ruleLabel: string | null;
309
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
310
+ transitionAt: string | null;
311
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
312
+ transitionBy: string | null;
313
+ };
305
314
  attribution: {
306
315
  isAssignee: boolean;
307
316
  hasOwnCommit: boolean;
@@ -309,14 +318,24 @@ export interface components {
309
318
  result: "assigned" | "committer" | "pr_author" | "none";
310
319
  } | null;
311
320
  linkedActivities: {
321
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
312
322
  id: string;
323
+ source: "github" | "gitlab";
324
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
325
+ externalId: string;
326
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
327
+ number: string | number;
328
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
313
329
  type: "pr" | "mr";
314
330
  title: string;
315
331
  url: string;
332
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
316
333
  state: "open" | "closed" | "merged" | "draft" | "unknown";
317
334
  isDraft: boolean;
335
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
318
336
  isMerged: boolean;
319
337
  hasConflicts: boolean;
338
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
320
339
  awaitingReview: boolean;
321
340
  author: string | null;
322
341
  authorResolved?: {
@@ -325,6 +344,15 @@ export interface components {
325
344
  name: string | null;
326
345
  email: string | null;
327
346
  } | null;
347
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
348
+ requestedReviewers: string[];
349
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
350
+ requestedReviewersResolved?: {
351
+ id: string;
352
+ login: string;
353
+ name: string | null;
354
+ email: string | null;
355
+ }[];
328
356
  updatedAt: string;
329
357
  mergedAt: string | null;
330
358
  reviewRequestedAt: string | null;
@@ -421,6 +449,41 @@ export interface components {
421
449
  id: string | number;
422
450
  displayName: string;
423
451
  } | null;
452
+ /** @description Issue body / description (Markdown). Use for the topic summary in narratives. */
453
+ body: string | null;
454
+ /** @description Raw issue state (open/closed). Distinct from `deliveryState` (the delivery workflow position). An issue can be closed without being delivered. */
455
+ state: "open" | "closed" | "unknown";
456
+ author: string | null;
457
+ createdAt: string;
458
+ updatedAt: string;
459
+ iteration: {
460
+ id: string | number;
461
+ title: string;
462
+ startDate: string | null;
463
+ dueDate: string | null;
464
+ state: "upcoming" | "current" | "closed" | "unknown";
465
+ } | null;
466
+ milestone: string | null;
467
+ assignees: string[];
468
+ assigneesResolved?: {
469
+ id: string;
470
+ login: string;
471
+ name: string | null;
472
+ email: string | null;
473
+ }[];
474
+ labels: {
475
+ name: string;
476
+ color: string | null;
477
+ }[];
478
+ statusHistory: {
479
+ label: {
480
+ name: string;
481
+ color: string | null;
482
+ };
483
+ action: "added" | "removed";
484
+ changedAt: string;
485
+ changedBy: string | null;
486
+ }[];
424
487
  };
425
488
  DeliverablesListResponse: {
426
489
  issues: {
@@ -431,7 +494,16 @@ export interface components {
431
494
  url: string;
432
495
  deliveryState: "delivered" | "in_progress" | "not_delivered";
433
496
  deliveredAt: string | null;
434
- deliveryLabel: string | null;
497
+ deliveryReason: {
498
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
499
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
500
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
501
+ ruleLabel: string | null;
502
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
503
+ transitionAt: string | null;
504
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
505
+ transitionBy: string | null;
506
+ };
435
507
  attribution: {
436
508
  isAssignee: boolean;
437
509
  hasOwnCommit: boolean;
@@ -439,14 +511,24 @@ export interface components {
439
511
  result: "assigned" | "committer" | "pr_author" | "none";
440
512
  } | null;
441
513
  linkedActivities: {
514
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
442
515
  id: string;
516
+ source: "github" | "gitlab";
517
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
518
+ externalId: string;
519
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
520
+ number: string | number;
521
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
443
522
  type: "pr" | "mr";
444
523
  title: string;
445
524
  url: string;
525
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
446
526
  state: "open" | "closed" | "merged" | "draft" | "unknown";
447
527
  isDraft: boolean;
528
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
448
529
  isMerged: boolean;
449
530
  hasConflicts: boolean;
531
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
450
532
  awaitingReview: boolean;
451
533
  author: string | null;
452
534
  authorResolved?: {
@@ -455,6 +537,15 @@ export interface components {
455
537
  name: string | null;
456
538
  email: string | null;
457
539
  } | null;
540
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
541
+ requestedReviewers: string[];
542
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
543
+ requestedReviewersResolved?: {
544
+ id: string;
545
+ login: string;
546
+ name: string | null;
547
+ email: string | null;
548
+ }[];
458
549
  updatedAt: string;
459
550
  mergedAt: string | null;
460
551
  reviewRequestedAt: string | null;
@@ -551,8 +642,53 @@ export interface components {
551
642
  id: string | number;
552
643
  displayName: string;
553
644
  } | null;
645
+ /** @description Issue body / description (Markdown). Use for the topic summary in narratives. */
646
+ body: string | null;
647
+ /** @description Raw issue state (open/closed). Distinct from `deliveryState` (the delivery workflow position). An issue can be closed without being delivered. */
648
+ state: "open" | "closed" | "unknown";
649
+ author: string | null;
650
+ createdAt: string;
651
+ updatedAt: string;
652
+ iteration: {
653
+ id: string | number;
654
+ title: string;
655
+ startDate: string | null;
656
+ dueDate: string | null;
657
+ state: "upcoming" | "current" | "closed" | "unknown";
658
+ } | null;
659
+ milestone: string | null;
660
+ assignees: string[];
661
+ assigneesResolved?: {
662
+ id: string;
663
+ login: string;
664
+ name: string | null;
665
+ email: string | null;
666
+ }[];
667
+ labels: {
668
+ name: string;
669
+ color: string | null;
670
+ }[];
671
+ statusHistory: {
672
+ label: {
673
+ name: string;
674
+ color: string | null;
675
+ };
676
+ action: "added" | "removed";
677
+ changedAt: string;
678
+ changedBy: string | null;
679
+ }[];
554
680
  }[];
555
681
  };
682
+ DeliveryReason: {
683
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
684
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
685
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
686
+ ruleLabel: string | null;
687
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
688
+ transitionAt: string | null;
689
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
690
+ transitionBy: string | null;
691
+ };
556
692
  DeliveryRules: {
557
693
  source: "github" | "gitlab";
558
694
  projectKey: string;
@@ -708,14 +844,24 @@ export interface components {
708
844
  kind: string;
709
845
  };
710
846
  LinkedActivity: {
847
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
711
848
  id: string;
849
+ source: "github" | "gitlab";
850
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
851
+ externalId: string;
852
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
853
+ number: string | number;
854
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
712
855
  type: "pr" | "mr";
713
856
  title: string;
714
857
  url: string;
858
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
715
859
  state: "open" | "closed" | "merged" | "draft" | "unknown";
716
860
  isDraft: boolean;
861
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
717
862
  isMerged: boolean;
718
863
  hasConflicts: boolean;
864
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
719
865
  awaitingReview: boolean;
720
866
  author: string | null;
721
867
  authorResolved?: {
@@ -724,6 +870,15 @@ export interface components {
724
870
  name: string | null;
725
871
  email: string | null;
726
872
  } | null;
873
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
874
+ requestedReviewers: string[];
875
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
876
+ requestedReviewersResolved?: {
877
+ id: string;
878
+ login: string;
879
+ name: string | null;
880
+ email: string | null;
881
+ }[];
727
882
  updatedAt: string;
728
883
  mergedAt: string | null;
729
884
  reviewRequestedAt: string | null;
@@ -910,14 +1065,24 @@ export interface components {
910
1065
  color: string | null;
911
1066
  }[];
912
1067
  linkedActivities: {
1068
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
913
1069
  id: string;
1070
+ source: "github" | "gitlab";
1071
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1072
+ externalId: string;
1073
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
1074
+ number: string | number;
1075
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
914
1076
  type: "pr" | "mr";
915
1077
  title: string;
916
1078
  url: string;
1079
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
917
1080
  state: "open" | "closed" | "merged" | "draft" | "unknown";
918
1081
  isDraft: boolean;
1082
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
919
1083
  isMerged: boolean;
920
1084
  hasConflicts: boolean;
1085
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
921
1086
  awaitingReview: boolean;
922
1087
  author: string | null;
923
1088
  authorResolved?: {
@@ -926,6 +1091,15 @@ export interface components {
926
1091
  name: string | null;
927
1092
  email: string | null;
928
1093
  } | null;
1094
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
1095
+ requestedReviewers: string[];
1096
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
1097
+ requestedReviewersResolved?: {
1098
+ id: string;
1099
+ login: string;
1100
+ name: string | null;
1101
+ email: string | null;
1102
+ }[];
929
1103
  updatedAt: string;
930
1104
  mergedAt: string | null;
931
1105
  reviewRequestedAt: string | null;
@@ -1052,14 +1226,24 @@ export interface components {
1052
1226
  color: string | null;
1053
1227
  }[];
1054
1228
  linkedActivities: {
1229
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1055
1230
  id: string;
1231
+ source: "github" | "gitlab";
1232
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1233
+ externalId: string;
1234
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
1235
+ number: string | number;
1236
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1056
1237
  type: "pr" | "mr";
1057
1238
  title: string;
1058
1239
  url: string;
1240
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1059
1241
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1060
1242
  isDraft: boolean;
1243
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1061
1244
  isMerged: boolean;
1062
1245
  hasConflicts: boolean;
1246
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1063
1247
  awaitingReview: boolean;
1064
1248
  author: string | null;
1065
1249
  authorResolved?: {
@@ -1068,6 +1252,15 @@ export interface components {
1068
1252
  name: string | null;
1069
1253
  email: string | null;
1070
1254
  } | null;
1255
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
1256
+ requestedReviewers: string[];
1257
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
1258
+ requestedReviewersResolved?: {
1259
+ id: string;
1260
+ login: string;
1261
+ name: string | null;
1262
+ email: string | null;
1263
+ }[];
1071
1264
  updatedAt: string;
1072
1265
  mergedAt: string | null;
1073
1266
  reviewRequestedAt: string | null;
@@ -1247,14 +1440,24 @@ export interface operations {
1247
1440
  color: string | null;
1248
1441
  }[];
1249
1442
  linkedActivities: {
1443
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1250
1444
  id: string;
1445
+ source: "github" | "gitlab";
1446
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1447
+ externalId: string;
1448
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
1449
+ number: string | number;
1450
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1251
1451
  type: "pr" | "mr";
1252
1452
  title: string;
1253
1453
  url: string;
1454
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1254
1455
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1255
1456
  isDraft: boolean;
1457
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1256
1458
  isMerged: boolean;
1257
1459
  hasConflicts: boolean;
1460
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1258
1461
  awaitingReview: boolean;
1259
1462
  author: string | null;
1260
1463
  authorResolved?: {
@@ -1263,6 +1466,15 @@ export interface operations {
1263
1466
  name: string | null;
1264
1467
  email: string | null;
1265
1468
  } | null;
1469
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
1470
+ requestedReviewers: string[];
1471
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
1472
+ requestedReviewersResolved?: {
1473
+ id: string;
1474
+ login: string;
1475
+ name: string | null;
1476
+ email: string | null;
1477
+ }[];
1266
1478
  updatedAt: string;
1267
1479
  mergedAt: string | null;
1268
1480
  reviewRequestedAt: string | null;
@@ -1393,14 +1605,24 @@ export interface operations {
1393
1605
  color: string | null;
1394
1606
  }[];
1395
1607
  linkedActivities: {
1608
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1396
1609
  id: string;
1610
+ source: "github" | "gitlab";
1611
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1612
+ externalId: string;
1613
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
1614
+ number: string | number;
1615
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1397
1616
  type: "pr" | "mr";
1398
1617
  title: string;
1399
1618
  url: string;
1619
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1400
1620
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1401
1621
  isDraft: boolean;
1622
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1402
1623
  isMerged: boolean;
1403
1624
  hasConflicts: boolean;
1625
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1404
1626
  awaitingReview: boolean;
1405
1627
  author: string | null;
1406
1628
  authorResolved?: {
@@ -1409,6 +1631,15 @@ export interface operations {
1409
1631
  name: string | null;
1410
1632
  email: string | null;
1411
1633
  } | null;
1634
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
1635
+ requestedReviewers: string[];
1636
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
1637
+ requestedReviewersResolved?: {
1638
+ id: string;
1639
+ login: string;
1640
+ name: string | null;
1641
+ email: string | null;
1642
+ }[];
1412
1643
  updatedAt: string;
1413
1644
  mergedAt: string | null;
1414
1645
  reviewRequestedAt: string | null;
@@ -1539,14 +1770,24 @@ export interface operations {
1539
1770
  color: string | null;
1540
1771
  }[];
1541
1772
  linkedActivities: {
1773
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1542
1774
  id: string;
1775
+ source: "github" | "gitlab";
1776
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1777
+ externalId: string;
1778
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
1779
+ number: string | number;
1780
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1543
1781
  type: "pr" | "mr";
1544
1782
  title: string;
1545
1783
  url: string;
1784
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1546
1785
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1547
1786
  isDraft: boolean;
1787
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1548
1788
  isMerged: boolean;
1549
1789
  hasConflicts: boolean;
1790
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1550
1791
  awaitingReview: boolean;
1551
1792
  author: string | null;
1552
1793
  authorResolved?: {
@@ -1555,6 +1796,15 @@ export interface operations {
1555
1796
  name: string | null;
1556
1797
  email: string | null;
1557
1798
  } | null;
1799
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
1800
+ requestedReviewers: string[];
1801
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
1802
+ requestedReviewersResolved?: {
1803
+ id: string;
1804
+ login: string;
1805
+ name: string | null;
1806
+ email: string | null;
1807
+ }[];
1558
1808
  updatedAt: string;
1559
1809
  mergedAt: string | null;
1560
1810
  reviewRequestedAt: string | null;
@@ -1741,14 +1991,24 @@ export interface operations {
1741
1991
  color: string | null;
1742
1992
  }[];
1743
1993
  linkedActivities: {
1994
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1744
1995
  id: string;
1996
+ source: "github" | "gitlab";
1997
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
1998
+ externalId: string;
1999
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
2000
+ number: string | number;
2001
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1745
2002
  type: "pr" | "mr";
1746
2003
  title: string;
1747
2004
  url: string;
2005
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1748
2006
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1749
2007
  isDraft: boolean;
2008
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1750
2009
  isMerged: boolean;
1751
2010
  hasConflicts: boolean;
2011
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1752
2012
  awaitingReview: boolean;
1753
2013
  author: string | null;
1754
2014
  authorResolved?: {
@@ -1757,6 +2017,15 @@ export interface operations {
1757
2017
  name: string | null;
1758
2018
  email: string | null;
1759
2019
  } | null;
2020
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
2021
+ requestedReviewers: string[];
2022
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
2023
+ requestedReviewersResolved?: {
2024
+ id: string;
2025
+ login: string;
2026
+ name: string | null;
2027
+ email: string | null;
2028
+ }[];
1760
2029
  updatedAt: string;
1761
2030
  mergedAt: string | null;
1762
2031
  reviewRequestedAt: string | null;
@@ -1882,14 +2151,24 @@ export interface operations {
1882
2151
  color: string | null;
1883
2152
  }[];
1884
2153
  linkedActivities: {
2154
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
1885
2155
  id: string;
2156
+ source: "github" | "gitlab";
2157
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
2158
+ externalId: string;
2159
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
2160
+ number: string | number;
2161
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
1886
2162
  type: "pr" | "mr";
1887
2163
  title: string;
1888
2164
  url: string;
2165
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
1889
2166
  state: "open" | "closed" | "merged" | "draft" | "unknown";
1890
2167
  isDraft: boolean;
2168
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
1891
2169
  isMerged: boolean;
1892
2170
  hasConflicts: boolean;
2171
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
1893
2172
  awaitingReview: boolean;
1894
2173
  author: string | null;
1895
2174
  authorResolved?: {
@@ -1898,6 +2177,15 @@ export interface operations {
1898
2177
  name: string | null;
1899
2178
  email: string | null;
1900
2179
  } | null;
2180
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
2181
+ requestedReviewers: string[];
2182
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
2183
+ requestedReviewersResolved?: {
2184
+ id: string;
2185
+ login: string;
2186
+ name: string | null;
2187
+ email: string | null;
2188
+ }[];
1901
2189
  updatedAt: string;
1902
2190
  mergedAt: string | null;
1903
2191
  reviewRequestedAt: string | null;
@@ -2023,14 +2311,24 @@ export interface operations {
2023
2311
  color: string | null;
2024
2312
  }[];
2025
2313
  linkedActivities: {
2314
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
2026
2315
  id: string;
2316
+ source: "github" | "gitlab";
2317
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
2318
+ externalId: string;
2319
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
2320
+ number: string | number;
2321
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
2027
2322
  type: "pr" | "mr";
2028
2323
  title: string;
2029
2324
  url: string;
2325
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
2030
2326
  state: "open" | "closed" | "merged" | "draft" | "unknown";
2031
2327
  isDraft: boolean;
2328
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
2032
2329
  isMerged: boolean;
2033
2330
  hasConflicts: boolean;
2331
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
2034
2332
  awaitingReview: boolean;
2035
2333
  author: string | null;
2036
2334
  authorResolved?: {
@@ -2039,6 +2337,15 @@ export interface operations {
2039
2337
  name: string | null;
2040
2338
  email: string | null;
2041
2339
  } | null;
2340
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
2341
+ requestedReviewers: string[];
2342
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
2343
+ requestedReviewersResolved?: {
2344
+ id: string;
2345
+ login: string;
2346
+ name: string | null;
2347
+ email: string | null;
2348
+ }[];
2042
2349
  updatedAt: string;
2043
2350
  mergedAt: string | null;
2044
2351
  reviewRequestedAt: string | null;
@@ -2556,7 +2863,16 @@ export interface operations {
2556
2863
  url: string;
2557
2864
  deliveryState: "delivered" | "in_progress" | "not_delivered";
2558
2865
  deliveredAt: string | null;
2559
- deliveryLabel: string | null;
2866
+ deliveryReason: {
2867
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
2868
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
2869
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
2870
+ ruleLabel: string | null;
2871
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
2872
+ transitionAt: string | null;
2873
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
2874
+ transitionBy: string | null;
2875
+ };
2560
2876
  attribution: {
2561
2877
  isAssignee: boolean;
2562
2878
  hasOwnCommit: boolean;
@@ -2564,14 +2880,24 @@ export interface operations {
2564
2880
  result: "assigned" | "committer" | "pr_author" | "none";
2565
2881
  } | null;
2566
2882
  linkedActivities: {
2883
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
2567
2884
  id: string;
2885
+ source: "github" | "gitlab";
2886
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
2887
+ externalId: string;
2888
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
2889
+ number: string | number;
2890
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
2568
2891
  type: "pr" | "mr";
2569
2892
  title: string;
2570
2893
  url: string;
2894
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
2571
2895
  state: "open" | "closed" | "merged" | "draft" | "unknown";
2572
2896
  isDraft: boolean;
2897
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
2573
2898
  isMerged: boolean;
2574
2899
  hasConflicts: boolean;
2900
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
2575
2901
  awaitingReview: boolean;
2576
2902
  author: string | null;
2577
2903
  authorResolved?: {
@@ -2580,6 +2906,15 @@ export interface operations {
2580
2906
  name: string | null;
2581
2907
  email: string | null;
2582
2908
  } | null;
2909
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
2910
+ requestedReviewers: string[];
2911
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
2912
+ requestedReviewersResolved?: {
2913
+ id: string;
2914
+ login: string;
2915
+ name: string | null;
2916
+ email: string | null;
2917
+ }[];
2583
2918
  updatedAt: string;
2584
2919
  mergedAt: string | null;
2585
2920
  reviewRequestedAt: string | null;
@@ -2676,6 +3011,41 @@ export interface operations {
2676
3011
  id: string | number;
2677
3012
  displayName: string;
2678
3013
  } | null;
3014
+ /** @description Issue body / description (Markdown). Use for the topic summary in narratives. */
3015
+ body: string | null;
3016
+ /** @description Raw issue state (open/closed). Distinct from `deliveryState` (the delivery workflow position). An issue can be closed without being delivered. */
3017
+ state: "open" | "closed" | "unknown";
3018
+ author: string | null;
3019
+ createdAt: string;
3020
+ updatedAt: string;
3021
+ iteration: {
3022
+ id: string | number;
3023
+ title: string;
3024
+ startDate: string | null;
3025
+ dueDate: string | null;
3026
+ state: "upcoming" | "current" | "closed" | "unknown";
3027
+ } | null;
3028
+ milestone: string | null;
3029
+ assignees: string[];
3030
+ assigneesResolved?: {
3031
+ id: string;
3032
+ login: string;
3033
+ name: string | null;
3034
+ email: string | null;
3035
+ }[];
3036
+ labels: {
3037
+ name: string;
3038
+ color: string | null;
3039
+ }[];
3040
+ statusHistory: {
3041
+ label: {
3042
+ name: string;
3043
+ color: string | null;
3044
+ };
3045
+ action: "added" | "removed";
3046
+ changedAt: string;
3047
+ changedBy: string | null;
3048
+ }[];
2679
3049
  }[];
2680
3050
  };
2681
3051
  "multipart/form-data": {
@@ -2687,7 +3057,16 @@ export interface operations {
2687
3057
  url: string;
2688
3058
  deliveryState: "delivered" | "in_progress" | "not_delivered";
2689
3059
  deliveredAt: string | null;
2690
- deliveryLabel: string | null;
3060
+ deliveryReason: {
3061
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
3062
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
3063
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
3064
+ ruleLabel: string | null;
3065
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
3066
+ transitionAt: string | null;
3067
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
3068
+ transitionBy: string | null;
3069
+ };
2691
3070
  attribution: {
2692
3071
  isAssignee: boolean;
2693
3072
  hasOwnCommit: boolean;
@@ -2695,14 +3074,24 @@ export interface operations {
2695
3074
  result: "assigned" | "committer" | "pr_author" | "none";
2696
3075
  } | null;
2697
3076
  linkedActivities: {
3077
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
2698
3078
  id: string;
3079
+ source: "github" | "gitlab";
3080
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
3081
+ externalId: string;
3082
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
3083
+ number: string | number;
3084
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
2699
3085
  type: "pr" | "mr";
2700
3086
  title: string;
2701
3087
  url: string;
3088
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
2702
3089
  state: "open" | "closed" | "merged" | "draft" | "unknown";
2703
3090
  isDraft: boolean;
3091
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
2704
3092
  isMerged: boolean;
2705
3093
  hasConflicts: boolean;
3094
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
2706
3095
  awaitingReview: boolean;
2707
3096
  author: string | null;
2708
3097
  authorResolved?: {
@@ -2711,6 +3100,15 @@ export interface operations {
2711
3100
  name: string | null;
2712
3101
  email: string | null;
2713
3102
  } | null;
3103
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
3104
+ requestedReviewers: string[];
3105
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
3106
+ requestedReviewersResolved?: {
3107
+ id: string;
3108
+ login: string;
3109
+ name: string | null;
3110
+ email: string | null;
3111
+ }[];
2714
3112
  updatedAt: string;
2715
3113
  mergedAt: string | null;
2716
3114
  reviewRequestedAt: string | null;
@@ -2807,6 +3205,41 @@ export interface operations {
2807
3205
  id: string | number;
2808
3206
  displayName: string;
2809
3207
  } | null;
3208
+ /** @description Issue body / description (Markdown). Use for the topic summary in narratives. */
3209
+ body: string | null;
3210
+ /** @description Raw issue state (open/closed). Distinct from `deliveryState` (the delivery workflow position). An issue can be closed without being delivered. */
3211
+ state: "open" | "closed" | "unknown";
3212
+ author: string | null;
3213
+ createdAt: string;
3214
+ updatedAt: string;
3215
+ iteration: {
3216
+ id: string | number;
3217
+ title: string;
3218
+ startDate: string | null;
3219
+ dueDate: string | null;
3220
+ state: "upcoming" | "current" | "closed" | "unknown";
3221
+ } | null;
3222
+ milestone: string | null;
3223
+ assignees: string[];
3224
+ assigneesResolved?: {
3225
+ id: string;
3226
+ login: string;
3227
+ name: string | null;
3228
+ email: string | null;
3229
+ }[];
3230
+ labels: {
3231
+ name: string;
3232
+ color: string | null;
3233
+ }[];
3234
+ statusHistory: {
3235
+ label: {
3236
+ name: string;
3237
+ color: string | null;
3238
+ };
3239
+ action: "added" | "removed";
3240
+ changedAt: string;
3241
+ changedBy: string | null;
3242
+ }[];
2810
3243
  }[];
2811
3244
  };
2812
3245
  "text/plain": {
@@ -2818,7 +3251,16 @@ export interface operations {
2818
3251
  url: string;
2819
3252
  deliveryState: "delivered" | "in_progress" | "not_delivered";
2820
3253
  deliveredAt: string | null;
2821
- deliveryLabel: string | null;
3254
+ deliveryReason: {
3255
+ /** @description Discriminator: WHY the deliveryState was set. `rule_label_added` = a delivery label was added in the window; `closed_in_window` = fallback (no rule, issue closed in the window); `in_progress_opened_label_active` = a configured opened-label is currently active; `in_progress_delivered_after_window` = delivery label was added AFTER the window; `in_progress_fallback_open` = fallback (no rule, issue is open). */
3256
+ kind: "rule_label_added" | "closed_in_window" | "in_progress_opened_label_active" | "in_progress_delivered_after_window" | "in_progress_fallback_open";
3257
+ /** @description The delivery (or opened) label name that triggered the classification. Null when no rule applied (fallback paths). */
3258
+ ruleLabel: string | null;
3259
+ /** @description ISO timestamp of the label transition or close event. Null for fallback paths that don't have a single anchor. */
3260
+ transitionAt: string | null;
3261
+ /** @description Login of the user who triggered the transition (label added). Null when not recorded by the provider. */
3262
+ transitionBy: string | null;
3263
+ };
2822
3264
  attribution: {
2823
3265
  isAssignee: boolean;
2824
3266
  hasOwnCommit: boolean;
@@ -2826,14 +3268,24 @@ export interface operations {
2826
3268
  result: "assigned" | "committer" | "pr_author" | "none";
2827
3269
  } | null;
2828
3270
  linkedActivities: {
3271
+ /** @description Stable, cross-endpoint activity id. Format `${source}:${repo}:${type}:${externalId}` (e.g. `gitlab:group/proj:mr:123`). USE THIS to dedupe linkedActivities[] against /v1/activities.items[] or any other endpoint exposing an activity. Never dedupe by `url`. */
2829
3272
  id: string;
3273
+ source: "github" | "gitlab";
3274
+ /** @description Provider-side identifier of the PR/MR (e.g. '123'). Pair with `source` for a semantic key; or use `id` for the canonical full key. */
3275
+ externalId: string;
3276
+ /** @description Numeric form of externalId (cast for convenience). Useful for display like '!123' or '#123'. */
3277
+ number: string | number;
3278
+ /** @description PR/MR linked via git_activity_links. Commit-level linkage is NOT included here — fetch /v1/events?parentActivityId=<id> if you need commits attached to this activity. */
2830
3279
  type: "pr" | "mr";
2831
3280
  title: string;
2832
3281
  url: string;
3282
+ /** @description Lifecycle bucket. Use this to render '2 merged, 1 open, 1 draft' summaries. */
2833
3283
  state: "open" | "closed" | "merged" | "draft" | "unknown";
2834
3284
  isDraft: boolean;
3285
+ /** @description True when the PR/MR was merged (state === 'merged'). Pairs with `mergedAt` for narratives like 'merged on 2026-05-15'. */
2835
3286
  isMerged: boolean;
2836
3287
  hasConflicts: boolean;
3288
+ /** @description True when the activity is open AND has at least one requested reviewer who has NOT yet responded. Use `requestedReviewers` for the names. */
2837
3289
  awaitingReview: boolean;
2838
3290
  author: string | null;
2839
3291
  authorResolved?: {
@@ -2842,6 +3294,15 @@ export interface operations {
2842
3294
  name: string | null;
2843
3295
  email: string | null;
2844
3296
  } | null;
3297
+ /** @description Provider-side logins requested as reviewers (GH `requested_reviewers`, GL `reviewers`). Empty array when no review request is pending. Combine with `requestedReviewersResolved` to display human names. */
3298
+ requestedReviewers: string[];
3299
+ /** @description Resolved form of `requestedReviewers` (id + login + name + email). Subset: only the logins that the GitLab user cache could resolve. Missing entries are left out — the consumer should fall back to the raw login from `requestedReviewers`. */
3300
+ requestedReviewersResolved?: {
3301
+ id: string;
3302
+ login: string;
3303
+ name: string | null;
3304
+ email: string | null;
3305
+ }[];
2845
3306
  updatedAt: string;
2846
3307
  mergedAt: string | null;
2847
3308
  reviewRequestedAt: string | null;
@@ -2938,6 +3399,41 @@ export interface operations {
2938
3399
  id: string | number;
2939
3400
  displayName: string;
2940
3401
  } | null;
3402
+ /** @description Issue body / description (Markdown). Use for the topic summary in narratives. */
3403
+ body: string | null;
3404
+ /** @description Raw issue state (open/closed). Distinct from `deliveryState` (the delivery workflow position). An issue can be closed without being delivered. */
3405
+ state: "open" | "closed" | "unknown";
3406
+ author: string | null;
3407
+ createdAt: string;
3408
+ updatedAt: string;
3409
+ iteration: {
3410
+ id: string | number;
3411
+ title: string;
3412
+ startDate: string | null;
3413
+ dueDate: string | null;
3414
+ state: "upcoming" | "current" | "closed" | "unknown";
3415
+ } | null;
3416
+ milestone: string | null;
3417
+ assignees: string[];
3418
+ assigneesResolved?: {
3419
+ id: string;
3420
+ login: string;
3421
+ name: string | null;
3422
+ email: string | null;
3423
+ }[];
3424
+ labels: {
3425
+ name: string;
3426
+ color: string | null;
3427
+ }[];
3428
+ statusHistory: {
3429
+ label: {
3430
+ name: string;
3431
+ color: string | null;
3432
+ };
3433
+ action: "added" | "removed";
3434
+ changedAt: string;
3435
+ changedBy: string | null;
3436
+ }[];
2941
3437
  }[];
2942
3438
  };
2943
3439
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cesar-richard/git-connector-sdk",
3
- "version": "1.67.1",
3
+ "version": "2.0.0",
4
4
  "description": "TypeScript SDK for the git-connector v1 API (work items + iterations aggregated from GitHub/GitLab). Version published on npm tracks server releases.",
5
5
  "license": "MIT",
6
6
  "repository": {