@kyoji2/intercom-cli 0.1.0 → 0.1.6

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/src/client.ts CHANGED
@@ -47,6 +47,8 @@ function createDryRunProxy(client: IntercomClient, logger: Logger): IntercomClie
47
47
  "away",
48
48
  "tag",
49
49
  "untag",
50
+ "reply",
51
+ "manage",
50
52
  ];
51
53
 
52
54
  const createNestedProxy = <T extends object>(target: T, path: string[]): T => {
@@ -107,6 +109,14 @@ function getDryRunResponse(method: string): unknown {
107
109
  }
108
110
 
109
111
  export function handleIntercomError(error: unknown): never {
112
+ if (error instanceof SyntaxError) {
113
+ throw new CLIError(
114
+ "Invalid JSON input provided to command.",
115
+ 400,
116
+ "Ensure your JSON data is valid and properly escaped for the shell.",
117
+ );
118
+ }
119
+
110
120
  if (error instanceof IntercomError) {
111
121
  let hint: string | undefined;
112
122
  if (error.statusCode === 401) {
@@ -7,7 +7,7 @@ export interface AdminGetOptions extends GlobalOptions {
7
7
  }
8
8
 
9
9
  export async function cmdAdminList(options: GlobalOptions): Promise<void> {
10
- const token = await getTokenAsync();
10
+ const token = await getTokenAsync(options.configDir);
11
11
  if (!token) {
12
12
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
13
13
  }
@@ -40,7 +40,7 @@ export async function cmdAdminList(options: GlobalOptions): Promise<void> {
40
40
  }
41
41
 
42
42
  export async function cmdAdminGet(options: AdminGetOptions): Promise<void> {
43
- const token = await getTokenAsync();
43
+ const token = await getTokenAsync(options.configDir);
44
44
  if (!token) {
45
45
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
46
46
  }
@@ -34,8 +34,8 @@ export interface ArticleDeleteOptions extends GlobalOptions {
34
34
  id: string;
35
35
  }
36
36
 
37
- async function requireToken(): Promise<string> {
38
- const token = await getTokenAsync();
37
+ async function requireToken(configDir: string): Promise<string> {
38
+ const token = await getTokenAsync(configDir);
39
39
  if (!token) {
40
40
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
41
41
  }
@@ -43,7 +43,7 @@ async function requireToken(): Promise<string> {
43
43
  }
44
44
 
45
45
  export async function cmdArticleList(options: ArticleListOptions): Promise<void> {
46
- const token = await requireToken();
46
+ const token = await requireToken(options.configDir);
47
47
  const spinner = ora("Listing articles...").start();
48
48
 
49
49
  try {
@@ -76,7 +76,7 @@ export async function cmdArticleList(options: ArticleListOptions): Promise<void>
76
76
  }
77
77
 
78
78
  export async function cmdArticleGet(options: ArticleGetOptions): Promise<void> {
79
- const token = await requireToken();
79
+ const token = await requireToken(options.configDir);
80
80
  const spinner = ora("Fetching article...").start();
81
81
 
82
82
  try {
@@ -109,7 +109,7 @@ export async function cmdArticleGet(options: ArticleGetOptions): Promise<void> {
109
109
  }
110
110
 
111
111
  export async function cmdArticleSearch(options: ArticleSearchOptions): Promise<void> {
112
- const token = await requireToken();
112
+ const token = await requireToken(options.configDir);
113
113
  const spinner = ora("Searching articles...").start();
114
114
 
115
115
  try {
@@ -146,7 +146,7 @@ export async function cmdArticleSearch(options: ArticleSearchOptions): Promise<v
146
146
  }
147
147
 
148
148
  export async function cmdArticleCreate(options: ArticleCreateOptions): Promise<void> {
149
- const token = await requireToken();
149
+ const token = await requireToken(options.configDir);
150
150
  const spinner = ora("Creating article...").start();
151
151
 
152
152
  try {
@@ -184,7 +184,7 @@ export async function cmdArticleCreate(options: ArticleCreateOptions): Promise<v
184
184
  }
185
185
 
186
186
  export async function cmdArticleUpdate(options: ArticleUpdateOptions): Promise<void> {
187
- const token = await requireToken();
187
+ const token = await requireToken(options.configDir);
188
188
  const spinner = ora("Updating article...").start();
189
189
 
190
190
  try {
@@ -212,7 +212,7 @@ export async function cmdArticleUpdate(options: ArticleUpdateOptions): Promise<v
212
212
  }
213
213
 
214
214
  export async function cmdArticleDelete(options: ArticleDeleteOptions): Promise<void> {
215
- const token = await requireToken();
215
+ const token = await requireToken(options.configDir);
216
216
  const spinner = ora("Deleting article...").start();
217
217
 
218
218
  try {
@@ -43,7 +43,7 @@ export async function cmdLogin(options: LoginOptions): Promise<void> {
43
43
  throw new CLIError("Could not verify token", 401, "The token may be invalid or expired.");
44
44
  }
45
45
 
46
- await saveConfig({ token });
46
+ await saveConfig(options.configDir, { token });
47
47
  spinner.succeed("Logged in successfully");
48
48
 
49
49
  output(
@@ -65,12 +65,12 @@ export async function cmdLogin(options: LoginOptions): Promise<void> {
65
65
  }
66
66
 
67
67
  export async function cmdLogout(options: GlobalOptions): Promise<void> {
68
- await deleteConfig();
68
+ await deleteConfig(options.configDir);
69
69
  output({ status: "success", message: "Logged out successfully" }, options.format);
70
70
  }
71
71
 
72
72
  export async function cmdWhoami(options: GlobalOptions): Promise<void> {
73
- const token = await getTokenAsync();
73
+ const token = await getTokenAsync(options.configDir);
74
74
  if (!token) {
75
75
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
76
76
  }
@@ -24,8 +24,8 @@ export interface CompanyUpdateOptions extends GlobalOptions {
24
24
  json: string;
25
25
  }
26
26
 
27
- async function requireToken(): Promise<string> {
28
- const token = await getTokenAsync();
27
+ async function requireToken(configDir: string): Promise<string> {
28
+ const token = await getTokenAsync(configDir);
29
29
  if (!token) {
30
30
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
31
31
  }
@@ -33,7 +33,7 @@ async function requireToken(): Promise<string> {
33
33
  }
34
34
 
35
35
  export async function cmdCompanyCreate(options: CompanyCreateOptions): Promise<void> {
36
- const token = await requireToken();
36
+ const token = await requireToken(options.configDir);
37
37
  const spinner = ora("Creating company...").start();
38
38
 
39
39
  try {
@@ -78,7 +78,7 @@ export async function cmdCompanyCreate(options: CompanyCreateOptions): Promise<v
78
78
  }
79
79
 
80
80
  export async function cmdCompanyGet(options: CompanyGetOptions): Promise<void> {
81
- const token = await requireToken();
81
+ const token = await requireToken(options.configDir);
82
82
  const spinner = ora("Fetching company...").start();
83
83
 
84
84
  try {
@@ -114,7 +114,7 @@ export async function cmdCompanyGet(options: CompanyGetOptions): Promise<void> {
114
114
  }
115
115
 
116
116
  export async function cmdCompanyList(options: CompanyListOptions): Promise<void> {
117
- const token = await requireToken();
117
+ const token = await requireToken(options.configDir);
118
118
  const spinner = ora("Listing companies...").start();
119
119
 
120
120
  try {
@@ -147,7 +147,7 @@ export async function cmdCompanyList(options: CompanyListOptions): Promise<void>
147
147
  }
148
148
 
149
149
  export async function cmdCompanyUpdate(options: CompanyUpdateOptions): Promise<void> {
150
- const token = await requireToken();
150
+ const token = await requireToken(options.configDir);
151
151
  const spinner = ora("Updating company...").start();
152
152
 
153
153
  try {
@@ -55,8 +55,8 @@ export interface ContactAttachCompanyOptions extends GlobalOptions {
55
55
  companyId: string;
56
56
  }
57
57
 
58
- async function requireToken(): Promise<string> {
59
- const token = await getTokenAsync();
58
+ async function requireToken(configDir: string): Promise<string> {
59
+ const token = await getTokenAsync(configDir);
60
60
  if (!token) {
61
61
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
62
62
  }
@@ -64,7 +64,7 @@ async function requireToken(): Promise<string> {
64
64
  }
65
65
 
66
66
  export async function cmdContactCreate(options: ContactCreateOptions): Promise<void> {
67
- const token = await requireToken();
67
+ const token = await requireToken(options.configDir);
68
68
  const spinner = ora("Creating contact...").start();
69
69
 
70
70
  try {
@@ -105,7 +105,7 @@ export async function cmdContactCreate(options: ContactCreateOptions): Promise<v
105
105
  }
106
106
 
107
107
  export async function cmdContactGet(options: ContactGetOptions): Promise<void> {
108
- const token = await requireToken();
108
+ const token = await requireToken(options.configDir);
109
109
  const spinner = ora("Fetching contact...").start();
110
110
 
111
111
  try {
@@ -141,7 +141,7 @@ export async function cmdContactGet(options: ContactGetOptions): Promise<void> {
141
141
  }
142
142
 
143
143
  export async function cmdContactUpdate(options: ContactUpdateOptions): Promise<void> {
144
- const token = await requireToken();
144
+ const token = await requireToken(options.configDir);
145
145
  const spinner = ora("Updating contact...").start();
146
146
 
147
147
  try {
@@ -179,7 +179,7 @@ export async function cmdContactUpdate(options: ContactUpdateOptions): Promise<v
179
179
  }
180
180
 
181
181
  export async function cmdContactDelete(options: ContactDeleteOptions): Promise<void> {
182
- const token = await requireToken();
182
+ const token = await requireToken(options.configDir);
183
183
  const spinner = ora("Deleting contact...").start();
184
184
 
185
185
  try {
@@ -196,7 +196,7 @@ export async function cmdContactDelete(options: ContactDeleteOptions): Promise<v
196
196
  }
197
197
 
198
198
  export async function cmdContactSearch(options: ContactSearchOptions): Promise<void> {
199
- const token = await requireToken();
199
+ const token = await requireToken(options.configDir);
200
200
  const spinner = ora("Searching contacts...").start();
201
201
 
202
202
  try {
@@ -246,7 +246,7 @@ export async function cmdContactSearch(options: ContactSearchOptions): Promise<v
246
246
  }
247
247
 
248
248
  export async function cmdContactList(options: ContactListOptions): Promise<void> {
249
- const token = await requireToken();
249
+ const token = await requireToken(options.configDir);
250
250
  const spinner = ora("Listing contacts...").start();
251
251
 
252
252
  try {
@@ -277,7 +277,7 @@ export async function cmdContactList(options: ContactListOptions): Promise<void>
277
277
  }
278
278
 
279
279
  export async function cmdContactNote(options: ContactNoteOptions): Promise<void> {
280
- const token = await requireToken();
280
+ const token = await requireToken(options.configDir);
281
281
  const spinner = ora("Adding note...").start();
282
282
 
283
283
  try {
@@ -305,7 +305,7 @@ export async function cmdContactNote(options: ContactNoteOptions): Promise<void>
305
305
  }
306
306
 
307
307
  export async function cmdContactNotes(options: ContactNotesListOptions): Promise<void> {
308
- const token = await requireToken();
308
+ const token = await requireToken(options.configDir);
309
309
  const spinner = ora("Fetching notes...").start();
310
310
 
311
311
  try {
@@ -332,7 +332,7 @@ export async function cmdContactNotes(options: ContactNotesListOptions): Promise
332
332
  }
333
333
 
334
334
  export async function cmdContactTag(options: ContactTagOptions): Promise<void> {
335
- const token = await requireToken();
335
+ const token = await requireToken(options.configDir);
336
336
  const spinner = ora("Tagging contact...").start();
337
337
 
338
338
  try {
@@ -358,7 +358,7 @@ export async function cmdContactTag(options: ContactTagOptions): Promise<void> {
358
358
  }
359
359
 
360
360
  export async function cmdContactUntag(options: ContactTagOptions): Promise<void> {
361
- const token = await requireToken();
361
+ const token = await requireToken(options.configDir);
362
362
  const spinner = ora("Removing tag...").start();
363
363
 
364
364
  try {
@@ -384,7 +384,7 @@ export async function cmdContactUntag(options: ContactTagOptions): Promise<void>
384
384
  }
385
385
 
386
386
  export async function cmdContactAttachCompany(options: ContactAttachCompanyOptions): Promise<void> {
387
- const token = await requireToken();
387
+ const token = await requireToken(options.configDir);
388
388
  const spinner = ora("Attaching company...").start();
389
389
 
390
390
  try {
@@ -1,6 +1,7 @@
1
1
  import ora from "ora";
2
2
  import { createClient, handleIntercomError } from "../client.ts";
3
3
  import { CLIError, type GlobalOptions, getTokenAsync, output } from "../utils/index.ts";
4
+ import { buildAdminReplyPayload } from "./replyPayload.ts";
4
5
 
5
6
  export interface ConversationListOptions extends GlobalOptions {
6
7
  limit?: string;
@@ -21,6 +22,7 @@ export interface ConversationReplyOptions extends GlobalOptions {
21
22
  id: string;
22
23
  adminId: string;
23
24
  body: string;
25
+ messageType?: string;
24
26
  json?: string;
25
27
  }
26
28
 
@@ -46,8 +48,16 @@ export interface ConversationSnoozeOptions extends GlobalOptions {
46
48
  until: string;
47
49
  }
48
50
 
49
- async function requireToken(): Promise<string> {
50
- const token = await getTokenAsync();
51
+ export interface ConversationConvertOptions extends GlobalOptions {
52
+ id: string;
53
+ ticketTypeId: string;
54
+ title?: string;
55
+ description?: string;
56
+ json?: string;
57
+ }
58
+
59
+ async function requireToken(configDir: string): Promise<string> {
60
+ const token = await getTokenAsync(configDir);
51
61
  if (!token) {
52
62
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
53
63
  }
@@ -55,7 +65,7 @@ async function requireToken(): Promise<string> {
55
65
  }
56
66
 
57
67
  export async function cmdConversationList(options: ConversationListOptions): Promise<void> {
58
- const token = await requireToken();
68
+ const token = await requireToken(options.configDir);
59
69
  const spinner = ora("Listing conversations...").start();
60
70
 
61
71
  try {
@@ -91,7 +101,7 @@ export async function cmdConversationList(options: ConversationListOptions): Pro
91
101
  }
92
102
 
93
103
  export async function cmdConversationGet(options: ConversationGetOptions): Promise<void> {
94
- const token = await requireToken();
104
+ const token = await requireToken(options.configDir);
95
105
  const spinner = ora("Fetching conversation...").start();
96
106
 
97
107
  try {
@@ -132,7 +142,7 @@ export async function cmdConversationGet(options: ConversationGetOptions): Promi
132
142
  }
133
143
 
134
144
  export async function cmdConversationSearch(options: ConversationSearchOptions): Promise<void> {
135
- const token = await requireToken();
145
+ const token = await requireToken(options.configDir);
136
146
  const spinner = ora("Searching conversations...").start();
137
147
 
138
148
  try {
@@ -192,7 +202,7 @@ export async function cmdConversationSearch(options: ConversationSearchOptions):
192
202
  }
193
203
 
194
204
  export async function cmdConversationReply(options: ConversationReplyOptions): Promise<void> {
195
- const token = await requireToken();
205
+ const token = await requireToken(options.configDir);
196
206
  const spinner = ora("Sending reply...").start();
197
207
 
198
208
  try {
@@ -200,12 +210,12 @@ export async function cmdConversationReply(options: ConversationReplyOptions): P
200
210
 
201
211
  const result = await client.conversations.reply({
202
212
  conversation_id: options.id,
203
- body: {
204
- message_type: "comment",
205
- type: "admin",
206
- admin_id: options.adminId,
213
+ body: buildAdminReplyPayload({
214
+ adminId: options.adminId,
207
215
  body: options.body,
208
- },
216
+ messageType: options.messageType,
217
+ json: options.json,
218
+ }),
209
219
  });
210
220
 
211
221
  spinner.succeed("Reply sent");
@@ -225,7 +235,7 @@ export async function cmdConversationReply(options: ConversationReplyOptions): P
225
235
  }
226
236
 
227
237
  export async function cmdConversationAssign(options: ConversationAssignOptions): Promise<void> {
228
- const token = await requireToken();
238
+ const token = await requireToken(options.configDir);
229
239
  const spinner = ora("Assigning conversation...").start();
230
240
 
231
241
  try {
@@ -257,7 +267,7 @@ export async function cmdConversationAssign(options: ConversationAssignOptions):
257
267
  }
258
268
 
259
269
  export async function cmdConversationClose(options: ConversationCloseOptions): Promise<void> {
260
- const token = await requireToken();
270
+ const token = await requireToken(options.configDir);
261
271
  const spinner = ora("Closing conversation...").start();
262
272
 
263
273
  try {
@@ -288,7 +298,7 @@ export async function cmdConversationClose(options: ConversationCloseOptions): P
288
298
  }
289
299
 
290
300
  export async function cmdConversationOpen(options: ConversationOpenOptions): Promise<void> {
291
- const token = await requireToken();
301
+ const token = await requireToken(options.configDir);
292
302
  const spinner = ora("Opening conversation...").start();
293
303
 
294
304
  try {
@@ -318,7 +328,7 @@ export async function cmdConversationOpen(options: ConversationOpenOptions): Pro
318
328
  }
319
329
 
320
330
  export async function cmdConversationSnooze(options: ConversationSnoozeOptions): Promise<void> {
321
- const token = await requireToken();
331
+ const token = await requireToken(options.configDir);
322
332
  const spinner = ora("Snoozing conversation...").start();
323
333
 
324
334
  try {
@@ -348,3 +358,50 @@ export async function cmdConversationSnooze(options: ConversationSnoozeOptions):
348
358
  handleIntercomError(error);
349
359
  }
350
360
  }
361
+
362
+ export async function cmdConversationConvert(options: ConversationConvertOptions): Promise<void> {
363
+ const token = await requireToken(options.configDir);
364
+ const spinner = ora("Converting conversation to ticket...").start();
365
+
366
+ try {
367
+ const client = createClient({ token, dryRun: options.dryRun });
368
+
369
+ let attributes: Record<string, unknown> | undefined;
370
+ if (options.json) {
371
+ attributes = JSON.parse(options.json);
372
+ } else if (options.title || options.description) {
373
+ attributes = {};
374
+ if (options.title) {
375
+ attributes._default_title_ = options.title;
376
+ }
377
+ if (options.description) {
378
+ attributes._default_description_ = options.description;
379
+ }
380
+ }
381
+
382
+ const ticket = await client.conversations.convertToTicket({
383
+ conversation_id: Number.parseInt(options.id, 10),
384
+ ticket_type_id: options.ticketTypeId,
385
+ attributes,
386
+ });
387
+
388
+ spinner.succeed("Conversation converted to ticket");
389
+
390
+ output(
391
+ {
392
+ id: ticket?.id,
393
+ ticket_id: ticket?.ticket_id,
394
+ category: ticket?.category,
395
+ ticket_type: ticket?.ticket_type,
396
+ ticket_state: ticket?.ticket_state,
397
+ ticket_attributes: ticket?.ticket_attributes,
398
+ open: ticket?.open,
399
+ created_at: ticket?.created_at,
400
+ },
401
+ options.format,
402
+ );
403
+ } catch (error) {
404
+ spinner.fail("Failed to convert conversation to ticket");
405
+ handleIntercomError(error);
406
+ }
407
+ }
@@ -13,8 +13,8 @@ export interface EventListOptions extends GlobalOptions {
13
13
  userId: string;
14
14
  }
15
15
 
16
- async function requireToken(): Promise<string> {
17
- const token = await getTokenAsync();
16
+ async function requireToken(configDir: string): Promise<string> {
17
+ const token = await getTokenAsync(configDir);
18
18
  if (!token) {
19
19
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
20
20
  }
@@ -22,7 +22,7 @@ async function requireToken(): Promise<string> {
22
22
  }
23
23
 
24
24
  export async function cmdEventTrack(options: EventTrackOptions): Promise<void> {
25
- const token = await requireToken();
25
+ const token = await requireToken(options.configDir);
26
26
  const spinner = ora("Tracking event...").start();
27
27
 
28
28
  try {
@@ -61,7 +61,7 @@ export async function cmdEventTrack(options: EventTrackOptions): Promise<void> {
61
61
  }
62
62
 
63
63
  export async function cmdEventList(options: EventListOptions): Promise<void> {
64
- const token = await requireToken();
64
+ const token = await requireToken(options.configDir);
65
65
  const spinner = ora("Fetching events...").start();
66
66
 
67
67
  try {
@@ -1,7 +1,4 @@
1
- // Auth commands
2
-
3
1
  export type { AdminGetOptions } from "./admins.ts";
4
- // Admin commands
5
2
  export { cmdAdminGet, cmdAdminList } from "./admins.ts";
6
3
  export type {
7
4
  ArticleCreateOptions,
@@ -11,7 +8,6 @@ export type {
11
8
  ArticleSearchOptions,
12
9
  ArticleUpdateOptions,
13
10
  } from "./articles.ts";
14
- // Article commands
15
11
  export {
16
12
  cmdArticleCreate,
17
13
  cmdArticleDelete,
@@ -23,7 +19,6 @@ export {
23
19
  export type { LoginOptions } from "./auth.ts";
24
20
  export { cmdLogin, cmdLogout, cmdWhoami } from "./auth.ts";
25
21
  export type { CompanyCreateOptions, CompanyGetOptions, CompanyListOptions, CompanyUpdateOptions } from "./companies.ts";
26
- // Company commands
27
22
  export { cmdCompanyCreate, cmdCompanyGet, cmdCompanyList, cmdCompanyUpdate } from "./companies.ts";
28
23
  export type {
29
24
  ContactAttachCompanyOptions,
@@ -37,7 +32,6 @@ export type {
37
32
  ContactTagOptions,
38
33
  ContactUpdateOptions,
39
34
  } from "./contacts.ts";
40
- // Contact commands
41
35
  export {
42
36
  cmdContactAttachCompany,
43
37
  cmdContactCreate,
@@ -54,6 +48,7 @@ export {
54
48
  export type {
55
49
  ConversationAssignOptions,
56
50
  ConversationCloseOptions,
51
+ ConversationConvertOptions,
57
52
  ConversationGetOptions,
58
53
  ConversationListOptions,
59
54
  ConversationOpenOptions,
@@ -61,10 +56,10 @@ export type {
61
56
  ConversationSearchOptions,
62
57
  ConversationSnoozeOptions,
63
58
  } from "./conversations.ts";
64
- // Conversation commands
65
59
  export {
66
60
  cmdConversationAssign,
67
61
  cmdConversationClose,
62
+ cmdConversationConvert,
68
63
  cmdConversationGet,
69
64
  cmdConversationList,
70
65
  cmdConversationOpen,
@@ -73,10 +68,29 @@ export {
73
68
  cmdConversationSnooze,
74
69
  } from "./conversations.ts";
75
70
  export type { EventListOptions, EventTrackOptions } from "./events.ts";
76
- // Event commands
77
71
  export { cmdEventList, cmdEventTrack } from "./events.ts";
78
- // Overview commands
79
72
  export { cmdContext, cmdSchema } from "./overview.ts";
80
73
  export type { TagCreateOptions, TagDeleteOptions, TagGetOptions } from "./tags.ts";
81
- // Tag commands
82
74
  export { cmdTagCreate, cmdTagDelete, cmdTagGet, cmdTagList } from "./tags.ts";
75
+ export type {
76
+ TicketAssignOptions,
77
+ TicketCloseOptions,
78
+ TicketCreateOptions,
79
+ TicketDeleteOptions,
80
+ TicketGetOptions,
81
+ TicketReplyOptions,
82
+ TicketSearchOptions,
83
+ TicketUpdateOptions,
84
+ } from "./tickets.ts";
85
+ export {
86
+ cmdTicketAssign,
87
+ cmdTicketClose,
88
+ cmdTicketCreate,
89
+ cmdTicketDelete,
90
+ cmdTicketGet,
91
+ cmdTicketReply,
92
+ cmdTicketSearch,
93
+ cmdTicketUpdate,
94
+ } from "./tickets.ts";
95
+ export type { TicketTypeGetOptions, TicketTypeListOptions } from "./ticketTypes.ts";
96
+ export { cmdTicketTypeGet, cmdTicketTypeList } from "./ticketTypes.ts";
@@ -3,7 +3,7 @@ import { createClient, handleIntercomError } from "../client.ts";
3
3
  import { CLIError, type GlobalOptions, getTokenAsync, output } from "../utils/index.ts";
4
4
 
5
5
  export async function cmdContext(options: GlobalOptions): Promise<void> {
6
- const token = await getTokenAsync();
6
+ const token = await getTokenAsync(options.configDir);
7
7
  if (!token) {
8
8
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
9
9
  }
@@ -118,7 +118,9 @@ export function cmdSchema(): void {
118
118
  create_contact: 'intercom contact create --email "user@example.com" --name "John Doe"',
119
119
  search_contacts: 'intercom contact search --email "user@example.com"',
120
120
  list_conversations: "intercom conversation list --limit 10",
121
- reply_conversation: 'intercom conversation reply <id> --admin <admin-id> --body "Thank you!"',
121
+ reply_conversation: 'intercom conversation reply <id> --admin <admin-id> --body "Internal note" --type note',
122
+ reply_ticket:
123
+ 'intercom ticket reply <id> --admin <admin-id> --body "Internal note" --json \'{"message_type":"note"}\'',
122
124
  create_tag: 'intercom tag create "VIP Customer"',
123
125
  search_articles: 'intercom article search "getting started"',
124
126
  },
@@ -0,0 +1,46 @@
1
+ import { CLIError } from "../utils/index.ts";
2
+
3
+ type ReplyPayloadInput = {
4
+ adminId: string;
5
+ body: string;
6
+ messageType?: string;
7
+ json?: string;
8
+ };
9
+
10
+ export type ReplyBodyPayload = {
11
+ message_type: "comment" | "note";
12
+ type: "admin";
13
+ admin_id: string;
14
+ body: string;
15
+ } & Record<string, unknown>;
16
+
17
+ function validateReplyType(value: unknown, source: "--type" | "--json"): "comment" | "note" {
18
+ if (value !== "comment" && value !== "note") {
19
+ throw new CLIError(`Invalid ${source} value for message type: ${String(value)}`, 400, "Use comment or note.");
20
+ }
21
+ return value;
22
+ }
23
+
24
+ export function buildAdminReplyPayload(input: ReplyPayloadInput): ReplyBodyPayload {
25
+ const parsed = input.json ? JSON.parse(input.json) : {};
26
+
27
+ if (parsed === null || Array.isArray(parsed) || typeof parsed !== "object") {
28
+ throw new CLIError("Invalid --json value. Expected a JSON object.", 400);
29
+ }
30
+
31
+ const messageTypeFromJson =
32
+ Object.hasOwn(parsed, "message_type") && (parsed as Record<string, unknown>).message_type !== undefined
33
+ ? validateReplyType((parsed as Record<string, unknown>).message_type, "--json")
34
+ : undefined;
35
+ const messageType = input.messageType
36
+ ? validateReplyType(input.messageType, "--type")
37
+ : (messageTypeFromJson ?? "comment");
38
+
39
+ return {
40
+ ...(parsed as Record<string, unknown>),
41
+ message_type: messageType,
42
+ type: "admin",
43
+ admin_id: input.adminId,
44
+ body: input.body,
45
+ };
46
+ }
@@ -14,8 +14,8 @@ export interface TagDeleteOptions extends GlobalOptions {
14
14
  id: string;
15
15
  }
16
16
 
17
- async function requireToken(): Promise<string> {
18
- const token = await getTokenAsync();
17
+ async function requireToken(configDir: string): Promise<string> {
18
+ const token = await getTokenAsync(configDir);
19
19
  if (!token) {
20
20
  throw new CLIError("Not logged in", 401, "Run 'intercom login' to authenticate.");
21
21
  }
@@ -23,7 +23,7 @@ async function requireToken(): Promise<string> {
23
23
  }
24
24
 
25
25
  export async function cmdTagList(options: GlobalOptions): Promise<void> {
26
- const token = await requireToken();
26
+ const token = await requireToken(options.configDir);
27
27
  const spinner = ora("Fetching tags...").start();
28
28
 
29
29
  try {
@@ -49,7 +49,7 @@ export async function cmdTagList(options: GlobalOptions): Promise<void> {
49
49
  }
50
50
 
51
51
  export async function cmdTagCreate(options: TagCreateOptions): Promise<void> {
52
- const token = await requireToken();
52
+ const token = await requireToken(options.configDir);
53
53
  const spinner = ora("Creating tag...").start();
54
54
 
55
55
  try {
@@ -72,7 +72,7 @@ export async function cmdTagCreate(options: TagCreateOptions): Promise<void> {
72
72
  }
73
73
 
74
74
  export async function cmdTagGet(options: TagGetOptions): Promise<void> {
75
- const token = await requireToken();
75
+ const token = await requireToken(options.configDir);
76
76
  const spinner = ora("Fetching tag...").start();
77
77
 
78
78
  try {
@@ -95,7 +95,7 @@ export async function cmdTagGet(options: TagGetOptions): Promise<void> {
95
95
  }
96
96
 
97
97
  export async function cmdTagDelete(options: TagDeleteOptions): Promise<void> {
98
- const token = await requireToken();
98
+ const token = await requireToken(options.configDir);
99
99
  const spinner = ora("Deleting tag...").start();
100
100
 
101
101
  try {