@velaro/cli 1.4.93 → 1.4.94
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/lib/commands/index.js +30 -1
- package/lib/commands/migrate.js +127 -1
- package/package.json +1 -1
package/lib/commands/index.js
CHANGED
|
@@ -238,6 +238,34 @@ const testCommand = {
|
|
|
238
238
|
|
|
239
239
|
// ── export ────────────────────────────────────────────────────────────────────
|
|
240
240
|
|
|
241
|
+
// -- create (Velaro staff only) -------------------------------------------------
|
|
242
|
+
// POST KnowledgeSetup/Staff/{siteId}/create-index on velaro-messaging. Idempotent: an existing
|
|
243
|
+
// index with the same (sanitized) name is returned unchanged.
|
|
244
|
+
|
|
245
|
+
const createCommand = {
|
|
246
|
+
command: 'create',
|
|
247
|
+
describe: 'Create a named virtual index on any site (Velaro staff only; idempotent)',
|
|
248
|
+
builder: (y) =>
|
|
249
|
+
y
|
|
250
|
+
.option('site', { type: 'number', demandOption: true, describe: 'Target site ID' })
|
|
251
|
+
.option('name', { type: 'string', demandOption: true, describe: 'Index name, e.g. 100140-troubleshooting' })
|
|
252
|
+
.option('purpose', {
|
|
253
|
+
type: 'string', default: 'general', choices: ['general', 'troubleshooting', 'catalog'],
|
|
254
|
+
describe: 'Index purpose',
|
|
255
|
+
})
|
|
256
|
+
.option('exclude-from-all-sources', { type: 'boolean', describe: 'Keep this index out of the ["*"] all-sources search' })
|
|
257
|
+
.option('json', { type: 'boolean', describe: 'Print raw JSON' }),
|
|
258
|
+
handler: async (argv) => {
|
|
259
|
+
const body = { indexName: argv.name, purpose: argv.purpose };
|
|
260
|
+
if (argv['exclude-from-all-sources'] !== undefined) body.excludeFromAllSources = argv['exclude-from-all-sources'];
|
|
261
|
+
const idx = await messagingPost(`/KnowledgeSetup/Staff/${encodeURIComponent(argv.site)}/create-index`, body);
|
|
262
|
+
if (argv.json) { console.log(JSON.stringify(idx, null, 2)); return; }
|
|
263
|
+
console.log(`
|
|
264
|
+
Index ready on site ${argv.site}: ${idx.name} (id: ${idx.id}, purpose: ${idx.purpose}, excludeFromAllSources: ${!!idx.excludeFromAllSources})
|
|
265
|
+
`);
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
|
|
241
269
|
export const indexCommand = {
|
|
242
270
|
command: 'index <subcommand>',
|
|
243
271
|
describe: 'Manage search indexes — view quota, physical index health, and reingest content',
|
|
@@ -248,6 +276,7 @@ export const indexCommand = {
|
|
|
248
276
|
.command(provisionCommand)
|
|
249
277
|
.command(reingestCommand)
|
|
250
278
|
.command(testCommand)
|
|
251
|
-
.
|
|
279
|
+
.command(createCommand)
|
|
280
|
+
.demandCommand(1, 'Specify a subcommand: list, site, provision, reingest, test, create'),
|
|
252
281
|
handler: () => {},
|
|
253
282
|
};
|
package/lib/commands/migrate.js
CHANGED
|
@@ -10,7 +10,9 @@ export const migrateCommand = {
|
|
|
10
10
|
.command(migrateLivefluenceCommand)
|
|
11
11
|
.command(migrateUrlRulesCommand)
|
|
12
12
|
.command(migrateTeamsCommand)
|
|
13
|
-
.
|
|
13
|
+
.command(migrateWorkflowsCommand)
|
|
14
|
+
.command(migrateRulesCommand)
|
|
15
|
+
.demandCommand(1, 'Specify a subcommand: export, livefluence, url-rules, teams, workflows, rules'),
|
|
14
16
|
handler: () => {},
|
|
15
17
|
};
|
|
16
18
|
|
|
@@ -195,3 +197,127 @@ const migrateTeamsCommand = {
|
|
|
195
197
|
console.log('\n Members are not copied; assign v20 agents to the new teams.\n');
|
|
196
198
|
}),
|
|
197
199
|
};
|
|
200
|
+
|
|
201
|
+
// -- staff, site-targeted workflow + rule ops (superadmin only) ----------------
|
|
202
|
+
// Act on ANOTHER v20 site's workflows/Rules after `migrate livefluence` created them disabled.
|
|
203
|
+
|
|
204
|
+
const csv = (v) => (v ? String(v).split(',').map(x => x.trim()).filter(Boolean) : []);
|
|
205
|
+
const printItems = (result) => {
|
|
206
|
+
for (const i of result.items ?? []) console.log(` ${String(i.status).padEnd(13)} [${i.id}] ${i.name ?? ''}${i.reason ? ` -- ${i.reason}` : ''}`);
|
|
207
|
+
for (const n of result.notFound ?? []) console.log(` not-found ${n}`);
|
|
208
|
+
console.log(`\n ${result.dryRun ? 'DRY RUN: ' : ''}changed ${result.changed}${result.refused !== undefined ? `, refused ${result.refused}` : ''}\n`);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const migrateWorkflowsCommand = {
|
|
212
|
+
command: 'workflows <op>',
|
|
213
|
+
describe: 'Staff: list / enable / disable / create / re-target workflows on a v20 site',
|
|
214
|
+
builder: (y) =>
|
|
215
|
+
y
|
|
216
|
+
.command({
|
|
217
|
+
command: 'list',
|
|
218
|
+
describe: 'List a v20 site workflows (id, name, enabled, priority, action, team/AI target)',
|
|
219
|
+
builder: (b) => b.option('site', { type: 'number', alias: 's', demandOption: true, describe: 'V20 site ID' }),
|
|
220
|
+
handler: runCommand(async (argv) => {
|
|
221
|
+
const r = await get(`/DatabaseTool/SiteWorkflows/${argv.site}`);
|
|
222
|
+
for (const w of r.workflows ?? []) {
|
|
223
|
+
const target = w.teamId ? `team ${w.teamId} ${w.teamName ?? ''}` : w.aiConfigId ? `ai ${w.aiConfigId} ${w.aiConfigName ?? ''}` : '-';
|
|
224
|
+
console.log(` [${w.id}] ${w.enabled ? 'ON ' : 'off'} p=${w.priority ?? '-'} ${String(w.action ?? '-').padEnd(12)} ${target.padEnd(28)} groups=${w.conditionGroups} ${w.name}`);
|
|
225
|
+
}
|
|
226
|
+
console.log(`\n ${r.count} workflow(s) on site ${r.siteId}\n`);
|
|
227
|
+
}),
|
|
228
|
+
})
|
|
229
|
+
.command({
|
|
230
|
+
command: 'set-enabled',
|
|
231
|
+
describe: 'Enable or disable workflows by ids or names. Enabling refuses partially converted triggers unless --force-partial.',
|
|
232
|
+
builder: (b) => b
|
|
233
|
+
.option('site', { type: 'number', alias: 's', demandOption: true, describe: 'V20 site ID' })
|
|
234
|
+
.option('ids', { type: 'string', describe: 'Comma-separated workflow ids' })
|
|
235
|
+
.option('names', { type: 'string', describe: 'Comma-separated workflow names' })
|
|
236
|
+
.option('enable', { type: 'boolean', demandOption: true, describe: '--enable to turn on, --no-enable to turn off' })
|
|
237
|
+
.option('v10-site-id', { type: 'number', alias: 'v', describe: 'Check each workflow against its same-named v10 rule conversion' })
|
|
238
|
+
.option('force-partial', { type: 'boolean', default: false, describe: 'Enable even if the v10 expression was not fully converted' })
|
|
239
|
+
.option('dry-run', { type: 'boolean', default: false }),
|
|
240
|
+
handler: runCommand(async (argv) => {
|
|
241
|
+
const r = await post('/DatabaseTool/SiteWorkflows/SetEnabled', {
|
|
242
|
+
siteId: argv.site, workflowIds: csv(argv.ids).map(Number), names: csv(argv.names),
|
|
243
|
+
enabled: argv.enable, dryRun: argv['dry-run'], forcePartial: argv['force-partial'], v10SiteId: argv['v10-site-id'] ?? null,
|
|
244
|
+
});
|
|
245
|
+
printItems(r);
|
|
246
|
+
}),
|
|
247
|
+
})
|
|
248
|
+
.command({
|
|
249
|
+
command: 'create',
|
|
250
|
+
describe: 'Create a workflow on a site from a nodes-blob JSON file (disabled unless --enable)',
|
|
251
|
+
builder: (b) => b
|
|
252
|
+
.option('site', { type: 'number', alias: 's', demandOption: true })
|
|
253
|
+
.option('name', { type: 'string', alias: 'n', demandOption: true })
|
|
254
|
+
.option('file', { type: 'string', alias: 'f', demandOption: true, describe: 'JSON file: the nodes object, e.g. {"1":{"type":"trigger",...},"2":{"type":"action",...}}' })
|
|
255
|
+
.option('trigger-type', { type: 'string', default: 'conversation_opened' })
|
|
256
|
+
.option('enable', { type: 'boolean', default: false })
|
|
257
|
+
.option('dry-run', { type: 'boolean', default: false }),
|
|
258
|
+
handler: runCommand(async (argv) => {
|
|
259
|
+
const { readFileSync } = await import('fs');
|
|
260
|
+
const nodesBlob = JSON.stringify(JSON.parse(readFileSync(argv.file, 'utf8')));
|
|
261
|
+
const r = await post('/DatabaseTool/SiteWorkflows/Create', {
|
|
262
|
+
siteId: argv.site, name: argv.name, triggerType: argv['trigger-type'], nodesBlob, enabled: argv.enable, dryRun: argv['dry-run'],
|
|
263
|
+
});
|
|
264
|
+
console.log(`\n ${r.status}${r.workflowId ? ` (workflow id=${r.workflowId})` : ''}\n`);
|
|
265
|
+
}),
|
|
266
|
+
})
|
|
267
|
+
.command({
|
|
268
|
+
command: 'set-action',
|
|
269
|
+
describe: 'Set a workflow action node to transferToAI {aiConfigId} or routeToTeam {teamId}',
|
|
270
|
+
builder: (b) => b
|
|
271
|
+
.option('site', { type: 'number', alias: 's', demandOption: true })
|
|
272
|
+
.option('workflow-id', { type: 'number', alias: 'w', demandOption: true })
|
|
273
|
+
.option('ai-config-id',{ type: 'number', describe: 'Set action to transferToAI with this AI config' })
|
|
274
|
+
.option('team-id', { type: 'number', describe: 'Set action to routeToTeam with this team' })
|
|
275
|
+
.check((a) => (!!a['ai-config-id'] !== !!a['team-id']) || 'Pass exactly one of --ai-config-id or --team-id')
|
|
276
|
+
.option('dry-run', { type: 'boolean', default: false }),
|
|
277
|
+
handler: runCommand(async (argv) => {
|
|
278
|
+
const r = await post('/DatabaseTool/SiteWorkflows/SetAction', {
|
|
279
|
+
siteId: argv.site, workflowId: argv['workflow-id'],
|
|
280
|
+
actionType: argv['ai-config-id'] ? 'transferToAI' : 'routeToTeam',
|
|
281
|
+
targetId: argv['ai-config-id'] || argv['team-id'], dryRun: argv['dry-run'],
|
|
282
|
+
});
|
|
283
|
+
console.log(`\n ${r.status} (workflow ${r.workflowId})\n`);
|
|
284
|
+
}),
|
|
285
|
+
})
|
|
286
|
+
.demandCommand(1, 'Specify: list, set-enabled, create, set-action'),
|
|
287
|
+
handler: () => {},
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const migrateRulesCommand = {
|
|
291
|
+
command: 'rules <op>',
|
|
292
|
+
describe: 'Staff: list / switch off v20 Rules on a site (e.g. the #1253 use-ai rules) without deleting them',
|
|
293
|
+
builder: (y) =>
|
|
294
|
+
y
|
|
295
|
+
.command({
|
|
296
|
+
command: 'list',
|
|
297
|
+
describe: 'List a v20 site Rules with enabled state',
|
|
298
|
+
builder: (b) => b.option('site', { type: 'number', alias: 's', demandOption: true }),
|
|
299
|
+
handler: runCommand(async (argv) => {
|
|
300
|
+
const r = await get(`/DatabaseTool/SiteRules/${argv.site}`);
|
|
301
|
+
for (const x of r.rules ?? []) console.log(` [${x.id}] ${x.enabled ? 'ON ' : 'off'} p=${x.priority} ${x.trigger} ${x.valueJson ?? ''}`);
|
|
302
|
+
console.log(`\n ${r.count} rule(s) on site ${r.siteId}\n`);
|
|
303
|
+
}),
|
|
304
|
+
})
|
|
305
|
+
.command({
|
|
306
|
+
command: 'set-enabled',
|
|
307
|
+
describe: 'Switch Rules off/on (reversible; a "disabled:" prefix on the trigger). Select by ids or --trigger use-ai.',
|
|
308
|
+
builder: (b) => b
|
|
309
|
+
.option('site', { type: 'number', alias: 's', demandOption: true })
|
|
310
|
+
.option('ids', { type: 'string', describe: 'Comma-separated rule ids' })
|
|
311
|
+
.option('trigger', { type: 'string', describe: 'Every rule with this trigger, e.g. use-ai' })
|
|
312
|
+
.option('enable', { type: 'boolean', demandOption: true, describe: '--enable to turn on, --no-enable to turn off' })
|
|
313
|
+
.option('dry-run', { type: 'boolean', default: false }),
|
|
314
|
+
handler: runCommand(async (argv) => {
|
|
315
|
+
const r = await post('/DatabaseTool/SiteRules/SetEnabled', {
|
|
316
|
+
siteId: argv.site, ruleIds: csv(argv.ids).map(Number), trigger: argv.trigger ?? null, enabled: argv.enable, dryRun: argv['dry-run'],
|
|
317
|
+
});
|
|
318
|
+
printItems(r);
|
|
319
|
+
}),
|
|
320
|
+
})
|
|
321
|
+
.demandCommand(1, 'Specify: list, set-enabled'),
|
|
322
|
+
handler: () => {},
|
|
323
|
+
};
|
package/package.json
CHANGED