@tenonhq/dovetail-servicenow 0.0.30 → 0.0.32
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 +43 -2
- package/dist/cli.js +189 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +15 -1
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/registry.js +72 -0
- package/dist/mcp/schemas.d.ts +62 -0
- package/dist/mcp/schemas.js +36 -1
- package/dist/publishApp.d.ts +173 -0
- package/dist/publishApp.js +664 -0
- package/dist/table/formSession.d.ts +8 -0
- package/dist/table/formSession.js +12 -4
- package/dist/table/index.d.ts +3 -1
- package/dist/table/index.js +5 -1
- package/dist/table/setTable.d.ts +73 -0
- package/dist/table/setTable.js +294 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -406,6 +406,45 @@ Programmatic: `invokeRest({ method, path, body, confirm })` is exported, and the
|
|
|
406
406
|
client gained `now.put` / `now.delete` / `now.invoke` (the latter returns
|
|
407
407
|
`{ status, body }` verbatim) alongside the existing `now.get` / `now.post`.
|
|
408
408
|
|
|
409
|
+
### Publish an app to the Store / application repository
|
|
410
|
+
|
|
411
|
+
Publish a scoped application to the **ServiceNow Store**, the **company
|
|
412
|
+
application repository**, or both — headlessly, with the publish's progress
|
|
413
|
+
tracker polled to completion.
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
# Dry-run — the DEFAULT: resolves the app, prints the plan, publishes NOTHING
|
|
417
|
+
npx dove-sn publish-app --app x_cadso_filter --version 6.0.20260716 --target both
|
|
418
|
+
|
|
419
|
+
# Publish for real (store, then repo, same version)
|
|
420
|
+
npx dove-sn publish-app --app x_cadso_filter --version 6.0.20260716 \
|
|
421
|
+
--target both --dev-notes "July release" --confirm --json
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Store publish is EXTERNALLY VISIBLE on the ServiceNow Store — treat
|
|
425
|
+
`--target store --confirm` as a release.** `publish-app` is dry-run by default:
|
|
426
|
+
without `--confirm` it prints the resolved plan and exits `1` (a deliberate
|
|
427
|
+
refusal). `--target both` runs store then repo sequentially and short-circuits
|
|
428
|
+
if the store leg fails.
|
|
429
|
+
|
|
430
|
+
The two targets ride different transports:
|
|
431
|
+
|
|
432
|
+
- **store** replays the `sys_app` form's upload flow (`xmlhttp.do` +
|
|
433
|
+
`sn_appauthor.ScopedAppUploaderAJAX`) over a form-login session — basic auth
|
|
434
|
+
alone no-ops there. It needs the Store account credentials in the loaded env
|
|
435
|
+
file as `SN_STORE_USERNAME` / `SN_STORE_PASSWORD`. The password is **never
|
|
436
|
+
accepted as a flag** and never appears in output, dry-run previews included.
|
|
437
|
+
- **repo** uses the supported CI/CD REST API (`POST /api/sn_cicd/app_repo/publish`
|
|
438
|
+
+ `GET /api/sn_cicd/progress/{id}`) over basic auth. The API user needs the
|
|
439
|
+
`sn_cicd` role (or admin).
|
|
440
|
+
|
|
441
|
+
`--app` accepts a scope name, `sys_app` sys_id, or app name; `--version` must be
|
|
442
|
+
above the currently published version. The result carries the progress-tracker
|
|
443
|
+
id, per-step states ("Packaging application", "Uploading application"), the
|
|
444
|
+
Store `appLink`, and the publish's update-set sys_id where the instance reports
|
|
445
|
+
one. Exit codes: `0` published or dry-run, `1` bad args/unconfirmed, `2`
|
|
446
|
+
failed/timeout. Programmatic: `publishApp({ app, version, target, confirm })`.
|
|
447
|
+
|
|
409
448
|
`test-flow` defaults to **validate** — a safe pre-flight (published? inputs match
|
|
410
449
|
declared variables?) that never runs the flow; `--execute --confirm` runs it via
|
|
411
450
|
the server-side FlowAPI runner (deploy `resources/runFlow.md` first).
|
|
@@ -488,8 +527,10 @@ publish is read back and verified), `flow_publish` (compile a flow/subflow snaps
|
|
|
488
527
|
publish, grafting a template), `flow_test` (validate or run a flow), and
|
|
489
528
|
`flow_edit` (patch a flow), plus `invoke_rest` (invoke an arbitrary authenticated
|
|
490
529
|
REST operation — Scripted REST included — with GET/POST/PUT/DELETE; dry-run by
|
|
491
|
-
default, response passed through verbatim, bodies never logged)
|
|
492
|
-
|
|
530
|
+
default, response passed through verbatim, bodies never logged) and `app_publish`
|
|
531
|
+
(publish a scoped app to the ServiceNow Store and/or the application repository;
|
|
532
|
+
dry-run by default, Store credentials env-only — they never transit tool
|
|
533
|
+
arguments). It reads ServiceNow credentials from the same env vars as the CLI.
|
|
493
534
|
|
|
494
535
|
```bash
|
|
495
536
|
npx dove-sn mcp --smoke # list the registered tools and exit
|
package/dist/cli.js
CHANGED
|
@@ -83,6 +83,7 @@ const table_1 = require("./table");
|
|
|
83
83
|
const setField_1 = require("./setField");
|
|
84
84
|
const createRecord_1 = require("./createRecord");
|
|
85
85
|
const invokeRest_1 = require("./invokeRest");
|
|
86
|
+
const publishApp_1 = require("./publishApp");
|
|
86
87
|
const hostAssets_1 = require("./hostAssets");
|
|
87
88
|
const flowDesigner_formatter_2 = require("./flowDesigner-formatter");
|
|
88
89
|
function parseArgs(argv) {
|
|
@@ -894,6 +895,14 @@ function printHelp() {
|
|
|
894
895
|
" Shorten or clear those values first, then re-run.\n" +
|
|
895
896
|
" --element / --internal-type are REFUSED with an explanation:\n" +
|
|
896
897
|
" ServiceNow silently ignores both on an existing column.\n" +
|
|
898
|
+
" set-table Update an EXISTING TABLE's own dictionary row (the collection row),\n" +
|
|
899
|
+
" into an update set, then verify against the instance\n" +
|
|
900
|
+
" (--table <t> --update-set <sys_id> [--audit true|false]\n" +
|
|
901
|
+
" [--dry-run] [--json])\n" +
|
|
902
|
+
" --audit turns RECORD AUDITING on/off for the whole table: with it\n" +
|
|
903
|
+
" true ServiceNow writes a sys_audit row per changed field on every\n" +
|
|
904
|
+
" insert and update — a real cost on a high-write table.\n" +
|
|
905
|
+
" Column attributes belong to set-column, record values to set-field.\n" +
|
|
897
906
|
" invoke-rest Invoke an arbitrary authenticated REST operation (Scripted REST incl.)\n" +
|
|
898
907
|
" DRY-RUN BY DEFAULT — nothing is sent without --confirm\n" +
|
|
899
908
|
" (--method <GET|POST|PUT|DELETE> --path /api/<scope>/<service>/<resource>\n" +
|
|
@@ -918,6 +927,15 @@ function printHelp() {
|
|
|
918
927
|
" [--script-input <name>] [--update-set <sys_id>] [--apply] [--json])\n" +
|
|
919
928
|
" edit-flow Patch a flow/subflow (rename, description, step inputs)\n" +
|
|
920
929
|
" (--sys-id <sys_id> --from-json <ops.json> [--apply] [--update-set <sys_id>] [--scope <sys_id>] [--json])\n" +
|
|
930
|
+
" publish-app Publish a scoped app to the ServiceNow Store and/or the company\n" +
|
|
931
|
+
" application repository, then poll the publish to completion.\n" +
|
|
932
|
+
" STORE PUBLISH IS EXTERNALLY VISIBLE on the ServiceNow Store.\n" +
|
|
933
|
+
" DRY-RUN BY DEFAULT — nothing is published without --confirm\n" +
|
|
934
|
+
" (--app <scope|sys_id|name> --version <v> --target store|repo|both\n" +
|
|
935
|
+
" [--dev-notes <text>] [--store-user <email>] [--timeout-ms <n>]\n" +
|
|
936
|
+
" [--dry-run] [--json] [--confirm])\n" +
|
|
937
|
+
" Store creds: SN_STORE_USERNAME/SN_STORE_PASSWORD in the --env file;\n" +
|
|
938
|
+
" the password is never a flag. Repo publish needs the sn_cicd role.\n" +
|
|
921
939
|
" mcp Run the MCP stdio server (--smoke lists tools and exits)\n" +
|
|
922
940
|
"\nGlobal flags:\n" +
|
|
923
941
|
" --env <path> Load credentials from a specific .env file (also --env-file,\n" +
|
|
@@ -1108,12 +1126,12 @@ async function runAddColumn(flags) {
|
|
|
1108
1126
|
}
|
|
1109
1127
|
/** Parse a CLI boolean flag. Bare `--mandatory` means true; `--mandatory false` means
|
|
1110
1128
|
* false. Anything else is rejected rather than quietly coerced to `true`. */
|
|
1111
|
-
function parseBoolFlag(name, raw) {
|
|
1129
|
+
function parseBoolFlag(name, raw, verb = "set-column") {
|
|
1112
1130
|
if (raw === "true")
|
|
1113
1131
|
return true;
|
|
1114
1132
|
if (raw === "false")
|
|
1115
1133
|
return false;
|
|
1116
|
-
throw new Error("
|
|
1134
|
+
throw new Error(verb + ": --" + name + " must be true or false (got '" + raw + "').");
|
|
1117
1135
|
}
|
|
1118
1136
|
/**
|
|
1119
1137
|
* dove-sn set-column:
|
|
@@ -1211,6 +1229,71 @@ async function runSetColumn(flags, bare) {
|
|
|
1211
1229
|
return 2;
|
|
1212
1230
|
return 0;
|
|
1213
1231
|
}
|
|
1232
|
+
/**
|
|
1233
|
+
* dove-sn set-table:
|
|
1234
|
+
* --table x_cadso_core_setting --audit true --update-set <sys_id>
|
|
1235
|
+
* [--dry-run] [--json]
|
|
1236
|
+
*
|
|
1237
|
+
* Updates the TABLE's own dictionary row (the `internal_type=collection` row, whose
|
|
1238
|
+
* `element` is empty) — not a column's. Column attributes belong to set-column; a
|
|
1239
|
+
* record's values belong to set-field.
|
|
1240
|
+
*/
|
|
1241
|
+
async function runSetTable(flags, bare) {
|
|
1242
|
+
// Guard the string flags AND the updateSetSysId alias: a value-less string flag
|
|
1243
|
+
// arrives as the literal "true", so --update-set (or its alias) with nothing after
|
|
1244
|
+
// it would silently become the sys_id "true" and later fail as "not found".
|
|
1245
|
+
var stringFlags = ["table", "update-set", "updateSetSysId"];
|
|
1246
|
+
for (var f = 0; f < stringFlags.length; f += 1) {
|
|
1247
|
+
if (bare[stringFlags[f]]) {
|
|
1248
|
+
process.stderr.write("set-table: --" + stringFlags[f] + " needs a value (it was given none).\n");
|
|
1249
|
+
return 1;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
var table = flags.table;
|
|
1253
|
+
if (!table) {
|
|
1254
|
+
process.stderr.write("set-table: --table is required " +
|
|
1255
|
+
"(--update-set is required too, unless --dry-run)\n");
|
|
1256
|
+
return 1;
|
|
1257
|
+
}
|
|
1258
|
+
var attributes = {};
|
|
1259
|
+
if (flags.audit !== undefined) {
|
|
1260
|
+
attributes.audit = parseBoolFlag("audit", flags.audit, "set-table");
|
|
1261
|
+
}
|
|
1262
|
+
var params = {
|
|
1263
|
+
client: (0, client_1.createClient)({}),
|
|
1264
|
+
table: table,
|
|
1265
|
+
attributes: attributes,
|
|
1266
|
+
};
|
|
1267
|
+
var setTableUs = flags["update-set"] || flags.updateSetSysId;
|
|
1268
|
+
if (setTableUs)
|
|
1269
|
+
params.updateSetSysId = setTableUs;
|
|
1270
|
+
if (flags["dry-run"] === "true")
|
|
1271
|
+
params.dryRun = true;
|
|
1272
|
+
var result = await (0, table_1.setTable)(params);
|
|
1273
|
+
if (flags.json === "true") {
|
|
1274
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
process.stdout.write("[" +
|
|
1278
|
+
result.status +
|
|
1279
|
+
"] " +
|
|
1280
|
+
result.table +
|
|
1281
|
+
(result.verified && result.status === "applied" ? " — verified" : "") +
|
|
1282
|
+
(result.status === "applied" && !result.capturedInUpdateSet
|
|
1283
|
+
? " — NOT CAPTURED"
|
|
1284
|
+
: "") +
|
|
1285
|
+
"\n" +
|
|
1286
|
+
result.note +
|
|
1287
|
+
"\n");
|
|
1288
|
+
}
|
|
1289
|
+
// 2 = the write landed but the instance does not reflect it (or it was not
|
|
1290
|
+
// captured), which must not read as success to a script.
|
|
1291
|
+
if (result.status === "failed")
|
|
1292
|
+
return 2;
|
|
1293
|
+
if (result.status === "applied" && !result.capturedInUpdateSet)
|
|
1294
|
+
return 2;
|
|
1295
|
+
return 0;
|
|
1296
|
+
}
|
|
1214
1297
|
/** Parse inline `--fields "k=v, k2=v2"` into a field map. */
|
|
1215
1298
|
function parseFieldsInline(input) {
|
|
1216
1299
|
var out = {};
|
|
@@ -1511,6 +1594,104 @@ async function runInvokeRest(flags) {
|
|
|
1511
1594
|
}
|
|
1512
1595
|
return 0;
|
|
1513
1596
|
}
|
|
1597
|
+
/**
|
|
1598
|
+
* dove-sn publish-app:
|
|
1599
|
+
* --app <scope|sys_id|name> Required. The sys_app to publish.
|
|
1600
|
+
* --version <v> Required. Version to publish (e.g. 6.0.20260716).
|
|
1601
|
+
* --target store|repo|both Required. STORE PUBLISH IS EXTERNALLY VISIBLE.
|
|
1602
|
+
* [--dev-notes <text>] Optional developer notes.
|
|
1603
|
+
* [--store-user <email>] Store account email (else SN_STORE_USERNAME).
|
|
1604
|
+
* The password comes ONLY from SN_STORE_PASSWORD —
|
|
1605
|
+
* there is no flag for it, ever.
|
|
1606
|
+
* [--timeout-ms <n>] Progress-poll budget (default 120000).
|
|
1607
|
+
* [--dry-run] [--json] [--confirm]
|
|
1608
|
+
*
|
|
1609
|
+
* DRY-RUN unless --confirm: without it the resolved plan is printed and the
|
|
1610
|
+
* command exits 1 (a deliberate refusal, not success). --target both publishes
|
|
1611
|
+
* store then repo sequentially with the same version and short-circuits if the
|
|
1612
|
+
* store leg fails; --json emits an array of per-target results.
|
|
1613
|
+
* Exit codes: 0 published/dry-run, 1 bad args/unconfirmed, 2 failed/timeout.
|
|
1614
|
+
*/
|
|
1615
|
+
async function runPublishApp(flags) {
|
|
1616
|
+
var app = flags.app;
|
|
1617
|
+
var version = flags.version;
|
|
1618
|
+
var target = flags.target;
|
|
1619
|
+
if (!app || !version || !target) {
|
|
1620
|
+
process.stderr.write("publish-app: --app, --version and --target store|repo|both are required\n");
|
|
1621
|
+
return 1;
|
|
1622
|
+
}
|
|
1623
|
+
if (target !== "store" && target !== "repo" && target !== "both") {
|
|
1624
|
+
process.stderr.write("publish-app: --target must be store, repo or both (got '" +
|
|
1625
|
+
target +
|
|
1626
|
+
"')\n");
|
|
1627
|
+
return 1;
|
|
1628
|
+
}
|
|
1629
|
+
var targets = target === "both" ? ["store", "repo"] : [target];
|
|
1630
|
+
var dryRun = flags["dry-run"] === "true";
|
|
1631
|
+
var confirmed = flags.confirm === "true";
|
|
1632
|
+
var client = (0, client_1.createClient)({});
|
|
1633
|
+
var results = [];
|
|
1634
|
+
var exitCode = 0;
|
|
1635
|
+
for (var i = 0; i < targets.length; i += 1) {
|
|
1636
|
+
var params = {
|
|
1637
|
+
client: client,
|
|
1638
|
+
app: app,
|
|
1639
|
+
version: version,
|
|
1640
|
+
target: targets[i],
|
|
1641
|
+
confirm: confirmed,
|
|
1642
|
+
dryRun: dryRun,
|
|
1643
|
+
};
|
|
1644
|
+
if (flags["dev-notes"])
|
|
1645
|
+
params.devNotes = flags["dev-notes"];
|
|
1646
|
+
if (flags["store-user"])
|
|
1647
|
+
params.storeUsername = flags["store-user"];
|
|
1648
|
+
if (flags["timeout-ms"]) {
|
|
1649
|
+
// A NaN timeout would make the poll-loop budget check always false —
|
|
1650
|
+
// an infinite loop. Validate here, exit 1 on garbage.
|
|
1651
|
+
var timeoutMs = Number(flags["timeout-ms"]);
|
|
1652
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
1653
|
+
process.stderr.write("publish-app: --timeout-ms must be a positive integer (got '" +
|
|
1654
|
+
flags["timeout-ms"] +
|
|
1655
|
+
"')\n");
|
|
1656
|
+
return 1;
|
|
1657
|
+
}
|
|
1658
|
+
params.timeoutMs = timeoutMs;
|
|
1659
|
+
}
|
|
1660
|
+
var result = await (0, publishApp_1.publishApp)(params);
|
|
1661
|
+
results.push(result);
|
|
1662
|
+
if (flags.json !== "true") {
|
|
1663
|
+
process.stdout.write("[" +
|
|
1664
|
+
result.status +
|
|
1665
|
+
"] " +
|
|
1666
|
+
result.target +
|
|
1667
|
+
" — " +
|
|
1668
|
+
result.appName +
|
|
1669
|
+
" (" +
|
|
1670
|
+
result.appScope +
|
|
1671
|
+
") v" +
|
|
1672
|
+
result.version +
|
|
1673
|
+
(result.appLink ? " — " + result.appLink : "") +
|
|
1674
|
+
(result.updateSetSysId
|
|
1675
|
+
? " — update set " + result.updateSetSysId
|
|
1676
|
+
: "") +
|
|
1677
|
+
"\n" +
|
|
1678
|
+
result.note +
|
|
1679
|
+
"\n");
|
|
1680
|
+
}
|
|
1681
|
+
if (result.status === "failed" || result.status === "timeout") {
|
|
1682
|
+
exitCode = 2;
|
|
1683
|
+
break; // Short-circuit: never repo-publish after a failed store leg.
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
if (flags.json === "true") {
|
|
1687
|
+
process.stdout.write(JSON.stringify(results, null, 2) + "\n");
|
|
1688
|
+
}
|
|
1689
|
+
if (exitCode === 0 && !dryRun && !confirmed) {
|
|
1690
|
+
process.stderr.write("publish-app: refusing to publish without --confirm (the plan above is a dry-run).\n");
|
|
1691
|
+
return 1;
|
|
1692
|
+
}
|
|
1693
|
+
return exitCode;
|
|
1694
|
+
}
|
|
1514
1695
|
async function main() {
|
|
1515
1696
|
var parsed = parseArgs(process.argv.slice(2));
|
|
1516
1697
|
// Load credentials before any command runs. `--env`/`--env-file` (or the
|
|
@@ -1551,6 +1732,9 @@ async function main() {
|
|
|
1551
1732
|
if (parsed.command === "set-column") {
|
|
1552
1733
|
return await runSetColumn(parsed.flags, parsed.bare);
|
|
1553
1734
|
}
|
|
1735
|
+
if (parsed.command === "set-table") {
|
|
1736
|
+
return await runSetTable(parsed.flags, parsed.bare);
|
|
1737
|
+
}
|
|
1554
1738
|
if (parsed.command === "set-field") {
|
|
1555
1739
|
return await runSetField(parsed.flags);
|
|
1556
1740
|
}
|
|
@@ -1585,6 +1769,9 @@ async function main() {
|
|
|
1585
1769
|
await runSetRelatedLists(parsed.flags);
|
|
1586
1770
|
return 0;
|
|
1587
1771
|
}
|
|
1772
|
+
if (parsed.command === "publish-app") {
|
|
1773
|
+
return await runPublishApp(parsed.flags);
|
|
1774
|
+
}
|
|
1588
1775
|
if (parsed.command === "mcp") {
|
|
1589
1776
|
return await runMcp(parsed.flags);
|
|
1590
1777
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,11 +19,13 @@ export { sincPlugin } from "./plugin";
|
|
|
19
19
|
export { listTemplates, verifyArtifact, cloneSubflow, cloneActionType, triggerPublication, publishActionType, editActionType, applyStepOps, verifySteps, summarizeSteps, formatStepPill, readFlow, readActionType, publishFlow, copyFlow, createFlow, buildPublishModel, editFlow, testFlow, DEFAULT_RUN_FLOW_PATH, generateSysId, topoSort, executeWritePlan, WriteOrderError, } from "./flowDesigner";
|
|
20
20
|
export type { TemplateRef, ListTemplatesParams, FlowKind, VerifyExpect, VerifyFound, VerifyFailure, VerifyReport, VerifyArtifactParams, CloneSubflowParams, CloneSubflowResult, CloneActionTypeParams, CloneActionTypeResult, TriggerPublicationParams, TriggerPublicationResult, PublishActionTypeParams, PublishActionTypeResult, EditActionTypeParams, EditActionTypeResult, EditActionTypeOps, StepOps, StepRecord, StepSummary, StepIoSummary, PatchStepScriptOp, AddStepOutputOp, AddStepInputOp, ApplyStepOpsResult, VerifyStepsResult, ReadFlowParams, ReadFlowResult, FlowStep, FlowVariable, ReadActionTypeParams, ReadActionTypeResult, ActionIo, PublishFlowParams, PublishFlowResult, CopyFlowParams, CopyFlowResult, CreateFlowParams, CreateFlowResult, EditFlowParams, EditFlowResult, EditFlowOps, StepInputPatch, TestFlowParams, TestFlowResult, WriteOp, WriteOpResult, } from "./flowDesigner";
|
|
21
21
|
export type { ServiceNowClientConfig, ChoiceValue, ChoiceType, AddChoicesParams, AddChoicesResult, ChoiceActionResult, DictionaryRecord, UpdateSetRecord, LayoutAction, LayoutRecordResult, LayoutResult, CreateViewParams, CreateViewResult, FormSectionSpec, SetFormLayoutParams, SetListLayoutParams, SetRelatedListsParams, ChunkRole, ChunkInfo, ChunkResult, PrunedResult, HostAssetsParams, HostAssetsResult, } from "./types";
|
|
22
|
-
export { createTable, projectTableGraph, buildColumnXml, normalizeColumns, resolveType, applyTableSaveOverlay, defaultAccessFlags, TYPE_MAP, DEFAULT_SUPER_CLASS, DEFAULT_SAVE_ACTION, addColumn, deriveElement, setColumn, resolveAttributes, toStoredValue, } from "./table";
|
|
23
|
-
export type { CreateTableParams, CreateTableResult, AddColumnParams, AddColumnResult, SetColumnParams, SetColumnResult, ColumnAttributes, AttributeChange, TableGraph, NormalizedColumn, ColumnSpec, AccessFlags, OverlaySpec, } from "./table";
|
|
22
|
+
export { createTable, projectTableGraph, buildColumnXml, normalizeColumns, resolveType, applyTableSaveOverlay, defaultAccessFlags, TYPE_MAP, DEFAULT_SUPER_CLASS, DEFAULT_SAVE_ACTION, addColumn, deriveElement, setColumn, resolveAttributes, toStoredValue, setTable, resolveTableAttributes, } from "./table";
|
|
23
|
+
export type { CreateTableParams, CreateTableResult, AddColumnParams, AddColumnResult, SetColumnParams, SetColumnResult, ColumnAttributes, AttributeChange, SetTableParams, SetTableResult, TableAttributes, TableGraph, NormalizedColumn, ColumnSpec, AccessFlags, OverlaySpec, } from "./table";
|
|
24
24
|
export { setField } from "./setField";
|
|
25
25
|
export { createRecord } from "./createRecord";
|
|
26
26
|
export type { RecordWriteResult, SetFieldParams, SetFieldResult, } from "./setField";
|
|
27
27
|
export type { CreateRecordParams, CreateRecordResult } from "./createRecord";
|
|
28
28
|
export { invokeRest, INVOKE_REST_METHODS } from "./invokeRest";
|
|
29
29
|
export type { InvokeRestParams, InvokeRestResult } from "./invokeRest";
|
|
30
|
+
export { publishApp, buildStartFields, parseXmlAnswer, parseProgressTree, classifyProgress, flattenSteps, harvestProgressResults, parseCicdPublishResponse, parseCicdProgress, DEFAULT_PUBLISH_TIMEOUT_MS, PUBLISH_POLL_DELAYS_MS, } from "./publishApp";
|
|
31
|
+
export type { PublishAppParams, PublishAppResult, PublishTarget, PublishStep, ProgressNode, CicdProgress, PublishTransport, } from "./publishApp";
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.addColumn = exports.DEFAULT_SAVE_ACTION = exports.DEFAULT_SUPER_CLASS = exports.TYPE_MAP = exports.defaultAccessFlags = exports.applyTableSaveOverlay = exports.resolveType = exports.normalizeColumns = exports.buildColumnXml = exports.projectTableGraph = exports.createTable = 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.formatStepPill = exports.summarizeSteps = exports.verifySteps = exports.applyStepOps = exports.editActionType = 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.formatHostAssetsResult = exports.classifyChunks = exports.hostAssets = exports.addChoicesToField = exports.resolveConfigFromEnvFile = exports.createClientFromEnvFile = exports.createClient = void 0;
|
|
10
|
-
exports.INVOKE_REST_METHODS = exports.invokeRest = exports.createRecord = exports.setField = exports.toStoredValue = exports.resolveAttributes = exports.setColumn = exports.deriveElement = void 0;
|
|
10
|
+
exports.PUBLISH_POLL_DELAYS_MS = exports.DEFAULT_PUBLISH_TIMEOUT_MS = exports.parseCicdProgress = exports.parseCicdPublishResponse = exports.harvestProgressResults = exports.flattenSteps = exports.classifyProgress = exports.parseProgressTree = exports.parseXmlAnswer = exports.buildStartFields = exports.publishApp = exports.INVOKE_REST_METHODS = exports.invokeRest = exports.createRecord = exports.setField = exports.resolveTableAttributes = exports.setTable = exports.toStoredValue = exports.resolveAttributes = exports.setColumn = exports.deriveElement = void 0;
|
|
11
11
|
var client_1 = require("./client");
|
|
12
12
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
13
13
|
var createClientFromEnvFile_1 = require("./createClientFromEnvFile");
|
|
@@ -75,6 +75,8 @@ Object.defineProperty(exports, "deriveElement", { enumerable: true, get: functio
|
|
|
75
75
|
Object.defineProperty(exports, "setColumn", { enumerable: true, get: function () { return table_1.setColumn; } });
|
|
76
76
|
Object.defineProperty(exports, "resolveAttributes", { enumerable: true, get: function () { return table_1.resolveAttributes; } });
|
|
77
77
|
Object.defineProperty(exports, "toStoredValue", { enumerable: true, get: function () { return table_1.toStoredValue; } });
|
|
78
|
+
Object.defineProperty(exports, "setTable", { enumerable: true, get: function () { return table_1.setTable; } });
|
|
79
|
+
Object.defineProperty(exports, "resolveTableAttributes", { enumerable: true, get: function () { return table_1.resolveTableAttributes; } });
|
|
78
80
|
var setField_1 = require("./setField");
|
|
79
81
|
Object.defineProperty(exports, "setField", { enumerable: true, get: function () { return setField_1.setField; } });
|
|
80
82
|
var createRecord_1 = require("./createRecord");
|
|
@@ -82,3 +84,15 @@ Object.defineProperty(exports, "createRecord", { enumerable: true, get: function
|
|
|
82
84
|
var invokeRest_1 = require("./invokeRest");
|
|
83
85
|
Object.defineProperty(exports, "invokeRest", { enumerable: true, get: function () { return invokeRest_1.invokeRest; } });
|
|
84
86
|
Object.defineProperty(exports, "INVOKE_REST_METHODS", { enumerable: true, get: function () { return invokeRest_1.INVOKE_REST_METHODS; } });
|
|
87
|
+
var publishApp_1 = require("./publishApp");
|
|
88
|
+
Object.defineProperty(exports, "publishApp", { enumerable: true, get: function () { return publishApp_1.publishApp; } });
|
|
89
|
+
Object.defineProperty(exports, "buildStartFields", { enumerable: true, get: function () { return publishApp_1.buildStartFields; } });
|
|
90
|
+
Object.defineProperty(exports, "parseXmlAnswer", { enumerable: true, get: function () { return publishApp_1.parseXmlAnswer; } });
|
|
91
|
+
Object.defineProperty(exports, "parseProgressTree", { enumerable: true, get: function () { return publishApp_1.parseProgressTree; } });
|
|
92
|
+
Object.defineProperty(exports, "classifyProgress", { enumerable: true, get: function () { return publishApp_1.classifyProgress; } });
|
|
93
|
+
Object.defineProperty(exports, "flattenSteps", { enumerable: true, get: function () { return publishApp_1.flattenSteps; } });
|
|
94
|
+
Object.defineProperty(exports, "harvestProgressResults", { enumerable: true, get: function () { return publishApp_1.harvestProgressResults; } });
|
|
95
|
+
Object.defineProperty(exports, "parseCicdPublishResponse", { enumerable: true, get: function () { return publishApp_1.parseCicdPublishResponse; } });
|
|
96
|
+
Object.defineProperty(exports, "parseCicdProgress", { enumerable: true, get: function () { return publishApp_1.parseCicdProgress; } });
|
|
97
|
+
Object.defineProperty(exports, "DEFAULT_PUBLISH_TIMEOUT_MS", { enumerable: true, get: function () { return publishApp_1.DEFAULT_PUBLISH_TIMEOUT_MS; } });
|
|
98
|
+
Object.defineProperty(exports, "PUBLISH_POLL_DELAYS_MS", { enumerable: true, get: function () { return publishApp_1.PUBLISH_POLL_DELAYS_MS; } });
|
package/dist/mcp/registry.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import type { ToolAnnotations } from "@tenonhq/dovetail-mcp-kit";
|
|
12
12
|
import type { ServiceNowClient } from "../client";
|
|
13
|
-
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", "action_edit", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit", "create_table", "add_column", "set_column", "set_field", "create_record", "host_assets", "invoke_rest"];
|
|
13
|
+
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", "action_edit", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit", "create_table", "add_column", "set_column", "set_table", "set_field", "create_record", "host_assets", "invoke_rest", "app_publish"];
|
|
14
14
|
export type ToolName = (typeof TOOL_NAMES)[number];
|
|
15
15
|
export interface RegistryDeps {
|
|
16
16
|
/** Optional client injection for tests; defaults to createClient({}). */
|
package/dist/mcp/registry.js
CHANGED
|
@@ -31,6 +31,7 @@ const hostAssets_1 = require("../hostAssets");
|
|
|
31
31
|
const setField_1 = require("../setField");
|
|
32
32
|
const createRecord_1 = require("../createRecord");
|
|
33
33
|
const invokeRest_1 = require("../invokeRest");
|
|
34
|
+
const publishApp_1 = require("../publishApp");
|
|
34
35
|
const schemas_1 = require("./schemas");
|
|
35
36
|
exports.TOOL_NAMES = [
|
|
36
37
|
"create_view",
|
|
@@ -49,10 +50,12 @@ exports.TOOL_NAMES = [
|
|
|
49
50
|
"create_table",
|
|
50
51
|
"add_column",
|
|
51
52
|
"set_column",
|
|
53
|
+
"set_table",
|
|
52
54
|
"set_field",
|
|
53
55
|
"create_record",
|
|
54
56
|
"host_assets",
|
|
55
57
|
"invoke_rest",
|
|
58
|
+
"app_publish",
|
|
56
59
|
];
|
|
57
60
|
// Annotation presets (READ_ONLY / WRITE_ADDITIVE_IDEMPOTENT / WRITE_CREATE /
|
|
58
61
|
// WRITE_OVERWRITE / WRITE_EXECUTE) come from @tenonhq/dovetail-mcp-kit.
|
|
@@ -391,6 +394,42 @@ function buildDescriptors(deps = {}) {
|
|
|
391
394
|
});
|
|
392
395
|
},
|
|
393
396
|
},
|
|
397
|
+
{
|
|
398
|
+
name: "set_table",
|
|
399
|
+
annotations: dovetail_mcp_kit_1.WRITE_OVERWRITE,
|
|
400
|
+
description: "Update an EXISTING ServiceNow TABLE's own dictionary attributes — the row where " +
|
|
401
|
+
"internal_type=collection and element is EMPTY — captured into a named update set, then " +
|
|
402
|
+
"READ BACK from the instance to verify. Completes the trio: set_field changes a RECORD's " +
|
|
403
|
+
"value, set_column changes a COLUMN's definition, set_table changes the TABLE's own. " +
|
|
404
|
+
"Currently settable: audit. audit=true turns RECORD AUDITING on for the whole table — " +
|
|
405
|
+
"ServiceNow then writes a sys_audit row per changed field on every insert and update, " +
|
|
406
|
+
"which is a real storage and write cost on a high-volume table, so weigh it before " +
|
|
407
|
+
"enabling. Attributes are a closed set, never an open field map; a COLUMN attribute " +
|
|
408
|
+
"(label/mandatory/default/maxLength/readOnly/element/internalType) is refused by name and " +
|
|
409
|
+
"redirected to set_column. When the requested value already matches, nothing is written " +
|
|
410
|
+
"and the status is 'unchanged' — note that an identical-value write also captures " +
|
|
411
|
+
"NOTHING, so there is no update-set row to promote. dryRun:true diffs against the " +
|
|
412
|
+
"instance and writes nothing.",
|
|
413
|
+
shape: schemas_1.setTableSchema.shape,
|
|
414
|
+
handler: async function (args) {
|
|
415
|
+
var p = schemas_1.setTableSchema.parse(args);
|
|
416
|
+
// Same live-path guard as set_column: the schema leaves updateSetSysId
|
|
417
|
+
// optional so dry-run works without one.
|
|
418
|
+
if (p.dryRun !== true &&
|
|
419
|
+
(!p.updateSetSysId || !p.updateSetSysId.trim())) {
|
|
420
|
+
throw new Error("set_table: updateSetSysId is required on the live path so the schema " +
|
|
421
|
+
"change is captured in a known update set — set dryRun:true to plan " +
|
|
422
|
+
"without one.");
|
|
423
|
+
}
|
|
424
|
+
return (0, table_1.setTable)({
|
|
425
|
+
client: client(),
|
|
426
|
+
table: p.table,
|
|
427
|
+
attributes: p.attributes,
|
|
428
|
+
updateSetSysId: p.updateSetSysId,
|
|
429
|
+
dryRun: p.dryRun,
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
},
|
|
394
433
|
{
|
|
395
434
|
name: "set_field",
|
|
396
435
|
annotations: dovetail_mcp_kit_1.WRITE_OVERWRITE,
|
|
@@ -491,6 +530,39 @@ function buildDescriptors(deps = {}) {
|
|
|
491
530
|
return (0, invokeRest_1.invokeRest)(params);
|
|
492
531
|
},
|
|
493
532
|
},
|
|
533
|
+
{
|
|
534
|
+
name: "app_publish",
|
|
535
|
+
annotations: dovetail_mcp_kit_1.WRITE_EXECUTE,
|
|
536
|
+
description: "Publish a scoped ServiceNow application to ONE target per call — the ServiceNow Store " +
|
|
537
|
+
"(target 'store') or the company Application Repository (target 'repo'); call twice to " +
|
|
538
|
+
"publish to both — then poll the publish to completion. STORE PUBLISH IS EXTERNALLY " +
|
|
539
|
+
"VISIBLE on the ServiceNow Store — treat it as a release. DRY-RUN BY DEFAULT: without " +
|
|
540
|
+
"confirm:true the resolved plan (app, current version, target) is returned and nothing is " +
|
|
541
|
+
"published. target 'store' replays the sys_app form's upload flow over a form-login session " +
|
|
542
|
+
"and requires SN_STORE_USERNAME/SN_STORE_PASSWORD in the server's env file — credentials " +
|
|
543
|
+
"never transit tool arguments. target 'repo' uses the supported CI/CD REST API " +
|
|
544
|
+
"(/api/sn_cicd/app_repo/publish) and requires the sn_cicd role. app is a scope name, " +
|
|
545
|
+
"sys_app sys_id, or app name; version must be above the currently published version. The " +
|
|
546
|
+
"result carries the progress-tracker id, per-step states, the Store appLink, and the " +
|
|
547
|
+
"publish's update-set sys_id where the instance reports one.",
|
|
548
|
+
shape: schemas_1.publishAppSchema.shape,
|
|
549
|
+
handler: async function (args) {
|
|
550
|
+
var p = schemas_1.publishAppSchema.parse(args);
|
|
551
|
+
var params = {
|
|
552
|
+
app: p.app,
|
|
553
|
+
version: p.version,
|
|
554
|
+
target: p.target,
|
|
555
|
+
devNotes: p.devNotes,
|
|
556
|
+
confirm: p.confirm,
|
|
557
|
+
dryRun: p.dryRun,
|
|
558
|
+
timeoutMs: p.timeoutMs,
|
|
559
|
+
};
|
|
560
|
+
if (deps.client) {
|
|
561
|
+
params.client = deps.client;
|
|
562
|
+
}
|
|
563
|
+
return (0, publishApp_1.publishApp)(params);
|
|
564
|
+
},
|
|
565
|
+
},
|
|
494
566
|
];
|
|
495
567
|
}
|
|
496
568
|
function registerAllTools(server, deps = {}) {
|
package/dist/mcp/schemas.d.ts
CHANGED
|
@@ -914,6 +914,43 @@ export declare var setColumnSchema: z.ZodObject<{
|
|
|
914
914
|
dryRun?: boolean | undefined;
|
|
915
915
|
updateSetSysId?: string | undefined;
|
|
916
916
|
}>;
|
|
917
|
+
export declare var tableAttributesSchema: z.ZodObject<{
|
|
918
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
919
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
920
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
921
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
922
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
923
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
924
|
+
export declare var setTableSchema: z.ZodObject<{
|
|
925
|
+
table: z.ZodString;
|
|
926
|
+
attributes: z.ZodObject<{
|
|
927
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
928
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
929
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
930
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
931
|
+
audit: z.ZodOptional<z.ZodBoolean>;
|
|
932
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
933
|
+
updateSetSysId: z.ZodOptional<z.ZodString>;
|
|
934
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
935
|
+
}, "strip", z.ZodTypeAny, {
|
|
936
|
+
table: string;
|
|
937
|
+
attributes: {
|
|
938
|
+
audit?: boolean | undefined;
|
|
939
|
+
} & {
|
|
940
|
+
[k: string]: unknown;
|
|
941
|
+
};
|
|
942
|
+
dryRun?: boolean | undefined;
|
|
943
|
+
updateSetSysId?: string | undefined;
|
|
944
|
+
}, {
|
|
945
|
+
table: string;
|
|
946
|
+
attributes: {
|
|
947
|
+
audit?: boolean | undefined;
|
|
948
|
+
} & {
|
|
949
|
+
[k: string]: unknown;
|
|
950
|
+
};
|
|
951
|
+
dryRun?: boolean | undefined;
|
|
952
|
+
updateSetSysId?: string | undefined;
|
|
953
|
+
}>;
|
|
917
954
|
export declare var setFieldSchema: z.ZodObject<{
|
|
918
955
|
table: z.ZodString;
|
|
919
956
|
sysId: z.ZodOptional<z.ZodString>;
|
|
@@ -958,6 +995,31 @@ export declare var createRecordSchema: z.ZodObject<{
|
|
|
958
995
|
dryRun?: boolean | undefined;
|
|
959
996
|
ifAbsentQuery?: string | undefined;
|
|
960
997
|
}>;
|
|
998
|
+
export declare var publishAppSchema: z.ZodObject<{
|
|
999
|
+
app: z.ZodString;
|
|
1000
|
+
version: z.ZodString;
|
|
1001
|
+
devNotes: z.ZodOptional<z.ZodString>;
|
|
1002
|
+
target: z.ZodUnion<[z.ZodLiteral<"store">, z.ZodLiteral<"repo">]>;
|
|
1003
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
1004
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
1005
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
1006
|
+
}, "strip", z.ZodTypeAny, {
|
|
1007
|
+
target: "store" | "repo";
|
|
1008
|
+
version: string;
|
|
1009
|
+
app: string;
|
|
1010
|
+
confirm?: boolean | undefined;
|
|
1011
|
+
dryRun?: boolean | undefined;
|
|
1012
|
+
devNotes?: string | undefined;
|
|
1013
|
+
timeoutMs?: number | undefined;
|
|
1014
|
+
}, {
|
|
1015
|
+
target: "store" | "repo";
|
|
1016
|
+
version: string;
|
|
1017
|
+
app: string;
|
|
1018
|
+
confirm?: boolean | undefined;
|
|
1019
|
+
dryRun?: boolean | undefined;
|
|
1020
|
+
devNotes?: string | undefined;
|
|
1021
|
+
timeoutMs?: number | undefined;
|
|
1022
|
+
}>;
|
|
961
1023
|
export declare var invokeRestSchema: z.ZodObject<{
|
|
962
1024
|
method: z.ZodEffects<z.ZodEnum<["GET", "POST", "PUT", "DELETE"]>, "GET" | "DELETE" | "POST" | "PUT", unknown>;
|
|
963
1025
|
path: z.ZodString;
|
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.invokeRestSchema = exports.createRecordSchema = exports.setFieldSchema = exports.setColumnSchema = exports.columnAttributesSchema = exports.addColumnSchema = exports.createTableSchema = exports.columnSpecSchema = exports.hostAssetsSchema = exports.editFlowSchema = exports.editActionSchema = 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;
|
|
7
|
+
exports.invokeRestSchema = exports.publishAppSchema = exports.createRecordSchema = exports.setFieldSchema = exports.setTableSchema = exports.tableAttributesSchema = exports.setColumnSchema = exports.columnAttributesSchema = exports.addColumnSchema = exports.createTableSchema = exports.columnSpecSchema = exports.hostAssetsSchema = exports.editFlowSchema = exports.editActionSchema = 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),
|
|
@@ -241,6 +241,28 @@ exports.setColumnSchema = zod_1.z.object({
|
|
|
241
241
|
updateSetSysId: zod_1.z.string().min(1).optional(),
|
|
242
242
|
dryRun: zod_1.z.boolean().optional(),
|
|
243
243
|
});
|
|
244
|
+
// set-table takes a CLOSED attribute set for the same reason set-column does: an
|
|
245
|
+
// unbounded write to sys_dictionary lets a caller silently corrupt schema. These are
|
|
246
|
+
// the TABLE's own attributes (the internal_type=collection row), not a column's.
|
|
247
|
+
//
|
|
248
|
+
// .passthrough() is deliberate: z.object() strips unknown keys by default, which would
|
|
249
|
+
// silently drop a column attribute (or a typo) BEFORE resolveTableAttributes could see
|
|
250
|
+
// it — so { audit:true, label:"x" } would succeed, quietly discarding label. Passing
|
|
251
|
+
// unknown keys through lets the core allowlist reject them (a column attribute earns the
|
|
252
|
+
// "use set-column" redirect; anything else, "not a settable table attribute").
|
|
253
|
+
exports.tableAttributesSchema = zod_1.z
|
|
254
|
+
.object({
|
|
255
|
+
audit: zod_1.z.boolean().optional(),
|
|
256
|
+
})
|
|
257
|
+
.passthrough();
|
|
258
|
+
exports.setTableSchema = zod_1.z.object({
|
|
259
|
+
table: zod_1.z.string().min(1),
|
|
260
|
+
attributes: exports.tableAttributesSchema,
|
|
261
|
+
// Optional because dryRun works without one; the live-path requirement is
|
|
262
|
+
// enforced at the tool boundary (registry.ts), matching set_column.
|
|
263
|
+
updateSetSysId: zod_1.z.string().min(1).optional(),
|
|
264
|
+
dryRun: zod_1.z.boolean().optional(),
|
|
265
|
+
});
|
|
244
266
|
// Data-record write verbs. Kept as plain z.object (no .refine wrapper) so
|
|
245
267
|
// registry.ts can read `.shape`; the deeper rules — one of sysId/query, at
|
|
246
268
|
// least one field, the schema-table refusal — are enforced by the core
|
|
@@ -261,6 +283,19 @@ exports.createRecordSchema = zod_1.z.object({
|
|
|
261
283
|
ifAbsentQuery: zod_1.z.string().optional(),
|
|
262
284
|
dryRun: zod_1.z.boolean().optional(),
|
|
263
285
|
});
|
|
286
|
+
// app_publish: publish a scoped app to the ServiceNow Store or the company
|
|
287
|
+
// application repository. Deliberately NO credential fields — the Store
|
|
288
|
+
// account resolves from SN_STORE_USERNAME/SN_STORE_PASSWORD inside the verb,
|
|
289
|
+
// so credentials never transit MCP arguments or telemetry.
|
|
290
|
+
exports.publishAppSchema = zod_1.z.object({
|
|
291
|
+
app: zod_1.z.string().min(1),
|
|
292
|
+
version: zod_1.z.string().min(1),
|
|
293
|
+
devNotes: zod_1.z.string().optional(),
|
|
294
|
+
target: zod_1.z.union([zod_1.z.literal("store"), zod_1.z.literal("repo")]),
|
|
295
|
+
confirm: zod_1.z.boolean().optional(),
|
|
296
|
+
dryRun: zod_1.z.boolean().optional(),
|
|
297
|
+
timeoutMs: zod_1.z.number().int().positive().optional(),
|
|
298
|
+
});
|
|
264
299
|
// invoke_rest: transport primitive for arbitrary authenticated REST operations
|
|
265
300
|
// (Scripted REST included). The dry-run-unless-confirm gate lives in invokeRest
|
|
266
301
|
// itself; the regex here rejects absolute URLs and non-/api/ paths early.
|