@tenonhq/dovetail-servicenow 0.0.12 → 0.0.13
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 +21 -1
- package/dist/cli.js +81 -0
- package/dist/flowDesigner/createFlow.d.ts +94 -0
- package/dist/flowDesigner/createFlow.js +289 -0
- package/dist/flowDesigner/index.d.ts +2 -0
- package/dist/flowDesigner/index.js +4 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/registry.js +31 -0
- package/dist/mcp/schemas.d.ts +31 -0
- package/dist/mcp/schemas.js +12 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -180,6 +180,10 @@ npx dove-sn view-action --sys-id <action_type_sys_id> --scope <scope_sys_id>
|
|
|
180
180
|
# Copy a flow / subflow (creates an INACTIVE DRAFT) via the Designer's Copy endpoint
|
|
181
181
|
npx dove-sn copy-flow --sys-id <sys_id> --name "My Copy" # scope defaults to source's
|
|
182
182
|
|
|
183
|
+
# Create a NEW flow (type=flow) from scratch and PUBLISH it (grafts a template's trigger+action)
|
|
184
|
+
npx dove-sn create-flow --name "My Flow" --template <published_flow_sys_id> --scope <scope_sys_id> \
|
|
185
|
+
--trigger-table customer_contact --log-message "hello" # add --dry-run to preview
|
|
186
|
+
|
|
183
187
|
# Publish (compile the snapshot of) a flow / subflow after editing in the Designer
|
|
184
188
|
npx dove-sn publish-flow --sys-id <sys_id> # scope defaults to the flow's
|
|
185
189
|
|
|
@@ -196,6 +200,21 @@ npx dove-sn edit-flow --sys-id <sys_id> --from-json ops.json --apply --update-se
|
|
|
196
200
|
`copy-flow` calls the Designer's own `POST /processflow/flow/{id}/copy` — a
|
|
197
201
|
complete, faithful clone created as an **inactive draft**. (Don't publish +
|
|
198
202
|
activate a copy of a triggered production flow unless you intend it to fire.)
|
|
203
|
+
|
|
204
|
+
`create-flow` mints a **brand-new** flow (`sys_hub_flow`, `type=flow`) from scratch
|
|
205
|
+
and **publishes** it: `POST /processflow/flow` initialises the envelope, the
|
|
206
|
+
trigger + action graph is grafted from a published template flow (`--template`,
|
|
207
|
+
ids remapped + values patched via `--trigger-table` / `--trigger-condition` /
|
|
208
|
+
`--log-message`), a `versioning/create_version` bookmark is written, then the
|
|
209
|
+
`/snapshot` POST compiles it. The result is a **published** flow — a published
|
|
210
|
+
triggered flow can fire on its trigger, so do NOT graft a production send template
|
|
211
|
+
you don't intend to fire (the `active` flag on the result reports whether it's
|
|
212
|
+
live). The
|
|
213
|
+
`POST /processflow/flow` create step is the crux: a Table-API / Dovetail
|
|
214
|
+
`createRecord` insert never initialises the processflow envelope, so its snapshot
|
|
215
|
+
POST silently no-ops (stays draft). Sequence reverse-engineered from Workflow
|
|
216
|
+
Studio HARs and validated live (2026-06-02, tenonworkstudio). Exit `0` published
|
|
217
|
+
or dry-run; `2` created-but-not-published.
|
|
199
218
|
`test-flow` defaults to **validate** — a safe pre-flight (published? inputs match
|
|
200
219
|
declared variables?) that never runs the flow; `--execute --confirm` runs it via
|
|
201
220
|
the server-side FlowAPI runner (deploy `resources/runFlow.md` first).
|
|
@@ -258,7 +277,8 @@ Claude Code and agents: `create_view`, `set_list_layout`, `set_form_layout`,
|
|
|
258
277
|
`set_related_lists`, `add_choices_to_field`, plus the Flow Designer tools
|
|
259
278
|
`flow_view` (read a flow/subflow's step graph), `action_view` (read an action
|
|
260
279
|
type's model), `flow_publish` (compile a flow/subflow snapshot), `flow_copy`
|
|
261
|
-
(copy a flow as an inactive draft), `
|
|
280
|
+
(copy a flow as an inactive draft), `flow_create` (create a NEW flow from scratch +
|
|
281
|
+
publish, grafting a template), `flow_test` (validate or run a flow), and
|
|
262
282
|
`flow_edit` (patch a flow). It reads ServiceNow credentials from the same env
|
|
263
283
|
vars as the CLI.
|
|
264
284
|
|
package/dist/cli.js
CHANGED
|
@@ -73,6 +73,7 @@ const readFlow_1 = require("./flowDesigner/readFlow");
|
|
|
73
73
|
const readActionType_1 = require("./flowDesigner/readActionType");
|
|
74
74
|
const publishFlow_1 = require("./flowDesigner/publishFlow");
|
|
75
75
|
const copyFlow_1 = require("./flowDesigner/copyFlow");
|
|
76
|
+
const createFlow_1 = require("./flowDesigner/createFlow");
|
|
76
77
|
const editFlow_1 = require("./flowDesigner/editFlow");
|
|
77
78
|
const testFlow_1 = require("./flowDesigner/testFlow");
|
|
78
79
|
const flowDesigner_formatter_2 = require("./flowDesigner-formatter");
|
|
@@ -424,6 +425,79 @@ async function runCopyFlow(flags) {
|
|
|
424
425
|
+ ") — inactive draft. Publish with: dove-sn publish-flow --sys-id " + result.sysId + "\n");
|
|
425
426
|
return 0;
|
|
426
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* dove-sn create-flow:
|
|
430
|
+
* --name <name> Required. Name for the new flow.
|
|
431
|
+
* --template <sys_id> Required. Published sys_hub_flow whose trigger+action graph is grafted.
|
|
432
|
+
* --scope <sys_id> Required. Target scope (sysparm_transaction_scope).
|
|
433
|
+
* --internal-name <name> Optional. internal_name (defaults to a slug of --name).
|
|
434
|
+
* --description <text> Optional.
|
|
435
|
+
* --trigger-table <table> Optional. Patch the trigger's table input (e.g. customer_contact).
|
|
436
|
+
* --trigger-condition <q> Optional. Patch the trigger's condition (encoded query).
|
|
437
|
+
* --log-message <text> Optional. Patch the action's message / short_description.
|
|
438
|
+
* --dry-run Optional. Print the plan + template graph counts; write nothing.
|
|
439
|
+
* --json Optional. Emit the structured CreateFlowResult.
|
|
440
|
+
*
|
|
441
|
+
* Creates a NEW flow from scratch and PUBLISHES it: POST /processflow/flow mints an
|
|
442
|
+
* initialised envelope, the template's trigger+action graph is grafted on (ids remapped,
|
|
443
|
+
* values patched), then the snapshot is compiled. The result is a published flow — a
|
|
444
|
+
* published triggered flow can fire on its trigger, so do NOT graft a production send
|
|
445
|
+
* template you don't intend to fire (the result's `active` flag reports whether it's live).
|
|
446
|
+
*
|
|
447
|
+
* Exit codes: 0 published OR dry-run; 2 created-but-not-published (snapshot didn't compile).
|
|
448
|
+
*/
|
|
449
|
+
async function runCreateFlow(flags) {
|
|
450
|
+
var name = flags.name;
|
|
451
|
+
var templateSysId = flags.template || flags["template-sys-id"] || flags.templateSysId;
|
|
452
|
+
var scope = flags.scope || flags.scopeSysId;
|
|
453
|
+
if (!name || !templateSysId || !scope) {
|
|
454
|
+
process.stderr.write("create-flow: --name, --template <sys_id> and --scope <sys_id> are required\n");
|
|
455
|
+
return 1;
|
|
456
|
+
}
|
|
457
|
+
var params = {
|
|
458
|
+
client: (0, client_1.createClient)({}),
|
|
459
|
+
name: name,
|
|
460
|
+
templateSysId: templateSysId,
|
|
461
|
+
scopeSysId: scope
|
|
462
|
+
};
|
|
463
|
+
if (flags["internal-name"] || flags.internalName) {
|
|
464
|
+
params.internalName = flags["internal-name"] || flags.internalName;
|
|
465
|
+
}
|
|
466
|
+
if (flags.description) {
|
|
467
|
+
params.description = flags.description;
|
|
468
|
+
}
|
|
469
|
+
if (flags["trigger-table"] || flags.triggerTable) {
|
|
470
|
+
params.triggerTable = flags["trigger-table"] || flags.triggerTable;
|
|
471
|
+
}
|
|
472
|
+
if (flags["trigger-condition"] !== undefined || flags.triggerCondition !== undefined) {
|
|
473
|
+
params.triggerCondition = flags["trigger-condition"] !== undefined ? flags["trigger-condition"] : flags.triggerCondition;
|
|
474
|
+
}
|
|
475
|
+
if (flags["log-message"] || flags.logMessage) {
|
|
476
|
+
params.logMessage = flags["log-message"] || flags.logMessage;
|
|
477
|
+
}
|
|
478
|
+
if (flags["dry-run"] === "true") {
|
|
479
|
+
params.dryRun = true;
|
|
480
|
+
}
|
|
481
|
+
var result = await (0, createFlow_1.createFlow)(params);
|
|
482
|
+
if (flags.json === "true") {
|
|
483
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
484
|
+
}
|
|
485
|
+
else if (result.status === "dry-run") {
|
|
486
|
+
process.stdout.write("[dry-run] would create '" + result.name + "' (internal " + result.internalName + ") in scope "
|
|
487
|
+
+ result.scopeSysId + " — grafting " + result.graph.triggers + " trigger + "
|
|
488
|
+
+ result.graph.actions + " action + " + result.graph.logic + " logic from template\n");
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
process.stdout.write("[" + result.status + "] '" + result.name + "' sys_id " + result.sysId
|
|
492
|
+
+ (result.snapshotSysId ? " — snapshot " + result.snapshotSysId : "")
|
|
493
|
+
+ (result.active === undefined ? "" : result.active ? " — ACTIVE (will fire)" : " — inactive")
|
|
494
|
+
+ "\n");
|
|
495
|
+
}
|
|
496
|
+
if (result.status === "not-published") {
|
|
497
|
+
return 2;
|
|
498
|
+
}
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
427
501
|
/**
|
|
428
502
|
* dove-sn test-flow:
|
|
429
503
|
* --sys-id <sys_id> Required. sys_hub_flow sys_id (flow or subflow).
|
|
@@ -554,6 +628,10 @@ function printHelp() {
|
|
|
554
628
|
" (--sys-id <sys_id> [--scope <sys_id>] [--json])\n" +
|
|
555
629
|
" copy-flow Copy a flow/subflow (inactive draft) via the Designer Copy API\n" +
|
|
556
630
|
" (--sys-id <sys_id> --name <name> [--scope <sys_id>] [--json])\n" +
|
|
631
|
+
" create-flow Create a NEW flow (type=flow) from scratch + publish (grafts a template)\n" +
|
|
632
|
+
" (--name <n> --template <sys_id> --scope <sys_id>\n" +
|
|
633
|
+
" [--trigger-table <t>] [--trigger-condition <q>] [--log-message <m>]\n" +
|
|
634
|
+
" [--internal-name <n>] [--description <d>] [--dry-run] [--json])\n" +
|
|
557
635
|
" test-flow Validate (default) or run a flow/subflow\n" +
|
|
558
636
|
" (--sys-id <sys_id> [--execute --confirm] [--inputs <json>] [--json])\n" +
|
|
559
637
|
" edit-flow Patch a flow/subflow (rename, description, step inputs)\n" +
|
|
@@ -588,6 +666,9 @@ async function main() {
|
|
|
588
666
|
if (parsed.command === "copy-flow") {
|
|
589
667
|
return await runCopyFlow(parsed.flags);
|
|
590
668
|
}
|
|
669
|
+
if (parsed.command === "create-flow") {
|
|
670
|
+
return await runCreateFlow(parsed.flags);
|
|
671
|
+
}
|
|
591
672
|
if (parsed.command === "test-flow") {
|
|
592
673
|
return await runTestFlow(parsed.flags);
|
|
593
674
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a whole Flow Designer FLOW (sys_hub_flow, type=flow) from scratch and
|
|
3
|
+
* publish it — headless, basic auth. The missing peer of copyFlow / publishFlow:
|
|
4
|
+
* copyFlow duplicates an existing flow; createFlow mints a NEW flow whose trigger
|
|
5
|
+
* + action graph is grafted from a template, then compiled.
|
|
6
|
+
*
|
|
7
|
+
* === CANONICAL SEQUENCE (reverse-engineered from Workflow Studio HARs, 2026-06-02) ===
|
|
8
|
+
* The Designer SPA holds the entire flow graph client-side and persists + compiles
|
|
9
|
+
* it in ONE shot at publish. There are NO incremental add-trigger / add-action REST
|
|
10
|
+
* calls — only version bookmarks. The proven, validated sequence is:
|
|
11
|
+
*
|
|
12
|
+
* 1. CREATE POST /api/now/processflow/flow?param_only_properties=true&sysparm_transaction_scope={scope}
|
|
13
|
+
* body = a small properties envelope. -> 200, result.data = a FULLY INITIALISED
|
|
14
|
+
* empty model (server-minted id, internalName, flowCatalogVariableModelId,
|
|
15
|
+
* version, authoredOnReleaseVersion). This initialisation is the piece a
|
|
16
|
+
* Dovetail createRecord / Table API insert never produces — and without it the
|
|
17
|
+
* snapshot POST silently no-ops (flow stays draft, no snapshot).
|
|
18
|
+
* 2. GRAFT GET /api/now/processflow/flow/{template}?sysparm_transaction_scope={scope}
|
|
19
|
+
* -> result.data carries the template's triggerInstances / actionInstances /
|
|
20
|
+
* flowLogicInstances. Build the publish model = the NEW envelope with those arrays
|
|
21
|
+
* grafted in, ids remapped (flowSysId -> new id; fresh id + uiUniqueIdentifier),
|
|
22
|
+
* and values patched (trigger table/condition, action message inputs).
|
|
23
|
+
* 3. VERSION POST /api/now/processflow/versioning/create_version?...
|
|
24
|
+
* body { item_sys_id: newFlow, type: "Activate/Publish", annotation: "", favorite: false }
|
|
25
|
+
* 4. PUBLISH POST /api/now/processflow/flow/{newFlow}/snapshot?... body = the FLAT model
|
|
26
|
+
* -> result.data.status="published", isPublished=true, latestSnapshot=<sys_id>.
|
|
27
|
+
*
|
|
28
|
+
* Validated live 2026-06-02 on tenonworkstudio (x_cadso_automate): flow
|
|
29
|
+
* aceb8e683395cb147b18bc534d5c7b5e published with a compiled snapshot
|
|
30
|
+
* (7ceb02a83395cb147b18bc534d5c7b03), 1 trigger in sys_hub_trigger_instance_v2,
|
|
31
|
+
* 1 action in sys_hub_action_instance_v2 — zero UI clicks.
|
|
32
|
+
*
|
|
33
|
+
* The clone inherits the template's trigger + action SHAPE; author a different
|
|
34
|
+
* shape by building that flow once in the Designer and pointing templateSysId at it.
|
|
35
|
+
*/
|
|
36
|
+
import type { ServiceNowClient } from "../client";
|
|
37
|
+
export interface CreateFlowParams {
|
|
38
|
+
client: ServiceNowClient;
|
|
39
|
+
/** Name for the new flow. */
|
|
40
|
+
name: string;
|
|
41
|
+
/**
|
|
42
|
+
* sys_id of an existing published sys_hub_flow whose trigger + action graph is
|
|
43
|
+
* grafted onto the new flow. Required — the trigger/action shape comes from here.
|
|
44
|
+
*/
|
|
45
|
+
templateSysId: string;
|
|
46
|
+
/** Target application scope sys_id (sysparm_transaction_scope). Required. */
|
|
47
|
+
scopeSysId: string;
|
|
48
|
+
/** internal_name; defaults to a slug of name. */
|
|
49
|
+
internalName?: string;
|
|
50
|
+
/** description on the new flow. */
|
|
51
|
+
description?: string;
|
|
52
|
+
/** Patch the trigger's `table` input (e.g. "customer_contact"). */
|
|
53
|
+
triggerTable?: string;
|
|
54
|
+
/** Patch the trigger's `condition` input (encoded query). Pass "" to clear. */
|
|
55
|
+
triggerCondition?: string;
|
|
56
|
+
/** Patch the action's `message` input (Log message) / short_description data. */
|
|
57
|
+
logMessage?: string;
|
|
58
|
+
/**
|
|
59
|
+
* When true, do everything up to but not including the writes and return the
|
|
60
|
+
* planned new name / internalName / template-graph counts. No network writes.
|
|
61
|
+
*/
|
|
62
|
+
dryRun?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface CreateFlowResult {
|
|
65
|
+
status: "published" | "dry-run" | "not-published";
|
|
66
|
+
/** sys_id of the new flow (empty on dry-run). */
|
|
67
|
+
sysId: string;
|
|
68
|
+
name: string;
|
|
69
|
+
internalName: string;
|
|
70
|
+
scopeSysId: string;
|
|
71
|
+
/** sys_id of the compiled snapshot, when published. */
|
|
72
|
+
snapshotSysId?: string;
|
|
73
|
+
/** Counts grafted from the template. */
|
|
74
|
+
graph: {
|
|
75
|
+
triggers: number;
|
|
76
|
+
actions: number;
|
|
77
|
+
logic: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Whether the published flow is ACTIVE (will fire on its trigger). Read back
|
|
81
|
+
* from the snapshot response when it reports it; `undefined` when the response
|
|
82
|
+
* doesn't carry an active flag (dry-run, or a server payload that omits it).
|
|
83
|
+
* Don't assume inactive on `undefined` — confirm against the flow record.
|
|
84
|
+
*/
|
|
85
|
+
active?: boolean;
|
|
86
|
+
/** HTTP status of the snapshot POST (0 on dry-run). */
|
|
87
|
+
httpStatus: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Graft the template's graph onto the freshly-created envelope and patch values.
|
|
91
|
+
* Exported for unit testing the pure transform without any network.
|
|
92
|
+
*/
|
|
93
|
+
export declare function buildPublishModel(envelope: any, template: any, newFlow: string, params: CreateFlowParams): any;
|
|
94
|
+
export declare function createFlow(params: CreateFlowParams): Promise<CreateFlowResult>;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Create a whole Flow Designer FLOW (sys_hub_flow, type=flow) from scratch and
|
|
4
|
+
* publish it — headless, basic auth. The missing peer of copyFlow / publishFlow:
|
|
5
|
+
* copyFlow duplicates an existing flow; createFlow mints a NEW flow whose trigger
|
|
6
|
+
* + action graph is grafted from a template, then compiled.
|
|
7
|
+
*
|
|
8
|
+
* === CANONICAL SEQUENCE (reverse-engineered from Workflow Studio HARs, 2026-06-02) ===
|
|
9
|
+
* The Designer SPA holds the entire flow graph client-side and persists + compiles
|
|
10
|
+
* it in ONE shot at publish. There are NO incremental add-trigger / add-action REST
|
|
11
|
+
* calls — only version bookmarks. The proven, validated sequence is:
|
|
12
|
+
*
|
|
13
|
+
* 1. CREATE POST /api/now/processflow/flow?param_only_properties=true&sysparm_transaction_scope={scope}
|
|
14
|
+
* body = a small properties envelope. -> 200, result.data = a FULLY INITIALISED
|
|
15
|
+
* empty model (server-minted id, internalName, flowCatalogVariableModelId,
|
|
16
|
+
* version, authoredOnReleaseVersion). This initialisation is the piece a
|
|
17
|
+
* Dovetail createRecord / Table API insert never produces — and without it the
|
|
18
|
+
* snapshot POST silently no-ops (flow stays draft, no snapshot).
|
|
19
|
+
* 2. GRAFT GET /api/now/processflow/flow/{template}?sysparm_transaction_scope={scope}
|
|
20
|
+
* -> result.data carries the template's triggerInstances / actionInstances /
|
|
21
|
+
* flowLogicInstances. Build the publish model = the NEW envelope with those arrays
|
|
22
|
+
* grafted in, ids remapped (flowSysId -> new id; fresh id + uiUniqueIdentifier),
|
|
23
|
+
* and values patched (trigger table/condition, action message inputs).
|
|
24
|
+
* 3. VERSION POST /api/now/processflow/versioning/create_version?...
|
|
25
|
+
* body { item_sys_id: newFlow, type: "Activate/Publish", annotation: "", favorite: false }
|
|
26
|
+
* 4. PUBLISH POST /api/now/processflow/flow/{newFlow}/snapshot?... body = the FLAT model
|
|
27
|
+
* -> result.data.status="published", isPublished=true, latestSnapshot=<sys_id>.
|
|
28
|
+
*
|
|
29
|
+
* Validated live 2026-06-02 on tenonworkstudio (x_cadso_automate): flow
|
|
30
|
+
* aceb8e683395cb147b18bc534d5c7b5e published with a compiled snapshot
|
|
31
|
+
* (7ceb02a83395cb147b18bc534d5c7b03), 1 trigger in sys_hub_trigger_instance_v2,
|
|
32
|
+
* 1 action in sys_hub_action_instance_v2 — zero UI clicks.
|
|
33
|
+
*
|
|
34
|
+
* The clone inherits the template's trigger + action SHAPE; author a different
|
|
35
|
+
* shape by building that flow once in the Designer and pointing templateSysId at it.
|
|
36
|
+
*/
|
|
37
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
38
|
+
if (k2 === undefined) k2 = k;
|
|
39
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
40
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
41
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
42
|
+
}
|
|
43
|
+
Object.defineProperty(o, k2, desc);
|
|
44
|
+
}) : (function(o, m, k, k2) {
|
|
45
|
+
if (k2 === undefined) k2 = k;
|
|
46
|
+
o[k2] = m[k];
|
|
47
|
+
}));
|
|
48
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
49
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
50
|
+
}) : function(o, v) {
|
|
51
|
+
o["default"] = v;
|
|
52
|
+
});
|
|
53
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
54
|
+
var ownKeys = function(o) {
|
|
55
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
56
|
+
var ar = [];
|
|
57
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
58
|
+
return ar;
|
|
59
|
+
};
|
|
60
|
+
return ownKeys(o);
|
|
61
|
+
};
|
|
62
|
+
return function (mod) {
|
|
63
|
+
if (mod && mod.__esModule) return mod;
|
|
64
|
+
var result = {};
|
|
65
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
66
|
+
__setModuleDefault(result, mod);
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
})();
|
|
70
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
71
|
+
exports.buildPublishModel = buildPublishModel;
|
|
72
|
+
exports.createFlow = createFlow;
|
|
73
|
+
const crypto = __importStar(require("crypto"));
|
|
74
|
+
function newId() {
|
|
75
|
+
return crypto.randomBytes(16).toString("hex");
|
|
76
|
+
}
|
|
77
|
+
function uuid() {
|
|
78
|
+
return crypto.randomUUID();
|
|
79
|
+
}
|
|
80
|
+
function slug(s) {
|
|
81
|
+
// The first replace collapses every run of non-alphanumerics to a single "_",
|
|
82
|
+
// so consecutive underscores can never occur here — a single-char trim (no "+"
|
|
83
|
+
// quantifier) is sufficient and avoids the polynomial-backtracking pattern.
|
|
84
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
85
|
+
}
|
|
86
|
+
/** Normalize `{ result: { data } }` / `{ data }` / `{ result }` / bare to the model. */
|
|
87
|
+
function unwrapModel(data) {
|
|
88
|
+
if (data && typeof data === "object" && data.result && typeof data.result === "object") {
|
|
89
|
+
if (data.result.data && typeof data.result.data === "object") {
|
|
90
|
+
return data.result.data;
|
|
91
|
+
}
|
|
92
|
+
return data.result;
|
|
93
|
+
}
|
|
94
|
+
if (data && typeof data === "object" && data.data && typeof data.data === "object") {
|
|
95
|
+
return data.data;
|
|
96
|
+
}
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
function flowGetPath(sysId, scopeSysId) {
|
|
100
|
+
return "/api/now/processflow/flow/" + encodeURIComponent(sysId)
|
|
101
|
+
+ "?sysparm_transaction_scope=" + encodeURIComponent(scopeSysId);
|
|
102
|
+
}
|
|
103
|
+
function flowCreatePath(scopeSysId) {
|
|
104
|
+
return "/api/now/processflow/flow?param_only_properties=true"
|
|
105
|
+
+ "&sysparm_transaction_scope=" + encodeURIComponent(scopeSysId);
|
|
106
|
+
}
|
|
107
|
+
function createVersionPath(scopeSysId) {
|
|
108
|
+
return "/api/now/processflow/versioning/create_version"
|
|
109
|
+
+ "?sysparm_transaction_scope=" + encodeURIComponent(scopeSysId);
|
|
110
|
+
}
|
|
111
|
+
function snapshotPath(sysId, scopeSysId) {
|
|
112
|
+
return "/api/now/processflow/flow/" + encodeURIComponent(sysId) + "/snapshot"
|
|
113
|
+
+ "?sysparm_transaction_scope=" + encodeURIComponent(scopeSysId);
|
|
114
|
+
}
|
|
115
|
+
function patchInputs(inst, kv) {
|
|
116
|
+
if (!inst || !Array.isArray(inst.inputs))
|
|
117
|
+
return;
|
|
118
|
+
for (var i = 0; i < inst.inputs.length; i += 1) {
|
|
119
|
+
var inp = inst.inputs[i];
|
|
120
|
+
if (Object.prototype.hasOwnProperty.call(kv, inp.name)) {
|
|
121
|
+
inp.value = kv[inp.name];
|
|
122
|
+
if (Object.prototype.hasOwnProperty.call(inp, "displayValue")) {
|
|
123
|
+
inp.displayValue = kv[inp.name];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function remapInstances(arr, newFlow) {
|
|
129
|
+
if (!Array.isArray(arr))
|
|
130
|
+
return [];
|
|
131
|
+
return arr.map(function (src) {
|
|
132
|
+
var inst = JSON.parse(JSON.stringify(src));
|
|
133
|
+
if (Object.prototype.hasOwnProperty.call(inst, "flowSysId"))
|
|
134
|
+
inst.flowSysId = newFlow;
|
|
135
|
+
if (Object.prototype.hasOwnProperty.call(inst, "id"))
|
|
136
|
+
inst.id = newId();
|
|
137
|
+
if (Object.prototype.hasOwnProperty.call(inst, "uiUniqueIdentifier"))
|
|
138
|
+
inst.uiUniqueIdentifier = uuid();
|
|
139
|
+
return inst;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Graft the template's graph onto the freshly-created envelope and patch values.
|
|
144
|
+
* Exported for unit testing the pure transform without any network.
|
|
145
|
+
*/
|
|
146
|
+
function buildPublishModel(envelope, template, newFlow, params) {
|
|
147
|
+
var M = JSON.parse(JSON.stringify(envelope));
|
|
148
|
+
M.id = newFlow;
|
|
149
|
+
M.status = "draft";
|
|
150
|
+
M.active = false;
|
|
151
|
+
M.latestSnapshot = "";
|
|
152
|
+
M.masterSnapshot = false;
|
|
153
|
+
M.masterSnapshotId = "";
|
|
154
|
+
M.isPublished = false;
|
|
155
|
+
M.snapshot = false;
|
|
156
|
+
M.jsonSnapshot = false;
|
|
157
|
+
M.deletedActions = [];
|
|
158
|
+
M.deletedTriggers = [];
|
|
159
|
+
M.deletedFlowLogicInstances = [];
|
|
160
|
+
M.triggerInstances = remapInstances(template.triggerInstances, newFlow);
|
|
161
|
+
M.actionInstances = remapInstances(template.actionInstances, newFlow);
|
|
162
|
+
M.flowLogicInstances = remapInstances(template.flowLogicInstances, newFlow);
|
|
163
|
+
M.subFlowInstances = remapInstances(template.subFlowInstances, newFlow);
|
|
164
|
+
var ti;
|
|
165
|
+
for (ti = 0; ti < M.triggerInstances.length; ti += 1) {
|
|
166
|
+
var kv = {};
|
|
167
|
+
if (params.triggerTable)
|
|
168
|
+
kv.table = params.triggerTable;
|
|
169
|
+
if (params.triggerCondition !== undefined)
|
|
170
|
+
kv.condition = params.triggerCondition;
|
|
171
|
+
patchInputs(M.triggerInstances[ti], kv);
|
|
172
|
+
}
|
|
173
|
+
var ai;
|
|
174
|
+
for (ai = 0; ai < M.actionInstances.length; ai += 1) {
|
|
175
|
+
var act = M.actionInstances[ai];
|
|
176
|
+
if (params.logMessage) {
|
|
177
|
+
patchInputs(act, { message: params.logMessage });
|
|
178
|
+
if (act.data && Object.prototype.hasOwnProperty.call(act.data, "values")) {
|
|
179
|
+
act.data.values = "short_description=" + params.logMessage;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return M;
|
|
184
|
+
}
|
|
185
|
+
function extractSnapshotSysId(body) {
|
|
186
|
+
if (!body || typeof body !== "object")
|
|
187
|
+
return undefined;
|
|
188
|
+
var snap = body.latestSnapshot || body.masterSnapshot
|
|
189
|
+
|| body.latest_snapshot || body.master_snapshot || body.snapshot;
|
|
190
|
+
if (snap && typeof snap === "object") {
|
|
191
|
+
return typeof snap.sys_id === "string" ? snap.sys_id : undefined;
|
|
192
|
+
}
|
|
193
|
+
if (typeof snap === "string" && snap.length >= 32)
|
|
194
|
+
return snap;
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
async function createFlow(params) {
|
|
198
|
+
var client = params.client;
|
|
199
|
+
if (!params.name || params.name.trim().length === 0) {
|
|
200
|
+
throw new Error("createFlow: name is required.");
|
|
201
|
+
}
|
|
202
|
+
if (!params.templateSysId) {
|
|
203
|
+
throw new Error("createFlow: templateSysId is required (the trigger/action shape is grafted from it).");
|
|
204
|
+
}
|
|
205
|
+
if (!params.scopeSysId) {
|
|
206
|
+
throw new Error("createFlow: scopeSysId is required.");
|
|
207
|
+
}
|
|
208
|
+
var internalName = params.internalName || slug(params.name);
|
|
209
|
+
// 1/2 (read): pull the template graph first — also validates the template exists.
|
|
210
|
+
var template = unwrapModel(await client.now.get(flowGetPath(params.templateSysId, params.scopeSysId)));
|
|
211
|
+
if (!template || !Array.isArray(template.triggerInstances) || template.triggerInstances.length === 0) {
|
|
212
|
+
throw new Error("createFlow: template flow " + params.templateSysId + " has no trigger to graft.");
|
|
213
|
+
}
|
|
214
|
+
var graph = {
|
|
215
|
+
triggers: (template.triggerInstances || []).length,
|
|
216
|
+
actions: (template.actionInstances || []).length,
|
|
217
|
+
logic: (template.flowLogicInstances || []).length,
|
|
218
|
+
};
|
|
219
|
+
if (params.dryRun) {
|
|
220
|
+
return {
|
|
221
|
+
status: "dry-run",
|
|
222
|
+
sysId: "",
|
|
223
|
+
name: params.name,
|
|
224
|
+
internalName: internalName,
|
|
225
|
+
scopeSysId: params.scopeSysId,
|
|
226
|
+
graph: graph,
|
|
227
|
+
httpStatus: 0,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// 1 (write): create the flow — server mints the initialised envelope.
|
|
231
|
+
var props = {
|
|
232
|
+
access: "public",
|
|
233
|
+
description: params.description || "",
|
|
234
|
+
flowPriority: "MEDIUM",
|
|
235
|
+
name: params.name,
|
|
236
|
+
protection: "",
|
|
237
|
+
runAs: "system",
|
|
238
|
+
runWithRoles: { value: "", displayValue: "" },
|
|
239
|
+
type: "flow",
|
|
240
|
+
active: false,
|
|
241
|
+
deleted: false,
|
|
242
|
+
security: { can_read: true, can_write: true },
|
|
243
|
+
scope: params.scopeSysId,
|
|
244
|
+
scopeName: "",
|
|
245
|
+
scopeDisplayName: "",
|
|
246
|
+
status: "draft",
|
|
247
|
+
userHasRolesAssignedToFlow: true,
|
|
248
|
+
};
|
|
249
|
+
var createResp = await client.now.post(flowCreatePath(params.scopeSysId), props);
|
|
250
|
+
var envelope = unwrapModel(createResp);
|
|
251
|
+
if (!envelope || typeof envelope.id !== "string" || envelope.id.length < 32) {
|
|
252
|
+
throw new Error("createFlow: create did not return an initialised flow id: "
|
|
253
|
+
+ JSON.stringify(createResp).substring(0, 300));
|
|
254
|
+
}
|
|
255
|
+
var newFlow = envelope.id;
|
|
256
|
+
if (envelope.internalName)
|
|
257
|
+
internalName = envelope.internalName;
|
|
258
|
+
// 2: build the publish model.
|
|
259
|
+
var model = buildPublishModel(envelope, template, newFlow, params);
|
|
260
|
+
// 3: version bookmark (Activate/Publish). Best-effort — publish is the gate.
|
|
261
|
+
try {
|
|
262
|
+
await client.now.post(createVersionPath(params.scopeSysId), {
|
|
263
|
+
item_sys_id: newFlow,
|
|
264
|
+
type: "Activate/Publish",
|
|
265
|
+
annotation: "",
|
|
266
|
+
favorite: false,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
// non-fatal; the snapshot POST is what compiles.
|
|
271
|
+
}
|
|
272
|
+
// 4: publish (compile the snapshot). request() throws on non-2xx.
|
|
273
|
+
var snapResp = await client.now.post(snapshotPath(newFlow, params.scopeSysId), model);
|
|
274
|
+
var snapBody = unwrapModel(snapResp);
|
|
275
|
+
var publishedFlag = snapBody && (snapBody.isPublished === true || snapBody.status === "published");
|
|
276
|
+
var snapshotSysId = extractSnapshotSysId(snapBody);
|
|
277
|
+
var active = snapBody && typeof snapBody.active === "boolean" ? snapBody.active : undefined;
|
|
278
|
+
return {
|
|
279
|
+
status: publishedFlag || snapshotSysId ? "published" : "not-published",
|
|
280
|
+
sysId: newFlow,
|
|
281
|
+
name: params.name,
|
|
282
|
+
internalName: internalName,
|
|
283
|
+
scopeSysId: params.scopeSysId,
|
|
284
|
+
snapshotSysId: snapshotSysId,
|
|
285
|
+
graph: graph,
|
|
286
|
+
active: active,
|
|
287
|
+
httpStatus: 200,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
@@ -24,6 +24,8 @@ export { publishFlow } from "./publishFlow";
|
|
|
24
24
|
export type { PublishFlowParams, PublishFlowResult } from "./publishFlow";
|
|
25
25
|
export { copyFlow } from "./copyFlow";
|
|
26
26
|
export type { CopyFlowParams, CopyFlowResult } from "./copyFlow";
|
|
27
|
+
export { createFlow, buildPublishModel } from "./createFlow";
|
|
28
|
+
export type { CreateFlowParams, CreateFlowResult } from "./createFlow";
|
|
27
29
|
export { editFlow } from "./editFlow";
|
|
28
30
|
export type { EditFlowParams, EditFlowResult, EditFlowOps, StepInputPatch } from "./editFlow";
|
|
29
31
|
export { testFlow, DEFAULT_RUN_FLOW_PATH } from "./testFlow";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* functions land in Phase 1.C/D.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.WriteOrderError = exports.executeWritePlan = exports.topoSort = exports.SYSTEM_FIELDS_TO_STRIP = exports.assertSysId = exports.applyScope = exports.stripSystemFields = exports.generateSysId = exports.DEFAULT_RUN_FLOW_PATH = exports.testFlow = exports.editFlow = exports.copyFlow = exports.publishFlow = exports.readActionType = exports.readFlow = exports.publishActionType = exports.triggerPublication = exports.cloneActionType = exports.cloneSubflow = exports.verifyArtifact = exports.listTemplates = void 0;
|
|
9
|
+
exports.WriteOrderError = exports.executeWritePlan = exports.topoSort = exports.SYSTEM_FIELDS_TO_STRIP = exports.assertSysId = exports.applyScope = exports.stripSystemFields = exports.generateSysId = exports.DEFAULT_RUN_FLOW_PATH = exports.testFlow = exports.editFlow = exports.buildPublishModel = exports.createFlow = exports.copyFlow = exports.publishFlow = exports.readActionType = exports.readFlow = exports.publishActionType = exports.triggerPublication = exports.cloneActionType = exports.cloneSubflow = exports.verifyArtifact = exports.listTemplates = void 0;
|
|
10
10
|
var listTemplates_1 = require("./listTemplates");
|
|
11
11
|
Object.defineProperty(exports, "listTemplates", { enumerable: true, get: function () { return listTemplates_1.listTemplates; } });
|
|
12
12
|
var verifyArtifact_1 = require("./verifyArtifact");
|
|
@@ -27,6 +27,9 @@ var publishFlow_1 = require("./publishFlow");
|
|
|
27
27
|
Object.defineProperty(exports, "publishFlow", { enumerable: true, get: function () { return publishFlow_1.publishFlow; } });
|
|
28
28
|
var copyFlow_1 = require("./copyFlow");
|
|
29
29
|
Object.defineProperty(exports, "copyFlow", { enumerable: true, get: function () { return copyFlow_1.copyFlow; } });
|
|
30
|
+
var createFlow_1 = require("./createFlow");
|
|
31
|
+
Object.defineProperty(exports, "createFlow", { enumerable: true, get: function () { return createFlow_1.createFlow; } });
|
|
32
|
+
Object.defineProperty(exports, "buildPublishModel", { enumerable: true, get: function () { return createFlow_1.buildPublishModel; } });
|
|
30
33
|
var editFlow_1 = require("./editFlow");
|
|
31
34
|
Object.defineProperty(exports, "editFlow", { enumerable: true, get: function () { return editFlow_1.editFlow; } });
|
|
32
35
|
var testFlow_1 = require("./testFlow");
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ export { setFormLayout } from "./layout/formLayout";
|
|
|
14
14
|
export { setRelatedLists } from "./layout/relatedLists";
|
|
15
15
|
export { formatLayoutResult, formatCreateViewResult } from "./layout/formatter";
|
|
16
16
|
export { sincPlugin } from "./plugin";
|
|
17
|
-
export { listTemplates, verifyArtifact, cloneSubflow, cloneActionType, triggerPublication, publishActionType, readFlow, readActionType, publishFlow, copyFlow, editFlow, testFlow, DEFAULT_RUN_FLOW_PATH, generateSysId, topoSort, executeWritePlan, WriteOrderError } from "./flowDesigner";
|
|
18
|
-
export type { TemplateRef, ListTemplatesParams, FlowKind, VerifyExpect, VerifyFound, VerifyFailure, VerifyReport, VerifyArtifactParams, CloneSubflowParams, CloneSubflowResult, CloneActionTypeParams, CloneActionTypeResult, TriggerPublicationParams, TriggerPublicationResult, PublishActionTypeParams, PublishActionTypeResult, ReadFlowParams, ReadFlowResult, FlowStep, FlowVariable, ReadActionTypeParams, ReadActionTypeResult, ActionIo, PublishFlowParams, PublishFlowResult, CopyFlowParams, CopyFlowResult, EditFlowParams, EditFlowResult, EditFlowOps, StepInputPatch, TestFlowParams, TestFlowResult, WriteOp, WriteOpResult } from "./flowDesigner";
|
|
17
|
+
export { listTemplates, verifyArtifact, cloneSubflow, cloneActionType, triggerPublication, publishActionType, readFlow, readActionType, publishFlow, copyFlow, createFlow, buildPublishModel, editFlow, testFlow, DEFAULT_RUN_FLOW_PATH, generateSysId, topoSort, executeWritePlan, WriteOrderError } from "./flowDesigner";
|
|
18
|
+
export type { TemplateRef, ListTemplatesParams, FlowKind, VerifyExpect, VerifyFound, VerifyFailure, VerifyReport, VerifyArtifactParams, CloneSubflowParams, CloneSubflowResult, CloneActionTypeParams, CloneActionTypeResult, TriggerPublicationParams, TriggerPublicationResult, PublishActionTypeParams, PublishActionTypeResult, ReadFlowParams, ReadFlowResult, FlowStep, FlowVariable, ReadActionTypeParams, ReadActionTypeResult, ActionIo, PublishFlowParams, PublishFlowResult, CopyFlowParams, CopyFlowResult, CreateFlowParams, CreateFlowResult, EditFlowParams, EditFlowResult, EditFlowOps, StepInputPatch, TestFlowParams, TestFlowResult, WriteOp, WriteOpResult } from "./flowDesigner";
|
|
19
19
|
export type { ServiceNowClientConfig, ChoiceValue, ChoiceType, AddChoicesParams, AddChoicesResult, ChoiceActionResult, DictionaryRecord, UpdateSetRecord, LayoutAction, LayoutRecordResult, LayoutResult, CreateViewParams, CreateViewResult, FormSectionSpec, SetFormLayoutParams, SetListLayoutParams, SetRelatedListsParams } from "./types";
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* REST API so every change lands in the target update set and scope.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.WriteOrderError = exports.executeWritePlan = exports.topoSort = exports.generateSysId = exports.DEFAULT_RUN_FLOW_PATH = exports.testFlow = exports.editFlow = exports.copyFlow = exports.publishFlow = exports.readActionType = exports.readFlow = exports.publishActionType = exports.triggerPublication = exports.cloneActionType = exports.cloneSubflow = exports.verifyArtifact = exports.listTemplates = exports.sincPlugin = exports.formatCreateViewResult = exports.formatLayoutResult = exports.setRelatedLists = exports.setFormLayout = exports.setListLayout = exports.createView = exports.formatAddChoicesResult = exports.addChoicesToField = exports.createClient = void 0;
|
|
9
|
+
exports.WriteOrderError = exports.executeWritePlan = exports.topoSort = exports.generateSysId = exports.DEFAULT_RUN_FLOW_PATH = exports.testFlow = exports.editFlow = exports.buildPublishModel = exports.createFlow = exports.copyFlow = exports.publishFlow = exports.readActionType = exports.readFlow = exports.publishActionType = exports.triggerPublication = exports.cloneActionType = exports.cloneSubflow = exports.verifyArtifact = exports.listTemplates = exports.sincPlugin = exports.formatCreateViewResult = exports.formatLayoutResult = exports.setRelatedLists = exports.setFormLayout = exports.setListLayout = exports.createView = exports.formatAddChoicesResult = exports.addChoicesToField = exports.createClient = void 0;
|
|
10
10
|
var client_1 = require("./client");
|
|
11
11
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
12
12
|
var choices_1 = require("./choices");
|
|
@@ -37,6 +37,8 @@ Object.defineProperty(exports, "readFlow", { enumerable: true, get: function ()
|
|
|
37
37
|
Object.defineProperty(exports, "readActionType", { enumerable: true, get: function () { return flowDesigner_1.readActionType; } });
|
|
38
38
|
Object.defineProperty(exports, "publishFlow", { enumerable: true, get: function () { return flowDesigner_1.publishFlow; } });
|
|
39
39
|
Object.defineProperty(exports, "copyFlow", { enumerable: true, get: function () { return flowDesigner_1.copyFlow; } });
|
|
40
|
+
Object.defineProperty(exports, "createFlow", { enumerable: true, get: function () { return flowDesigner_1.createFlow; } });
|
|
41
|
+
Object.defineProperty(exports, "buildPublishModel", { enumerable: true, get: function () { return flowDesigner_1.buildPublishModel; } });
|
|
40
42
|
Object.defineProperty(exports, "editFlow", { enumerable: true, get: function () { return flowDesigner_1.editFlow; } });
|
|
41
43
|
Object.defineProperty(exports, "testFlow", { enumerable: true, get: function () { return flowDesigner_1.testFlow; } });
|
|
42
44
|
Object.defineProperty(exports, "DEFAULT_RUN_FLOW_PATH", { enumerable: true, get: function () { return flowDesigner_1.DEFAULT_RUN_FLOW_PATH; } });
|
package/dist/mcp/registry.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import type { ServiceNowClient } from "../client";
|
|
12
|
-
export declare var TOOL_NAMES: readonly ["create_view", "set_list_layout", "set_form_layout", "set_related_lists", "add_choices_to_field", "flow_view", "action_view", "flow_publish", "flow_copy", "flow_test", "flow_edit"];
|
|
12
|
+
export declare var TOOL_NAMES: readonly ["create_view", "set_list_layout", "set_form_layout", "set_related_lists", "add_choices_to_field", "flow_view", "action_view", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit"];
|
|
13
13
|
export type ToolName = typeof TOOL_NAMES[number];
|
|
14
14
|
export interface RegistryDeps {
|
|
15
15
|
/** Optional client injection for tests; defaults to createClient({}). */
|
package/dist/mcp/registry.js
CHANGED
|
@@ -21,6 +21,7 @@ const readFlow_1 = require("../flowDesigner/readFlow");
|
|
|
21
21
|
const readActionType_1 = require("../flowDesigner/readActionType");
|
|
22
22
|
const publishFlow_1 = require("../flowDesigner/publishFlow");
|
|
23
23
|
const copyFlow_1 = require("../flowDesigner/copyFlow");
|
|
24
|
+
const createFlow_1 = require("../flowDesigner/createFlow");
|
|
24
25
|
const editFlow_1 = require("../flowDesigner/editFlow");
|
|
25
26
|
const testFlow_1 = require("../flowDesigner/testFlow");
|
|
26
27
|
const schemas_1 = require("./schemas");
|
|
@@ -34,6 +35,7 @@ exports.TOOL_NAMES = [
|
|
|
34
35
|
"action_view",
|
|
35
36
|
"flow_publish",
|
|
36
37
|
"flow_copy",
|
|
38
|
+
"flow_create",
|
|
37
39
|
"flow_test",
|
|
38
40
|
"flow_edit"
|
|
39
41
|
];
|
|
@@ -141,6 +143,35 @@ function buildDescriptors(deps = {}) {
|
|
|
141
143
|
return (0, copyFlow_1.copyFlow)({ client: client(), sourceSysId: p.sourceSysId, newName: p.newName, scopeSysId: p.scopeSysId });
|
|
142
144
|
}
|
|
143
145
|
},
|
|
146
|
+
{
|
|
147
|
+
name: "flow_create",
|
|
148
|
+
description: "Create a NEW ServiceNow Flow Designer flow (sys_hub_flow, type=flow) from scratch and "
|
|
149
|
+
+ "PUBLISH it, headless. Mints a fresh flow via POST /processflow/flow, grafts the trigger + "
|
|
150
|
+
+ "action graph from an existing published template flow (templateSysId), then compiles the "
|
|
151
|
+
+ "snapshot — leaving a published flow (the result's `active` flag reports whether it will "
|
|
152
|
+
+ "fire). Unlike flow_copy (which duplicates a flow), "
|
|
153
|
+
+ "this creates a new flow you can re-point at a different trigger table / message. "
|
|
154
|
+
+ "name + templateSysId + scopeSysId are required; triggerTable / triggerCondition / "
|
|
155
|
+
+ "logMessage patch the grafted graph; dryRun:true returns the plan + template graph counts "
|
|
156
|
+
+ "without writing. WARNING: a published triggered flow can fire on its trigger — do not graft "
|
|
157
|
+
+ "a production send template you don't intend to fire.",
|
|
158
|
+
shape: schemas_1.createFlowSchema.shape,
|
|
159
|
+
handler: async function (args) {
|
|
160
|
+
var p = schemas_1.createFlowSchema.parse(args);
|
|
161
|
+
return (0, createFlow_1.createFlow)({
|
|
162
|
+
client: client(),
|
|
163
|
+
name: p.name,
|
|
164
|
+
templateSysId: p.templateSysId,
|
|
165
|
+
scopeSysId: p.scopeSysId,
|
|
166
|
+
internalName: p.internalName,
|
|
167
|
+
description: p.description,
|
|
168
|
+
triggerTable: p.triggerTable,
|
|
169
|
+
triggerCondition: p.triggerCondition,
|
|
170
|
+
logMessage: p.logMessage,
|
|
171
|
+
dryRun: p.dryRun
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
144
175
|
{
|
|
145
176
|
name: "flow_test",
|
|
146
177
|
description: "Test or run a ServiceNow flow/subflow. mode='validate' (default) is a safe, read-only "
|
package/dist/mcp/schemas.d.ts
CHANGED
|
@@ -231,6 +231,37 @@ export declare var copyFlowSchema: z.ZodObject<{
|
|
|
231
231
|
newName: string;
|
|
232
232
|
scopeSysId?: string | undefined;
|
|
233
233
|
}>;
|
|
234
|
+
export declare var createFlowSchema: z.ZodObject<{
|
|
235
|
+
name: z.ZodString;
|
|
236
|
+
templateSysId: z.ZodString;
|
|
237
|
+
scopeSysId: z.ZodString;
|
|
238
|
+
internalName: z.ZodOptional<z.ZodString>;
|
|
239
|
+
description: z.ZodOptional<z.ZodString>;
|
|
240
|
+
triggerTable: z.ZodOptional<z.ZodString>;
|
|
241
|
+
triggerCondition: z.ZodOptional<z.ZodString>;
|
|
242
|
+
logMessage: z.ZodOptional<z.ZodString>;
|
|
243
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
244
|
+
}, "strip", z.ZodTypeAny, {
|
|
245
|
+
name: string;
|
|
246
|
+
scopeSysId: string;
|
|
247
|
+
templateSysId: string;
|
|
248
|
+
description?: string | undefined;
|
|
249
|
+
dryRun?: boolean | undefined;
|
|
250
|
+
internalName?: string | undefined;
|
|
251
|
+
triggerTable?: string | undefined;
|
|
252
|
+
triggerCondition?: string | undefined;
|
|
253
|
+
logMessage?: string | undefined;
|
|
254
|
+
}, {
|
|
255
|
+
name: string;
|
|
256
|
+
scopeSysId: string;
|
|
257
|
+
templateSysId: string;
|
|
258
|
+
description?: string | undefined;
|
|
259
|
+
dryRun?: boolean | undefined;
|
|
260
|
+
internalName?: string | undefined;
|
|
261
|
+
triggerTable?: string | undefined;
|
|
262
|
+
triggerCondition?: string | undefined;
|
|
263
|
+
logMessage?: string | undefined;
|
|
264
|
+
}>;
|
|
234
265
|
export declare var testFlowSchema: z.ZodObject<{
|
|
235
266
|
sysId: z.ZodString;
|
|
236
267
|
mode: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"validate">, z.ZodLiteral<"execute">]>>;
|
package/dist/mcp/schemas.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* own file so registry.ts stays focused on wiring.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.editFlowSchema = exports.stepInputPatchSchema = exports.testFlowSchema = exports.copyFlowSchema = exports.publishFlowSchema = exports.viewActionSchema = exports.viewFlowSchema = exports.addChoicesToFieldSchema = exports.choiceValueSchema = exports.setRelatedListsSchema = exports.setFormLayoutSchema = exports.formSectionSchema = exports.setListLayoutSchema = exports.createViewSchema = void 0;
|
|
7
|
+
exports.editFlowSchema = exports.stepInputPatchSchema = exports.testFlowSchema = exports.createFlowSchema = exports.copyFlowSchema = exports.publishFlowSchema = exports.viewActionSchema = exports.viewFlowSchema = exports.addChoicesToFieldSchema = exports.choiceValueSchema = exports.setRelatedListsSchema = exports.setFormLayoutSchema = exports.formSectionSchema = exports.setListLayoutSchema = exports.createViewSchema = void 0;
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
9
|
exports.createViewSchema = zod_1.z.object({
|
|
10
10
|
name: zod_1.z.string().min(1),
|
|
@@ -76,6 +76,17 @@ exports.copyFlowSchema = zod_1.z.object({
|
|
|
76
76
|
newName: zod_1.z.string().min(1),
|
|
77
77
|
scopeSysId: zod_1.z.string().optional()
|
|
78
78
|
});
|
|
79
|
+
exports.createFlowSchema = zod_1.z.object({
|
|
80
|
+
name: zod_1.z.string().min(1),
|
|
81
|
+
templateSysId: zod_1.z.string().min(1),
|
|
82
|
+
scopeSysId: zod_1.z.string().min(1),
|
|
83
|
+
internalName: zod_1.z.string().optional(),
|
|
84
|
+
description: zod_1.z.string().optional(),
|
|
85
|
+
triggerTable: zod_1.z.string().optional(),
|
|
86
|
+
triggerCondition: zod_1.z.string().optional(),
|
|
87
|
+
logMessage: zod_1.z.string().optional(),
|
|
88
|
+
dryRun: zod_1.z.boolean().optional()
|
|
89
|
+
});
|
|
79
90
|
exports.testFlowSchema = zod_1.z.object({
|
|
80
91
|
sysId: zod_1.z.string().min(1),
|
|
81
92
|
mode: zod_1.z.union([zod_1.z.literal("validate"), zod_1.z.literal("execute")]).optional(),
|