@bike4mind/cli 0.2.30-subagent-delegation.19188 → 0.2.30

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.
@@ -171,6 +171,20 @@ var ChatModels;
171
171
  })(ChatModels || (ChatModels = {}));
172
172
  var CHAT_MODELS = Object.values(ChatModels);
173
173
  var supportedChatModels = z.nativeEnum(ChatModels);
174
+ var REASONING_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
175
+ ChatModels.O1,
176
+ ChatModels.O3_MINI,
177
+ ChatModels.O3,
178
+ ChatModels.O4_MINI,
179
+ ChatModels.GPT5,
180
+ ChatModels.GPT5_MINI,
181
+ ChatModels.GPT5_NANO,
182
+ ChatModels.GPT5_CHAT_LATEST,
183
+ ChatModels.GPT5_1,
184
+ ChatModels.GPT5_1_CHAT_LATEST,
185
+ ChatModels.GPT5_2,
186
+ ChatModels.GPT5_2_CHAT_LATEST
187
+ ]);
174
188
  var SpeechToTextModels;
175
189
  (function(SpeechToTextModels2) {
176
190
  SpeechToTextModels2["WHISPER_1"] = "whisper-1";
@@ -310,9 +324,7 @@ var b4mLLMTools = z5.enum([
310
324
  "iss_tracker",
311
325
  "planet_visibility",
312
326
  // Knowledge base search
313
- "search_knowledge_base",
314
- // Agent delegation
315
- "delegate_to_agent"
327
+ "search_knowledge_base"
316
328
  ]);
317
329
  var B4MLLMToolsList = b4mLLMTools.options.map((tool) => tool);
318
330
  var RechartsChartTypeSchema = z5.enum([
@@ -1063,6 +1075,25 @@ var WebhookDeliveryStatus;
1063
1075
  WebhookDeliveryStatus2["Pending"] = "pending";
1064
1076
  })(WebhookDeliveryStatus || (WebhookDeliveryStatus = {}));
1065
1077
 
1078
+ // ../../b4m-core/packages/common/dist/src/types/entities/JiraWebhookConfigTypes.js
1079
+ var COMMON_JIRA_WEBHOOK_EVENTS = [
1080
+ "jira:issue_created",
1081
+ "jira:issue_updated",
1082
+ "comment_created",
1083
+ "comment_updated",
1084
+ "sprint_started",
1085
+ "sprint_closed"
1086
+ ];
1087
+
1088
+ // ../../b4m-core/packages/common/dist/src/types/entities/JiraWebhookDeliveryTypes.js
1089
+ var JiraWebhookDeliveryStatus;
1090
+ (function(JiraWebhookDeliveryStatus2) {
1091
+ JiraWebhookDeliveryStatus2["Success"] = "success";
1092
+ JiraWebhookDeliveryStatus2["Failed"] = "failed";
1093
+ JiraWebhookDeliveryStatus2["Filtered"] = "filtered";
1094
+ JiraWebhookDeliveryStatus2["Pending"] = "pending";
1095
+ })(JiraWebhookDeliveryStatus || (JiraWebhookDeliveryStatus = {}));
1096
+
1066
1097
  // ../../b4m-core/packages/common/dist/src/types/common.js
1067
1098
  var SupportedFabFileMimeTypes;
1068
1099
  (function(SupportedFabFileMimeTypes2) {
@@ -7258,6 +7289,632 @@ var AgileApi = class {
7258
7289
  }
7259
7290
  };
7260
7291
 
7292
+ // ../../b4m-core/packages/common/dist/src/jira/webhook/format.js
7293
+ function daysUntil(dateString) {
7294
+ const expirationDate = new Date(dateString);
7295
+ const now = /* @__PURE__ */ new Date();
7296
+ const diffMs = expirationDate.getTime() - now.getTime();
7297
+ return Math.ceil(diffMs / (1e3 * 60 * 60 * 24));
7298
+ }
7299
+ function formatWebhook(webhook) {
7300
+ const daysUntilExpiry = daysUntil(webhook.expirationDate);
7301
+ return {
7302
+ id: webhook.id,
7303
+ events: webhook.events,
7304
+ jqlFilter: webhook.jqlFilter,
7305
+ expirationDate: webhook.expirationDate,
7306
+ daysUntilExpiry,
7307
+ isExpiringSoon: daysUntilExpiry < 7
7308
+ };
7309
+ }
7310
+ function formatWebhookList(response) {
7311
+ return {
7312
+ webhooks: response.values.map(formatWebhook),
7313
+ total: response.total,
7314
+ hasMore: !response.isLast
7315
+ };
7316
+ }
7317
+ function extractAdfText(body, maxLength = 500) {
7318
+ if (!body || typeof body !== "object")
7319
+ return "";
7320
+ const doc = body;
7321
+ if (doc.type !== "doc" || !Array.isArray(doc.content))
7322
+ return "";
7323
+ const parts = [];
7324
+ let totalLength = 0;
7325
+ function walk(nodes) {
7326
+ for (const node of nodes) {
7327
+ if (totalLength >= maxLength)
7328
+ return;
7329
+ if (!node || typeof node !== "object")
7330
+ continue;
7331
+ const n = node;
7332
+ if (n.type === "text" && typeof n.text === "string") {
7333
+ const remaining = maxLength - totalLength;
7334
+ const text = n.text.slice(0, remaining);
7335
+ parts.push(text);
7336
+ totalLength += text.length;
7337
+ }
7338
+ if (Array.isArray(n.content)) {
7339
+ walk(n.content);
7340
+ }
7341
+ }
7342
+ }
7343
+ walk(doc.content);
7344
+ const result = parts.join("");
7345
+ if (totalLength >= maxLength)
7346
+ return result + "...";
7347
+ return result;
7348
+ }
7349
+ function escapeSlackMrkdwn(text) {
7350
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\*/g, "\u2217").replace(/_/g, "\uFF3F").replace(/~/g, "\u223C").replace(/`/g, "\u02CB");
7351
+ }
7352
+ var PRIORITY_EMOJI = {
7353
+ Highest: ":red_circle:",
7354
+ High: ":large_orange_circle:",
7355
+ Medium: ":large_yellow_circle:",
7356
+ Low: ":large_green_circle:",
7357
+ Lowest: ":white_circle:"
7358
+ };
7359
+ function getPriorityEmoji(priority) {
7360
+ if (!priority)
7361
+ return "";
7362
+ return PRIORITY_EMOJI[priority] || ":blue_circle:";
7363
+ }
7364
+ function formatIssueEventForSlack(event, siteUrl) {
7365
+ const { issue, webhookEvent, user, changelog } = event;
7366
+ const { fields } = issue;
7367
+ const priorityEmoji = getPriorityEmoji(fields.priority?.name);
7368
+ const issueUrl = `${siteUrl}/browse/${issue.key}`;
7369
+ let action;
7370
+ let emoji;
7371
+ switch (webhookEvent) {
7372
+ case "jira:issue_created":
7373
+ action = "created";
7374
+ emoji = ":new:";
7375
+ break;
7376
+ case "jira:issue_updated":
7377
+ action = "updated";
7378
+ emoji = ":pencil2:";
7379
+ break;
7380
+ case "jira:issue_deleted":
7381
+ action = "deleted";
7382
+ emoji = ":wastebasket:";
7383
+ break;
7384
+ default:
7385
+ action = "changed";
7386
+ emoji = ":bell:";
7387
+ }
7388
+ let changelogText = "";
7389
+ if (changelog?.items && changelog.items.length > 0) {
7390
+ const changes = changelog.items.slice(0, 3).map((item) => {
7391
+ const from = escapeSlackMrkdwn(item.fromString || "None");
7392
+ const to = escapeSlackMrkdwn(item.toString || "None");
7393
+ if (item.field === "status") {
7394
+ return `Status: ${from} \u2192 ${to}`;
7395
+ }
7396
+ if (item.field === "assignee") {
7397
+ return `Assignee: ${escapeSlackMrkdwn(item.fromString || "Unassigned")} \u2192 ${escapeSlackMrkdwn(item.toString || "Unassigned")}`;
7398
+ }
7399
+ if (item.field === "priority") {
7400
+ return `Priority: ${from} \u2192 ${to}`;
7401
+ }
7402
+ return `${escapeSlackMrkdwn(item.field)}: ${from} \u2192 ${to}`;
7403
+ });
7404
+ if (changes.length > 0) {
7405
+ changelogText = "\n" + changes.map((c) => `\u2022 ${c}`).join("\n");
7406
+ if (changelog.items.length > 3) {
7407
+ changelogText += `
7408
+ _...and ${changelog.items.length - 3} more changes_`;
7409
+ }
7410
+ }
7411
+ }
7412
+ const blocks = [
7413
+ {
7414
+ type: "header",
7415
+ text: {
7416
+ type: "plain_text",
7417
+ text: `${emoji} Issue ${action}: ${escapeSlackMrkdwn(issue.key)}`,
7418
+ emoji: true
7419
+ }
7420
+ },
7421
+ {
7422
+ type: "section",
7423
+ text: {
7424
+ type: "mrkdwn",
7425
+ text: `*<${issueUrl}|${escapeSlackMrkdwn(issue.key)}>* ${escapeSlackMrkdwn(fields.summary)}`
7426
+ }
7427
+ },
7428
+ {
7429
+ type: "section",
7430
+ text: {
7431
+ type: "mrkdwn",
7432
+ text: [
7433
+ `${priorityEmoji} *Priority:* ${escapeSlackMrkdwn(fields.priority?.name || "None")}`,
7434
+ `*Status:* ${escapeSlackMrkdwn(fields.status.name)}`,
7435
+ `*Type:* ${escapeSlackMrkdwn(fields.issuetype.name)}`,
7436
+ `*Assignee:* ${escapeSlackMrkdwn(fields.assignee?.displayName || "Unassigned")}`
7437
+ ].join(" | ")
7438
+ }
7439
+ }
7440
+ ];
7441
+ if (changelogText) {
7442
+ blocks.push({
7443
+ type: "section",
7444
+ text: {
7445
+ type: "mrkdwn",
7446
+ text: `*Changes:*${changelogText}`
7447
+ }
7448
+ });
7449
+ }
7450
+ blocks.push({
7451
+ type: "context",
7452
+ elements: [
7453
+ {
7454
+ type: "mrkdwn",
7455
+ text: `${escapeSlackMrkdwn(user?.displayName || "Someone")} \u2022 ${escapeSlackMrkdwn(fields.project.name)} (${escapeSlackMrkdwn(fields.project.key)})`
7456
+ }
7457
+ ]
7458
+ });
7459
+ blocks.push({
7460
+ type: "actions",
7461
+ elements: [
7462
+ {
7463
+ type: "button",
7464
+ text: {
7465
+ type: "plain_text",
7466
+ text: "View in Jira",
7467
+ emoji: true
7468
+ },
7469
+ url: issueUrl,
7470
+ style: "primary"
7471
+ }
7472
+ ]
7473
+ });
7474
+ return {
7475
+ blocks,
7476
+ text: `${emoji} ${escapeSlackMrkdwn(issue.key)} ${action}: ${escapeSlackMrkdwn(fields.summary)}`
7477
+ };
7478
+ }
7479
+ function formatCommentEventForSlack(event, siteUrl) {
7480
+ const { issue, comment, webhookEvent } = event;
7481
+ const issueUrl = `${siteUrl}/browse/${issue.key}`;
7482
+ let action;
7483
+ let emoji;
7484
+ switch (webhookEvent) {
7485
+ case "comment_created":
7486
+ action = "commented on";
7487
+ emoji = ":speech_balloon:";
7488
+ break;
7489
+ case "comment_updated":
7490
+ action = "updated comment on";
7491
+ emoji = ":pencil:";
7492
+ break;
7493
+ case "comment_deleted":
7494
+ action = "deleted comment on";
7495
+ emoji = ":x:";
7496
+ break;
7497
+ default:
7498
+ action = "commented on";
7499
+ emoji = ":speech_balloon:";
7500
+ }
7501
+ const blocks = [
7502
+ {
7503
+ type: "header",
7504
+ text: {
7505
+ type: "plain_text",
7506
+ text: `${emoji} ${escapeSlackMrkdwn(comment.author.displayName)} ${action} ${escapeSlackMrkdwn(issue.key)}`,
7507
+ emoji: true
7508
+ }
7509
+ },
7510
+ {
7511
+ type: "section",
7512
+ text: {
7513
+ type: "mrkdwn",
7514
+ text: `*<${issueUrl}|${escapeSlackMrkdwn(issue.key)}>* ${escapeSlackMrkdwn(issue.fields.summary)}`
7515
+ }
7516
+ }
7517
+ ];
7518
+ if (webhookEvent !== "comment_deleted") {
7519
+ const bodyText = extractAdfText(comment.body);
7520
+ if (bodyText) {
7521
+ blocks.push({
7522
+ type: "section",
7523
+ text: {
7524
+ type: "mrkdwn",
7525
+ text: `> ${escapeSlackMrkdwn(bodyText).replace(/\n/g, "\n> ")}`
7526
+ }
7527
+ });
7528
+ }
7529
+ }
7530
+ blocks.push({
7531
+ type: "context",
7532
+ elements: [
7533
+ {
7534
+ type: "mrkdwn",
7535
+ text: `${escapeSlackMrkdwn(issue.fields.project.name)} \u2022 ${escapeSlackMrkdwn(issue.fields.issuetype.name)}`
7536
+ }
7537
+ ]
7538
+ }, {
7539
+ type: "actions",
7540
+ elements: [
7541
+ {
7542
+ type: "button",
7543
+ text: {
7544
+ type: "plain_text",
7545
+ text: "View in Jira",
7546
+ emoji: true
7547
+ },
7548
+ url: issueUrl,
7549
+ style: "primary"
7550
+ }
7551
+ ]
7552
+ });
7553
+ return {
7554
+ blocks,
7555
+ text: `${emoji} ${escapeSlackMrkdwn(comment.author.displayName)} ${action} ${escapeSlackMrkdwn(issue.key)}: ${escapeSlackMrkdwn(issue.fields.summary)}`
7556
+ };
7557
+ }
7558
+ function formatSprintEventForSlack(event, siteUrl) {
7559
+ const { sprint, webhookEvent, user } = event;
7560
+ let action;
7561
+ let emoji;
7562
+ switch (webhookEvent) {
7563
+ case "sprint_created":
7564
+ action = "created";
7565
+ emoji = ":calendar:";
7566
+ break;
7567
+ case "sprint_started":
7568
+ action = "started";
7569
+ emoji = ":rocket:";
7570
+ break;
7571
+ case "sprint_closed":
7572
+ action = "completed";
7573
+ emoji = ":checkered_flag:";
7574
+ break;
7575
+ case "sprint_updated":
7576
+ action = "updated";
7577
+ emoji = ":pencil2:";
7578
+ break;
7579
+ case "sprint_deleted":
7580
+ action = "deleted";
7581
+ emoji = ":wastebasket:";
7582
+ break;
7583
+ default:
7584
+ action = "changed";
7585
+ emoji = ":bell:";
7586
+ }
7587
+ const sprintUrl = `${siteUrl}/secure/RapidBoard.jspa?rapidView=${sprint.originBoardId}`;
7588
+ const blocks = [
7589
+ {
7590
+ type: "header",
7591
+ text: {
7592
+ type: "plain_text",
7593
+ text: `${emoji} Sprint ${action}: ${escapeSlackMrkdwn(sprint.name)}`,
7594
+ emoji: true
7595
+ }
7596
+ },
7597
+ {
7598
+ type: "section",
7599
+ text: {
7600
+ type: "mrkdwn",
7601
+ text: [
7602
+ `*State:* ${escapeSlackMrkdwn(sprint.state)}`,
7603
+ sprint.startDate ? `*Start:* ${new Date(sprint.startDate).toLocaleDateString()}` : "",
7604
+ sprint.endDate ? `*End:* ${new Date(sprint.endDate).toLocaleDateString()}` : ""
7605
+ ].filter(Boolean).join(" | ")
7606
+ }
7607
+ }
7608
+ ];
7609
+ if (sprint.goal) {
7610
+ blocks.push({
7611
+ type: "section",
7612
+ text: {
7613
+ type: "mrkdwn",
7614
+ text: `*Goal:* ${escapeSlackMrkdwn(sprint.goal)}`
7615
+ }
7616
+ });
7617
+ }
7618
+ blocks.push({
7619
+ type: "context",
7620
+ elements: [
7621
+ {
7622
+ type: "mrkdwn",
7623
+ text: user?.displayName ? escapeSlackMrkdwn(user.displayName) : "System"
7624
+ }
7625
+ ]
7626
+ });
7627
+ blocks.push({
7628
+ type: "actions",
7629
+ elements: [
7630
+ {
7631
+ type: "button",
7632
+ text: {
7633
+ type: "plain_text",
7634
+ text: "View Board",
7635
+ emoji: true
7636
+ },
7637
+ url: sprintUrl,
7638
+ style: "primary"
7639
+ }
7640
+ ]
7641
+ });
7642
+ return {
7643
+ blocks,
7644
+ text: `${emoji} Sprint ${action}: ${escapeSlackMrkdwn(sprint.name)}`
7645
+ };
7646
+ }
7647
+ function formatGenericEventForSlack(eventType, payload, siteUrl) {
7648
+ const issue = payload.issue;
7649
+ const user = payload.user;
7650
+ const issueLink = payload.issueLink;
7651
+ const changelog = payload.changelog;
7652
+ const project = payload.project ?? issue?.fields?.project;
7653
+ const version = payload.version;
7654
+ const worklog = payload.worklog;
7655
+ const board = payload.board;
7656
+ const readableEvent = eventType.replace(/^jira:/, "").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7657
+ const blocks = [
7658
+ {
7659
+ type: "header",
7660
+ text: {
7661
+ type: "plain_text",
7662
+ text: `:bell: ${readableEvent}`,
7663
+ emoji: true
7664
+ }
7665
+ }
7666
+ ];
7667
+ const details = [];
7668
+ if (issue?.key) {
7669
+ const issueUrl = `${siteUrl}/browse/${issue.key}`;
7670
+ blocks.push({
7671
+ type: "section",
7672
+ text: {
7673
+ type: "mrkdwn",
7674
+ text: `*<${issueUrl}|${escapeSlackMrkdwn(issue.key)}>* ${escapeSlackMrkdwn(issue.fields?.summary || "")}`
7675
+ }
7676
+ });
7677
+ const meta = [];
7678
+ if (issue.fields?.status?.name)
7679
+ meta.push(`*Status:* ${escapeSlackMrkdwn(issue.fields.status.name)}`);
7680
+ if (issue.fields?.issuetype?.name)
7681
+ meta.push(`*Type:* ${escapeSlackMrkdwn(issue.fields.issuetype.name)}`);
7682
+ if (issue.fields?.priority?.name) {
7683
+ const emoji = getPriorityEmoji(issue.fields.priority.name);
7684
+ meta.push(`${emoji} *Priority:* ${escapeSlackMrkdwn(issue.fields.priority.name)}`);
7685
+ }
7686
+ if (issue.fields?.assignee?.displayName)
7687
+ meta.push(`*Assignee:* ${escapeSlackMrkdwn(issue.fields.assignee.displayName)}`);
7688
+ if (meta.length > 0)
7689
+ details.push(meta.join(" | "));
7690
+ }
7691
+ if (issueLink?.issueLinkType) {
7692
+ const linkType = issueLink.issueLinkType;
7693
+ const linkDesc = escapeSlackMrkdwn(linkType.outwardName || linkType.name || "linked");
7694
+ details.push(`*Link type:* ${linkDesc}`);
7695
+ if (issueLink.sourceIssueId)
7696
+ details.push(`*Source issue ID:* ${issueLink.sourceIssueId}`);
7697
+ if (issueLink.destinationIssueId)
7698
+ details.push(`*Destination issue ID:* ${issueLink.destinationIssueId}`);
7699
+ }
7700
+ if (version?.name) {
7701
+ const versionParts = [`*Version:* ${escapeSlackMrkdwn(version.name)}`];
7702
+ if (version.description)
7703
+ versionParts.push(escapeSlackMrkdwn(version.description));
7704
+ if (version.released !== void 0)
7705
+ versionParts.push(version.released ? ":white_check_mark: Released" : "Unreleased");
7706
+ details.push(versionParts.join(" | "));
7707
+ }
7708
+ if (worklog) {
7709
+ const wlParts = [];
7710
+ if (worklog.author?.displayName)
7711
+ wlParts.push(`*By:* ${escapeSlackMrkdwn(worklog.author.displayName)}`);
7712
+ if (worklog.timeSpent)
7713
+ wlParts.push(`*Time:* ${escapeSlackMrkdwn(worklog.timeSpent)}`);
7714
+ if (wlParts.length > 0)
7715
+ details.push(wlParts.join(" | "));
7716
+ }
7717
+ if (board?.name) {
7718
+ details.push(`*Board:* ${escapeSlackMrkdwn(board.name)}`);
7719
+ }
7720
+ if (changelog?.items && changelog.items.length > 0) {
7721
+ const changes = changelog.items.slice(0, 3).map((item) => `\u2022 ${escapeSlackMrkdwn(item.field || "")}: ${escapeSlackMrkdwn(item.fromString || "None")} \u2192 ${escapeSlackMrkdwn(item.toString || "None")}`);
7722
+ if (changelog.items.length > 3) {
7723
+ changes.push(`_...and ${changelog.items.length - 3} more_`);
7724
+ }
7725
+ details.push(`*Changes:*
7726
+ ${changes.join("\n")}`);
7727
+ }
7728
+ if (details.length > 0) {
7729
+ blocks.push({
7730
+ type: "section",
7731
+ text: {
7732
+ type: "mrkdwn",
7733
+ text: details.join("\n")
7734
+ }
7735
+ });
7736
+ }
7737
+ const contextParts = [];
7738
+ if (user?.displayName)
7739
+ contextParts.push(escapeSlackMrkdwn(user.displayName));
7740
+ if (project?.name)
7741
+ contextParts.push(`${escapeSlackMrkdwn(project.name)}${project.key ? ` (${escapeSlackMrkdwn(project.key)})` : ""}`);
7742
+ if (contextParts.length > 0) {
7743
+ blocks.push({
7744
+ type: "context",
7745
+ elements: [{ type: "mrkdwn", text: contextParts.join(" \u2022 ") }]
7746
+ });
7747
+ }
7748
+ if (issue?.key) {
7749
+ const issueUrl = `${siteUrl}/browse/${issue.key}`;
7750
+ blocks.push({
7751
+ type: "actions",
7752
+ elements: [
7753
+ {
7754
+ type: "button",
7755
+ text: { type: "plain_text", text: "View in Jira", emoji: true },
7756
+ url: issueUrl,
7757
+ style: "primary"
7758
+ }
7759
+ ]
7760
+ });
7761
+ }
7762
+ const summary = issue?.key ? `${escapeSlackMrkdwn(issue.key)}: ${escapeSlackMrkdwn(issue.fields?.summary || readableEvent)}` : readableEvent;
7763
+ return {
7764
+ blocks,
7765
+ text: `:bell: ${summary}`
7766
+ };
7767
+ }
7768
+
7769
+ // ../../b4m-core/packages/common/dist/src/jira/webhook/api.js
7770
+ var WebhookApi = class {
7771
+ config;
7772
+ constructor(config) {
7773
+ this.config = config;
7774
+ }
7775
+ /**
7776
+ * Build URL for webhook API endpoints.
7777
+ *
7778
+ * Note: Webhooks use a different base URL than other Jira APIs.
7779
+ */
7780
+ buildUrl(path, query = {}) {
7781
+ const url = new URL(`${this.config.apiBaseUrl}${path}`);
7782
+ for (const [key, value] of Object.entries(query)) {
7783
+ if (value !== void 0) {
7784
+ url.searchParams.append(key, String(value));
7785
+ }
7786
+ }
7787
+ return url.toString();
7788
+ }
7789
+ /**
7790
+ * Make an authenticated request to the Jira Webhook API.
7791
+ */
7792
+ async request(method, path, options = {}) {
7793
+ const url = this.buildUrl(path, options.query);
7794
+ const headers = {
7795
+ Authorization: this.config.authHeader,
7796
+ Accept: "application/json",
7797
+ "Content-Type": "application/json"
7798
+ };
7799
+ const response = await fetch(url, {
7800
+ method,
7801
+ headers,
7802
+ body: options.body ? JSON.stringify(options.body) : void 0
7803
+ });
7804
+ if (!response.ok) {
7805
+ const errorBody = await response.text();
7806
+ throw new Error(`Jira Webhook API error (${response.status}): ${errorBody}`);
7807
+ }
7808
+ if (response.status === 204) {
7809
+ return {};
7810
+ }
7811
+ const data = await response.json();
7812
+ return data;
7813
+ }
7814
+ // ============================================================================
7815
+ // Webhook CRUD Operations
7816
+ // ============================================================================
7817
+ /**
7818
+ * List all webhooks registered by this OAuth app.
7819
+ *
7820
+ * @param startAt - Pagination start index (default: 0)
7821
+ * @param maxResults - Max results per page (default: 50, max: 100)
7822
+ */
7823
+ async listWebhooks(params = {}) {
7824
+ const { startAt = 0, maxResults = 50 } = params;
7825
+ const response = await this.request("GET", "/webhook", {
7826
+ query: { startAt, maxResults }
7827
+ });
7828
+ return formatWebhookList(response);
7829
+ }
7830
+ /**
7831
+ * Register a new webhook.
7832
+ *
7833
+ * @param url - The URL where Jira will POST webhook events
7834
+ * @param events - Events to subscribe to
7835
+ * @param jqlFilter - Optional JQL filter (only matching issues trigger events)
7836
+ * @returns The created webhook ID
7837
+ */
7838
+ async registerWebhook(params) {
7839
+ const { url, events, jqlFilter } = params;
7840
+ const webhook = {
7841
+ // Jira webhook API requires jqlFilter but has limited operator support.
7842
+ // "IS NOT EMPTY" and empty strings are rejected. Use a universally-true expression.
7843
+ jqlFilter: jqlFilter || "project != null",
7844
+ events
7845
+ };
7846
+ const body = {
7847
+ url,
7848
+ webhooks: [webhook]
7849
+ };
7850
+ const response = await this.request("POST", "/webhook", {
7851
+ body
7852
+ });
7853
+ console.log("[JIRA-WEBHOOK-API] registerWebhook raw response:", JSON.stringify(response, null, 2));
7854
+ if (!response.webhookRegistrationResult || response.webhookRegistrationResult.length === 0) {
7855
+ throw new Error("Failed to register webhook: No registration result returned");
7856
+ }
7857
+ const result = response.webhookRegistrationResult[0];
7858
+ if (result.errors && result.errors.length > 0) {
7859
+ throw new Error(`Failed to register webhook: ${result.errors.join(", ")}`);
7860
+ }
7861
+ if (result.createdWebhookId === void 0 || result.createdWebhookId === null) {
7862
+ throw new Error(`Failed to register webhook: No webhook ID in response. Full result: ${JSON.stringify(result)}`);
7863
+ }
7864
+ return {
7865
+ webhookId: result.createdWebhookId
7866
+ };
7867
+ }
7868
+ /**
7869
+ * Refresh webhook expiration dates.
7870
+ *
7871
+ * Jira webhooks expire after 30 days. Call this to extend expiration.
7872
+ *
7873
+ * @param webhookIds - IDs of webhooks to refresh
7874
+ * @returns New expiration date
7875
+ */
7876
+ async refreshWebhooks(params) {
7877
+ const { webhookIds } = params;
7878
+ const body = {
7879
+ webhookIds
7880
+ };
7881
+ const response = await this.request("PUT", "/webhook/refresh", {
7882
+ body
7883
+ });
7884
+ return {
7885
+ expirationDate: response.expirationDate
7886
+ };
7887
+ }
7888
+ /**
7889
+ * Delete webhooks by ID.
7890
+ *
7891
+ * @param webhookIds - IDs of webhooks to delete
7892
+ */
7893
+ async deleteWebhooks(params) {
7894
+ const { webhookIds } = params;
7895
+ const body = {
7896
+ webhookIds
7897
+ };
7898
+ await this.request("DELETE", "/webhook", {
7899
+ body
7900
+ });
7901
+ }
7902
+ /**
7903
+ * Get a specific webhook by ID.
7904
+ *
7905
+ * Note: Jira API doesn't have a direct "get by ID" endpoint,
7906
+ * so we list and filter.
7907
+ */
7908
+ async getWebhook(params) {
7909
+ const { webhookId } = params;
7910
+ const response = await this.request("GET", "/webhook", {
7911
+ query: { startAt: 0, maxResults: 100 }
7912
+ });
7913
+ const webhook = response.values.find((w) => w.id === webhookId);
7914
+ return webhook || null;
7915
+ }
7916
+ };
7917
+
7261
7918
  // ../../b4m-core/packages/common/dist/src/jira/api.js
7262
7919
  var JIRA_MAX_ATTACHMENT_SIZE = 20 * 1024 * 1024;
7263
7920
  function isValidIssueKey(key) {
@@ -8009,8 +8666,71 @@ var JiraApi = class {
8009
8666
  }
8010
8667
  return this._agileApi;
8011
8668
  }
8669
+ // ============================================================================
8670
+ // Webhook API Access (Webhook Management)
8671
+ // ============================================================================
8672
+ _webhookApi = null;
8673
+ /**
8674
+ * Get the Webhook API client for webhook management operations.
8675
+ * Lazily instantiated on first access.
8676
+ */
8677
+ get webhook() {
8678
+ if (!this._webhookApi) {
8679
+ this._webhookApi = new WebhookApi(this.config);
8680
+ }
8681
+ return this._webhookApi;
8682
+ }
8012
8683
  };
8013
8684
 
8685
+ // ../../b4m-core/packages/common/dist/src/jira/webhook/types.js
8686
+ function isIssueWebhookEvent(payload) {
8687
+ const event = payload.webhookEvent;
8688
+ if (typeof event !== "string" || !event.startsWith("jira:issue_"))
8689
+ return false;
8690
+ const issue = payload.issue;
8691
+ if (!issue || typeof issue.key !== "string")
8692
+ return false;
8693
+ const fields = issue.fields;
8694
+ if (!fields || typeof fields.summary !== "string")
8695
+ return false;
8696
+ const status = fields.status;
8697
+ const issuetype = fields.issuetype;
8698
+ const project = fields.project;
8699
+ if (!status?.name || !issuetype?.name || !project?.key)
8700
+ return false;
8701
+ return true;
8702
+ }
8703
+ function isCommentWebhookEvent(payload) {
8704
+ const event = payload.webhookEvent;
8705
+ if (typeof event !== "string" || !event.startsWith("comment_"))
8706
+ return false;
8707
+ const issue = payload.issue;
8708
+ if (!issue || typeof issue.key !== "string")
8709
+ return false;
8710
+ const comment = payload.comment;
8711
+ if (!comment || typeof comment.id !== "string")
8712
+ return false;
8713
+ const author = comment.author;
8714
+ if (!author || typeof author.displayName !== "string")
8715
+ return false;
8716
+ return true;
8717
+ }
8718
+ function isSprintWebhookEvent(payload) {
8719
+ const event = payload.webhookEvent;
8720
+ if (typeof event !== "string" || !event.startsWith("sprint_"))
8721
+ return false;
8722
+ const sprint = payload.sprint;
8723
+ if (!sprint || typeof sprint.name !== "string")
8724
+ return false;
8725
+ return true;
8726
+ }
8727
+ function extractWebhookEventType(payload) {
8728
+ const event = payload.webhookEvent;
8729
+ if (typeof event !== "string" || event.length === 0)
8730
+ return null;
8731
+ return event;
8732
+ }
8733
+
8014
8734
  // ../../b4m-core/packages/common/dist/src/atlassian/config.js
8015
8735
  function getErrorMessage(error) {
8016
8736
  if (error instanceof Error) {
@@ -8597,6 +9317,7 @@ export {
8597
9317
  ChatModels,
8598
9318
  CHAT_MODELS,
8599
9319
  supportedChatModels,
9320
+ REASONING_SUPPORTED_MODELS,
8600
9321
  SpeechToTextModels,
8601
9322
  SPEECH_TO_TEXT_MODELS,
8602
9323
  supportedSpeechToTextModels,
@@ -8703,6 +9424,8 @@ export {
8703
9424
  isPlaceholderValue,
8704
9425
  SecretAuditEvents,
8705
9426
  WebhookDeliveryStatus,
9427
+ COMMON_JIRA_WEBHOOK_EVENTS,
9428
+ JiraWebhookDeliveryStatus,
8706
9429
  SupportedFabFileMimeTypes,
8707
9430
  REASONING_EFFORT_LABELS,
8708
9431
  REASONING_EFFORT_DESCRIPTIONS,
@@ -8940,11 +9663,24 @@ export {
8940
9663
  formatIssueLinkTypes,
8941
9664
  formatIssueLinks,
8942
9665
  AgileApi,
9666
+ formatWebhook,
9667
+ formatWebhookList,
9668
+ extractAdfText,
9669
+ escapeSlackMrkdwn,
9670
+ formatIssueEventForSlack,
9671
+ formatCommentEventForSlack,
9672
+ formatSprintEventForSlack,
9673
+ formatGenericEventForSlack,
9674
+ WebhookApi,
8943
9675
  JIRA_MAX_ATTACHMENT_SIZE,
8944
9676
  isValidIssueKey,
8945
9677
  wikiMarkupToAdf,
8946
9678
  containsWikiTable,
8947
9679
  JiraApi,
9680
+ isIssueWebhookEvent,
9681
+ isCommentWebhookEvent,
9682
+ isSprintWebhookEvent,
9683
+ extractWebhookEventType,
8948
9684
  getErrorMessage,
8949
9685
  getAtlassianConfig,
8950
9686
  MCP_PROVIDER_METADATA,