@velaro/mcp-server 0.6.93 → 0.6.95
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/package.json +1 -1
- package/server.js +321 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.95",
|
|
4
4
|
"description": "Velaro MCP server — connect Claude and other AI agents directly to your Velaro account: KB, workflows, bots, conversations, contacts, routing, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/server.js
CHANGED
|
@@ -151,6 +151,18 @@ function extractLogEntries(response) {
|
|
|
151
151
|
return [];
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Body for PUT avatar/groups|workflows/{id}/override. Merge by default (only passed fields change, "" clears one);
|
|
156
|
+
* `replace: true` replaces the whole override. Mirrors cli/lib/commands/avatar.js.
|
|
157
|
+
*/
|
|
158
|
+
function avatarOverrideBody(args) {
|
|
159
|
+
const body = { merge: args.replace !== true };
|
|
160
|
+
for (const k of ['providerSlug', 'avatarId', 'personalityPresetSlug', 'voiceId', 'displayName', 'backgroundMode', 'backgroundValue']) {
|
|
161
|
+
if (args[k] !== undefined) body[k] = args[k];
|
|
162
|
+
}
|
|
163
|
+
return body;
|
|
164
|
+
}
|
|
165
|
+
|
|
154
166
|
async function messagingRequest(method, path, body) {
|
|
155
167
|
if (!MESSAGING_API) throw new Error(
|
|
156
168
|
'VELARO_MESSAGING_API is not configured. Add "VELARO_MESSAGING_API": "https://velaro-messaging-api-staging.azurewebsites.net" to your MCP env config.'
|
|
@@ -1715,6 +1727,8 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1715
1727
|
v20_site_id: { type: 'number', description: 'V20 site ID to migrate TO (defaults to the authenticated site)' },
|
|
1716
1728
|
dry_run: { type: 'boolean', description: 'Preview what would be created without creating. Default: false.' },
|
|
1717
1729
|
enable: { type: 'boolean', description: 'Enable created workflows immediately. Default: false.' },
|
|
1730
|
+
include_non_routing: { type: 'boolean', description: 'Also migrate v10 rules with IsRouting=false (group-assignment rules). Default: false.' },
|
|
1731
|
+
route_bot_groups_to_team: { type: 'boolean', description: 'Route to the v20 team named after the v10 group even if it had a v10 bot. Default: false.' },
|
|
1718
1732
|
team_mappings: { type: 'array', description: 'Override auto-resolution: [{v10GroupId, v20TeamId}]', items: { type: 'object' } },
|
|
1719
1733
|
ai_config_mappings: { type: 'array', description: 'Override auto-resolution: [{v10GroupId, v20AiConfigId}]', items: { type: 'object' } },
|
|
1720
1734
|
},
|
|
@@ -1729,10 +1743,25 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1729
1743
|
properties: {
|
|
1730
1744
|
v10_site_id: { type: 'number', description: 'V10 (Livefluence) site ID' },
|
|
1731
1745
|
v20_site_id: { type: 'number', description: 'V20 site ID to match against (for name suggestions)' },
|
|
1746
|
+
include_non_routing: { type: 'boolean', description: 'Also include v10 rules with IsRouting=false. Default: false.' },
|
|
1732
1747
|
},
|
|
1733
1748
|
required: ['v10_site_id'],
|
|
1734
1749
|
},
|
|
1735
1750
|
},
|
|
1751
|
+
{
|
|
1752
|
+
name: 'livefluence_create_teams',
|
|
1753
|
+
description: 'Copy v10 (Livefluence) groups to v20 teams on a site. v10 is read-only; idempotent by name; "Default Group" maps to the site default team; members are not copied. Use dry_run=true first.',
|
|
1754
|
+
inputSchema: {
|
|
1755
|
+
type: 'object',
|
|
1756
|
+
properties: {
|
|
1757
|
+
v10_site_id: { type: 'number', description: 'V10 (Livefluence) site ID to copy FROM' },
|
|
1758
|
+
v20_site_id: { type: 'number', description: 'V20 site ID to create teams on' },
|
|
1759
|
+
group_names: { type: 'array', items: { type: 'string' }, description: 'Group names to copy (default: every non-deleted v10 group)' },
|
|
1760
|
+
dry_run: { type: 'boolean', description: 'Preview without creating. Default: false.' },
|
|
1761
|
+
},
|
|
1762
|
+
required: ['v10_site_id', 'v20_site_id'],
|
|
1763
|
+
},
|
|
1764
|
+
},
|
|
1736
1765
|
|
|
1737
1766
|
// ── Smart Routing Engine ──────────────────────────────────────────────────
|
|
1738
1767
|
{
|
|
@@ -3328,19 +3357,24 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3328
3357
|
},
|
|
3329
3358
|
{
|
|
3330
3359
|
name: 'avatar_get_group_effective',
|
|
3331
|
-
description: 'Show the effective avatar settings for a group
|
|
3332
|
-
inputSchema: { type: 'object', properties: { groupId: { type: 'number' } }, required: ['groupId'] },
|
|
3360
|
+
description: 'Show the effective avatar settings (person, personality, voice, display name, backdrop) for a group, layered perWorkflow ?? perGroup ?? perSite. Pass workflowId too to see what a conversation in that workflow inside that group gets. Also returns whether each override exists.',
|
|
3361
|
+
inputSchema: { type: 'object', properties: { groupId: { type: 'number', description: 'Team (group) id.' }, workflowId: { type: 'number', description: 'Optional workflow id to layer on top of the group.' } }, required: ['groupId'] },
|
|
3333
3362
|
},
|
|
3334
3363
|
{
|
|
3335
3364
|
name: 'avatar_set_group_override',
|
|
3336
|
-
description: 'Override avatar/personality/
|
|
3365
|
+
description: 'Override the avatar person/personality/voice/display name/backdrop for one group (a group is a Team). Only the fields you pass change (merge); pass an empty string to clear one field back to the site default. A library avatarId always uses the velaro provider. Backdrop: backgroundMode none|color|gradient|image with backgroundValue (hex, "#a,#b", or an https image URL).',
|
|
3337
3366
|
inputSchema: {
|
|
3338
3367
|
type: 'object',
|
|
3339
3368
|
properties: {
|
|
3340
3369
|
groupId: { type: 'number' },
|
|
3341
3370
|
providerSlug: { type: 'string' },
|
|
3342
|
-
avatarId: { type: 'string' },
|
|
3371
|
+
avatarId: { type: 'string', description: 'Library slug (see avatar_list_library), e.g. priya.' },
|
|
3343
3372
|
personalityPresetSlug: { type: 'string' },
|
|
3373
|
+
voiceId: { type: 'string', description: 'ElevenLabs voice id.' },
|
|
3374
|
+
displayName: { type: 'string', description: 'Visitor-facing avatar name.' },
|
|
3375
|
+
backgroundMode: { type: 'string', description: 'none | color | gradient | image. "none" = explicitly no backdrop.' },
|
|
3376
|
+
backgroundValue: { type: 'string', description: 'Hex color, "#a,#b" gradient, or https image URL.' },
|
|
3377
|
+
replace: { type: 'boolean', description: 'true = replace the whole override (omitted fields inherit) instead of merging.' },
|
|
3344
3378
|
},
|
|
3345
3379
|
required: ['groupId'],
|
|
3346
3380
|
},
|
|
@@ -3350,9 +3384,38 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3350
3384
|
description: 'Reset one group to the site default avatar settings (removes its override).',
|
|
3351
3385
|
inputSchema: { type: 'object', properties: { groupId: { type: 'number' } }, required: ['groupId'] },
|
|
3352
3386
|
},
|
|
3387
|
+
{
|
|
3388
|
+
name: 'avatar_get_workflow_effective',
|
|
3389
|
+
description: 'Show the effective avatar settings for a workflow (workflow override, else its group, else site). Pass groupId to include a group override beneath the workflow.',
|
|
3390
|
+
inputSchema: { type: 'object', properties: { workflowId: { type: 'number' }, groupId: { type: 'number' } }, required: ['workflowId'] },
|
|
3391
|
+
},
|
|
3392
|
+
{
|
|
3393
|
+
name: 'avatar_set_workflow_override',
|
|
3394
|
+
description: 'Override the avatar person/personality/voice/display name/backdrop for one workflow (wins over its group and the site). Same fields and merge semantics as avatar_set_group_override. Example: library avatar priya with the Timken HR office backdrop https://admin.velaro.com/avatar-backdrops/timken-hr-office.png for the recruiter workflow.',
|
|
3395
|
+
inputSchema: {
|
|
3396
|
+
type: 'object',
|
|
3397
|
+
properties: {
|
|
3398
|
+
workflowId: { type: 'number' },
|
|
3399
|
+
providerSlug: { type: 'string' },
|
|
3400
|
+
avatarId: { type: 'string' },
|
|
3401
|
+
personalityPresetSlug: { type: 'string' },
|
|
3402
|
+
voiceId: { type: 'string' },
|
|
3403
|
+
displayName: { type: 'string' },
|
|
3404
|
+
backgroundMode: { type: 'string', description: 'none | color | gradient | image' },
|
|
3405
|
+
backgroundValue: { type: 'string' },
|
|
3406
|
+
replace: { type: 'boolean' },
|
|
3407
|
+
},
|
|
3408
|
+
required: ['workflowId'],
|
|
3409
|
+
},
|
|
3410
|
+
},
|
|
3411
|
+
{
|
|
3412
|
+
name: 'avatar_reset_workflow',
|
|
3413
|
+
description: 'Reset one workflow to its group / site default avatar settings (removes its override).',
|
|
3414
|
+
inputSchema: { type: 'object', properties: { workflowId: { type: 'number' } }, required: ['workflowId'] },
|
|
3415
|
+
},
|
|
3353
3416
|
{
|
|
3354
3417
|
name: 'avatar_reset_all_overrides',
|
|
3355
|
-
description: 'Reset ALL group overrides for the calling site back to the site default.',
|
|
3418
|
+
description: 'Reset ALL group and workflow overrides for the calling site back to the site default.',
|
|
3356
3419
|
inputSchema: { type: 'object', properties: {} },
|
|
3357
3420
|
},
|
|
3358
3421
|
|
|
@@ -5177,18 +5240,138 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
5177
5240
|
required: ['listingId'],
|
|
5178
5241
|
},
|
|
5179
5242
|
},
|
|
5243
|
+
// -- Job Board hosted pages (package "job-board-hosted", default OFF: 403 for a site without it) --
|
|
5244
|
+
{
|
|
5245
|
+
name: 'jobboard_hosted_status',
|
|
5246
|
+
description: 'Hosted public job pages for this site: is the package included, are the pages published, and the opaque board link, sitemap, Indeed feed and Google feed URLs (the feed URLs contain a secret key). Returns { entitled, enabled, boardUrl, sitemapUrl, indeedFeedUrl, googleFeedUrl, publicApplyEnabled, eeocSelfIdAvailable, liveListings }; { entitled:false } without the package.',
|
|
5247
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
5248
|
+
},
|
|
5249
|
+
{
|
|
5250
|
+
name: 'jobboard_hosted_set',
|
|
5251
|
+
description: 'Publish or unpublish the hosted job pages (apply-if-present). enabled=true issues the opaque board link and feed key the first time. regenerateLink=true issues a NEW board link and every old hosted URL answers 404 (administrators only). Requires the Job Board hosted pages package (403 otherwise).',
|
|
5252
|
+
inputSchema: {
|
|
5253
|
+
type: 'object',
|
|
5254
|
+
properties: {
|
|
5255
|
+
enabled: { type: 'boolean' },
|
|
5256
|
+
regenerateLink: { type: 'boolean', description: 'Retire the current board link and issue a new one (administrators only)' },
|
|
5257
|
+
},
|
|
5258
|
+
required: [],
|
|
5259
|
+
},
|
|
5260
|
+
},
|
|
5261
|
+
{
|
|
5262
|
+
name: 'jobboard_rotate_feed_key',
|
|
5263
|
+
description: 'Rotate the outbound feed key: the current Indeed and Google feed URLs stop working immediately and the response carries the new ones. Administrators only; requires the Job Board hosted pages package (403 otherwise).',
|
|
5264
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
5265
|
+
},
|
|
5266
|
+
{
|
|
5267
|
+
name: 'jobboard_set_listing_pay',
|
|
5268
|
+
description: 'Set or clear the pay range of a job listing (pay transparency): shown on the hosted page and in its schema.org baseSalary. A manual value is never overwritten by a feed sync. Pass clear=true to remove it. Requires the Job Board hosted pages package (403 otherwise); 404 for an id that is not on this site.',
|
|
5269
|
+
inputSchema: {
|
|
5270
|
+
type: 'object',
|
|
5271
|
+
properties: {
|
|
5272
|
+
listingId: { type: 'number' },
|
|
5273
|
+
min: { type: 'number', description: 'Minimum (or only) amount, greater than 0' },
|
|
5274
|
+
max: { type: 'number', description: 'Maximum amount, at least min (optional)' },
|
|
5275
|
+
currency: { type: 'string', description: '3-letter ISO code, default USD' },
|
|
5276
|
+
period: { type: 'string', description: 'Hour | Day | Week | Month | Year' },
|
|
5277
|
+
clear: { type: 'boolean', description: 'Remove the stated pay' },
|
|
5278
|
+
},
|
|
5279
|
+
required: ['listingId'],
|
|
5280
|
+
},
|
|
5281
|
+
},
|
|
5180
5282
|
{
|
|
5181
5283
|
name: 'jobboard_move_application_stage',
|
|
5182
|
-
description: 'Move a candidate application to a new HR/agency-side pipeline stage on the applicant Kanban board
|
|
5284
|
+
description: 'Move a candidate application to a new HR/agency-side pipeline stage on the applicant Kanban board. Default stages: Applied, Screened, Interview, Offer, Hired, Rejected; a site with the Job board pipeline package uses its own configured stage keys (see jobboard_pipeline_get). Optional note is recorded in the stage history.',
|
|
5183
5285
|
inputSchema: {
|
|
5184
5286
|
type: 'object',
|
|
5185
5287
|
properties: {
|
|
5186
5288
|
applicationId: { type: 'number' },
|
|
5187
|
-
stage: { type: 'string', description: 'Applied | Screened | Interview | Offer | Hired | Rejected' },
|
|
5289
|
+
stage: { type: 'string', description: 'A stage key from jobboard_pipeline_get (default list: Applied | Screened | Interview | Offer | Hired | Rejected)' },
|
|
5290
|
+
note: { type: 'string', description: 'Optional note recorded in the stage history (2000 characters max)' },
|
|
5188
5291
|
},
|
|
5189
5292
|
required: ['applicationId', 'stage'],
|
|
5190
5293
|
},
|
|
5191
5294
|
},
|
|
5295
|
+
// -- Job Board pipeline (package "job-board-pipeline", default OFF: 403 job_board_pipeline_not_entitled without it, except jobboard_pipeline_get) --
|
|
5296
|
+
{
|
|
5297
|
+
name: 'jobboard_pipeline_get',
|
|
5298
|
+
description: 'The recruiter pipeline stages for this site. Returns { entitled, source: "default"|"caseType", caseTypeId, stages:[{key,label,color,applicantVisible,applicantLabel}] }. Without the Job board pipeline package it returns the default list with entitled:false (stage moves still work on the default stages).',
|
|
5299
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
5300
|
+
},
|
|
5301
|
+
{
|
|
5302
|
+
name: 'jobboard_pipeline_set',
|
|
5303
|
+
description: 'Replace the pipeline stages (1 to 12, unique keys up to 64 characters). Removing a stage that still holds applications is refused with a 400 naming the count; move them first. Requires the Job board pipeline package (403 otherwise). Applicants see only stages with applicantVisible=true (using applicantLabel or label); every other stage shows as In review.',
|
|
5304
|
+
inputSchema: {
|
|
5305
|
+
type: 'object',
|
|
5306
|
+
properties: {
|
|
5307
|
+
stages: {
|
|
5308
|
+
type: 'array',
|
|
5309
|
+
description: 'The full ordered stage list',
|
|
5310
|
+
items: {
|
|
5311
|
+
type: 'object',
|
|
5312
|
+
properties: {
|
|
5313
|
+
key: { type: 'string' },
|
|
5314
|
+
label: { type: 'string' },
|
|
5315
|
+
color: { type: 'string', description: '#rrggbb (optional)' },
|
|
5316
|
+
applicantVisible: { type: 'boolean' },
|
|
5317
|
+
applicantLabel: { type: 'string', description: 'Name applicants see (optional)' },
|
|
5318
|
+
},
|
|
5319
|
+
required: ['key', 'label'],
|
|
5320
|
+
},
|
|
5321
|
+
},
|
|
5322
|
+
},
|
|
5323
|
+
required: ['stages'],
|
|
5324
|
+
},
|
|
5325
|
+
},
|
|
5326
|
+
{
|
|
5327
|
+
name: 'jobboard_application_history',
|
|
5328
|
+
description: 'Stage, note and assignment history of one application, newest first: { events:[{id,kind:"Stage"|"Note"|"Assign",fromStage,toStage,actorType:"User"|"ApiKey"|"CaseSync"|"System",actorId,at,note}] }. For an Assign event the new recruiter is in note (empty = unassigned) and toStage is only the stage at that time. Requires the Job board pipeline package (403 otherwise); 404 for an id not on this site.',
|
|
5329
|
+
inputSchema: { type: 'object', properties: { applicationId: { type: 'number' } }, required: ['applicationId'] },
|
|
5330
|
+
},
|
|
5331
|
+
{
|
|
5332
|
+
name: 'jobboard_application_note',
|
|
5333
|
+
description: 'Add an internal note to an application (1 to 2000 characters). Never shown to the applicant. Requires the Job board pipeline package (403 otherwise).',
|
|
5334
|
+
inputSchema: {
|
|
5335
|
+
type: 'object',
|
|
5336
|
+
properties: { applicationId: { type: 'number' }, note: { type: 'string' } },
|
|
5337
|
+
required: ['applicationId', 'note'],
|
|
5338
|
+
},
|
|
5339
|
+
},
|
|
5340
|
+
{
|
|
5341
|
+
name: 'jobboard_application_assign',
|
|
5342
|
+
description: 'Assign a recruiter to an application (free text up to 200 characters, for example an email). Pass assignedTo as null or an empty string to unassign. Requires the Job board pipeline package (403 otherwise).',
|
|
5343
|
+
inputSchema: {
|
|
5344
|
+
type: 'object',
|
|
5345
|
+
properties: { applicationId: { type: 'number' }, assignedTo: { type: ['string', 'null'] } },
|
|
5346
|
+
required: ['applicationId'],
|
|
5347
|
+
},
|
|
5348
|
+
},
|
|
5349
|
+
{
|
|
5350
|
+
name: 'jobboard_retention_get',
|
|
5351
|
+
description: 'Applicant record retention settings: { enabled, dryRun, retentionDays, isFederalContractor, legalHold, floorDays, effectiveDays, lastRunAt, lastRunDeleted, lastRunWouldDelete }. Records are never deleted before 1 year (2 years for federal contractors; 29 CFR 1602.14), so effectiveDays is never below floorDays. Requires the Job board pipeline package (403 otherwise).',
|
|
5352
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
5353
|
+
},
|
|
5354
|
+
{
|
|
5355
|
+
name: 'jobboard_retention_set',
|
|
5356
|
+
description: 'Change retention settings (apply-if-present). retentionDays below the legal floor is accepted and the floor applies. legalHold=true stops all deletion. Administrators only; requires the Job board pipeline package (403 otherwise).',
|
|
5357
|
+
inputSchema: {
|
|
5358
|
+
type: 'object',
|
|
5359
|
+
properties: {
|
|
5360
|
+
enabled: { type: 'boolean' },
|
|
5361
|
+
dryRun: { type: 'boolean', description: 'Count only, never delete' },
|
|
5362
|
+
retentionDays: { type: 'number' },
|
|
5363
|
+
isFederalContractor: { type: 'boolean' },
|
|
5364
|
+
legalHold: { type: 'boolean' },
|
|
5365
|
+
confirm: { type: 'boolean', description: 'Required true when dryRun=false or legalHold=false (this can start real deletion or lift a hold)' },
|
|
5366
|
+
},
|
|
5367
|
+
required: [],
|
|
5368
|
+
},
|
|
5369
|
+
},
|
|
5370
|
+
{
|
|
5371
|
+
name: 'jobboard_retention_run',
|
|
5372
|
+
description: 'Run retention now. dryRun defaults to true: counts what is due and deletes nothing. dryRun=false really deletes records past retention (never before the legal floor, never under a legal hold). Returns counts only: { dryRun, due, deleted, resumesDeleted, skippedLegalHold, floorDays }. Administrators only; requires the Job board pipeline package (403 otherwise).',
|
|
5373
|
+
inputSchema: { type: 'object', properties: { dryRun: { type: 'boolean', description: 'Default true' }, confirm: { type: 'boolean', description: 'Required true when dryRun=false (permanently deletes records)' } }, required: [] },
|
|
5374
|
+
},
|
|
5192
5375
|
|
|
5193
5376
|
// ── Velaro Appointments ──────────────────────────────────────────────────────
|
|
5194
5377
|
// Backend: server/Velaro.Messaging/Controllers/AppointmentsController.cs.
|
|
@@ -6924,7 +7107,10 @@ async function handleTool(name, args) {
|
|
|
6924
7107
|
|
|
6925
7108
|
// ── Livefluence Migration ──────────────────────────────────────────────
|
|
6926
7109
|
case 'livefluence_export': {
|
|
6927
|
-
const
|
|
7110
|
+
const params = [];
|
|
7111
|
+
if (args.v20_site_id) params.push(`v20SiteId=${args.v20_site_id}`);
|
|
7112
|
+
if (args.include_non_routing) params.push('includeNonRouting=true');
|
|
7113
|
+
const qs = params.length ? `?${params.join('&')}` : '';
|
|
6928
7114
|
const data = await api('GET', `/DatabaseTool/V10Export/${args.v10_site_id}${qs}`);
|
|
6929
7115
|
const lines = [
|
|
6930
7116
|
`V10 Site ${data.v10SiteId} — ${data.ruleCount} routing rule(s), ${data.groupCount} group(s)`,
|
|
@@ -6949,6 +7135,16 @@ async function handleTool(name, args) {
|
|
|
6949
7135
|
return lines.join('\n');
|
|
6950
7136
|
}
|
|
6951
7137
|
|
|
7138
|
+
case 'livefluence_create_teams': {
|
|
7139
|
+
const result = await api('POST', '/DatabaseTool/V10CreateTeams', {
|
|
7140
|
+
v10SiteId: args.v10_site_id,
|
|
7141
|
+
v20SiteId: args.v20_site_id,
|
|
7142
|
+
dryRun: args.dry_run ?? false,
|
|
7143
|
+
groupNames: args.group_names ?? [],
|
|
7144
|
+
});
|
|
7145
|
+
return JSON.stringify(result, null, 2);
|
|
7146
|
+
}
|
|
7147
|
+
|
|
6952
7148
|
case 'livefluence_seed_url_rules': {
|
|
6953
7149
|
const result = await api('POST', '/DatabaseTool/V10SeedUrlRules', {
|
|
6954
7150
|
siteId: args.site_id, aiConfigId: args.ai_config_id, dryRun: !!args.dry_run, rules: args.rules,
|
|
@@ -6962,6 +7158,8 @@ async function handleTool(name, args) {
|
|
|
6962
7158
|
v20SiteId: args.v20_site_id ?? null,
|
|
6963
7159
|
dryRun: args.dry_run ?? false,
|
|
6964
7160
|
enable: args.enable ?? false,
|
|
7161
|
+
includeNonRouting: args.include_non_routing ?? false,
|
|
7162
|
+
routeBotGroupsToTeam: args.route_bot_groups_to_team ?? false,
|
|
6965
7163
|
teamMappings: args.team_mappings ?? [],
|
|
6966
7164
|
aiConfigMappings: args.ai_config_mappings ?? [],
|
|
6967
7165
|
});
|
|
@@ -6977,6 +7175,7 @@ async function handleTool(name, args) {
|
|
|
6977
7175
|
for (const item of result.createdItems) {
|
|
6978
7176
|
lines.push(` [#${item.priority}] ${item.ruleName}${item.workflowId ? ` → id=${item.workflowId}` : ''}`);
|
|
6979
7177
|
lines.push(` Action: ${item.action}${item.v2AiConfigId ? `, aiConfigId=${item.v2AiConfigId}` : ''}${item.v2TeamId ? `, teamId=${item.v2TeamId}` : ''}`);
|
|
7178
|
+
for (const u of item.unconverted ?? []) lines.push(` not converted: ${u}`);
|
|
6980
7179
|
}
|
|
6981
7180
|
lines.push('');
|
|
6982
7181
|
}
|
|
@@ -8771,12 +8970,17 @@ async function handleTool(name, args) {
|
|
|
8771
8970
|
return JSON.stringify(await messagingRequest('POST', '/avatar/site-default', {
|
|
8772
8971
|
providerSlug: args.providerSlug, avatarId: args.avatarId, personalityPresetSlug: args.personalityPresetSlug }), null, 2);
|
|
8773
8972
|
case 'avatar_get_group_effective':
|
|
8774
|
-
return JSON.stringify(await messagingRequest('GET', `/avatar/groups/${Number(args.groupId)}/effective`), null, 2);
|
|
8973
|
+
return JSON.stringify(await messagingRequest('GET', `/avatar/groups/${Number(args.groupId)}/effective${args.workflowId != null ? `?workflowId=${Number(args.workflowId)}` : ''}`), null, 2);
|
|
8775
8974
|
case 'avatar_set_group_override':
|
|
8776
|
-
return JSON.stringify(await messagingRequest('PUT', `/avatar/groups/${Number(args.groupId)}/override`,
|
|
8777
|
-
providerSlug: args.providerSlug, avatarId: args.avatarId, personalityPresetSlug: args.personalityPresetSlug }), null, 2);
|
|
8975
|
+
return JSON.stringify(await messagingRequest('PUT', `/avatar/groups/${Number(args.groupId)}/override`, avatarOverrideBody(args)), null, 2);
|
|
8778
8976
|
case 'avatar_reset_group':
|
|
8779
8977
|
return JSON.stringify(await messagingRequest('DELETE', `/avatar/groups/${Number(args.groupId)}/override`), null, 2);
|
|
8978
|
+
case 'avatar_get_workflow_effective':
|
|
8979
|
+
return JSON.stringify(await messagingRequest('GET', `/avatar/workflows/${Number(args.workflowId)}/effective${args.groupId != null ? `?groupId=${Number(args.groupId)}` : ''}`), null, 2);
|
|
8980
|
+
case 'avatar_set_workflow_override':
|
|
8981
|
+
return JSON.stringify(await messagingRequest('PUT', `/avatar/workflows/${Number(args.workflowId)}/override`, avatarOverrideBody(args)), null, 2);
|
|
8982
|
+
case 'avatar_reset_workflow':
|
|
8983
|
+
return JSON.stringify(await messagingRequest('DELETE', `/avatar/workflows/${Number(args.workflowId)}/override`), null, 2);
|
|
8780
8984
|
case 'avatar_reset_all_overrides':
|
|
8781
8985
|
return JSON.stringify(await messagingRequest('POST', '/avatar/group-overrides/reset-all', {}), null, 2);
|
|
8782
8986
|
|
|
@@ -10512,10 +10716,115 @@ async function handleTool(name, args) {
|
|
|
10512
10716
|
return JSON.stringify(r, null, 2);
|
|
10513
10717
|
}
|
|
10514
10718
|
|
|
10719
|
+
case 'jobboard_hosted_status': {
|
|
10720
|
+
const r = await messagingGet('/Recruiting/Hosted');
|
|
10721
|
+
return JSON.stringify(r, null, 2);
|
|
10722
|
+
}
|
|
10723
|
+
case 'jobboard_hosted_set': {
|
|
10724
|
+
const body = {};
|
|
10725
|
+
if (args.enabled !== undefined) body.enabled = Boolean(args.enabled);
|
|
10726
|
+
if (args.regenerateLink) body.regenerateSlug = true;
|
|
10727
|
+
if (!Object.keys(body).length) throw new Error('Specify enabled and/or regenerateLink (use jobboard_hosted_status to read).');
|
|
10728
|
+
const r = await messagingPut('/Recruiting/Hosted', body);
|
|
10729
|
+
return JSON.stringify(r, null, 2);
|
|
10730
|
+
}
|
|
10731
|
+
case 'jobboard_rotate_feed_key': {
|
|
10732
|
+
const r = await messagingPost('/Recruiting/Hosted/FeedKey/Rotate', {});
|
|
10733
|
+
return JSON.stringify(r, null, 2);
|
|
10734
|
+
}
|
|
10735
|
+
case 'jobboard_set_listing_pay': {
|
|
10736
|
+
const id = Number(args.listingId);
|
|
10737
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('listingId must be a positive integer.');
|
|
10738
|
+
let body;
|
|
10739
|
+
if (args.clear) {
|
|
10740
|
+
body = { clear: true };
|
|
10741
|
+
} else {
|
|
10742
|
+
const lo = Number(args.min);
|
|
10743
|
+
if (args.min === undefined || !Number.isFinite(lo) || lo <= 0) throw new Error('min must be a number greater than 0 (or pass clear=true).');
|
|
10744
|
+
body = { salaryMin: lo };
|
|
10745
|
+
if (args.max !== undefined) {
|
|
10746
|
+
const hi = Number(args.max);
|
|
10747
|
+
if (!Number.isFinite(hi) || hi < lo) throw new Error('max must be a number greater than or equal to min.');
|
|
10748
|
+
body.salaryMax = hi;
|
|
10749
|
+
}
|
|
10750
|
+
const cur = String(args.currency ?? 'USD').trim().toUpperCase();
|
|
10751
|
+
if (!/^[A-Z]{3}$/.test(cur)) throw new Error('currency must be a 3-letter ISO code such as USD.');
|
|
10752
|
+
body.salaryCurrency = cur;
|
|
10753
|
+
const per = ['Hour', 'Day', 'Week', 'Month', 'Year'].find((p) => p.toLowerCase() === String(args.period ?? '').trim().toLowerCase());
|
|
10754
|
+
if (!per) throw new Error('period must be one of: Hour, Day, Week, Month, Year.');
|
|
10755
|
+
body.salaryPeriod = per;
|
|
10756
|
+
}
|
|
10757
|
+
const r = await messagingPut(`/Recruiting/Jobs/${id}/Pay`, body);
|
|
10758
|
+
return JSON.stringify(r, null, 2);
|
|
10759
|
+
}
|
|
10760
|
+
|
|
10515
10761
|
case 'jobboard_move_application_stage': {
|
|
10516
|
-
const
|
|
10762
|
+
const id = Number(args.applicationId);
|
|
10763
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('applicationId must be a positive integer.');
|
|
10764
|
+
const stage = String(args.stage ?? '').trim();
|
|
10765
|
+
if (!stage) throw new Error('stage is required.');
|
|
10766
|
+
const body = { stage };
|
|
10767
|
+
if (args.note !== undefined && String(args.note).trim()) {
|
|
10768
|
+
if (String(args.note).length > 2000) throw new Error('note must be 2000 characters or fewer.');
|
|
10769
|
+
body.note = String(args.note).trim();
|
|
10770
|
+
}
|
|
10771
|
+
const app = await messagingPut(`/Recruiting/Applications/${id}/Stage`, body);
|
|
10517
10772
|
return JSON.stringify(app, null, 2);
|
|
10518
10773
|
}
|
|
10774
|
+
case 'jobboard_pipeline_get': {
|
|
10775
|
+
return JSON.stringify(await messagingGet('/Recruiting/Pipeline'), null, 2);
|
|
10776
|
+
}
|
|
10777
|
+
case 'jobboard_pipeline_set': {
|
|
10778
|
+
const stages = args.stages;
|
|
10779
|
+
if (!Array.isArray(stages) || stages.length < 1 || stages.length > 12) throw new Error('stages must be an array of 1 to 12 stages.');
|
|
10780
|
+
const keys = new Set();
|
|
10781
|
+
for (const s of stages) {
|
|
10782
|
+
if (!s || typeof s.key !== 'string' || !s.key.trim() || s.key.length > 64) throw new Error('every stage needs a key (up to 64 characters).');
|
|
10783
|
+
if (typeof s.label !== 'string' || !s.label.trim()) throw new Error(`stage ${s.key} needs a label.`);
|
|
10784
|
+
if (keys.has(s.key)) throw new Error(`duplicate stage key: ${s.key}.`);
|
|
10785
|
+
keys.add(s.key);
|
|
10786
|
+
}
|
|
10787
|
+
return JSON.stringify(await messagingPut('/Recruiting/Pipeline', { stages }), null, 2);
|
|
10788
|
+
}
|
|
10789
|
+
case 'jobboard_application_history': {
|
|
10790
|
+
const id = Number(args.applicationId);
|
|
10791
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('applicationId must be a positive integer.');
|
|
10792
|
+
return JSON.stringify(await messagingGet(`/Recruiting/Applications/${id}/History`), null, 2);
|
|
10793
|
+
}
|
|
10794
|
+
case 'jobboard_application_note': {
|
|
10795
|
+
const id = Number(args.applicationId);
|
|
10796
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('applicationId must be a positive integer.');
|
|
10797
|
+
const note = String(args.note ?? '').trim();
|
|
10798
|
+
if (!note || note.length > 2000) throw new Error('note must be 1 to 2000 characters.');
|
|
10799
|
+
return JSON.stringify(await messagingPost(`/Recruiting/Applications/${id}/Notes`, { note }), null, 2);
|
|
10800
|
+
}
|
|
10801
|
+
case 'jobboard_application_assign': {
|
|
10802
|
+
const id = Number(args.applicationId);
|
|
10803
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('applicationId must be a positive integer.');
|
|
10804
|
+
const who = String(args.assignedTo ?? '').trim();
|
|
10805
|
+
if (who.length > 200) throw new Error('assignedTo must be 200 characters or fewer.');
|
|
10806
|
+
return JSON.stringify(await messagingPut(`/Recruiting/Applications/${id}/Assign`, { assignedTo: who || null }), null, 2);
|
|
10807
|
+
}
|
|
10808
|
+
case 'jobboard_retention_get': {
|
|
10809
|
+
return JSON.stringify(await messagingGet('/Recruiting/Retention'), null, 2);
|
|
10810
|
+
}
|
|
10811
|
+
case 'jobboard_retention_set': {
|
|
10812
|
+
const body = {};
|
|
10813
|
+
for (const k of ['enabled', 'dryRun', 'isFederalContractor', 'legalHold']) if (args[k] !== undefined) body[k] = Boolean(args[k]);
|
|
10814
|
+
if (args.retentionDays !== undefined) {
|
|
10815
|
+
const n = Number(args.retentionDays);
|
|
10816
|
+
if (!Number.isInteger(n) || n < 1 || n > 36500) throw new Error('retentionDays must be a whole number from 1 to 36500.');
|
|
10817
|
+
body.retentionDays = n;
|
|
10818
|
+
}
|
|
10819
|
+
if (!Object.keys(body).length) throw new Error('Specify at least one retention setting (use jobboard_retention_get to read).');
|
|
10820
|
+
if ((body.dryRun === false || body.legalHold === false) && args.confirm !== true) throw new Error('dryRun=false or legalHold=false can start real deletion of applicant records or lift a legal hold. Preview with jobboard_retention_run first, then repeat with confirm=true.');
|
|
10821
|
+
return JSON.stringify(await messagingPut('/Recruiting/Retention', body), null, 2);
|
|
10822
|
+
}
|
|
10823
|
+
case 'jobboard_retention_run': {
|
|
10824
|
+
const dry = args.dryRun === undefined ? true : Boolean(args.dryRun);
|
|
10825
|
+
if (!dry && args.confirm !== true) throw new Error('dryRun=false permanently deletes applicant records past retention. Preview first (dryRun=true), then repeat with confirm=true.');
|
|
10826
|
+
return JSON.stringify(await messagingPost(`/Recruiting/Retention/Run?dryRun=${dry ? 'true' : 'false'}`, {}), null, 2);
|
|
10827
|
+
}
|
|
10519
10828
|
|
|
10520
10829
|
// -- Velaro Appointments --
|
|
10521
10830
|
case 'appointments_manual_book': {
|