11import { readFileSync } from "node:fs"
2- import {
3- customerToolContracts ,
4- notificationProviderValues ,
5- notificationSeverityValues ,
6- } from "@outlit/tools"
2+ import { customerToolContracts , notificationSeverityValues } from "@outlit/tools"
73import { defineCommand } from "citty"
84import { authArgs } from "../args/auth"
95import { AGENT_JSON_HINT , outputArgs } from "../args/output"
106import { getClientOrExit , runTool } from "../lib/api"
117import { errorMessage , outputError } from "../lib/output"
128
139type NotificationSeverity = ( typeof notificationSeverityValues ) [ number ]
14- type NotificationProvider = ( typeof notificationProviderValues ) [ number ]
15- type NotificationDestination = {
16- provider : NotificationProvider
17- channelId ?: string
18- }
1910
20- const MAX_DESTINATION_COUNT = 10
21- const MAX_DESTINATION_CHANNEL_ID_LENGTH = 240
11+ const MAX_DESTINATION_ID_COUNT = 10
12+ const UUID_PATTERN = / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } $ / i
2213
2314function parsePayload ( raw : string ) : unknown {
2415 try {
@@ -56,40 +47,20 @@ function payloadSizeIsValid(payload: unknown): boolean {
5647 return typeof serialized === "string" && serialized . length <= 100000
5748}
5849
59- function parseDestinations ( raw : string | undefined ) : NotificationDestination [ ] | null | undefined {
50+ function parseDestinationIds ( raw : string | undefined ) : string [ ] | null | undefined {
6051 if ( raw === undefined ) {
6152 return undefined
6253 }
6354
64- const destinations = raw . split ( "," ) . map ( ( entry ) => entry . trim ( ) )
55+ const destinationIds = raw . split ( "," ) . map ( ( entry ) => entry . trim ( ) )
6556 if (
66- destinations . length > MAX_DESTINATION_COUNT ||
67- destinations . some ( ( entry ) => entry . length === 0 )
57+ destinationIds . length > MAX_DESTINATION_ID_COUNT ||
58+ destinationIds . some ( ( entry ) => entry . length === 0 || ! UUID_PATTERN . test ( entry ) )
6859 ) {
6960 return null
7061 }
7162
72- const parsed : NotificationDestination [ ] = [ ]
73- for ( const destination of destinations ) {
74- const [ providerInput , ...channelParts ] = destination . split ( ":" )
75- const provider = providerInput ?. trim ( ) . toLowerCase ( )
76- const channelId = channelParts . join ( ":" ) . trim ( )
77-
78- if ( ! notificationProviderValues . includes ( provider as NotificationProvider ) ) {
79- return null
80- }
81-
82- if ( channelId . length > MAX_DESTINATION_CHANNEL_ID_LENGTH ) {
83- return null
84- }
85-
86- parsed . push ( {
87- provider : provider as NotificationProvider ,
88- ...( channelId . length > 0 ? { channelId } : { } ) ,
89- } )
90- }
91-
92- return parsed
63+ return destinationIds
9364}
9465
9566export default defineCommand ( {
@@ -99,13 +70,13 @@ export default defineCommand({
9970 "Send a notification through Outlit to the organization's configured notifier." ,
10071 "" ,
10172 "Use --markdown or --markdown-file for the human-readable body; Outlit renders it for the destination platform." ,
102- "Add a JSON or raw payload when useful for structured context. When --destination is omitted, Outlit uses the default notifier." ,
73+ "Add a JSON or raw payload when useful for structured context. When --destination-id is omitted, Outlit uses the default notifier." ,
10374 "" ,
10475 "Examples:" ,
10576 " outlit notify --title 'Risk found' --markdown '**Risk found**\\n\\n- Customer: acme.com'" ,
10677 " outlit notify --title 'Risk found' '{\"customer\":\"acme.com\"}'" ,
10778 " outlit notify --title 'Risk found' --payload-file ./payload.json" ,
108- " outlit notify --title 'Escalation' --markdown '**Check this account**' --destination slack:C123 " ,
79+ " outlit notify --title 'Escalation' --markdown '**Check this account**' --destination-id 00000000-0000-4000-8000-000000000001 " ,
10980 " outlit notify --title 'Escalation' --severity HIGH --message 'Check this account' '{\"customer\":\"acme.com\"}'" ,
11081 "" ,
11182 AGENT_JSON_HINT ,
@@ -152,10 +123,10 @@ export default defineCommand({
152123 type : "string" ,
153124 description : "Optional subject line" ,
154125 } ,
155- destination : {
126+ " destination-id" : {
156127 type : "string" ,
157128 description :
158- "Optional comma-separated destinations in provider[:channelId] form. Supported provider: slack " ,
129+ "Optional comma-separated notification destination IDs. Omit to use the default notifier. " ,
159130 } ,
160131 } ,
161132 async run ( { args } ) {
@@ -250,11 +221,11 @@ export default defineCommand({
250221 severity = normalized
251222 }
252223
253- const destinations = parseDestinations ( args . destination )
254- if ( destinations === null ) {
224+ const destinationIds = parseDestinationIds ( args [ " destination-id" ] )
225+ if ( destinationIds === null ) {
255226 return outputError (
256227 {
257- message : ` --destination must use provider[:channelId] with provider one of: ${ notificationProviderValues . join ( ", " ) } ` ,
228+ message : " --destination-id must be one or more comma-separated UUIDs" ,
258229 code : "invalid_input" ,
259230 } ,
260231 json ,
@@ -329,8 +300,8 @@ export default defineCommand({
329300 params . subject = subject
330301 }
331302
332- if ( destinations !== undefined ) {
333- params . destinations = destinations
303+ if ( destinationIds !== undefined ) {
304+ params . destinationIds = destinationIds
334305 }
335306
336307 return runTool ( client , customerToolContracts . outlit_send_notification . toolName , params , json )
0 commit comments