deepline 0.2.39 → 0.2.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundling-sources/sdk/src/client.ts +141 -0
- package/dist/bundling-sources/sdk/src/http.ts +8 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +42 -0
- package/dist/bundling-sources/shared_libs/product-notifications/contract.ts +134 -0
- package/dist/cli/index.js +747 -1
- package/dist/cli/index.mjs +747 -1
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +148 -1
- package/dist/index.mjs +148 -1
- package/dist/install-integrity.json +1 -0
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1030,7 +1030,7 @@ var SDK_RELEASE = {
|
|
|
1030
1030
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1031
1031
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1032
1032
|
// release keeps lazy paging semantics independent of row residency.
|
|
1033
|
-
version: "0.2.
|
|
1033
|
+
version: "0.2.40",
|
|
1034
1034
|
contracts: {
|
|
1035
1035
|
api: {
|
|
1036
1036
|
name: "sdk-http-api",
|
|
@@ -1658,6 +1658,9 @@ var HttpClient = class {
|
|
|
1658
1658
|
headers
|
|
1659
1659
|
});
|
|
1660
1660
|
}
|
|
1661
|
+
async put(path, body, headers) {
|
|
1662
|
+
return this.request(path, { method: "PUT", body, headers });
|
|
1663
|
+
}
|
|
1661
1664
|
/**
|
|
1662
1665
|
* Send a DELETE request.
|
|
1663
1666
|
*
|
|
@@ -1808,6 +1811,61 @@ function withCoworkNetworkHint(message) {
|
|
|
1808
1811
|
${COWORK_NETWORK_HINT}`;
|
|
1809
1812
|
}
|
|
1810
1813
|
|
|
1814
|
+
// ../shared_libs/product-notifications/contract.ts
|
|
1815
|
+
var PRODUCT_NOTIFICATION_EVENT_CATALOG = [
|
|
1816
|
+
{
|
|
1817
|
+
id: "play.cron.succeeded",
|
|
1818
|
+
label: "Cron success",
|
|
1819
|
+
description: "A scheduled Play run completed successfully.",
|
|
1820
|
+
source: "cron",
|
|
1821
|
+
outcome: "succeeded",
|
|
1822
|
+
defaultEnabled: true
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
id: "play.cron.failed",
|
|
1826
|
+
label: "Cron failure",
|
|
1827
|
+
description: "A scheduled Play could not start or its run reached a failed terminal state.",
|
|
1828
|
+
source: "cron",
|
|
1829
|
+
outcome: "failed",
|
|
1830
|
+
defaultEnabled: true
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
id: "play.webhook.succeeded",
|
|
1834
|
+
label: "Webhook success",
|
|
1835
|
+
description: "An accepted webhook-triggered Play completed successfully.",
|
|
1836
|
+
source: "webhook",
|
|
1837
|
+
outcome: "succeeded",
|
|
1838
|
+
defaultEnabled: true
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
id: "play.webhook.failed",
|
|
1842
|
+
label: "Webhook failure",
|
|
1843
|
+
description: "An accepted webhook-triggered Play reached a failed terminal state.",
|
|
1844
|
+
source: "webhook",
|
|
1845
|
+
outcome: "failed",
|
|
1846
|
+
defaultEnabled: true
|
|
1847
|
+
}
|
|
1848
|
+
];
|
|
1849
|
+
var PRODUCT_NOTIFICATION_EVENT_TYPE_SET = new Set(
|
|
1850
|
+
PRODUCT_NOTIFICATION_EVENT_CATALOG.map((event) => event.id)
|
|
1851
|
+
);
|
|
1852
|
+
var PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES = [
|
|
1853
|
+
"channels:read",
|
|
1854
|
+
"chat:write",
|
|
1855
|
+
"groups:read"
|
|
1856
|
+
];
|
|
1857
|
+
var PRODUCT_NOTIFICATION_RETRY_DELAYS_MS = [
|
|
1858
|
+
0,
|
|
1859
|
+
6e4,
|
|
1860
|
+
5 * 6e4,
|
|
1861
|
+
15 * 6e4,
|
|
1862
|
+
60 * 6e4
|
|
1863
|
+
];
|
|
1864
|
+
var PRODUCT_NOTIFICATION_MAX_ATTEMPTS = PRODUCT_NOTIFICATION_RETRY_DELAYS_MS.length;
|
|
1865
|
+
var PRODUCT_NOTIFICATION_DELIVERY_LEASE_MS = 2 * 6e4;
|
|
1866
|
+
var PRODUCT_NOTIFICATION_SUCCESS_TTL_MS = 15 * 6e4;
|
|
1867
|
+
var PRODUCT_NOTIFICATION_FAILURE_TTL_MS = 24 * 60 * 6e4;
|
|
1868
|
+
|
|
1811
1869
|
// src/stream-reconnect.ts
|
|
1812
1870
|
var STREAM_RECONNECT_BASE_DELAY_MS = 500;
|
|
1813
1871
|
var STREAM_RECONNECT_MAX_DELAY_MS = 15e3;
|
|
@@ -5364,6 +5422,95 @@ var DeeplineClient = class {
|
|
|
5364
5422
|
);
|
|
5365
5423
|
return response.plays ?? [];
|
|
5366
5424
|
}
|
|
5425
|
+
/** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
|
|
5426
|
+
async getNotificationSettings() {
|
|
5427
|
+
return this.http.get("/api/v2/settings/notifications");
|
|
5428
|
+
}
|
|
5429
|
+
/** Start the Slack OAuth flow required by product notifications. */
|
|
5430
|
+
async connectNotificationSlack(options) {
|
|
5431
|
+
return this.http.post("/api/v2/integrations/connect", {
|
|
5432
|
+
provider: "slack",
|
|
5433
|
+
scopes: [...PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES],
|
|
5434
|
+
...options?.successUrl ? { success_url: options.successUrl } : {},
|
|
5435
|
+
...options?.failureUrl ? { failure_url: options.failureUrl } : {}
|
|
5436
|
+
});
|
|
5437
|
+
}
|
|
5438
|
+
/** List Slack channels visible to the connected Deepline Slack app. */
|
|
5439
|
+
async listNotificationSlackChannels(query) {
|
|
5440
|
+
const suffix = query ? `?query=${encodeURIComponent(query)}` : "";
|
|
5441
|
+
return this.http.get(`/api/v2/settings/notifications/channels${suffix}`);
|
|
5442
|
+
}
|
|
5443
|
+
/** Select the Slack channel used for product notifications. */
|
|
5444
|
+
async setNotificationSlack(channel) {
|
|
5445
|
+
return this.http.put("/api/v2/settings/notifications", { channel });
|
|
5446
|
+
}
|
|
5447
|
+
/** Send one synchronous test ping and return Slack's delivery result. */
|
|
5448
|
+
async testNotificationSlack() {
|
|
5449
|
+
return this.http.post("/api/v2/settings/notifications/test", {});
|
|
5450
|
+
}
|
|
5451
|
+
/** Disable Slack product notifications without deleting the OAuth connection. */
|
|
5452
|
+
async disableNotificationSlack() {
|
|
5453
|
+
return this.http.delete("/api/v2/settings/notifications");
|
|
5454
|
+
}
|
|
5455
|
+
/** Enable or disable event IDs from the server-provided notification catalog. */
|
|
5456
|
+
async setNotificationSubscriptions(eventTypes, enabled) {
|
|
5457
|
+
return this.http.patch("/api/v2/settings/notifications/subscriptions", {
|
|
5458
|
+
eventTypes,
|
|
5459
|
+
enabled
|
|
5460
|
+
});
|
|
5461
|
+
}
|
|
5462
|
+
/** List exhausted deliveries. Dead-lettered messages never replay automatically. */
|
|
5463
|
+
async listNotificationDlq(limit = 25) {
|
|
5464
|
+
return this.http.get(
|
|
5465
|
+
`/api/v2/settings/notifications/dlq?limit=${encodeURIComponent(String(limit))}`
|
|
5466
|
+
);
|
|
5467
|
+
}
|
|
5468
|
+
/** Inspect one exhausted notification delivery. */
|
|
5469
|
+
async getNotificationDlqDelivery(deliveryId) {
|
|
5470
|
+
return this.http.get(
|
|
5471
|
+
`/api/v2/settings/notifications/dlq/${encodeURIComponent(deliveryId)}`
|
|
5472
|
+
);
|
|
5473
|
+
}
|
|
5474
|
+
/** Explicitly retry or archive one dead-lettered notification delivery. */
|
|
5475
|
+
async updateNotificationDlqDelivery(deliveryId, action) {
|
|
5476
|
+
return this.http.post(
|
|
5477
|
+
`/api/v2/settings/notifications/dlq/${encodeURIComponent(deliveryId)}`,
|
|
5478
|
+
{ action }
|
|
5479
|
+
);
|
|
5480
|
+
}
|
|
5481
|
+
/** List the workspace's named notification rules. */
|
|
5482
|
+
async getNotifications() {
|
|
5483
|
+
return this.http.get("/api/v2/notifications");
|
|
5484
|
+
}
|
|
5485
|
+
/** List Slack channels available to an already-connected Slack integration. */
|
|
5486
|
+
async listNotificationChannels(query) {
|
|
5487
|
+
const suffix = query ? `?search=${encodeURIComponent(query)}` : "";
|
|
5488
|
+
return this.http.get(`/api/v2/notifications/slack/channels${suffix}`);
|
|
5489
|
+
}
|
|
5490
|
+
/** Create a named notification routed through an existing provider integration. */
|
|
5491
|
+
async createNotification(input2) {
|
|
5492
|
+
return this.http.post("/api/v2/notifications", input2);
|
|
5493
|
+
}
|
|
5494
|
+
/** Update a notification's target, event selection, or enabled state. */
|
|
5495
|
+
async updateNotification(notificationId, input2) {
|
|
5496
|
+
return this.http.patch(
|
|
5497
|
+
`/api/v2/notifications/${encodeURIComponent(notificationId)}`,
|
|
5498
|
+
input2
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
/** Send a validation ping to one notification. */
|
|
5502
|
+
async testNotification(notificationId) {
|
|
5503
|
+
return this.http.post(
|
|
5504
|
+
`/api/v2/notifications/${encodeURIComponent(notificationId)}/test`,
|
|
5505
|
+
{}
|
|
5506
|
+
);
|
|
5507
|
+
}
|
|
5508
|
+
/** Archive one notification without touching its provider integration. */
|
|
5509
|
+
async deleteNotification(notificationId) {
|
|
5510
|
+
return this.http.delete(
|
|
5511
|
+
`/api/v2/notifications/${encodeURIComponent(notificationId)}`
|
|
5512
|
+
);
|
|
5513
|
+
}
|
|
5367
5514
|
/**
|
|
5368
5515
|
* Search callable plays and return compact play descriptions.
|
|
5369
5516
|
*
|
|
@@ -22787,6 +22934,20 @@ async function handlePlayList(args) {
|
|
|
22787
22934
|
if (play.inputSchema || play.hasInputSchema) {
|
|
22788
22935
|
process.stdout.write(" inputSchema: yes\n");
|
|
22789
22936
|
}
|
|
22937
|
+
const configuredTriggers = [
|
|
22938
|
+
play.triggerStatus?.cron ? `cron=${play.triggerStatus.cron}` : null,
|
|
22939
|
+
play.triggerStatus?.webhook ? `webhook=${play.triggerStatus.webhook}` : null
|
|
22940
|
+
].filter(Boolean);
|
|
22941
|
+
if (configuredTriggers.length > 0) {
|
|
22942
|
+
process.stdout.write(` triggers: ${configuredTriggers.join(", ")}
|
|
22943
|
+
`);
|
|
22944
|
+
if (play.triggerStatus?.blockedReason) {
|
|
22945
|
+
process.stdout.write(
|
|
22946
|
+
` trigger issue: ${play.triggerStatus.blockedReason}
|
|
22947
|
+
`
|
|
22948
|
+
);
|
|
22949
|
+
}
|
|
22950
|
+
}
|
|
22790
22951
|
process.stdout.write(` run: deepline plays run ${reference} --watch
|
|
22791
22952
|
`);
|
|
22792
22953
|
}
|
|
@@ -36109,6 +36270,7 @@ var SDK_SIDECAR_CRITICAL_PACKAGE_FILES = [
|
|
|
36109
36270
|
"dist/bundling-sources/shared_libs/observability/telemetry.ts",
|
|
36110
36271
|
"dist/bundling-sources/shared_libs/play-runtime/backend.ts",
|
|
36111
36272
|
"dist/bundling-sources/shared_libs/plays/bundling/index.ts",
|
|
36273
|
+
"dist/bundling-sources/shared_libs/product-notifications/contract.ts",
|
|
36112
36274
|
"dist/bundling-sources/shared_libs/tool-execution-error.ts"
|
|
36113
36275
|
];
|
|
36114
36276
|
var SDK_SIDECAR_CRITICAL_DEPENDENCY_FILES = [
|
|
@@ -37974,6 +38136,588 @@ Examples:
|
|
|
37974
38136
|
});
|
|
37975
38137
|
}
|
|
37976
38138
|
|
|
38139
|
+
// src/cli/commands/settings.ts
|
|
38140
|
+
var eventHelp = PRODUCT_NOTIFICATION_EVENT_CATALOG.map(
|
|
38141
|
+
(event) => ` ${event.id.padEnd(28)} ${event.description}`
|
|
38142
|
+
).join("\n");
|
|
38143
|
+
function slackDestination(settings) {
|
|
38144
|
+
return settings.destinations.find((entry) => entry.kind === "slack");
|
|
38145
|
+
}
|
|
38146
|
+
function eventLines(settings) {
|
|
38147
|
+
const enabled = new Map(
|
|
38148
|
+
settings.subscriptions.map((entry) => [entry.eventType, entry.enabled])
|
|
38149
|
+
);
|
|
38150
|
+
return settings.catalog.map(
|
|
38151
|
+
(event) => `${event.id}: ${enabled.get(event.id) === true ? "enabled" : "disabled"} \u2014 ${event.description}`
|
|
38152
|
+
);
|
|
38153
|
+
}
|
|
38154
|
+
function requireCatalogEvent(settings, eventType) {
|
|
38155
|
+
const event = settings.catalog.find((entry) => entry.id === eventType);
|
|
38156
|
+
if (!event) {
|
|
38157
|
+
throw new Error(
|
|
38158
|
+
`Unknown notification event "${eventType}". Run deepline settings notifications subscriptions list.`
|
|
38159
|
+
);
|
|
38160
|
+
}
|
|
38161
|
+
return event;
|
|
38162
|
+
}
|
|
38163
|
+
async function printSettings(options) {
|
|
38164
|
+
const settings = await new DeeplineClient().getNotificationSettings();
|
|
38165
|
+
const slack = slackDestination(settings);
|
|
38166
|
+
printCommandEnvelope(
|
|
38167
|
+
{
|
|
38168
|
+
settings,
|
|
38169
|
+
render: {
|
|
38170
|
+
sections: [
|
|
38171
|
+
{
|
|
38172
|
+
title: "Slack destination",
|
|
38173
|
+
lines: slack ? [
|
|
38174
|
+
`status: ${String(slack.status ?? "unknown")}`,
|
|
38175
|
+
`channel: #${String(slack.channelName ?? slack.channelId ?? "unknown")}`,
|
|
38176
|
+
...slack.lastErrorMessage ? [`issue: ${String(slack.lastErrorMessage)}`] : []
|
|
38177
|
+
] : ["Not configured."]
|
|
38178
|
+
},
|
|
38179
|
+
{ title: "subscriptions", lines: eventLines(settings) },
|
|
38180
|
+
{
|
|
38181
|
+
title: "dead letter queue",
|
|
38182
|
+
lines: [
|
|
38183
|
+
`${settings.dlq.count}${settings.dlq.capped ? "+" : ""} deliveries require review`
|
|
38184
|
+
]
|
|
38185
|
+
}
|
|
38186
|
+
],
|
|
38187
|
+
actions: slack ? [
|
|
38188
|
+
{
|
|
38189
|
+
label: "Validate Slack",
|
|
38190
|
+
command: "deepline settings notifications test slack"
|
|
38191
|
+
}
|
|
38192
|
+
] : [
|
|
38193
|
+
{
|
|
38194
|
+
label: "Connect Slack",
|
|
38195
|
+
command: "deepline settings notifications connect slack --open"
|
|
38196
|
+
}
|
|
38197
|
+
]
|
|
38198
|
+
}
|
|
38199
|
+
},
|
|
38200
|
+
{ json: options.json }
|
|
38201
|
+
);
|
|
38202
|
+
}
|
|
38203
|
+
function registerSettingsCommands(program) {
|
|
38204
|
+
const settings = program.command("settings").description("Manage workspace product settings.");
|
|
38205
|
+
const notifications = settings.command("notifications").description(
|
|
38206
|
+
"Configure Deepline product notifications and delivery safety."
|
|
38207
|
+
).addHelpText(
|
|
38208
|
+
"after",
|
|
38209
|
+
`
|
|
38210
|
+
Workflow:
|
|
38211
|
+
1. deepline settings notifications connect slack --open
|
|
38212
|
+
2. deepline settings notifications channels --query pipeline
|
|
38213
|
+
3. deepline settings notifications set slack --channel '#pipeline-alerts'
|
|
38214
|
+
4. deepline settings notifications test slack
|
|
38215
|
+
5. deepline settings notifications subscriptions list
|
|
38216
|
+
|
|
38217
|
+
Slack is the delivery integration. This command group only manages product
|
|
38218
|
+
notifications; there is no general integrations CLI.
|
|
38219
|
+
`
|
|
38220
|
+
);
|
|
38221
|
+
notifications.command("get").description("Show destination, subscriptions, and DLQ health.").option("--json", "Emit JSON output").action(printSettings);
|
|
38222
|
+
notifications.command("connect").description("Start the OAuth connection required by a destination.").argument("<destination>", "Destination kind (currently slack)").option("--open", "Open the Slack authorization URL in a browser").option("--dry-run", "Describe the mutation without starting OAuth").option("--json", "Emit JSON output").action(
|
|
38223
|
+
async (destination, options) => {
|
|
38224
|
+
if (destination !== "slack")
|
|
38225
|
+
throw new Error("Only slack is supported.");
|
|
38226
|
+
if (options.dryRun) {
|
|
38227
|
+
printCommandEnvelope(
|
|
38228
|
+
{ dryRun: true, destination, action: "start_oauth" },
|
|
38229
|
+
{ json: options.json }
|
|
38230
|
+
);
|
|
38231
|
+
return;
|
|
38232
|
+
}
|
|
38233
|
+
const result = await new DeeplineClient().connectNotificationSlack();
|
|
38234
|
+
const browser = options.open ? openInBrowser(result.redirect_url, { deduplicate: false }) : "not_requested";
|
|
38235
|
+
printCommandEnvelope(
|
|
38236
|
+
{
|
|
38237
|
+
...result,
|
|
38238
|
+
browser,
|
|
38239
|
+
render: {
|
|
38240
|
+
sections: [
|
|
38241
|
+
{
|
|
38242
|
+
title: "Slack authorization",
|
|
38243
|
+
lines: [result.redirect_url, `browser: ${browser}`]
|
|
38244
|
+
}
|
|
38245
|
+
],
|
|
38246
|
+
actions: [
|
|
38247
|
+
{
|
|
38248
|
+
label: "After authorization",
|
|
38249
|
+
command: "deepline settings notifications set slack --channel '#channel'"
|
|
38250
|
+
}
|
|
38251
|
+
]
|
|
38252
|
+
}
|
|
38253
|
+
},
|
|
38254
|
+
{ json: options.json }
|
|
38255
|
+
);
|
|
38256
|
+
}
|
|
38257
|
+
);
|
|
38258
|
+
notifications.command("channels").description("List Slack channels visible to the connected Deepline app.").option("--query <text>", "Filter channels by name").option("--json", "Emit JSON output").action(async (options) => {
|
|
38259
|
+
const result = await new DeeplineClient().listNotificationSlackChannels(
|
|
38260
|
+
options.query
|
|
38261
|
+
);
|
|
38262
|
+
printCommandEnvelope(
|
|
38263
|
+
{
|
|
38264
|
+
...result,
|
|
38265
|
+
render: {
|
|
38266
|
+
sections: [
|
|
38267
|
+
{
|
|
38268
|
+
title: "Slack channels",
|
|
38269
|
+
lines: result.channels.length ? result.channels.map(
|
|
38270
|
+
(channel) => `#${channel.name} (${channel.id})${channel.isPrivate ? " private" : ""}`
|
|
38271
|
+
) : ["No visible channels matched."]
|
|
38272
|
+
}
|
|
38273
|
+
]
|
|
38274
|
+
}
|
|
38275
|
+
},
|
|
38276
|
+
{ json: options.json }
|
|
38277
|
+
);
|
|
38278
|
+
});
|
|
38279
|
+
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(
|
|
38280
|
+
async (destination, options) => {
|
|
38281
|
+
if (destination !== "slack")
|
|
38282
|
+
throw new Error("Only slack is supported.");
|
|
38283
|
+
if (options.dryRun) {
|
|
38284
|
+
printCommandEnvelope(
|
|
38285
|
+
{ dryRun: true, destination, channel: options.channel },
|
|
38286
|
+
{ json: options.json }
|
|
38287
|
+
);
|
|
38288
|
+
return;
|
|
38289
|
+
}
|
|
38290
|
+
const result = await new DeeplineClient().setNotificationSlack(
|
|
38291
|
+
options.channel
|
|
38292
|
+
);
|
|
38293
|
+
printCommandEnvelope(
|
|
38294
|
+
{
|
|
38295
|
+
ok: true,
|
|
38296
|
+
result,
|
|
38297
|
+
render: {
|
|
38298
|
+
sections: [
|
|
38299
|
+
{ title: "Slack destination saved", lines: [options.channel] }
|
|
38300
|
+
],
|
|
38301
|
+
actions: [
|
|
38302
|
+
{
|
|
38303
|
+
label: "Validate delivery",
|
|
38304
|
+
command: "deepline settings notifications test slack"
|
|
38305
|
+
}
|
|
38306
|
+
]
|
|
38307
|
+
}
|
|
38308
|
+
},
|
|
38309
|
+
{ json: options.json }
|
|
38310
|
+
);
|
|
38311
|
+
}
|
|
38312
|
+
);
|
|
38313
|
+
notifications.command("test").description("Send a validation ping to a destination.").argument("<destination>", "Destination kind (currently slack)").option("--dry-run", "Describe the external send without sending").option("--json", "Emit JSON output").action(async (destination, options) => {
|
|
38314
|
+
if (destination !== "slack") throw new Error("Only slack is supported.");
|
|
38315
|
+
if (options.dryRun) {
|
|
38316
|
+
printCommandEnvelope(
|
|
38317
|
+
{ dryRun: true, destination, action: "send_test_ping" },
|
|
38318
|
+
{ json: options.json }
|
|
38319
|
+
);
|
|
38320
|
+
return;
|
|
38321
|
+
}
|
|
38322
|
+
const result = await new DeeplineClient().testNotificationSlack();
|
|
38323
|
+
printCommandEnvelope(
|
|
38324
|
+
{
|
|
38325
|
+
...result,
|
|
38326
|
+
render: {
|
|
38327
|
+
sections: [{ title: "Slack validation", lines: [result.message] }]
|
|
38328
|
+
}
|
|
38329
|
+
},
|
|
38330
|
+
{ json: options.json }
|
|
38331
|
+
);
|
|
38332
|
+
});
|
|
38333
|
+
notifications.command("disable").description("Disable a product-notification destination.").argument("<destination>", "Destination kind (currently slack)").option("--dry-run", "Describe the mutation without changing settings").option("--json", "Emit JSON output").action(async (destination, options) => {
|
|
38334
|
+
if (destination !== "slack") throw new Error("Only slack is supported.");
|
|
38335
|
+
if (options.dryRun) {
|
|
38336
|
+
printCommandEnvelope(
|
|
38337
|
+
{ dryRun: true, destination, action: "disable" },
|
|
38338
|
+
{ json: options.json }
|
|
38339
|
+
);
|
|
38340
|
+
return;
|
|
38341
|
+
}
|
|
38342
|
+
const result = await new DeeplineClient().disableNotificationSlack();
|
|
38343
|
+
printCommandEnvelope(
|
|
38344
|
+
{
|
|
38345
|
+
ok: true,
|
|
38346
|
+
result,
|
|
38347
|
+
render: {
|
|
38348
|
+
sections: [{ title: "Slack destination", lines: ["disabled"] }]
|
|
38349
|
+
}
|
|
38350
|
+
},
|
|
38351
|
+
{ json: options.json }
|
|
38352
|
+
);
|
|
38353
|
+
});
|
|
38354
|
+
const subscriptions = notifications.command("subscriptions").description("List and configure supported notification events.").addHelpText(
|
|
38355
|
+
"after",
|
|
38356
|
+
`
|
|
38357
|
+
Supported events (shared product catalog):
|
|
38358
|
+
${eventHelp}
|
|
38359
|
+
`
|
|
38360
|
+
);
|
|
38361
|
+
subscriptions.command("list").description("List every supported event and its current state.").option("--json", "Emit JSON output").action(async (options) => {
|
|
38362
|
+
const current = await new DeeplineClient().getNotificationSettings();
|
|
38363
|
+
printCommandEnvelope(
|
|
38364
|
+
{
|
|
38365
|
+
catalog: current.catalog,
|
|
38366
|
+
subscriptions: current.subscriptions,
|
|
38367
|
+
render: {
|
|
38368
|
+
sections: [{ title: "subscriptions", lines: eventLines(current) }]
|
|
38369
|
+
}
|
|
38370
|
+
},
|
|
38371
|
+
{ json: options.json }
|
|
38372
|
+
);
|
|
38373
|
+
});
|
|
38374
|
+
subscriptions.command("describe").description("Describe one event from the shared product catalog.").argument("<event>", "Event ID; run subscriptions list to enumerate").option("--json", "Emit JSON output").action(async (eventType, options) => {
|
|
38375
|
+
const current = await new DeeplineClient().getNotificationSettings();
|
|
38376
|
+
const event = requireCatalogEvent(current, eventType);
|
|
38377
|
+
const subscription = current.subscriptions.find(
|
|
38378
|
+
(entry) => entry.eventType === event.id
|
|
38379
|
+
);
|
|
38380
|
+
printCommandEnvelope(
|
|
38381
|
+
{
|
|
38382
|
+
event,
|
|
38383
|
+
enabled: subscription?.enabled === true,
|
|
38384
|
+
render: {
|
|
38385
|
+
sections: [
|
|
38386
|
+
{
|
|
38387
|
+
title: event.id,
|
|
38388
|
+
lines: [
|
|
38389
|
+
event.description,
|
|
38390
|
+
`enabled: ${subscription?.enabled === true}`
|
|
38391
|
+
]
|
|
38392
|
+
}
|
|
38393
|
+
]
|
|
38394
|
+
}
|
|
38395
|
+
},
|
|
38396
|
+
{ json: options.json }
|
|
38397
|
+
);
|
|
38398
|
+
});
|
|
38399
|
+
for (const enabled of [true, false]) {
|
|
38400
|
+
subscriptions.command(enabled ? "enable" : "disable").description(`${enabled ? "Enable" : "Disable"} one supported event.`).argument("<event>", "Event ID; run subscriptions list to enumerate").option("--dry-run", "Validate intent without changing settings").option("--json", "Emit JSON output").action(async (eventType, options) => {
|
|
38401
|
+
const client2 = new DeeplineClient();
|
|
38402
|
+
const current = await client2.getNotificationSettings();
|
|
38403
|
+
const event = requireCatalogEvent(current, eventType);
|
|
38404
|
+
if (options.dryRun) {
|
|
38405
|
+
printCommandEnvelope(
|
|
38406
|
+
{ dryRun: true, event, enabled },
|
|
38407
|
+
{ json: options.json }
|
|
38408
|
+
);
|
|
38409
|
+
return;
|
|
38410
|
+
}
|
|
38411
|
+
const result = await client2.setNotificationSubscriptions(
|
|
38412
|
+
[event.id],
|
|
38413
|
+
enabled
|
|
38414
|
+
);
|
|
38415
|
+
printCommandEnvelope(
|
|
38416
|
+
{
|
|
38417
|
+
ok: true,
|
|
38418
|
+
event: event.id,
|
|
38419
|
+
enabled,
|
|
38420
|
+
result,
|
|
38421
|
+
render: {
|
|
38422
|
+
sections: [
|
|
38423
|
+
{
|
|
38424
|
+
title: "subscription updated",
|
|
38425
|
+
lines: [`${event.id}: ${enabled ? "enabled" : "disabled"}`]
|
|
38426
|
+
}
|
|
38427
|
+
]
|
|
38428
|
+
}
|
|
38429
|
+
},
|
|
38430
|
+
{ json: options.json }
|
|
38431
|
+
);
|
|
38432
|
+
});
|
|
38433
|
+
}
|
|
38434
|
+
const dlq = notifications.command("dlq").description("Inspect and explicitly resolve inert failed deliveries.");
|
|
38435
|
+
dlq.command("list").option("--limit <count>", "Maximum deliveries", "25").option("--json", "Emit JSON output").action(async (options) => {
|
|
38436
|
+
const result = await new DeeplineClient().listNotificationDlq(
|
|
38437
|
+
Number(options.limit)
|
|
38438
|
+
);
|
|
38439
|
+
const deliveries = result.deliveries ?? [];
|
|
38440
|
+
printCommandEnvelope(
|
|
38441
|
+
{
|
|
38442
|
+
...result,
|
|
38443
|
+
render: {
|
|
38444
|
+
sections: [
|
|
38445
|
+
{
|
|
38446
|
+
title: "dead letter queue",
|
|
38447
|
+
lines: deliveries.length ? deliveries.map(
|
|
38448
|
+
(entry) => `${String(entry._id)}: ${String(entry.lastErrorCode ?? "delivery_failed")}`
|
|
38449
|
+
) : ["empty"]
|
|
38450
|
+
}
|
|
38451
|
+
]
|
|
38452
|
+
}
|
|
38453
|
+
},
|
|
38454
|
+
{ json: options.json }
|
|
38455
|
+
);
|
|
38456
|
+
});
|
|
38457
|
+
dlq.command("get").argument("<delivery-id>").option("--json", "Emit JSON output").action(async (deliveryId, options) => {
|
|
38458
|
+
const result = await new DeeplineClient().getNotificationDlqDelivery(
|
|
38459
|
+
deliveryId
|
|
38460
|
+
);
|
|
38461
|
+
printCommandEnvelope(result, {
|
|
38462
|
+
json: options.json
|
|
38463
|
+
});
|
|
38464
|
+
});
|
|
38465
|
+
for (const action of ["retry", "archive"]) {
|
|
38466
|
+
dlq.command(action).description(
|
|
38467
|
+
`${action === "retry" ? "Replay once from attempt zero" : "Archive"} one delivery.`
|
|
38468
|
+
).argument("<delivery-id>").option("--dry-run", "Describe the mutation without changing state").option("--json", "Emit JSON output").action(async (deliveryId, options) => {
|
|
38469
|
+
if (options.dryRun) {
|
|
38470
|
+
printCommandEnvelope(
|
|
38471
|
+
{ dryRun: true, action, deliveryId },
|
|
38472
|
+
{ json: options.json }
|
|
38473
|
+
);
|
|
38474
|
+
return;
|
|
38475
|
+
}
|
|
38476
|
+
const result = await new DeeplineClient().updateNotificationDlqDelivery(
|
|
38477
|
+
deliveryId,
|
|
38478
|
+
action
|
|
38479
|
+
);
|
|
38480
|
+
printCommandEnvelope(
|
|
38481
|
+
{ ok: true, action, deliveryId, result },
|
|
38482
|
+
{ json: options.json }
|
|
38483
|
+
);
|
|
38484
|
+
});
|
|
38485
|
+
}
|
|
38486
|
+
}
|
|
38487
|
+
function notificationByName(settings, reference) {
|
|
38488
|
+
const notification = (settings.notifications ?? []).find(
|
|
38489
|
+
(entry) => entry.id === reference || entry.name === reference
|
|
38490
|
+
);
|
|
38491
|
+
if (!notification) {
|
|
38492
|
+
throw new Error(
|
|
38493
|
+
`No notification named "${reference}". Run deepline notifications list.`
|
|
38494
|
+
);
|
|
38495
|
+
}
|
|
38496
|
+
return notification;
|
|
38497
|
+
}
|
|
38498
|
+
function parseSlackTarget(value) {
|
|
38499
|
+
const match = /^slack:(.+)$/i.exec(value.trim());
|
|
38500
|
+
if (!match?.[1]) {
|
|
38501
|
+
throw new Error("Use --to slack:#channel.");
|
|
38502
|
+
}
|
|
38503
|
+
return match[1];
|
|
38504
|
+
}
|
|
38505
|
+
function collectEvent(value, previous = []) {
|
|
38506
|
+
return [...previous, value];
|
|
38507
|
+
}
|
|
38508
|
+
function registerNotificationCommands(program) {
|
|
38509
|
+
const notifications = program.command("notifications").description("Choose which Play outcomes notify which people and channels.").addHelpText(
|
|
38510
|
+
"after",
|
|
38511
|
+
`
|
|
38512
|
+
Examples:
|
|
38513
|
+
deepline notifications events
|
|
38514
|
+
deepline notifications slack channels --search pipeline
|
|
38515
|
+
deepline notifications add pipeline-watchdog --to slack:#pipeline-alerts --for play.cron.failed
|
|
38516
|
+
deepline notifications test pipeline-watchdog
|
|
38517
|
+
|
|
38518
|
+
Slack connections are managed in Dashboard \u2192 Integrations. This command only
|
|
38519
|
+
chooses the connected Slack channel and the events it receives.
|
|
38520
|
+
`
|
|
38521
|
+
);
|
|
38522
|
+
notifications.command("events").description("List the Play events available to a notification.").option("--json", "Emit JSON output").action(async (options) => {
|
|
38523
|
+
const settings = await new DeeplineClient().getNotifications();
|
|
38524
|
+
printCommandEnvelope(
|
|
38525
|
+
{
|
|
38526
|
+
events: settings.catalog,
|
|
38527
|
+
render: {
|
|
38528
|
+
sections: [
|
|
38529
|
+
{
|
|
38530
|
+
title: "available events",
|
|
38531
|
+
lines: settings.catalog.length ? settings.catalog.map(
|
|
38532
|
+
(event) => `${event.id}: ${event.description}`
|
|
38533
|
+
) : ["No notification events are available."]
|
|
38534
|
+
}
|
|
38535
|
+
]
|
|
38536
|
+
}
|
|
38537
|
+
},
|
|
38538
|
+
{ json: options.json }
|
|
38539
|
+
);
|
|
38540
|
+
});
|
|
38541
|
+
notifications.command("list").description("List named notifications and their selected Play events.").option("--json", "Emit JSON output").option("--compact", "Emit only names, state, target, and event IDs").action(async (options) => {
|
|
38542
|
+
const settings = await new DeeplineClient().getNotifications();
|
|
38543
|
+
const rules = settings.notifications ?? [];
|
|
38544
|
+
printCommandEnvelope(
|
|
38545
|
+
{
|
|
38546
|
+
notifications: options.compact ? rules.map((rule) => ({
|
|
38547
|
+
id: rule.id,
|
|
38548
|
+
name: rule.name,
|
|
38549
|
+
enabled: rule.enabled,
|
|
38550
|
+
target: `#${rule.target.name}`,
|
|
38551
|
+
eventTypes: rule.eventTypes
|
|
38552
|
+
})) : rules,
|
|
38553
|
+
count: rules.length,
|
|
38554
|
+
render: {
|
|
38555
|
+
sections: [
|
|
38556
|
+
{
|
|
38557
|
+
title: "notifications",
|
|
38558
|
+
lines: rules.length ? rules.map(
|
|
38559
|
+
(rule) => `${rule.name}: ${rule.enabled ? "on" : "paused"} \u2192 #${rule.target.name} (${rule.eventTypes.join(", ") || "no events"})`
|
|
38560
|
+
) : [
|
|
38561
|
+
"None yet. Add one with deepline notifications add <name> --to slack:#channel --for play.cron.failed."
|
|
38562
|
+
]
|
|
38563
|
+
}
|
|
38564
|
+
]
|
|
38565
|
+
}
|
|
38566
|
+
},
|
|
38567
|
+
{ json: options.json }
|
|
38568
|
+
);
|
|
38569
|
+
});
|
|
38570
|
+
notifications.command("get").argument("<name>", "Notification name or ID").description("Show one named notification.").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
38571
|
+
const rule = notificationByName(
|
|
38572
|
+
await new DeeplineClient().getNotifications(),
|
|
38573
|
+
name
|
|
38574
|
+
);
|
|
38575
|
+
printCommandEnvelope({ notification: rule }, { json: options.json });
|
|
38576
|
+
});
|
|
38577
|
+
notifications.command("add").argument("<name>", "Short stable name, for example pipeline-watchdog").requiredOption(
|
|
38578
|
+
"--to <target>",
|
|
38579
|
+
"Target, for example slack:#pipeline-alerts"
|
|
38580
|
+
).option(
|
|
38581
|
+
"--for <event>",
|
|
38582
|
+
"Event ID; repeat for more events. Run notifications events to list them",
|
|
38583
|
+
collectEvent,
|
|
38584
|
+
[]
|
|
38585
|
+
).option("--dry-run", "Describe the notification without saving it").option("--json", "Emit JSON output").action(
|
|
38586
|
+
async (name, options) => {
|
|
38587
|
+
if (!options.for.length) {
|
|
38588
|
+
throw new Error("Choose at least one event with --for <event>.");
|
|
38589
|
+
}
|
|
38590
|
+
const channel = parseSlackTarget(options.to);
|
|
38591
|
+
if (options.dryRun) {
|
|
38592
|
+
printCommandEnvelope(
|
|
38593
|
+
{ dryRun: true, name, target: options.to, eventTypes: options.for },
|
|
38594
|
+
{ json: options.json }
|
|
38595
|
+
);
|
|
38596
|
+
return;
|
|
38597
|
+
}
|
|
38598
|
+
const result = await new DeeplineClient().createNotification({
|
|
38599
|
+
name,
|
|
38600
|
+
provider: "slack",
|
|
38601
|
+
channel,
|
|
38602
|
+
eventTypes: options.for
|
|
38603
|
+
});
|
|
38604
|
+
printCommandEnvelope(
|
|
38605
|
+
{
|
|
38606
|
+
notification: result,
|
|
38607
|
+
render: {
|
|
38608
|
+
sections: [{ title: "notification saved", lines: [name] }],
|
|
38609
|
+
actions: [
|
|
38610
|
+
{
|
|
38611
|
+
label: "Send a test",
|
|
38612
|
+
command: `deepline notifications test ${name}`
|
|
38613
|
+
}
|
|
38614
|
+
]
|
|
38615
|
+
}
|
|
38616
|
+
},
|
|
38617
|
+
{ json: options.json }
|
|
38618
|
+
);
|
|
38619
|
+
}
|
|
38620
|
+
);
|
|
38621
|
+
notifications.command("edit").argument("<name>", "Notification name or ID").option("--to <target>", "New target, for example slack:#pipeline-alerts").option(
|
|
38622
|
+
"--for <event>",
|
|
38623
|
+
"Replace selected events; repeat for more events. Run notifications events to list them",
|
|
38624
|
+
collectEvent,
|
|
38625
|
+
[]
|
|
38626
|
+
).option("--dry-run", "Describe the change without saving it").option("--json", "Emit JSON output").action(
|
|
38627
|
+
async (name, options) => {
|
|
38628
|
+
const client2 = new DeeplineClient();
|
|
38629
|
+
const rule = notificationByName(await client2.getNotifications(), name);
|
|
38630
|
+
const channel = options.to ? parseSlackTarget(options.to) : rule.target.name;
|
|
38631
|
+
const eventTypes = options.for.length ? options.for : rule.eventTypes;
|
|
38632
|
+
if (options.dryRun) {
|
|
38633
|
+
printCommandEnvelope(
|
|
38634
|
+
{ dryRun: true, notification: rule.id, channel, eventTypes },
|
|
38635
|
+
{ json: options.json }
|
|
38636
|
+
);
|
|
38637
|
+
return;
|
|
38638
|
+
}
|
|
38639
|
+
const result = await client2.updateNotification(rule.id, {
|
|
38640
|
+
name: rule.name,
|
|
38641
|
+
channel,
|
|
38642
|
+
eventTypes
|
|
38643
|
+
});
|
|
38644
|
+
printCommandEnvelope({ notification: result }, { json: options.json });
|
|
38645
|
+
}
|
|
38646
|
+
);
|
|
38647
|
+
const slack = notifications.command("slack").description("Select a channel from the connected Slack integration.");
|
|
38648
|
+
slack.command("channels").option("--search <text>", "Filter channel names").option("--json", "Emit JSON output").action(async (options) => {
|
|
38649
|
+
const result = await new DeeplineClient().listNotificationChannels(
|
|
38650
|
+
options.search
|
|
38651
|
+
);
|
|
38652
|
+
printCommandEnvelope(
|
|
38653
|
+
{
|
|
38654
|
+
...result,
|
|
38655
|
+
render: {
|
|
38656
|
+
sections: [
|
|
38657
|
+
{
|
|
38658
|
+
title: "Slack channels",
|
|
38659
|
+
lines: result.channels.length ? result.channels.map((channel) => `#${channel.name}`) : ["No visible channels matched."]
|
|
38660
|
+
}
|
|
38661
|
+
]
|
|
38662
|
+
}
|
|
38663
|
+
},
|
|
38664
|
+
{ json: options.json }
|
|
38665
|
+
);
|
|
38666
|
+
});
|
|
38667
|
+
for (const [command, enabled] of [
|
|
38668
|
+
["pause", false],
|
|
38669
|
+
["resume", true]
|
|
38670
|
+
]) {
|
|
38671
|
+
notifications.command(command).argument("<name>", "Notification name or ID").option("--dry-run", "Describe the change without saving it").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
38672
|
+
const client2 = new DeeplineClient();
|
|
38673
|
+
const rule = notificationByName(await client2.getNotifications(), name);
|
|
38674
|
+
if (options.dryRun) {
|
|
38675
|
+
printCommandEnvelope(
|
|
38676
|
+
{ dryRun: true, notification: rule.id, enabled },
|
|
38677
|
+
{ json: options.json }
|
|
38678
|
+
);
|
|
38679
|
+
return;
|
|
38680
|
+
}
|
|
38681
|
+
const result = await client2.updateNotification(rule.id, { enabled });
|
|
38682
|
+
printCommandEnvelope({ notification: result }, { json: options.json });
|
|
38683
|
+
});
|
|
38684
|
+
}
|
|
38685
|
+
notifications.command("test").argument("<name>", "Notification name or ID").option("--dry-run", "Describe the external send without sending").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
38686
|
+
const client2 = new DeeplineClient();
|
|
38687
|
+
const rule = notificationByName(await client2.getNotifications(), name);
|
|
38688
|
+
if (options.dryRun) {
|
|
38689
|
+
printCommandEnvelope(
|
|
38690
|
+
{ dryRun: true, notification: rule.id, action: "send_test" },
|
|
38691
|
+
{ json: options.json }
|
|
38692
|
+
);
|
|
38693
|
+
return;
|
|
38694
|
+
}
|
|
38695
|
+
const result = await client2.testNotification(rule.id);
|
|
38696
|
+
printCommandEnvelope(
|
|
38697
|
+
{ ...result, notification: rule.name },
|
|
38698
|
+
{ json: options.json }
|
|
38699
|
+
);
|
|
38700
|
+
});
|
|
38701
|
+
notifications.command("delete").argument("<name>", "Notification name or ID").description(
|
|
38702
|
+
"Archive one notification without touching its provider integration."
|
|
38703
|
+
).option("--dry-run", "Describe the deletion without changing state").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
38704
|
+
const client2 = new DeeplineClient();
|
|
38705
|
+
const rule = notificationByName(await client2.getNotifications(), name);
|
|
38706
|
+
if (options.dryRun) {
|
|
38707
|
+
printCommandEnvelope(
|
|
38708
|
+
{ dryRun: true, notification: rule.id, action: "archive" },
|
|
38709
|
+
{ json: options.json }
|
|
38710
|
+
);
|
|
38711
|
+
return;
|
|
38712
|
+
}
|
|
38713
|
+
const result = await client2.deleteNotification(rule.id);
|
|
38714
|
+
printCommandEnvelope(
|
|
38715
|
+
{ ...result, notification: rule.name },
|
|
38716
|
+
{ json: options.json }
|
|
38717
|
+
);
|
|
38718
|
+
});
|
|
38719
|
+
}
|
|
38720
|
+
|
|
37977
38721
|
// ../shared_libs/cli/command-compatibility.json
|
|
37978
38722
|
var command_compatibility_default = {
|
|
37979
38723
|
enrich: {
|
|
@@ -39116,6 +39860,8 @@ Exit codes:
|
|
|
39116
39860
|
registerSessionsCommands(program);
|
|
39117
39861
|
registerWorkflowCommands(program);
|
|
39118
39862
|
registerSecretsCommands(program);
|
|
39863
|
+
registerSettingsCommands(program);
|
|
39864
|
+
registerNotificationCommands(program);
|
|
39119
39865
|
registerBillingCommands(program);
|
|
39120
39866
|
registerMonitorsCommands(program);
|
|
39121
39867
|
registerOrgCommands(program);
|