@fruition/fcp-mcp-server 1.27.1 → 1.28.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.
- package/README.md +9 -0
- package/dist/index.d.ts +397 -0
- package/dist/index.js +124 -2
- package/dist/skills-sync.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,15 @@ MCP (Model Context Protocol) server that gives Claude Code direct access to the
|
|
|
16
16
|
| `fcp_add_progress_note` | Add progress notes to document work done |
|
|
17
17
|
| `fcp_get_claude_md` | Generate CLAUDE.md content for a launch |
|
|
18
18
|
|
|
19
|
+
### Tasker Freeze Management Tools
|
|
20
|
+
|
|
21
|
+
| Tool | Description |
|
|
22
|
+
|------|-------------|
|
|
23
|
+
| `fcp_list_freezes` | List active + scheduled auto-merge freezes and the available repos |
|
|
24
|
+
| `fcp_freeze_repo` | Schedule a freeze (by days or explicit window) to hold a repo's deploys |
|
|
25
|
+
| `fcp_update_freeze` | Edit an existing freeze's window or reason |
|
|
26
|
+
| `fcp_unfreeze` | Remove a freeze by id, or clear all freezes for a repo |
|
|
27
|
+
|
|
19
28
|
### Unroo Task Management Tools
|
|
20
29
|
|
|
21
30
|
| Tool | Description |
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,401 @@
|
|
|
7
7
|
* - Update checklist item status
|
|
8
8
|
* - Get project context for migrations
|
|
9
9
|
*/
|
|
10
|
+
interface Launch {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string | null;
|
|
14
|
+
platform: string;
|
|
15
|
+
launch_type: string;
|
|
16
|
+
status: string;
|
|
17
|
+
priority: string;
|
|
18
|
+
target_launch_date: string;
|
|
19
|
+
domain: string | null;
|
|
20
|
+
legacy_domain: string | null;
|
|
21
|
+
legacy_access_info: Record<string, any>;
|
|
22
|
+
[key: string]: any;
|
|
23
|
+
}
|
|
24
|
+
interface ChecklistItem {
|
|
25
|
+
id: number;
|
|
26
|
+
title: string;
|
|
27
|
+
description: string | null;
|
|
28
|
+
status: string;
|
|
29
|
+
category: string;
|
|
30
|
+
is_blocker: boolean;
|
|
31
|
+
claude_instructions: string | null;
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}
|
|
34
|
+
interface LaunchDetail {
|
|
35
|
+
launch: Launch;
|
|
36
|
+
checklist: ChecklistItem[];
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}
|
|
39
|
+
export declare class FCPClient {
|
|
40
|
+
private baseUrl;
|
|
41
|
+
private token;
|
|
42
|
+
private defaultTimeout;
|
|
43
|
+
constructor(baseUrl: string, token: string);
|
|
44
|
+
private fetch;
|
|
45
|
+
listLaunches(filters?: {
|
|
46
|
+
status?: string;
|
|
47
|
+
platform?: string;
|
|
48
|
+
upcoming?: number;
|
|
49
|
+
limit?: number;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
launches: Launch[];
|
|
52
|
+
}>;
|
|
53
|
+
getLaunch(id: number): Promise<LaunchDetail>;
|
|
54
|
+
createChecklistItem(launchId: number, input: {
|
|
55
|
+
title: string;
|
|
56
|
+
category: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
role?: string;
|
|
59
|
+
environment?: string;
|
|
60
|
+
assigned_to_id?: number;
|
|
61
|
+
due_date?: string;
|
|
62
|
+
sort_order?: number;
|
|
63
|
+
depends_on_item_id?: number;
|
|
64
|
+
is_required?: boolean;
|
|
65
|
+
is_blocking?: boolean;
|
|
66
|
+
external_link?: string;
|
|
67
|
+
}): Promise<ChecklistItem>;
|
|
68
|
+
updateChecklistItem(launchId: number, itemId: number, updates: {
|
|
69
|
+
status?: string;
|
|
70
|
+
notes?: string;
|
|
71
|
+
title?: string;
|
|
72
|
+
description?: string | null;
|
|
73
|
+
category?: string;
|
|
74
|
+
role?: string;
|
|
75
|
+
environment?: string;
|
|
76
|
+
assigned_to_id?: number | null;
|
|
77
|
+
due_date?: string | null;
|
|
78
|
+
sort_order?: number;
|
|
79
|
+
depends_on_item_id?: number | null;
|
|
80
|
+
is_required?: boolean;
|
|
81
|
+
is_blocking?: boolean;
|
|
82
|
+
external_link?: string | null;
|
|
83
|
+
evidence_url?: string | null;
|
|
84
|
+
jira_ticket_key?: string | null;
|
|
85
|
+
completion_notes?: string | null;
|
|
86
|
+
}): Promise<ChecklistItem>;
|
|
87
|
+
deleteChecklistItem(launchId: number, itemId: number): Promise<{
|
|
88
|
+
success: boolean;
|
|
89
|
+
}>;
|
|
90
|
+
private buildQuery;
|
|
91
|
+
listAlerts(q?: {
|
|
92
|
+
status?: string;
|
|
93
|
+
source?: string;
|
|
94
|
+
severity?: string;
|
|
95
|
+
cluster?: string;
|
|
96
|
+
namespace?: string;
|
|
97
|
+
domain?: string;
|
|
98
|
+
websiteId?: number;
|
|
99
|
+
environment?: string;
|
|
100
|
+
from?: string;
|
|
101
|
+
to?: string;
|
|
102
|
+
page?: number;
|
|
103
|
+
limit?: number;
|
|
104
|
+
}): Promise<any>;
|
|
105
|
+
getAlert(id: number): Promise<any>;
|
|
106
|
+
createAlert(input: {
|
|
107
|
+
alertName: string;
|
|
108
|
+
severity?: string;
|
|
109
|
+
summary?: string;
|
|
110
|
+
cluster?: string;
|
|
111
|
+
namespace?: string;
|
|
112
|
+
domain?: string;
|
|
113
|
+
websiteId?: number;
|
|
114
|
+
}): Promise<any>;
|
|
115
|
+
updateAlert(id: number, updates: {
|
|
116
|
+
status?: string;
|
|
117
|
+
acknowledgedBy?: string;
|
|
118
|
+
silencedUntil?: string;
|
|
119
|
+
silencedBy?: string;
|
|
120
|
+
adminNotes?: string;
|
|
121
|
+
websiteId?: number;
|
|
122
|
+
unrooTaskId?: number;
|
|
123
|
+
}): Promise<any>;
|
|
124
|
+
getAlertStats(): Promise<any>;
|
|
125
|
+
listAlertRules(accountId?: number): Promise<any>;
|
|
126
|
+
getAlertRule(ruleId: number): Promise<any>;
|
|
127
|
+
createAlertRule(input: Record<string, any>): Promise<any>;
|
|
128
|
+
updateAlertRule(ruleId: number, updates: Record<string, any>): Promise<any>;
|
|
129
|
+
deleteAlertRule(ruleId: number): Promise<any>;
|
|
130
|
+
listOutages(q?: {
|
|
131
|
+
status?: string;
|
|
132
|
+
accountId?: number;
|
|
133
|
+
limit?: number;
|
|
134
|
+
}): Promise<any>;
|
|
135
|
+
getOutage(outageId: number): Promise<any>;
|
|
136
|
+
createOutage(input: Record<string, any>): Promise<any>;
|
|
137
|
+
updateOutage(outageId: number, updates: Record<string, any>): Promise<any>;
|
|
138
|
+
resolveOutage(outageId: number): Promise<any>;
|
|
139
|
+
bulkNotifyClients(input: {
|
|
140
|
+
outageIds: number[];
|
|
141
|
+
notificationType: string;
|
|
142
|
+
subject: string;
|
|
143
|
+
message: string;
|
|
144
|
+
channels?: string[];
|
|
145
|
+
sentBy?: string;
|
|
146
|
+
}): Promise<any>;
|
|
147
|
+
getBulkNotifyHistory(limit?: number): Promise<any>;
|
|
148
|
+
createLaunch(input: {
|
|
149
|
+
name: string;
|
|
150
|
+
platform: string;
|
|
151
|
+
launch_type: string;
|
|
152
|
+
target_launch_date: string;
|
|
153
|
+
website_id?: number;
|
|
154
|
+
account_id?: number;
|
|
155
|
+
description?: string;
|
|
156
|
+
soft_launch_date?: string;
|
|
157
|
+
kickoff_date?: string;
|
|
158
|
+
priority?: string;
|
|
159
|
+
jira_project_key?: string;
|
|
160
|
+
unroo_project_id?: number;
|
|
161
|
+
webops_lead_id?: number;
|
|
162
|
+
devops_lead_id?: number;
|
|
163
|
+
dev_lead_id?: number;
|
|
164
|
+
seo_lead_id?: number;
|
|
165
|
+
client_contact?: string;
|
|
166
|
+
client_contact_email?: string;
|
|
167
|
+
use_default_checklist?: boolean;
|
|
168
|
+
}): Promise<{
|
|
169
|
+
launch: Launch;
|
|
170
|
+
}>;
|
|
171
|
+
updateLaunch(id: number, updates: {
|
|
172
|
+
website_id?: number | null;
|
|
173
|
+
account_id?: number | null;
|
|
174
|
+
name?: string;
|
|
175
|
+
description?: string;
|
|
176
|
+
platform?: string;
|
|
177
|
+
launch_type?: string;
|
|
178
|
+
target_launch_date?: string;
|
|
179
|
+
soft_launch_date?: string | null;
|
|
180
|
+
actual_launch_date?: string | null;
|
|
181
|
+
kickoff_date?: string | null;
|
|
182
|
+
status?: string;
|
|
183
|
+
priority?: string;
|
|
184
|
+
jira_project_key?: string | null;
|
|
185
|
+
unroo_project_id?: number | null;
|
|
186
|
+
webops_lead_id?: number | null;
|
|
187
|
+
devops_lead_id?: number | null;
|
|
188
|
+
dev_lead_id?: number | null;
|
|
189
|
+
seo_lead_id?: number | null;
|
|
190
|
+
client_contact?: string | null;
|
|
191
|
+
client_contact_email?: string | null;
|
|
192
|
+
}): Promise<any>;
|
|
193
|
+
deleteLaunch(id: number): Promise<{
|
|
194
|
+
success: boolean;
|
|
195
|
+
}>;
|
|
196
|
+
getSuccessFactors(launchId: number, itemId: number): Promise<{
|
|
197
|
+
factors: any[];
|
|
198
|
+
}>;
|
|
199
|
+
validateChecklistItem(launchId: number, itemId: number): Promise<any>;
|
|
200
|
+
getClaudeMd(launchId: number): Promise<{
|
|
201
|
+
content: string;
|
|
202
|
+
}>;
|
|
203
|
+
addNote(launchId: number, content: string): Promise<any>;
|
|
204
|
+
listFileSyncConfigs(filters?: {
|
|
205
|
+
enabled?: boolean;
|
|
206
|
+
search?: string;
|
|
207
|
+
sync_direction?: string;
|
|
208
|
+
}): Promise<{
|
|
209
|
+
success: boolean;
|
|
210
|
+
data: any[];
|
|
211
|
+
count: number;
|
|
212
|
+
}>;
|
|
213
|
+
getFileSyncJobs(filters?: {
|
|
214
|
+
config_id?: number;
|
|
215
|
+
status?: string;
|
|
216
|
+
limit?: number;
|
|
217
|
+
}): Promise<{
|
|
218
|
+
success: boolean;
|
|
219
|
+
data: any[];
|
|
220
|
+
count: number;
|
|
221
|
+
}>;
|
|
222
|
+
startFileSync(input: {
|
|
223
|
+
config_id: number;
|
|
224
|
+
trigger_type?: string;
|
|
225
|
+
triggered_by?: string;
|
|
226
|
+
confirmation_token?: string;
|
|
227
|
+
}): Promise<{
|
|
228
|
+
success: boolean;
|
|
229
|
+
data: any;
|
|
230
|
+
message: string;
|
|
231
|
+
}>;
|
|
232
|
+
cancelFileSync(jobId: string): Promise<{
|
|
233
|
+
success: boolean;
|
|
234
|
+
message: string;
|
|
235
|
+
}>;
|
|
236
|
+
getFileSyncConfirmation(configId: number): Promise<{
|
|
237
|
+
success: boolean;
|
|
238
|
+
data: {
|
|
239
|
+
token: string;
|
|
240
|
+
config_id: number;
|
|
241
|
+
expires_at: string;
|
|
242
|
+
ttl_seconds: number;
|
|
243
|
+
warnings: string[];
|
|
244
|
+
};
|
|
245
|
+
}>;
|
|
246
|
+
triggerNucleiScan(websiteId: number, options?: {
|
|
247
|
+
url?: string;
|
|
248
|
+
severity?: string;
|
|
249
|
+
templates?: string;
|
|
250
|
+
}): Promise<any>;
|
|
251
|
+
getNucleiResults(websiteId: number, options?: {
|
|
252
|
+
scan_id?: string;
|
|
253
|
+
limit?: number;
|
|
254
|
+
status?: string;
|
|
255
|
+
}): Promise<any>;
|
|
256
|
+
scanSecurityHeaders(websiteId: number): Promise<any>;
|
|
257
|
+
getSecurityHeadersResults(websiteId: number, scanId?: string): Promise<any>;
|
|
258
|
+
listSites(filters?: {
|
|
259
|
+
account_id?: number;
|
|
260
|
+
cms?: string;
|
|
261
|
+
environment?: string;
|
|
262
|
+
fru_hosted?: boolean;
|
|
263
|
+
retired?: string;
|
|
264
|
+
limit?: number;
|
|
265
|
+
offset?: number;
|
|
266
|
+
}): Promise<any>;
|
|
267
|
+
searchSites(query: string, limit?: number): Promise<any>;
|
|
268
|
+
getSite(siteId: number): Promise<any>;
|
|
269
|
+
createSite(production: {
|
|
270
|
+
account_id: number;
|
|
271
|
+
domain: string;
|
|
272
|
+
cms: string;
|
|
273
|
+
url_full?: string;
|
|
274
|
+
git_provider?: string;
|
|
275
|
+
git_link?: string;
|
|
276
|
+
hosting_provider?: string;
|
|
277
|
+
fru_hosted?: boolean;
|
|
278
|
+
k8s_cluster?: string;
|
|
279
|
+
k8s_namespace?: string;
|
|
280
|
+
}, staging?: Array<{
|
|
281
|
+
domain: string;
|
|
282
|
+
k8s_namespace: string;
|
|
283
|
+
}>): Promise<any>;
|
|
284
|
+
updateSite(siteId: number, updates: Record<string, any>): Promise<any>;
|
|
285
|
+
deleteSite(siteId: number, options?: {
|
|
286
|
+
reason?: string;
|
|
287
|
+
forward_url?: string;
|
|
288
|
+
}): Promise<any>;
|
|
289
|
+
getLocalSetupGuide(siteId: number): Promise<any>;
|
|
290
|
+
listClients(filters?: {
|
|
291
|
+
q?: string;
|
|
292
|
+
webops_lead?: string;
|
|
293
|
+
contract_type?: string;
|
|
294
|
+
tier?: string;
|
|
295
|
+
marketing?: boolean;
|
|
296
|
+
status?: string;
|
|
297
|
+
limit?: number;
|
|
298
|
+
}): Promise<any>;
|
|
299
|
+
getClient(accountId: number): Promise<any>;
|
|
300
|
+
updateClientProfile(accountId: number, updates: Record<string, any>): Promise<any>;
|
|
301
|
+
shieldListDomains(filters?: {
|
|
302
|
+
status?: string;
|
|
303
|
+
account_id?: number;
|
|
304
|
+
}): Promise<any>;
|
|
305
|
+
shieldAddDomain(input: {
|
|
306
|
+
domain: string;
|
|
307
|
+
origin_type?: 'custom' | 's3';
|
|
308
|
+
origin_host?: string;
|
|
309
|
+
origin_port?: number;
|
|
310
|
+
origin_protocol?: string;
|
|
311
|
+
s3_bucket?: string;
|
|
312
|
+
s3_region?: string;
|
|
313
|
+
s3_origin_path?: string;
|
|
314
|
+
website_id?: number;
|
|
315
|
+
account_id?: number;
|
|
316
|
+
cache_profile?: string;
|
|
317
|
+
waf_profile?: string;
|
|
318
|
+
geo_block_countries?: string[];
|
|
319
|
+
bot_control_enabled?: boolean;
|
|
320
|
+
notes?: string;
|
|
321
|
+
}): Promise<any>;
|
|
322
|
+
shieldGetDomain(domainId: number): Promise<any>;
|
|
323
|
+
shieldUpdateDomain(domainId: number, updates: Record<string, any>): Promise<any>;
|
|
324
|
+
shieldRemoveDomain(domainId: number): Promise<any>;
|
|
325
|
+
shieldGetMetrics(): Promise<any>;
|
|
326
|
+
shieldVerifyDomain(domainId: number): Promise<any>;
|
|
327
|
+
private fetchText;
|
|
328
|
+
trustedIpListRanges(filters?: {
|
|
329
|
+
group?: string;
|
|
330
|
+
include_pending?: boolean;
|
|
331
|
+
include_expired?: boolean;
|
|
332
|
+
}): Promise<any>;
|
|
333
|
+
trustedIpAddRange(input: {
|
|
334
|
+
group_id: number;
|
|
335
|
+
cidr: string;
|
|
336
|
+
label?: string;
|
|
337
|
+
purpose?: string;
|
|
338
|
+
ticket_ref?: string;
|
|
339
|
+
expires_at?: string;
|
|
340
|
+
override_reason?: string;
|
|
341
|
+
}): Promise<any>;
|
|
342
|
+
trustedIpUpdateRange(id: number, updates: Record<string, unknown>): Promise<any>;
|
|
343
|
+
trustedIpRemoveRange(id: number): Promise<any>;
|
|
344
|
+
trustedIpExport(opts?: {
|
|
345
|
+
format?: string;
|
|
346
|
+
group?: string;
|
|
347
|
+
purpose?: string;
|
|
348
|
+
separator?: string;
|
|
349
|
+
}): Promise<string>;
|
|
350
|
+
listFreezes(): Promise<any>;
|
|
351
|
+
freezeRepo(input: {
|
|
352
|
+
repo: string;
|
|
353
|
+
reason: string;
|
|
354
|
+
days?: number;
|
|
355
|
+
starts_at?: string;
|
|
356
|
+
ends_at?: string;
|
|
357
|
+
}): Promise<any>;
|
|
358
|
+
updateFreeze(id: number, updates: Record<string, unknown>): Promise<any>;
|
|
359
|
+
unfreeze(input: {
|
|
360
|
+
id?: number;
|
|
361
|
+
repo?: string;
|
|
362
|
+
}): Promise<any>;
|
|
363
|
+
backupListSites(): Promise<any>;
|
|
364
|
+
backupGetConfig(): Promise<any>;
|
|
365
|
+
backupListEligible(): Promise<any>;
|
|
366
|
+
backupEnable(siteId: number): Promise<any>;
|
|
367
|
+
backupTrigger(websiteId: number, triggerType?: string): Promise<any>;
|
|
368
|
+
backupCheckTrigger(websiteId: number): Promise<any>;
|
|
369
|
+
backupListBackups(siteId: string): Promise<any>;
|
|
370
|
+
backupGetStatus(options: {
|
|
371
|
+
backupId?: string;
|
|
372
|
+
websiteId?: number;
|
|
373
|
+
}): Promise<any>;
|
|
374
|
+
backupDownload(backupId: string): Promise<any>;
|
|
375
|
+
backupDownloadPrepared(input: {
|
|
376
|
+
siteId: string;
|
|
377
|
+
backupId: string;
|
|
378
|
+
downloadType: string;
|
|
379
|
+
format?: string;
|
|
380
|
+
sanitize?: boolean;
|
|
381
|
+
}): Promise<any>;
|
|
382
|
+
backupSanitizeStatus(jobId: string): Promise<any>;
|
|
383
|
+
backupListPairings(siteId?: number): Promise<any>;
|
|
384
|
+
backupUpdatePairing(siteId: number, pairingConfig: Record<string, any>): Promise<any>;
|
|
385
|
+
backupDeletePairing(siteId: number): Promise<any>;
|
|
386
|
+
kinstaBackupListSites(): Promise<any>;
|
|
387
|
+
kinstaBackupListBackups(siteId: string): Promise<any>;
|
|
388
|
+
kinstaBackupDownload(s3Key: string): Promise<any>;
|
|
389
|
+
cloneToStagingConfirm(productionSiteId: number, stagingSiteId: number): Promise<any>;
|
|
390
|
+
cloneToStaging(params: {
|
|
391
|
+
productionSiteId: number;
|
|
392
|
+
stagingSiteId: number;
|
|
393
|
+
includeFiles?: boolean;
|
|
394
|
+
includeDatabase?: boolean;
|
|
395
|
+
runSearchReplace?: boolean;
|
|
396
|
+
confirmationToken: string;
|
|
397
|
+
backupId?: string;
|
|
398
|
+
}): Promise<any>;
|
|
399
|
+
getCloneStatus(cloneId: string): Promise<any>;
|
|
400
|
+
listCloneOperations(params?: {
|
|
401
|
+
productionSiteId?: number;
|
|
402
|
+
stagingSiteId?: number;
|
|
403
|
+
limit?: number;
|
|
404
|
+
}): Promise<any>;
|
|
405
|
+
getDevEnvironmentInfo(siteId: number): Promise<any>;
|
|
406
|
+
}
|
|
10
407
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -98,6 +98,7 @@ const TOOL_PERMISSIONS = {
|
|
|
98
98
|
fcp_trusted_ip_remove_range: 'super_admin',
|
|
99
99
|
fcp_backup_delete_pairing: 'super_admin',
|
|
100
100
|
fcp_filesync_cancel_sync: 'super_admin',
|
|
101
|
+
fcp_unfreeze: 'super_admin', // lifting a freeze releases a held deploy
|
|
101
102
|
// --- admin+: mutating ops with real-world side effects ---
|
|
102
103
|
fcp_create_launch: 'admin',
|
|
103
104
|
fcp_update_launch: 'admin',
|
|
@@ -108,6 +109,8 @@ const TOOL_PERMISSIONS = {
|
|
|
108
109
|
fcp_shield_update_domain: 'admin',
|
|
109
110
|
fcp_trusted_ip_add_range: 'admin',
|
|
110
111
|
fcp_trusted_ip_update_range: 'admin',
|
|
112
|
+
fcp_freeze_repo: 'admin',
|
|
113
|
+
fcp_update_freeze: 'admin',
|
|
111
114
|
fcp_backup_enable: 'admin',
|
|
112
115
|
fcp_backup_trigger: 'admin',
|
|
113
116
|
fcp_backup_check_trigger: 'admin',
|
|
@@ -157,6 +160,7 @@ const TOOL_PERMISSIONS = {
|
|
|
157
160
|
fcp_shield_get_metrics: 'viewer',
|
|
158
161
|
fcp_trusted_ip_list_ranges: 'viewer',
|
|
159
162
|
fcp_trusted_ip_export: 'viewer',
|
|
163
|
+
fcp_list_freezes: 'viewer',
|
|
160
164
|
fcp_backup_list_sites: 'viewer',
|
|
161
165
|
fcp_backup_get_config: 'viewer',
|
|
162
166
|
fcp_backup_list_eligible: 'viewer',
|
|
@@ -346,7 +350,7 @@ async function initializeProjectDetection() {
|
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
352
|
// API Client
|
|
349
|
-
class FCPClient {
|
|
353
|
+
export class FCPClient {
|
|
350
354
|
baseUrl;
|
|
351
355
|
token;
|
|
352
356
|
defaultTimeout = 15000; // 15 seconds
|
|
@@ -795,6 +799,36 @@ class FCPClient {
|
|
|
795
799
|
return this.fetchText(`/api/infrastructure/trusted-ips/export${qs ? `?${qs}` : ''}`);
|
|
796
800
|
}
|
|
797
801
|
// ============================================================================
|
|
802
|
+
// Tasker Freeze Management Methods
|
|
803
|
+
// ============================================================================
|
|
804
|
+
async listFreezes() {
|
|
805
|
+
return this.fetch('/api/ticket-workflow/freeze');
|
|
806
|
+
}
|
|
807
|
+
async freezeRepo(input) {
|
|
808
|
+
return this.fetch('/api/ticket-workflow/freeze', {
|
|
809
|
+
method: 'POST',
|
|
810
|
+
body: JSON.stringify(input),
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async updateFreeze(id, updates) {
|
|
814
|
+
return this.fetch('/api/ticket-workflow/freeze', {
|
|
815
|
+
method: 'PATCH',
|
|
816
|
+
body: JSON.stringify({ id, ...updates }),
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
async unfreeze(input) {
|
|
820
|
+
const hasId = input.id !== undefined && input.id !== null;
|
|
821
|
+
const hasRepo = typeof input.repo === 'string' && input.repo.length > 0;
|
|
822
|
+
if (hasId === hasRepo) {
|
|
823
|
+
throw new Error('unfreeze requires exactly one of "id" or "repo"');
|
|
824
|
+
}
|
|
825
|
+
const body = hasId ? { id: input.id } : { repo: input.repo };
|
|
826
|
+
return this.fetch('/api/ticket-workflow/freeze', {
|
|
827
|
+
method: 'DELETE',
|
|
828
|
+
body: JSON.stringify(body),
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
// ============================================================================
|
|
798
832
|
// Backup Management Methods
|
|
799
833
|
// ============================================================================
|
|
800
834
|
async backupListSites() {
|
|
@@ -3075,6 +3109,55 @@ const TOOLS = [
|
|
|
3075
3109
|
},
|
|
3076
3110
|
},
|
|
3077
3111
|
},
|
|
3112
|
+
{
|
|
3113
|
+
name: 'fcp_list_freezes',
|
|
3114
|
+
description: 'List Tasker auto-merge freezes. Returns frozen_repos (active now), scheduled_repos (future windows), and available_repos (every repo you may freeze, with project keys + domains). A frozen repo has its release/security PRs held from the 6-7 AM MT deployment window. Call this before fcp_freeze_repo to pick a valid repo and avoid duplicate freezes.',
|
|
3115
|
+
inputSchema: {
|
|
3116
|
+
type: 'object',
|
|
3117
|
+
properties: {},
|
|
3118
|
+
},
|
|
3119
|
+
},
|
|
3120
|
+
{
|
|
3121
|
+
name: 'fcp_freeze_repo',
|
|
3122
|
+
description: 'Schedule a Tasker auto-merge freeze for a repo (blocks release-PR auto-promotion + security auto-merge while active). Provide either days (1-90) or an explicit ends_at; starts_at defaults to now and cannot be backdated >5 min. The repo must exist in github_repo_mappings (else 404 \u2014 use fcp_list_freezes available_repos). Appends a new window each call.',
|
|
3123
|
+
inputSchema: {
|
|
3124
|
+
type: 'object',
|
|
3125
|
+
properties: {
|
|
3126
|
+
repo: { type: 'string', description: 'owner/repo, e.g. "fruition/metroairport"' },
|
|
3127
|
+
reason: { type: 'string', description: 'Why the repo is being frozen (required)' },
|
|
3128
|
+
days: { type: 'number', description: 'Freeze length in days (1-90); alternative to ends_at' },
|
|
3129
|
+
starts_at: { type: 'string', description: 'ISO-8601 start (optional; defaults to now, no backdating >5 min)' },
|
|
3130
|
+
ends_at: { type: 'string', description: 'ISO-8601 end (alternative to days)' },
|
|
3131
|
+
},
|
|
3132
|
+
required: ['repo', 'reason'],
|
|
3133
|
+
},
|
|
3134
|
+
},
|
|
3135
|
+
{
|
|
3136
|
+
name: 'fcp_update_freeze',
|
|
3137
|
+
description: 'Edit an existing freeze by id (from fcp_list_freezes). Change the window (starts_at / ends_at, or days as a shorthand for ends_at) and/or the reason. Window rules match fcp_freeze_repo (<=90 days, no backdating >5 min).',
|
|
3138
|
+
inputSchema: {
|
|
3139
|
+
type: 'object',
|
|
3140
|
+
properties: {
|
|
3141
|
+
id: { type: 'number', description: 'Freeze id to edit' },
|
|
3142
|
+
starts_at: { type: 'string', description: 'New ISO-8601 start' },
|
|
3143
|
+
ends_at: { type: 'string', description: 'New ISO-8601 end' },
|
|
3144
|
+
days: { type: 'number', description: 'New length in days (recomputes ends_at from starts_at)' },
|
|
3145
|
+
reason: { type: 'string', description: 'New reason' },
|
|
3146
|
+
},
|
|
3147
|
+
required: ['id'],
|
|
3148
|
+
},
|
|
3149
|
+
},
|
|
3150
|
+
{
|
|
3151
|
+
name: 'fcp_unfreeze',
|
|
3152
|
+
description: 'Remove a Tasker freeze. Pass exactly one of: id (remove that single freeze) or repo (remove ALL active + scheduled freezes for that owner/repo). Lifting a freeze lets a held deploy through, so this is a super_admin action.',
|
|
3153
|
+
inputSchema: {
|
|
3154
|
+
type: 'object',
|
|
3155
|
+
properties: {
|
|
3156
|
+
id: { type: 'number', description: 'Freeze id to remove (single)' },
|
|
3157
|
+
repo: { type: 'string', description: 'owner/repo to clear all active+scheduled freezes for' },
|
|
3158
|
+
},
|
|
3159
|
+
},
|
|
3160
|
+
},
|
|
3078
3161
|
// ============================================================================
|
|
3079
3162
|
// Backup Management Tools
|
|
3080
3163
|
// ============================================================================
|
|
@@ -4924,6 +5007,45 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
4924
5007
|
};
|
|
4925
5008
|
}
|
|
4926
5009
|
// ============================================================================
|
|
5010
|
+
// Tasker Freeze Management Handlers
|
|
5011
|
+
// ============================================================================
|
|
5012
|
+
case 'fcp_list_freezes': {
|
|
5013
|
+
const result = await client.listFreezes();
|
|
5014
|
+
return {
|
|
5015
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
5016
|
+
};
|
|
5017
|
+
}
|
|
5018
|
+
case 'fcp_freeze_repo': {
|
|
5019
|
+
const { repo, reason, days, starts_at, ends_at } = args;
|
|
5020
|
+
const result = await client.freezeRepo({ repo, reason, days, starts_at, ends_at });
|
|
5021
|
+
return {
|
|
5022
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
5023
|
+
};
|
|
5024
|
+
}
|
|
5025
|
+
case 'fcp_update_freeze': {
|
|
5026
|
+
const { id, starts_at, ends_at, days, reason } = args;
|
|
5027
|
+
const updates = {};
|
|
5028
|
+
if (starts_at !== undefined)
|
|
5029
|
+
updates.starts_at = starts_at;
|
|
5030
|
+
if (ends_at !== undefined)
|
|
5031
|
+
updates.ends_at = ends_at;
|
|
5032
|
+
if (days !== undefined)
|
|
5033
|
+
updates.days = days;
|
|
5034
|
+
if (reason !== undefined)
|
|
5035
|
+
updates.reason = reason;
|
|
5036
|
+
const result = await client.updateFreeze(id, updates);
|
|
5037
|
+
return {
|
|
5038
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
5039
|
+
};
|
|
5040
|
+
}
|
|
5041
|
+
case 'fcp_unfreeze': {
|
|
5042
|
+
const { id, repo } = args;
|
|
5043
|
+
const result = await client.unfreeze({ id, repo });
|
|
5044
|
+
return {
|
|
5045
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
5048
|
+
// ============================================================================
|
|
4927
5049
|
// Backup Management Handlers
|
|
4928
5050
|
// ============================================================================
|
|
4929
5051
|
case 'fcp_backup_list_sites': {
|
|
@@ -5581,7 +5703,7 @@ if (process.argv[2] === 'sync-skills') {
|
|
|
5581
5703
|
process.exit(1);
|
|
5582
5704
|
});
|
|
5583
5705
|
}
|
|
5584
|
-
else {
|
|
5706
|
+
else if (!process.env.VITEST) {
|
|
5585
5707
|
main().catch((error) => {
|
|
5586
5708
|
console.error('Fatal error:', error);
|
|
5587
5709
|
process.exit(1);
|
package/dist/skills-sync.d.ts
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* - `private: true` in frontmatter also opts out.
|
|
23
23
|
* - Network failures and missing auth never block startup — we log + continue.
|
|
24
24
|
*/
|
|
25
|
+
import { basename } from 'path';
|
|
25
26
|
export interface SkillFrontmatter {
|
|
26
27
|
name?: string;
|
|
27
28
|
description?: string;
|
|
@@ -151,5 +152,5 @@ export declare const __test__: {
|
|
|
151
152
|
detectSecret: typeof detectSecret;
|
|
152
153
|
pushSkipReason: typeof pushSkipReason;
|
|
153
154
|
hashBody: typeof hashBody;
|
|
154
|
-
basename:
|
|
155
|
+
basename: typeof basename;
|
|
155
156
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fruition/fcp-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "MCP Server for FCP Launch Coordination System - enables Claude Code to interact with FCP launches and track development time",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|