@wilnertech/halopsa-mcp-server 1.0.2 → 1.1.0

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.
Files changed (72) hide show
  1. package/.env.example +18 -18
  2. package/LICENSE +21 -21
  3. package/README.md +252 -205
  4. package/dist/api/client.d.ts +7 -2
  5. package/dist/api/client.d.ts.map +1 -1
  6. package/dist/api/client.js +35 -8
  7. package/dist/api/client.js.map +1 -1
  8. package/dist/cache/memory-cache.d.ts +7 -0
  9. package/dist/cache/memory-cache.d.ts.map +1 -1
  10. package/dist/cache/memory-cache.js +7 -0
  11. package/dist/cache/memory-cache.js.map +1 -1
  12. package/dist/cache/prewarm.d.ts +3 -1
  13. package/dist/cache/prewarm.d.ts.map +1 -1
  14. package/dist/cache/prewarm.js +17 -1
  15. package/dist/cache/prewarm.js.map +1 -1
  16. package/dist/schemas/common.d.ts +30 -99
  17. package/dist/schemas/common.d.ts.map +1 -1
  18. package/dist/schemas/common.js +2 -2
  19. package/dist/schemas/common.js.map +1 -1
  20. package/dist/tools/assets.d.ts +69 -297
  21. package/dist/tools/assets.d.ts.map +1 -1
  22. package/dist/tools/batch-operations.d.ts +49 -81
  23. package/dist/tools/batch-operations.d.ts.map +1 -1
  24. package/dist/tools/batch-operations.js +62 -0
  25. package/dist/tools/batch-operations.js.map +1 -1
  26. package/dist/tools/clients.d.ts +24 -92
  27. package/dist/tools/clients.d.ts.map +1 -1
  28. package/dist/tools/reference-data.d.ts +44 -72
  29. package/dist/tools/reference-data.d.ts.map +1 -1
  30. package/dist/tools/reference-data.js +27 -0
  31. package/dist/tools/reference-data.js.map +1 -1
  32. package/dist/tools/registrations.d.ts +7 -1
  33. package/dist/tools/registrations.d.ts.map +1 -1
  34. package/dist/tools/registrations.js +43 -7
  35. package/dist/tools/registrations.js.map +1 -1
  36. package/dist/tools/registry.d.ts +12 -5
  37. package/dist/tools/registry.d.ts.map +1 -1
  38. package/dist/tools/registry.js +26 -2
  39. package/dist/tools/registry.js.map +1 -1
  40. package/dist/tools/sites.d.ts +19 -111
  41. package/dist/tools/sites.d.ts.map +1 -1
  42. package/dist/tools/ticket-actions.d.ts +41 -0
  43. package/dist/tools/ticket-actions.d.ts.map +1 -0
  44. package/dist/tools/ticket-actions.js +222 -0
  45. package/dist/tools/ticket-actions.js.map +1 -0
  46. package/dist/tools/ticket-custom-fields.d.ts +33 -0
  47. package/dist/tools/ticket-custom-fields.d.ts.map +1 -0
  48. package/dist/tools/ticket-custom-fields.js +155 -0
  49. package/dist/tools/ticket-custom-fields.js.map +1 -0
  50. package/dist/tools/ticket-reference-data.d.ts +88 -0
  51. package/dist/tools/ticket-reference-data.d.ts.map +1 -0
  52. package/dist/tools/ticket-reference-data.js +185 -0
  53. package/dist/tools/ticket-reference-data.js.map +1 -0
  54. package/dist/tools/tickets.d.ts +168 -0
  55. package/dist/tools/tickets.d.ts.map +1 -0
  56. package/dist/tools/tickets.js +572 -0
  57. package/dist/tools/tickets.js.map +1 -0
  58. package/dist/tools/users.d.ts +37 -193
  59. package/dist/tools/users.d.ts.map +1 -1
  60. package/dist/types/tickets.d.ts +193 -0
  61. package/dist/types/tickets.d.ts.map +1 -0
  62. package/dist/types/tickets.js +14 -0
  63. package/dist/types/tickets.js.map +1 -0
  64. package/dist/utils/formatter.d.ts +15 -1
  65. package/dist/utils/formatter.d.ts.map +1 -1
  66. package/dist/utils/formatter.js +52 -6
  67. package/dist/utils/formatter.js.map +1 -1
  68. package/package.json +68 -61
  69. package/dist/utils/zod-to-schema.d.ts +0 -29
  70. package/dist/utils/zod-to-schema.d.ts.map +0 -1
  71. package/dist/utils/zod-to-schema.js +0 -182
  72. package/dist/utils/zod-to-schema.js.map +0 -1
