deepline 0.3.14 → 0.3.15

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.
@@ -98,6 +98,7 @@ import {
98
98
  TOOL_EXECUTION_ERROR_SCHEMA_HEADER,
99
99
  TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
100
100
  } from '../../shared_libs/tool-execution-error.js';
101
+
101
102
  import { decodePlayRunPublicStatus } from '../../shared_libs/play-runtime/run-lifecycle-policy.js';
102
103
  import {
103
104
  legacyRawFromToolResponseRawV2,
@@ -105,6 +106,20 @@ import {
105
106
  RAW_V2_TOOL_RESPONSE_CONTRACT,
106
107
  } from '../../shared_libs/play-runtime/tool-response-contract.js';
107
108
 
109
+ export type SlackNotificationTarget =
110
+ | { channel: string; memberId?: never }
111
+ | { channel?: never; memberId: string };
112
+
113
+ export type CreateNotificationInput = {
114
+ name: string;
115
+ provider: 'slack';
116
+ eventTypes: string[];
117
+ } & SlackNotificationTarget;
118
+
119
+ export type UpdateNotificationInput =
120
+ | { enabled: boolean }
121
+ | ({ name: string; eventTypes: string[] } & SlackNotificationTarget);
122
+
108
123
  const TERMINAL_PLAY_STATUSES = new Set(['completed', 'failed', 'cancelled']);
109
124
  const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
110
125
  const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
@@ -2835,7 +2850,8 @@ export class DeeplineClient {
2835
2850
  }
2836
2851
 
2837
2852
  type DirectStageResult =
2838
- { ref: PlayStagedFileRef } | { fallbackFile: (typeof files)[number] };
2853
+ | { ref: PlayStagedFileRef }
2854
+ | { fallbackFile: (typeof files)[number] };
2839
2855
  const directResults: DirectStageResult[] = await Promise.all(
2840
2856
  files.map(async (file) => {
2841
2857
  const upload = uploadByIdentity.get(
@@ -3930,9 +3946,12 @@ export class DeeplineClient {
3930
3946
  return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
3931
3947
  }
3932
3948
 
3933
- /** Select the Slack channel used for product notifications. */
3934
- async setNotificationSlack(channel: string) {
3935
- return this.http.put('/api/v2/settings/notifications', { channel });
3949
+ /** Select a Slack channel or direct member used for product notifications. */
3950
+ async setNotificationSlack(destination: string | { memberId: string }) {
3951
+ return this.http.put(
3952
+ '/api/v2/settings/notifications',
3953
+ typeof destination === 'string' ? { channel: destination } : destination,
3954
+ );
3936
3955
  }
3937
3956
 
3938
3957
  /** Send one synchronous test ping and return Slack's delivery result. */
@@ -3998,21 +4017,14 @@ export class DeeplineClient {
3998
4017
  }
3999
4018
 
4000
4019
  /** Create a named notification routed through an existing provider integration. */
4001
- async createNotification(input: {
4002
- name: string;
4003
- provider: 'slack';
4004
- channel: string;
4005
- eventTypes: string[];
4006
- }) {
4020
+ async createNotification(input: CreateNotificationInput) {
4007
4021
  return this.http.post('/api/v2/notifications', input);
4008
4022
  }
4009
4023
 
4010
4024
  /** Update a notification's target, event selection, or enabled state. */
4011
4025
  async updateNotification(
4012
4026
  notificationId: string,
4013
- input:
4014
- | { enabled: boolean }
4015
- | { name: string; channel: string; eventTypes: string[] },
4027
+ input: UpdateNotificationInput,
4016
4028
  ) {
4017
4029
  return this.http.patch(
4018
4030
  `/api/v2/notifications/${encodeURIComponent(notificationId)}`,
@@ -192,7 +192,7 @@ export const SDK_RELEASE = {
192
192
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
193
193
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
194
194
  // getters keep their established compatibility behavior.
195
- version: '0.3.14',
195
+ version: '0.3.15',
196
196
  updateSummary:
197
197
  'New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.',
198
198
  contracts: {
@@ -1136,7 +1136,7 @@ export interface ProductNotification {
1136
1136
  id: string;
1137
1137
  name: string;
1138
1138
  provider: string;
1139
- target: { id: string; name: string };
1139
+ target: { id: string; name: string; kind?: 'channel' | 'member' };
1140
1140
  enabled: boolean;
1141
1141
  status: string;
1142
1142
  eventTypes: string[];
@@ -79,10 +79,25 @@ export const PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
79
79
  'channels:read',
80
80
  'chat:write',
81
81
  'groups:read',
82
+ 'im:write',
82
83
  ] as const;
83
84
  export type ProductNotificationDestinationKind =
84
85
  (typeof PRODUCT_NOTIFICATION_DESTINATION_KINDS)[number];
85
86
 
87
+ export const PRODUCT_NOTIFICATION_SLACK_TARGET_KINDS = [
88
+ 'channel',
89
+ 'member',
90
+ ] as const;
91
+ export type ProductNotificationSlackTargetKind =
92
+ (typeof PRODUCT_NOTIFICATION_SLACK_TARGET_KINDS)[number];
93
+
94
+ /** Slack member IDs begin with U (or W for Enterprise Grid workspaces). */
95
+ export function isProductNotificationSlackMemberId(
96
+ value: unknown,
97
+ ): value is string {
98
+ return typeof value === 'string' && /^[UW][A-Z0-9]{8,}$/.test(value.trim());
99
+ }
100
+
86
101
  export const PRODUCT_NOTIFICATION_DELIVERY_STATES = [
87
102
  'pending',
88
103
  'delivering',
package/dist/cli/index.js CHANGED
@@ -1047,7 +1047,7 @@ var SDK_RELEASE = {
1047
1047
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1048
1048
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1049
1049
  // getters keep their established compatibility behavior.
1050
- version: "0.3.14",
1050
+ version: "0.3.15",
1051
1051
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1052
1052
  contracts: {
1053
1053
  api: {
@@ -1907,7 +1907,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
1907
1907
  var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
1908
1908
  "channels:read",
1909
1909
  "chat:write",
1910
- "groups:read"
1910
+ "groups:read",
1911
+ "im:write"
1911
1912
  ];
1912
1913
  var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
1913
1914
  0,
@@ -5987,9 +5988,12 @@ var DeeplineClient = class {
5987
5988
  const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
5988
5989
  return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
5989
5990
  }
5990
- /** Select the Slack channel used for product notifications. */
5991
- async setNotificationSlack(channel) {
5992
- return this.http.put("/api/v2/settings/notifications", { channel });
5991
+ /** Select a Slack channel or direct member used for product notifications. */
5992
+ async setNotificationSlack(destination) {
5993
+ return this.http.put(
5994
+ "/api/v2/settings/notifications",
5995
+ typeof destination === "string" ? { channel: destination } : destination
5996
+ );
5993
5997
  }
5994
5998
  /** Send one synchronous test ping and return Slack's delivery result. */
5995
5999
  async testNotificationSlack() {
@@ -36120,7 +36124,7 @@ async function printSettings(options) {
36120
36124
  title: "Slack destination",
36121
36125
  lines: slack ? [
36122
36126
  `status: ${String(slack.status ?? "unknown")}`,
36123
- `channel: #${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
36127
+ `${slack.targetKind === "member" ? "member" : "channel"}: ${slack.targetKind === "member" ? "@" : "#"}${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
36124
36128
  ...slack.lastErrorMessage ? [`issue: ${String(slack.lastErrorMessage)}`] : []
36125
36129
  ] : ["Not configured."]
36126
36130
  },
@@ -36224,27 +36228,32 @@ notifications; there is no general integrations CLI.
36224
36228
  { json: options.json }
36225
36229
  );
36226
36230
  });
36227
- notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").requiredOption("--channel <channel>", "Slack channel name or ID").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
36231
+ notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").option("--channel <channel>", "Slack channel name or ID").option("--member-id <id>", "Slack member ID, for example U0123456789").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
36228
36232
  async (destination, options) => {
36229
36233
  if (destination !== "slack")
36230
36234
  throw new Error("Only slack is supported.");
36235
+ if (Boolean(options.channel) === Boolean(options.memberId)) {
36236
+ throw new Error("Provide exactly one of --channel or --member-id.");
36237
+ }
36238
+ const target = options.memberId ? { memberId: options.memberId } : options.channel;
36231
36239
  if (options.dryRun) {
36232
36240
  printCommandEnvelope(
36233
- { dryRun: true, destination, channel: options.channel },
36241
+ { dryRun: true, destination, target },
36234
36242
  { json: options.json }
36235
36243
  );
36236
36244
  return;
36237
36245
  }
36238
- const result = await new DeeplineClient().setNotificationSlack(
36239
- options.channel
36240
- );
36246
+ const result = await new DeeplineClient().setNotificationSlack(target);
36241
36247
  printCommandEnvelope(
36242
36248
  {
36243
36249
  ok: true,
36244
36250
  result,
36245
36251
  render: {
36246
36252
  sections: [
36247
- { title: "Slack destination saved", lines: [options.channel] }
36253
+ {
36254
+ title: "Slack destination saved",
36255
+ lines: [options.memberId ?? options.channel]
36256
+ }
36248
36257
  ],
36249
36258
  actions: [
36250
36259
  {
@@ -36446,9 +36455,22 @@ function notificationByName(settings, reference) {
36446
36455
  function parseSlackTarget(value) {
36447
36456
  const match = /^slack:(.+)$/i.exec(value.trim());
36448
36457
  if (!match?.[1]) {
36449
- throw new Error("Use --to slack:#channel.");
36458
+ throw new Error(
36459
+ "Use --to slack:#channel or --to slack:member:U0123456789."
36460
+ );
36450
36461
  }
36451
- return match[1];
36462
+ const target = match[1].trim();
36463
+ const member = /^member:([UW][A-Z0-9]{8,})$/i.exec(target);
36464
+ if (member?.[1]) return { memberId: member[1].toUpperCase() };
36465
+ if (target.toLowerCase().startsWith("member:")) {
36466
+ throw new Error(
36467
+ "Slack member IDs must look like slack:member:U0123456789."
36468
+ );
36469
+ }
36470
+ return { channel: target };
36471
+ }
36472
+ function displaySlackTarget(target) {
36473
+ return `${target.kind === "member" ? "@" : "#"}${target.name}`;
36452
36474
  }
36453
36475
  function collectEvent(value, previous = []) {
36454
36476
  return [...previous, value];
@@ -36461,10 +36483,11 @@ Examples:
36461
36483
  deepline notifications events
36462
36484
  deepline notifications slack channels --search pipeline
36463
36485
  deepline notifications add pipeline-watchdog --to slack:#pipeline-alerts --for play.cron.failed
36486
+ deepline notifications add owner-alerts --to slack:member:U0123456789 --for play.cron.failed
36464
36487
  deepline notifications test pipeline-watchdog
36465
36488
 
36466
36489
  Slack connections are managed in Dashboard \u2192 Integrations. This command only
36467
- chooses the connected Slack channel and the events it receives.
36490
+ chooses the connected Slack channel or member and the events it receives.
36468
36491
  `
36469
36492
  );
36470
36493
  notifications.command("events").description("List the Play events available to a notification.").option("--json", "Emit JSON output").action(async (options) => {
@@ -36495,7 +36518,7 @@ chooses the connected Slack channel and the events it receives.
36495
36518
  id: rule.id,
36496
36519
  name: rule.name,
36497
36520
  enabled: rule.enabled,
36498
- target: `#${rule.target.name}`,
36521
+ target: displaySlackTarget(rule.target),
36499
36522
  eventTypes: rule.eventTypes
36500
36523
  })) : rules,
36501
36524
  count: rules.length,
@@ -36504,7 +36527,7 @@ chooses the connected Slack channel and the events it receives.
36504
36527
  {
36505
36528
  title: "notifications",
36506
36529
  lines: rules.length ? rules.map(
36507
- (rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 #${rule.target.name} (${rule.eventTypes.join(", ") || "no events"})`
36530
+ (rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 ${displaySlackTarget(rule.target)} (${rule.eventTypes.join(", ") || "no events"})`
36508
36531
  ) : [
36509
36532
  "None yet. Add one with deepline notifications add <name> --to slack:#channel --for play.cron.failed."
36510
36533
  ]
@@ -36524,7 +36547,7 @@ chooses the connected Slack channel and the events it receives.
36524
36547
  });
36525
36548
  notifications.command("add").argument("<name>", "Short stable name, for example pipeline-watchdog").requiredOption(
36526
36549
  "--to <target>",
36527
- "Target, for example slack:#pipeline-alerts"
36550
+ "Target, for example slack:#pipeline-alerts or slack:member:U0123456789"
36528
36551
  ).option(
36529
36552
  "--for <event>",
36530
36553
  "Event ID; repeat for more events. Run notifications events to list them",
@@ -36535,7 +36558,7 @@ chooses the connected Slack channel and the events it receives.
36535
36558
  if (!options.for.length) {
36536
36559
  throw new Error("Choose at least one event with --for <event>.");
36537
36560
  }
36538
- const channel = parseSlackTarget(options.to);
36561
+ const target = parseSlackTarget(options.to);
36539
36562
  if (options.dryRun) {
36540
36563
  printCommandEnvelope(
36541
36564
  { dryRun: true, name, target: options.to, eventTypes: options.for },
@@ -36546,7 +36569,7 @@ chooses the connected Slack channel and the events it receives.
36546
36569
  const result = await new DeeplineClient().createNotification({
36547
36570
  name,
36548
36571
  provider: "slack",
36549
- channel,
36572
+ ...target,
36550
36573
  eventTypes: options.for
36551
36574
  });
36552
36575
  printCommandEnvelope(
@@ -36566,7 +36589,10 @@ chooses the connected Slack channel and the events it receives.
36566
36589
  );
36567
36590
  }
36568
36591
  );
36569
- notifications.command("edit").argument("<name>", "Notification name or ID").option("--to <target>", "New target, for example slack:#pipeline-alerts").option(
36592
+ notifications.command("edit").argument("<name>", "Notification name or ID").option(
36593
+ "--to <target>",
36594
+ "New target, for example slack:#pipeline-alerts or slack:member:U0123456789"
36595
+ ).option(
36570
36596
  "--for <event>",
36571
36597
  "Replace selected events; repeat for more events. Run notifications events to list them",
36572
36598
  collectEvent,
@@ -36575,18 +36601,18 @@ chooses the connected Slack channel and the events it receives.
36575
36601
  async (name, options) => {
36576
36602
  const client2 = new DeeplineClient();
36577
36603
  const rule = notificationByName(await client2.getNotifications(), name);
36578
- const channel = options.to ? parseSlackTarget(options.to) : rule.target.name;
36604
+ const target = options.to ? parseSlackTarget(options.to) : rule.target.kind === "member" ? { memberId: rule.target.id } : { channel: rule.target.name };
36579
36605
  const eventTypes = options.for.length ? options.for : rule.eventTypes;
36580
36606
  if (options.dryRun) {
36581
36607
  printCommandEnvelope(
36582
- { dryRun: true, notification: rule.id, channel, eventTypes },
36608
+ { dryRun: true, notification: rule.id, target, eventTypes },
36583
36609
  { json: options.json }
36584
36610
  );
36585
36611
  return;
36586
36612
  }
36587
36613
  const result = await client2.updateNotification(rule.id, {
36588
36614
  name: rule.name,
36589
- channel,
36615
+ ...target,
36590
36616
  eventTypes
36591
36617
  });
36592
36618
  printCommandEnvelope({ notification: result }, { json: options.json });
@@ -1033,7 +1033,7 @@ var SDK_RELEASE = {
1033
1033
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1034
1034
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1035
1035
  // getters keep their established compatibility behavior.
1036
- version: "0.3.14",
1036
+ version: "0.3.15",
1037
1037
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1038
1038
  contracts: {
1039
1039
  api: {
@@ -1893,7 +1893,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
1893
1893
  var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
1894
1894
  "channels:read",
1895
1895
  "chat:write",
1896
- "groups:read"
1896
+ "groups:read",
1897
+ "im:write"
1897
1898
  ];
1898
1899
  var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
1899
1900
  0,
@@ -5973,9 +5974,12 @@ var DeeplineClient = class {
5973
5974
  const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
5974
5975
  return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
5975
5976
  }
5976
- /** Select the Slack channel used for product notifications. */
5977
- async setNotificationSlack(channel) {
5978
- return this.http.put("/api/v2/settings/notifications", { channel });
5977
+ /** Select a Slack channel or direct member used for product notifications. */
5978
+ async setNotificationSlack(destination) {
5979
+ return this.http.put(
5980
+ "/api/v2/settings/notifications",
5981
+ typeof destination === "string" ? { channel: destination } : destination
5982
+ );
5979
5983
  }
5980
5984
  /** Send one synchronous test ping and return Slack's delivery result. */
5981
5985
  async testNotificationSlack() {
@@ -36198,7 +36202,7 @@ async function printSettings(options) {
36198
36202
  title: "Slack destination",
36199
36203
  lines: slack ? [
36200
36204
  `status: ${String(slack.status ?? "unknown")}`,
36201
- `channel: #${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
36205
+ `${slack.targetKind === "member" ? "member" : "channel"}: ${slack.targetKind === "member" ? "@" : "#"}${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
36202
36206
  ...slack.lastErrorMessage ? [`issue: ${String(slack.lastErrorMessage)}`] : []
36203
36207
  ] : ["Not configured."]
36204
36208
  },
@@ -36302,27 +36306,32 @@ notifications; there is no general integrations CLI.
36302
36306
  { json: options.json }
36303
36307
  );
36304
36308
  });
36305
- notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").requiredOption("--channel <channel>", "Slack channel name or ID").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
36309
+ notifications.command("set").description("Set a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").option("--channel <channel>", "Slack channel name or ID").option("--member-id <id>", "Slack member ID, for example U0123456789").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(
36306
36310
  async (destination, options) => {
36307
36311
  if (destination !== "slack")
36308
36312
  throw new Error("Only slack is supported.");
36313
+ if (Boolean(options.channel) === Boolean(options.memberId)) {
36314
+ throw new Error("Provide exactly one of --channel or --member-id.");
36315
+ }
36316
+ const target = options.memberId ? { memberId: options.memberId } : options.channel;
36309
36317
  if (options.dryRun) {
36310
36318
  printCommandEnvelope(
36311
- { dryRun: true, destination, channel: options.channel },
36319
+ { dryRun: true, destination, target },
36312
36320
  { json: options.json }
36313
36321
  );
36314
36322
  return;
36315
36323
  }
36316
- const result = await new DeeplineClient().setNotificationSlack(
36317
- options.channel
36318
- );
36324
+ const result = await new DeeplineClient().setNotificationSlack(target);
36319
36325
  printCommandEnvelope(
36320
36326
  {
36321
36327
  ok: true,
36322
36328
  result,
36323
36329
  render: {
36324
36330
  sections: [
36325
- { title: "Slack destination saved", lines: [options.channel] }
36331
+ {
36332
+ title: "Slack destination saved",
36333
+ lines: [options.memberId ?? options.channel]
36334
+ }
36326
36335
  ],
36327
36336
  actions: [
36328
36337
  {
@@ -36524,9 +36533,22 @@ function notificationByName(settings, reference) {
36524
36533
  function parseSlackTarget(value) {
36525
36534
  const match = /^slack:(.+)$/i.exec(value.trim());
36526
36535
  if (!match?.[1]) {
36527
- throw new Error("Use --to slack:#channel.");
36536
+ throw new Error(
36537
+ "Use --to slack:#channel or --to slack:member:U0123456789."
36538
+ );
36528
36539
  }
36529
- return match[1];
36540
+ const target = match[1].trim();
36541
+ const member = /^member:([UW][A-Z0-9]{8,})$/i.exec(target);
36542
+ if (member?.[1]) return { memberId: member[1].toUpperCase() };
36543
+ if (target.toLowerCase().startsWith("member:")) {
36544
+ throw new Error(
36545
+ "Slack member IDs must look like slack:member:U0123456789."
36546
+ );
36547
+ }
36548
+ return { channel: target };
36549
+ }
36550
+ function displaySlackTarget(target) {
36551
+ return `${target.kind === "member" ? "@" : "#"}${target.name}`;
36530
36552
  }
36531
36553
  function collectEvent(value, previous = []) {
36532
36554
  return [...previous, value];
@@ -36539,10 +36561,11 @@ Examples:
36539
36561
  deepline notifications events
36540
36562
  deepline notifications slack channels --search pipeline
36541
36563
  deepline notifications add pipeline-watchdog --to slack:#pipeline-alerts --for play.cron.failed
36564
+ deepline notifications add owner-alerts --to slack:member:U0123456789 --for play.cron.failed
36542
36565
  deepline notifications test pipeline-watchdog
36543
36566
 
36544
36567
  Slack connections are managed in Dashboard \u2192 Integrations. This command only
36545
- chooses the connected Slack channel and the events it receives.
36568
+ chooses the connected Slack channel or member and the events it receives.
36546
36569
  `
36547
36570
  );
36548
36571
  notifications.command("events").description("List the Play events available to a notification.").option("--json", "Emit JSON output").action(async (options) => {
@@ -36573,7 +36596,7 @@ chooses the connected Slack channel and the events it receives.
36573
36596
  id: rule.id,
36574
36597
  name: rule.name,
36575
36598
  enabled: rule.enabled,
36576
- target: `#${rule.target.name}`,
36599
+ target: displaySlackTarget(rule.target),
36577
36600
  eventTypes: rule.eventTypes
36578
36601
  })) : rules,
36579
36602
  count: rules.length,
@@ -36582,7 +36605,7 @@ chooses the connected Slack channel and the events it receives.
36582
36605
  {
36583
36606
  title: "notifications",
36584
36607
  lines: rules.length ? rules.map(
36585
- (rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 #${rule.target.name} (${rule.eventTypes.join(", ") || "no events"})`
36608
+ (rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 ${displaySlackTarget(rule.target)} (${rule.eventTypes.join(", ") || "no events"})`
36586
36609
  ) : [
36587
36610
  "None yet. Add one with deepline notifications add <name> --to slack:#channel --for play.cron.failed."
36588
36611
  ]
@@ -36602,7 +36625,7 @@ chooses the connected Slack channel and the events it receives.
36602
36625
  });
36603
36626
  notifications.command("add").argument("<name>", "Short stable name, for example pipeline-watchdog").requiredOption(
36604
36627
  "--to <target>",
36605
- "Target, for example slack:#pipeline-alerts"
36628
+ "Target, for example slack:#pipeline-alerts or slack:member:U0123456789"
36606
36629
  ).option(
36607
36630
  "--for <event>",
36608
36631
  "Event ID; repeat for more events. Run notifications events to list them",
@@ -36613,7 +36636,7 @@ chooses the connected Slack channel and the events it receives.
36613
36636
  if (!options.for.length) {
36614
36637
  throw new Error("Choose at least one event with --for <event>.");
36615
36638
  }
36616
- const channel = parseSlackTarget(options.to);
36639
+ const target = parseSlackTarget(options.to);
36617
36640
  if (options.dryRun) {
36618
36641
  printCommandEnvelope(
36619
36642
  { dryRun: true, name, target: options.to, eventTypes: options.for },
@@ -36624,7 +36647,7 @@ chooses the connected Slack channel and the events it receives.
36624
36647
  const result = await new DeeplineClient().createNotification({
36625
36648
  name,
36626
36649
  provider: "slack",
36627
- channel,
36650
+ ...target,
36628
36651
  eventTypes: options.for
36629
36652
  });
36630
36653
  printCommandEnvelope(
@@ -36644,7 +36667,10 @@ chooses the connected Slack channel and the events it receives.
36644
36667
  );
36645
36668
  }
36646
36669
  );
36647
- notifications.command("edit").argument("<name>", "Notification name or ID").option("--to <target>", "New target, for example slack:#pipeline-alerts").option(
36670
+ notifications.command("edit").argument("<name>", "Notification name or ID").option(
36671
+ "--to <target>",
36672
+ "New target, for example slack:#pipeline-alerts or slack:member:U0123456789"
36673
+ ).option(
36648
36674
  "--for <event>",
36649
36675
  "Replace selected events; repeat for more events. Run notifications events to list them",
36650
36676
  collectEvent,
@@ -36653,18 +36679,18 @@ chooses the connected Slack channel and the events it receives.
36653
36679
  async (name, options) => {
36654
36680
  const client2 = new DeeplineClient();
36655
36681
  const rule = notificationByName(await client2.getNotifications(), name);
36656
- const channel = options.to ? parseSlackTarget(options.to) : rule.target.name;
36682
+ const target = options.to ? parseSlackTarget(options.to) : rule.target.kind === "member" ? { memberId: rule.target.id } : { channel: rule.target.name };
36657
36683
  const eventTypes = options.for.length ? options.for : rule.eventTypes;
36658
36684
  if (options.dryRun) {
36659
36685
  printCommandEnvelope(
36660
- { dryRun: true, notification: rule.id, channel, eventTypes },
36686
+ { dryRun: true, notification: rule.id, target, eventTypes },
36661
36687
  { json: options.json }
36662
36688
  );
36663
36689
  return;
36664
36690
  }
36665
36691
  const result = await client2.updateNotification(rule.id, {
36666
36692
  name: rule.name,
36667
- channel,
36693
+ ...target,
36668
36694
  eventTypes
36669
36695
  });
36670
36696
  printCommandEnvelope({ notification: result }, { json: options.json });
package/dist/index.d.mts CHANGED
@@ -1243,6 +1243,7 @@ interface ProductNotification {
1243
1243
  target: {
1244
1244
  id: string;
1245
1245
  name: string;
1246
+ kind?: 'channel' | 'member';
1246
1247
  };
1247
1248
  enabled: boolean;
1248
1249
  status: string;
@@ -1894,6 +1895,24 @@ type EnrichCompiledConfig = {
1894
1895
  };
1895
1896
  };
1896
1897
 
1898
+ type SlackNotificationTarget = {
1899
+ channel: string;
1900
+ memberId?: never;
1901
+ } | {
1902
+ channel?: never;
1903
+ memberId: string;
1904
+ };
1905
+ type CreateNotificationInput = {
1906
+ name: string;
1907
+ provider: 'slack';
1908
+ eventTypes: string[];
1909
+ } & SlackNotificationTarget;
1910
+ type UpdateNotificationInput = {
1911
+ enabled: boolean;
1912
+ } | ({
1913
+ name: string;
1914
+ eventTypes: string[];
1915
+ } & SlackNotificationTarget);
1897
1916
  type IngestionStorageRepairResult = {
1898
1917
  status?: 'repaired';
1899
1918
  connection_grants: {
@@ -3364,8 +3383,10 @@ declare class DeeplineClient {
3364
3383
  isPrivate: boolean;
3365
3384
  }>;
3366
3385
  }>;
3367
- /** Select the Slack channel used for product notifications. */
3368
- setNotificationSlack(channel: string): Promise<unknown>;
3386
+ /** Select a Slack channel or direct member used for product notifications. */
3387
+ setNotificationSlack(destination: string | {
3388
+ memberId: string;
3389
+ }): Promise<unknown>;
3369
3390
  /** Send one synchronous test ping and return Slack's delivery result. */
3370
3391
  testNotificationSlack(): Promise<{
3371
3392
  ok: boolean;
@@ -3398,20 +3419,9 @@ declare class DeeplineClient {
3398
3419
  }>;
3399
3420
  }>;
3400
3421
  /** Create a named notification routed through an existing provider integration. */
3401
- createNotification(input: {
3402
- name: string;
3403
- provider: 'slack';
3404
- channel: string;
3405
- eventTypes: string[];
3406
- }): Promise<unknown>;
3422
+ createNotification(input: CreateNotificationInput): Promise<unknown>;
3407
3423
  /** Update a notification's target, event selection, or enabled state. */
3408
- updateNotification(notificationId: string, input: {
3409
- enabled: boolean;
3410
- } | {
3411
- name: string;
3412
- channel: string;
3413
- eventTypes: string[];
3414
- }): Promise<unknown>;
3424
+ updateNotification(notificationId: string, input: UpdateNotificationInput): Promise<unknown>;
3415
3425
  /** Send a validation ping to one notification. */
3416
3426
  testNotification(notificationId: string): Promise<{
3417
3427
  ok: boolean;
package/dist/index.d.ts CHANGED
@@ -1243,6 +1243,7 @@ interface ProductNotification {
1243
1243
  target: {
1244
1244
  id: string;
1245
1245
  name: string;
1246
+ kind?: 'channel' | 'member';
1246
1247
  };
1247
1248
  enabled: boolean;
1248
1249
  status: string;
@@ -1894,6 +1895,24 @@ type EnrichCompiledConfig = {
1894
1895
  };
1895
1896
  };
1896
1897
 
1898
+ type SlackNotificationTarget = {
1899
+ channel: string;
1900
+ memberId?: never;
1901
+ } | {
1902
+ channel?: never;
1903
+ memberId: string;
1904
+ };
1905
+ type CreateNotificationInput = {
1906
+ name: string;
1907
+ provider: 'slack';
1908
+ eventTypes: string[];
1909
+ } & SlackNotificationTarget;
1910
+ type UpdateNotificationInput = {
1911
+ enabled: boolean;
1912
+ } | ({
1913
+ name: string;
1914
+ eventTypes: string[];
1915
+ } & SlackNotificationTarget);
1897
1916
  type IngestionStorageRepairResult = {
1898
1917
  status?: 'repaired';
1899
1918
  connection_grants: {
@@ -3364,8 +3383,10 @@ declare class DeeplineClient {
3364
3383
  isPrivate: boolean;
3365
3384
  }>;
3366
3385
  }>;
3367
- /** Select the Slack channel used for product notifications. */
3368
- setNotificationSlack(channel: string): Promise<unknown>;
3386
+ /** Select a Slack channel or direct member used for product notifications. */
3387
+ setNotificationSlack(destination: string | {
3388
+ memberId: string;
3389
+ }): Promise<unknown>;
3369
3390
  /** Send one synchronous test ping and return Slack's delivery result. */
3370
3391
  testNotificationSlack(): Promise<{
3371
3392
  ok: boolean;
@@ -3398,20 +3419,9 @@ declare class DeeplineClient {
3398
3419
  }>;
3399
3420
  }>;
3400
3421
  /** Create a named notification routed through an existing provider integration. */
3401
- createNotification(input: {
3402
- name: string;
3403
- provider: 'slack';
3404
- channel: string;
3405
- eventTypes: string[];
3406
- }): Promise<unknown>;
3422
+ createNotification(input: CreateNotificationInput): Promise<unknown>;
3407
3423
  /** Update a notification's target, event selection, or enabled state. */
3408
- updateNotification(notificationId: string, input: {
3409
- enabled: boolean;
3410
- } | {
3411
- name: string;
3412
- channel: string;
3413
- eventTypes: string[];
3414
- }): Promise<unknown>;
3424
+ updateNotification(notificationId: string, input: UpdateNotificationInput): Promise<unknown>;
3415
3425
  /** Send a validation ping to one notification. */
3416
3426
  testNotification(notificationId: string): Promise<{
3417
3427
  ok: boolean;
package/dist/index.js CHANGED
@@ -783,7 +783,7 @@ var SDK_RELEASE = {
783
783
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
784
784
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
785
785
  // getters keep their established compatibility behavior.
786
- version: "0.3.14",
786
+ version: "0.3.15",
787
787
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
788
788
  contracts: {
789
789
  api: {
@@ -1643,7 +1643,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
1643
1643
  var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
1644
1644
  "channels:read",
1645
1645
  "chat:write",
1646
- "groups:read"
1646
+ "groups:read",
1647
+ "im:write"
1647
1648
  ];
1648
1649
  var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
1649
1650
  0,
@@ -5723,9 +5724,12 @@ var DeeplineClient = class {
5723
5724
  const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
5724
5725
  return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
5725
5726
  }
5726
- /** Select the Slack channel used for product notifications. */
5727
- async setNotificationSlack(channel) {
5728
- return this.http.put("/api/v2/settings/notifications", { channel });
5727
+ /** Select a Slack channel or direct member used for product notifications. */
5728
+ async setNotificationSlack(destination) {
5729
+ return this.http.put(
5730
+ "/api/v2/settings/notifications",
5731
+ typeof destination === "string" ? { channel: destination } : destination
5732
+ );
5729
5733
  }
5730
5734
  /** Send one synchronous test ping and return Slack's delivery result. */
5731
5735
  async testNotificationSlack() {
package/dist/index.mjs CHANGED
@@ -706,7 +706,7 @@ var SDK_RELEASE = {
706
706
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
707
707
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
708
708
  // getters keep their established compatibility behavior.
709
- version: "0.3.14",
709
+ version: "0.3.15",
710
710
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
711
711
  contracts: {
712
712
  api: {
@@ -1566,7 +1566,8 @@ var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
1566
1566
  var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
1567
1567
  "channels:read",
1568
1568
  "chat:write",
1569
- "groups:read"
1569
+ "groups:read",
1570
+ "im:write"
1570
1571
  ];
1571
1572
  var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
1572
1573
  0,
@@ -5646,9 +5647,12 @@ var DeeplineClient = class {
5646
5647
  const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
5647
5648
  return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
5648
5649
  }
5649
- /** Select the Slack channel used for product notifications. */
5650
- async setNotificationSlack(channel) {
5651
- return this.http.put("/api/v2/settings/notifications", { channel });
5650
+ /** Select a Slack channel or direct member used for product notifications. */
5651
+ async setNotificationSlack(destination) {
5652
+ return this.http.put(
5653
+ "/api/v2/settings/notifications",
5654
+ typeof destination === "string" ? { channel: destination } : destination
5655
+ );
5652
5656
  }
5653
5657
  /** Send one synchronous test ping and return Slack's delivery result. */
5654
5658
  async testNotificationSlack() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",