@@ -0,0 +1,572 @@
1
+ /**
2
+ * HaloPSA Ticket CRUD tools.
3
+ *
4
+ * Tickets are append-only business events — unlike assets/users/sites,
5
+ * there is no `find_*_match` deduplication step. Update by explicit id
6
+ * always.
7
+ *
8
+ * Update mechanics mirror `updateAsset` in `src/tools/assets.ts`:
9
+ * Halo's POST /api/Tickets is REPLACE-not-PATCH, so we read the current
10
+ * record first and spread it under the partial payload before sending.
11
+ *
12
+ * Compact responses INTENTIONALLY omit `details_html` (HTML body, can be
13
+ * 50KB+) and `customfields[]` to keep MCP responses sub-second and
14
+ * within token budgets. Callers that need them call `get_halopsa_ticket`
15
+ * or pass `format_options.format = 'detailed'` / `full: true`.
16
+ */
17
+ import { z } from 'zod';
18
+ import { formatResponse } from '../utils/formatter.js';
19
+ import { TTL } from '../cache/memory-cache.js';
20
+ import { FormatOptionsSchema } from '../schemas/common.js';
21
+ // =============================================================================
22
+ // Schemas
23
+ // =============================================================================
24
+ const CustomFieldInputSchema = z.object({
25
+ id: z.number().int().optional(),
26
+ name: z.string().optional(),
27
+ value: z.union([z.string(), z.number(), z.boolean(), z.null()]),
28
+ });
29
+ // Swagger declares category_1..4 and agent/client_ids as "array of int"
30
+ // (comma-separated string on the wire). Accept a single int OR an array
31
+ // so existing single-int callers continue to work unchanged.
32
+ const IntOrIntArray = z.union([z.number().int(), z.array(z.number().int())]);
33
+ /** Serialize an int or int[] to the comma-separated string Halo expects. */
34
+ function toCommaList(v) {
35
+ return Array.isArray(v) ? v.join(',') : String(v);
36
+ }
37
+ export const ListTicketsArgsSchema = z.object({
38
+ client_id: z.number().int().optional()
39
+ .describe('Filter by a single client ID (int). Use client_ids for multiple.'),
40
+ client_ids: IntOrIntArray.optional()
41
+ .describe('Filter by one or more client IDs (int or array of int, serialised comma-separated). Additive to client_id.'),
42
+ site_id: z.number().int().optional()
43
+ .describe('Filter by site/location ID'),
44
+ user_id: z.number().int().optional()
45
+ .describe('Filter by end-user ID'),
46
+ agent_id: z.number().int().optional()
47
+ .describe('Filter by assigned agent ID (single int). Use agent for multiple.'),
48
+ agent: IntOrIntArray.optional()
49
+ .describe('Filter by one or more agent IDs (int or array of int, serialised comma-separated). Swagger param: agent (array of int).'),
50
+ team_id: z.number().int().optional()
51
+ .describe('Filter by team ID'),
52
+ tickettype_id: IntOrIntArray.optional()
53
+ .describe('Filter by ticket type ID(s) (int or array of int, serialised comma-separated).'),
54
+ status_id: z.number().int().optional()
55
+ .describe('Filter by status ID'),
56
+ category_1: IntOrIntArray.optional()
57
+ .describe('Filter by category-1 ID(s) (int or array of int, serialised comma-separated). Swagger: array of int.'),
58
+ category_2: IntOrIntArray.optional()
59
+ .describe('Filter by category-2 ID(s) (int or array of int, serialised comma-separated).'),
60
+ category_3: IntOrIntArray.optional()
61
+ .describe('Filter by category-3 ID(s) (int or array of int, serialised comma-separated).'),
62
+ category_4: IntOrIntArray.optional()
63
+ .describe('Filter by category-4 ID(s) (int or array of int, serialised comma-separated).'),
64
+ search: z.string().optional()
65
+ .describe('Free-text search across summary/details'),
66
+ open_only: z.boolean().optional()
67
+ .describe('If true, exclude closed tickets'),
68
+ date_from: z.string().optional()
69
+ .describe('ISO 8601 lower bound on dateoccurred'),
70
+ date_to: z.string().optional()
71
+ .describe('ISO 8601 upper bound on dateoccurred'),
72
+ count: z.number().int().min(1).max(100).optional()
73
+ .describe('Results per page (max 100, default 50)'),
74
+ page_no: z.number().int().min(1).optional()
75
+ .describe('Page number (1-indexed)'),
76
+ format_options: FormatOptionsSchema,
77
+ });
78
+ export const GetTicketArgsSchema = z.object({
79
+ ticket_id: z.number().int()
80
+ .describe('HaloPSA ticket ID'),
81
+ format_options: FormatOptionsSchema,
82
+ });
83
+ export const SearchTicketsArgsSchema = z.object({
84
+ search: z.string().min(1)
85
+ .describe('Free-text search term (matches summary and details)'),
86
+ client_id: z.number().int().optional()
87
+ .describe('Limit search to a specific client'),
88
+ open_only: z.boolean().optional()
89
+ .describe('If true, exclude closed tickets'),
90
+ count: z.number().int().min(1).max(100).optional()
91
+ .describe('Results per page (max 100, default 50)'),
92
+ format_options: FormatOptionsSchema,
93
+ });
94
+ export const CreateTicketArgsSchema = z.object({
95
+ summary: z.string().min(1)
96
+ .describe('Ticket summary / title (required)'),
97
+ tickettype_id: z.number().int()
98
+ .describe('Ticket type ID — see list_halopsa_tickettypes'),
99
+ client_id: z.number().int()
100
+ .describe('Client ID the ticket belongs to'),
101
+ details_html: z.string().optional()
102
+ .describe('Sanitized HTML body of the ticket'),
103
+ category_1: z.string().optional()
104
+ .describe('Primary category — see list_halopsa_ticket_categories'),
105
+ priority_id: z.number().int().optional()
106
+ .describe('Priority ID — see list_halopsa_ticket_priorities'),
107
+ status_id: z.number().int().optional()
108
+ .describe('Initial status ID — see list_halopsa_ticket_statuses'),
109
+ source: z.number().int().optional()
110
+ .describe('Source enum (tenant-specific integer). Halo auto-sets source=3 (API) when omitted.'),
111
+ agent_id: z.number().int().optional()
112
+ .describe('Assigned agent'),
113
+ team_id: z.number().int().optional()
114
+ .describe('Assigned team'),
115
+ site_id: z.number().int().optional()
116
+ .describe('Site/location'),
117
+ user_id: z.number().int().optional()
118
+ .describe('End-user contact'),
119
+ parent_id: z.number().int().optional()
120
+ .describe('Parent ticket ID for child/subtask creation. Halo denormalises parent_ticket_type_name and increments the parent child_count on save.'),
121
+ dateoccurred: z.string().optional()
122
+ .describe('ISO 8601 datetime of when the issue occurred. Halo defaults to now() when omitted; pass to backdate.'),
123
+ startdate: z.string().optional()
124
+ .describe('ISO 8601 datetime for project ticket start date.'),
125
+ customfields: z.array(CustomFieldInputSchema).optional()
126
+ .describe('Ticket custom fields'),
127
+ });
128
+ export const UpdateTicketArgsSchema = z.object({
129
+ ticket_id: z.number().int()
130
+ .describe('HaloPSA ticket ID to update'),
131
+ summary: z.string().optional(),
132
+ details_html: z.string().optional(),
133
+ tickettype_id: z.number().int().optional()
134
+ .describe('Change the ticket type in-place. Halo re-categorises via apply_workflow_on_type_change but does NOT swap workflows — the existing workflow continues.'),
135
+ status_id: z.number().int().optional(),
136
+ priority_id: z.number().int().optional(),
137
+ category_1: z.string().optional(),
138
+ agent_id: z.number().int().optional(),
139
+ team_id: z.number().int().optional(),
140
+ site_id: z.number().int().optional(),
141
+ user_id: z.number().int().optional(),
142
+ parent_id: z.number().int().optional()
143
+ .describe('Set or change the parent ticket ID. Halo denormalises parent_ticket_type_name and adjusts parent child_count.'),
144
+ dateoccurred: z.string().optional()
145
+ .describe('ISO 8601 datetime of when the issue occurred.'),
146
+ startdate: z.string().optional()
147
+ .describe('ISO 8601 datetime for project ticket start date.'),
148
+ source: z.number().int().optional()
149
+ .describe('Source enum (tenant-specific integer). Halo auto-sets source=3 (API) when omitted.'),
150
+ customfields: z.array(CustomFieldInputSchema).optional(),
151
+ });
152
+ export const CloseTicketArgsSchema = z.object({
153
+ ticket_id: z.number().int()
154
+ .describe('HaloPSA ticket ID to close'),
155
+ resolution_note: z.string().optional()
156
+ .describe('Optional final action note added before status change'),
157
+ });
158
+ export const DeleteTicketArgsSchema = z.object({
159
+ ticket_id: z.number().int().describe('HaloPSA ticket ID to delete'),
160
+ reason: z.string().min(5).describe('REQUIRED audit-trail reason. To bypass safety blocks, the reason MUST include the substring "OVERRIDE" (case-sensitive) AND confirm_destructive must be true.'),
161
+ confirm_destructive: z.boolean().optional().default(false).describe('When safety pre-flight checks would block the delete, set true AND include "OVERRIDE" in `reason` to proceed. Default false.'),
162
+ });
163
+ // =============================================================================
164
+ // Helpers
165
+ // =============================================================================
166
+ const TICKET_COMPACT_FIELDS = [
167
+ 'id', 'summary', 'status_id', 'status_name', 'tickettype_id',
168
+ 'tickettype_name', 'client_id', 'client_name', 'priority_id',
169
+ 'priority_name', 'agent_id', 'agent_name', 'dateoccurred',
170
+ 'lastactiondate',
171
+ ];
172
+ /**
173
+ * Default ticket-list responses to a small allowlist of ticket-relevant
174
+ * fields. We deliberately pass `format: 'standard'` (NOT `'compact'`)
175
+ * because `formatter.compactItem()` is asset-oriented and would strip
176
+ * ticket-only fields like `tickettype_id`, `priority_id`, `agent_name`
177
+ * even after `filterFields` runs. The `fields` allowlist alone gives
178
+ * us the size reduction without the asset-shaped collateral damage.
179
+ */
180
+ function resolveListFormat(input) {
181
+ const opts = { ...(input || {}) };
182
+ if (!opts.format) {
183
+ opts.format = 'standard';
184
+ opts.fields = opts.fields ?? TICKET_COMPACT_FIELDS;
185
+ }
186
+ return opts;
187
+ }
188
+ /**
189
+ * Halo write endpoints (POST /Tickets, POST /Actions) sometimes return
190
+ * `[{...}]` and sometimes `{...}` depending on tenant configuration.
191
+ * Normalize to a single object so handlers and callers don't have to
192
+ * branch.
193
+ */
194
+ function unwrapWriteResponse(response) {
195
+ return Array.isArray(response) ? response[0] : response;
196
+ }
197
+ function unwrapTicketList(response) {
198
+ if (Array.isArray(response)) {
199
+ return { tickets: response, record_count: response.length };
200
+ }
201
+ return {
202
+ tickets: response.tickets ?? [],
203
+ record_count: response.record_count ?? response.tickets?.length ?? 0,
204
+ page_count: response.page_count,
205
+ };
206
+ }
207
+ /**
208
+ * Dynamically resolve a "closed" status id for the current Halo tenant.
209
+ * Tries `type === 'closed'`, then `complete === true`, then `is_closed`,
210
+ * then a name-regex fallback. Throws if nothing matches.
211
+ */
212
+ async function resolveClosedStatusId(client) {
213
+ const response = await client.getCached('/Status', { count: 500 }, {
214
+ enabled: true,
215
+ ttl: TTL.TICKET_STATUSES,
216
+ keyPrefix: 'ticketstatuses:all',
217
+ });
218
+ const items = Array.isArray(response)
219
+ ? response
220
+ : (response.statuses ?? []);
221
+ // Strategy 1: exact name match + type === 0 (standard open-family, non-project
222
+ // closed state confirmed on the Wilner Tech tenant — Phase 1.3 finding).
223
+ // Phase 1.3 confirmed this tenant does NOT have `complete` or `is_closed`
224
+ // fields, so we do NOT use them. The naive /closed|complete/i regex was
225
+ // picking id=13 "Closed Order" (type=1) over id=9 "Closed" (type=0).
226
+ const exactClosed = items.filter((s) => s.name === 'Closed' && s.type === 0);
227
+ if (exactClosed.length === 1) {
228
+ return exactClosed[0].id;
229
+ }
230
+ // Strategy 2: "Completed" + type === 0 fallback.
231
+ const exactCompleted = items.filter((s) => s.name === 'Completed' && s.type === 0);
232
+ if (exactCompleted.length === 1) {
233
+ return exactCompleted[0].id;
234
+ }
235
+ throw new Error(`Could not resolve closed-status id — no status matches name === "Closed" && type === 0. ` +
236
+ `(received ${items.length} statuses; "Closed" matches: ${exactClosed.length}, "Completed" matches: ${exactCompleted.length}) ` +
237
+ 'Pass status_id explicitly via update_halopsa_ticket.');
238
+ }
239
+ // =============================================================================
240
+ // Implementations
241
+ // =============================================================================
242
+ export async function listTickets(client, args) {
243
+ const params = {};
244
+ if (args.client_id !== undefined)
245
+ params.client_id = args.client_id;
246
+ // client_ids, category_1..4, and agent are "array of int" params — Halo
247
+ // expects a comma-separated string. A single int is also accepted by Halo
248
+ // when encoded as a string (empirically confirmed).
249
+ if (args.client_ids !== undefined)
250
+ params.client_ids = toCommaList(args.client_ids);
251
+ if (args.site_id !== undefined)
252
+ params.site_id = args.site_id;
253
+ if (args.user_id !== undefined)
254
+ params.user_id = args.user_id;
255
+ if (args.agent_id !== undefined)
256
+ params.agent_id = args.agent_id;
257
+ if (args.agent !== undefined)
258
+ params.agent = toCommaList(args.agent);
259
+ if (args.team_id !== undefined)
260
+ params.team_id = args.team_id;
261
+ if (args.tickettype_id !== undefined)
262
+ params.tickettype_id = toCommaList(args.tickettype_id);
263
+ if (args.status_id !== undefined)
264
+ params.status_id = args.status_id;
265
+ if (args.category_1 !== undefined)
266
+ params.category_1 = toCommaList(args.category_1);
267
+ if (args.category_2 !== undefined)
268
+ params.category_2 = toCommaList(args.category_2);
269
+ if (args.category_3 !== undefined)
270
+ params.category_3 = toCommaList(args.category_3);
271
+ if (args.category_4 !== undefined)
272
+ params.category_4 = toCommaList(args.category_4);
273
+ if (args.search !== undefined)
274
+ params.search = args.search;
275
+ if (args.open_only !== undefined)
276
+ params.open_only = args.open_only;
277
+ if (args.date_from !== undefined)
278
+ params.date_from = args.date_from;
279
+ if (args.date_to !== undefined)
280
+ params.date_to = args.date_to;
281
+ if (args.count !== undefined)
282
+ params.count = args.count;
283
+ if (args.page_no !== undefined)
284
+ params.page_no = args.page_no;
285
+ const formatOpts = resolveListFormat(args.format_options);
286
+ const cacheKey = `tickets:client_${args.client_id ?? 'all'}:status_${args.status_id ?? 'all'}`;
287
+ const response = await client.getCached('/Tickets', params, {
288
+ enabled: true,
289
+ ttl: TTL.TICKET_LIST,
290
+ keyPrefix: cacheKey,
291
+ });
292
+ const { tickets, record_count, page_count } = unwrapTicketList(response);
293
+ return formatResponse(tickets, formatOpts, { record_count, page_count });
294
+ }
295
+ export async function getTicket(client, args) {
296
+ const formatOpts = args.format_options || { format: 'detailed' };
297
+ const response = await client.getCached(`/Tickets/${args.ticket_id}`, { includedetails: true }, {
298
+ enabled: true,
299
+ ttl: TTL.TICKET_LIST,
300
+ keyPrefix: `ticket:${args.ticket_id}`,
301
+ });
302
+ return formatResponse(response, formatOpts);
303
+ }
304
+ export async function searchTickets(client, args) {
305
+ return listTickets(client, {
306
+ search: args.search,
307
+ client_id: args.client_id,
308
+ open_only: args.open_only,
309
+ count: args.count,
310
+ format_options: args.format_options,
311
+ });
312
+ }
313
+ export async function createTicket(client, args) {
314
+ const payload = {
315
+ summary: args.summary,
316
+ tickettype_id: args.tickettype_id,
317
+ client_id: args.client_id,
318
+ };
319
+ if (args.details_html !== undefined)
320
+ payload.details_html = args.details_html;
321
+ if (args.category_1 !== undefined)
322
+ payload.category_1 = args.category_1;
323
+ if (args.priority_id !== undefined)
324
+ payload.priority_id = args.priority_id;
325
+ if (args.status_id !== undefined)
326
+ payload.status_id = args.status_id;
327
+ if (args.source !== undefined)
328
+ payload.source = args.source;
329
+ if (args.agent_id !== undefined)
330
+ payload.agent_id = args.agent_id;
331
+ if (args.team_id !== undefined)
332
+ payload.team_id = args.team_id;
333
+ if (args.site_id !== undefined)
334
+ payload.site_id = args.site_id;
335
+ if (args.user_id !== undefined)
336
+ payload.user_id = args.user_id;
337
+ if (args.parent_id !== undefined)
338
+ payload.parent_id = args.parent_id;
339
+ if (args.dateoccurred !== undefined)
340
+ payload.dateoccurred = args.dateoccurred;
341
+ if (args.startdate !== undefined)
342
+ payload.startdate = args.startdate;
343
+ if (args.customfields !== undefined)
344
+ payload.customfields = args.customfields;
345
+ const created = unwrapWriteResponse(await client.post('/Tickets', [payload]));
346
+ client.invalidateCache('tickets:*');
347
+ return formatResponse(created, { format: 'standard' });
348
+ }
349
+ export async function updateTicket(client, args) {
350
+ const partial = {};
351
+ if (args.summary !== undefined)
352
+ partial.summary = args.summary;
353
+ if (args.details_html !== undefined)
354
+ partial.details_html = args.details_html;
355
+ if (args.tickettype_id !== undefined)
356
+ partial.tickettype_id = args.tickettype_id;
357
+ if (args.status_id !== undefined)
358
+ partial.status_id = args.status_id;
359
+ if (args.priority_id !== undefined)
360
+ partial.priority_id = args.priority_id;
361
+ if (args.category_1 !== undefined)
362
+ partial.category_1 = args.category_1;
363
+ if (args.agent_id !== undefined)
364
+ partial.agent_id = args.agent_id;
365
+ if (args.team_id !== undefined)
366
+ partial.team_id = args.team_id;
367
+ if (args.site_id !== undefined)
368
+ partial.site_id = args.site_id;
369
+ if (args.user_id !== undefined)
370
+ partial.user_id = args.user_id;
371
+ if (args.parent_id !== undefined)
372
+ partial.parent_id = args.parent_id;
373
+ if (args.dateoccurred !== undefined)
374
+ partial.dateoccurred = args.dateoccurred;
375
+ if (args.startdate !== undefined)
376
+ partial.startdate = args.startdate;
377
+ if (args.source !== undefined)
378
+ partial.source = args.source;
379
+ if (args.customfields !== undefined)
380
+ partial.customfields = args.customfields;
381
+ if (Object.keys(partial).length === 0) {
382
+ return JSON.stringify({
383
+ error: true,
384
+ message: 'At least one field must be provided for update',
385
+ }, null, 2);
386
+ }
387
+ // Halo POST /Tickets is REPLACE not PATCH — read-before-write merge to
388
+ // preserve fields the caller didn't touch (mirrors updateAsset).
389
+ const existing = await client.get(`/Tickets/${args.ticket_id}`, { includedetails: true });
390
+ const response = unwrapWriteResponse(await client.post('/Tickets', [{ ...existing, ...partial, id: args.ticket_id }]));
391
+ client.invalidateCache('tickets:*');
392
+ client.invalidateCache(`ticket:${args.ticket_id}*`);
393
+ return formatResponse(response, { format: 'standard' });
394
+ }
395
+ /**
396
+ * Permanently delete a HaloPSA ticket by ID after running four safety
397
+ * pre-flight checks:
398
+ *
399
+ * 1. Financial — refuses if `timetaken > 0` or `hoursinvoiced > 0` (billable
400
+ * history would be destroyed on delete).
401
+ * 2. Cascade — refuses if `child_count > 0` (children would orphan; Halo
402
+ * cascade behavior is undocumented).
403
+ * 3. Historical — refuses if the ticket is closed or completed. Uses a
404
+ * tenant-portable dual-check: primary `hasbeenclosed === true` (Halo
405
+ * boolean); secondary fetches `/Status` (cached 1h) and matches against
406
+ * known closed-flavour names (Closed, Closed Order, Closed Item, Completed).
407
+ * 4. Authorship — refuses unless `who === 'claude_mcp'` (prevents accidental
408
+ * deletion of human-created tickets).
409
+ *
410
+ * OVERRIDE mechanism: when violations exist, pass `confirm_destructive: true`
411
+ * AND include the substring `"OVERRIDE"` (case-sensitive) in `reason` to
412
+ * bypass all checks and proceed with the DELETE.
413
+ *
414
+ * Return shapes:
415
+ * - `{ already_absent: true, deleted_id }` — 404 on GET (idempotent).
416
+ * - `{ deleted: false, refused: true, violations, remediation }` — safety block.
417
+ * - `{ deleted: true, ticket_id, reason, override_used, safety_violations_bypassed? }` — success.
418
+ */
419
+ export async function deleteTicket(client, args) {
420
+ // Step 1: Fetch the ticket. 404 is idempotent — caller may be retrying.
421
+ let ticket;
422
+ try {
423
+ ticket = await client.get(`/Tickets/${args.ticket_id}`, { includedetails: true });
424
+ }
425
+ catch (error) {
426
+ const status = error?.response?.status;
427
+ if (status === 404) {
428
+ return JSON.stringify({ already_absent: true, deleted_id: args.ticket_id }, null, 2);
429
+ }
430
+ throw error;
431
+ }
432
+ // Step 2: Accumulate ALL violations (no short-circuit).
433
+ const violations = [];
434
+ const timetaken = ticket.timetaken ?? 0;
435
+ const hoursinvoiced = ticket.hoursinvoiced ?? 0;
436
+ if (timetaken > 0 || hoursinvoiced > 0) {
437
+ violations.push(`financial: timetaken=${timetaken}, hoursinvoiced=${hoursinvoiced} — billable history would be destroyed`);
438
+ }
439
+ const childCount = ticket.child_count ?? 0;
440
+ if (childCount > 0) {
441
+ violations.push(`cascade: child_count=${childCount} — children would orphan (Halo cascade behavior undocumented)`);
442
+ }
443
+ // Dynamic closed-status check: tenant-portable, does not rely on
444
+ // hardcoded IDs. Primary path uses `hasbeenclosed` (Halo-derived
445
+ // boolean). Secondary path fetches /Status (cached 1h) and matches on
446
+ // known closed-flavour names. Falls back to name-set-only when
447
+ // `hasbeenclosed` is absent from the response.
448
+ const statusId = ticket.status_id ?? 0;
449
+ let isClosedOrCompleted = false;
450
+ if (ticket.hasbeenclosed === true) {
451
+ isClosedOrCompleted = true;
452
+ }
453
+ else if (statusId > 0) {
454
+ // Secondary: fetch the status list, build the set of closed-flavour IDs.
455
+ const statusResponse = await client.getCached('/Status', { count: 500 }, {
456
+ enabled: true,
457
+ ttl: TTL.TICKET_STATUSES,
458
+ keyPrefix: 'ticketstatuses:all',
459
+ });
460
+ const statusItems = Array.isArray(statusResponse)
461
+ ? statusResponse
462
+ : (statusResponse.statuses ?? []);
463
+ const closedNames = new Set(['Closed', 'Closed Order', 'Closed Item', 'Completed']);
464
+ const closedStatusIdSet = new Set(statusItems
465
+ .filter((s) => closedNames.has(s.name))
466
+ .map((s) => s.id));
467
+ if (closedStatusIdSet.has(statusId)) {
468
+ isClosedOrCompleted = true;
469
+ }
470
+ }
471
+ if (isClosedOrCompleted) {
472
+ violations.push(`historical: ticket is in closed/completed state (status_id=${statusId}, hasbeenclosed=${ticket.hasbeenclosed ?? false})`);
473
+ }
474
+ const who = ticket.who ?? '';
475
+ if (who !== 'claude_mcp') {
476
+ violations.push(`authorship: ticket created by '${who}', not API smoke harness`);
477
+ }
478
+ // Step 3: Decision matrix.
479
+ if (violations.length > 0) {
480
+ const overrideProvided = args.confirm_destructive === true && args.reason.includes('OVERRIDE');
481
+ if (!overrideProvided) {
482
+ return JSON.stringify({
483
+ deleted: false,
484
+ refused: true,
485
+ ticket_id: args.ticket_id,
486
+ violations,
487
+ remediation: "Pass confirm_destructive: true AND include 'OVERRIDE' (case-sensitive) in the reason to proceed.",
488
+ }, null, 2);
489
+ }
490
+ // Override provided — fall through to DELETE and record it.
491
+ }
492
+ // Step 4: Execute DELETE with reason as URL-encoded query param.
493
+ const endpoint = `/Tickets/${args.ticket_id}?reason=${encodeURIComponent(args.reason)}`;
494
+ await client.delete(endpoint);
495
+ // Step 5: Cache invalidation.
496
+ client.invalidateCache('tickets:*');
497
+ client.invalidateCache('ticket-actions:*');
498
+ // Step 6: Return structured success.
499
+ const overrideUsed = violations.length > 0;
500
+ const result = {
501
+ deleted: true,
502
+ ticket_id: args.ticket_id,
503
+ reason: args.reason,
504
+ override_used: overrideUsed,
505
+ };
506
+ if (overrideUsed) {
507
+ result['safety_violations_bypassed'] = violations;
508
+ }
509
+ return JSON.stringify(result, null, 2);
510
+ }
511
+ export async function closeTicket(client, args) {
512
+ // If a resolution note was supplied, post it as a final action first so
513
+ // the close-out is auditable.
514
+ if (args.resolution_note) {
515
+ await client.post('/Actions', [{
516
+ ticket_id: args.ticket_id,
517
+ note: args.resolution_note,
518
+ }]);
519
+ client.invalidateCache(`ticket-actions:${args.ticket_id}*`);
520
+ }
521
+ const closedStatusId = await resolveClosedStatusId(client);
522
+ return updateTicket(client, {
523
+ ticket_id: args.ticket_id,
524
+ status_id: closedStatusId,
525
+ });
526
+ }
527
+ // =============================================================================
528
+ // Tool Definitions
529
+ // =============================================================================
530
+ export const listTicketsTool = {
531
+ name: 'list_halopsa_tickets',
532
+ description: 'List HaloPSA tickets with extensive filtering (client/site/user/agent/team/type/status/category/search/date-range/open-only). Compact response by default — excludes details_html and customfields[]. Cached 1min.',
533
+ schema: ListTicketsArgsSchema,
534
+ handler: listTickets,
535
+ };
536
+ export const getTicketTool = {
537
+ name: 'get_halopsa_ticket',
538
+ description: 'Get a single HaloPSA ticket by ID with full details (includes details_html and customfields[]). Cached 1min.',
539
+ schema: GetTicketArgsSchema,
540
+ handler: getTicket,
541
+ };
542
+ export const searchTicketsTool = {
543
+ name: 'search_halopsa_tickets',
544
+ description: 'Free-text search across HaloPSA ticket summaries and details. Convenience wrapper on list_halopsa_tickets.',
545
+ schema: SearchTicketsArgsSchema,
546
+ handler: searchTickets,
547
+ };
548
+ export const createTicketTool = {
549
+ name: 'create_halopsa_ticket',
550
+ description: 'Create a new HaloPSA ticket. Required: summary, tickettype_id, client_id. Body is sent as POST /Tickets with array wrapper [{ ... }] (HaloPSA convention). Invalidates ticket cache.',
551
+ schema: CreateTicketArgsSchema,
552
+ handler: createTicket,
553
+ };
554
+ export const updateTicketTool = {
555
+ name: 'update_halopsa_ticket',
556
+ description: 'Update an existing HaloPSA ticket. Performs read-before-write merge (Halo POST is REPLACE not PATCH). Update by explicit id only — no force/dedup flags (tickets are append-only events). Invalidates ticket cache.',
557
+ schema: UpdateTicketArgsSchema,
558
+ handler: updateTicket,
559
+ };
560
+ export const closeTicketTool = {
561
+ name: 'close_halopsa_ticket',
562
+ description: 'Close a HaloPSA ticket. Resolves the closed-status id dynamically via /Status (cached). Optionally posts a resolution note as a final action before status change.',
563
+ schema: CloseTicketArgsSchema,
564
+ handler: closeTicket,
565
+ };
566
+ export const deleteTicketTool = {
567
+ name: 'delete_halopsa_ticket',
568
+ description: 'Permanently delete a HaloPSA ticket by ID. Runs four safety checks before deleting (financial, cascade, historical, authorship). Returns a refusal with violations list if any check fails; pass confirm_destructive: true AND include "OVERRIDE" in reason to bypass. 404 on GET returns already_absent: true (idempotent). Invalidates ticket and ticket_actions caches.',
569
+ schema: DeleteTicketArgsSchema,
570
+ handler: deleteTicket,
571
+ };
572
+ //# sourceMappingURL=tickets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tickets.js","sourceRoot":"","sources":["../../src/tools/tickets.ts"],"names":[],"mappings":"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"}