@tenonhq/dovetail-servicenow 0.0.48 → 0.0.50
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 +12 -1
- package/dist/cli.js +59 -3
- package/dist/cliUsage.js +37 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -2
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/registry.js +44 -1
- package/dist/mcp/schemas.d.ts +22 -0
- package/dist/mcp/schemas.js +18 -1
- package/dist/table/addColumn.d.ts +70 -3
- package/dist/table/addColumn.js +334 -45
- package/dist/table/designAccess.d.ts +75 -0
- package/dist/table/designAccess.js +250 -0
- package/dist/table/index.d.ts +3 -1
- package/dist/table/index.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1151,7 +1151,18 @@ console.log(formatLayoutResult("form layout", result));
|
|
|
1151
1151
|
`dove-sn mcp` runs a self-contained MCP stdio server exposing the tools to
|
|
1152
1152
|
Claude Code and agents: `create_view`, `set_list_layout`, `set_form_layout`,
|
|
1153
1153
|
`set_related_lists`, `add_choices_to_field`, the schema verbs `create_table` /
|
|
1154
|
-
`add_column`
|
|
1154
|
+
`add_column` (same-scope by default; `crossScope: true` with `scope` adds a column OWNED
|
|
1155
|
+
by another app — a Journey field on an Automate table, element `<scope>_<name>` —
|
|
1156
|
+
guarded by `sys_db_object.alter_access` and the update set's scope, with the stored
|
|
1157
|
+
element and `sys_scope` read back; the CLI flag is `--cross-scope`. A cross-scope
|
|
1158
|
+
result also carries `designAccess`: the platform UI refuses cross-scope authoring
|
|
1159
|
+
without a `sys_scope_design_access` record (column scope -> table scope), so a missing
|
|
1160
|
+
one is FLAGGED — not blocking, the headless insert works without it — and
|
|
1161
|
+
`ensureDesignAccess: true` / `--ensure-design-access` creates it first in the same
|
|
1162
|
+
update set) / `design_access` (ensure that record on its own — idempotent, created in
|
|
1163
|
+
the SOURCE app's update set and read back; CLI `dove-sn design-access --source <app>
|
|
1164
|
+
--target <app> --update-set <sys_id>`, `--dry-run` only reports exists/missing) /
|
|
1165
|
+
`add_index` (a single-column unique index via `sys_dictionary.unique`,
|
|
1155
1166
|
read back from the `v_db_index` view - uniqueness enforcement is always reported
|
|
1156
1167
|
unverified) / `index_list` (read-only: a table's database indexes from `v_db_index`,
|
|
1157
1168
|
the only index read surface - `sys_index` is API-level-ACL 403 and `sys_index_column`
|
package/dist/cli.js
CHANGED
|
@@ -1340,14 +1340,60 @@ async function runCreateTable(flags) {
|
|
|
1340
1340
|
return 2;
|
|
1341
1341
|
return 0;
|
|
1342
1342
|
}
|
|
1343
|
+
/**
|
|
1344
|
+
* dove-sn design-access:
|
|
1345
|
+
* --source x_cadso_journey --target x_cadso_automate
|
|
1346
|
+
* [--update-set <sys_id in source>] [--dry-run] [--json]
|
|
1347
|
+
* Ensures the sys_scope_design_access record that lets the SOURCE app author in the
|
|
1348
|
+
* TARGET app's tables (required by the platform UI for cross-scope columns). Idempotent;
|
|
1349
|
+
* --dry-run only reports whether it exists. --update-set is required unless --dry-run.
|
|
1350
|
+
*/
|
|
1351
|
+
async function runDesignAccess(flags) {
|
|
1352
|
+
if (!flags.source || !flags.target) {
|
|
1353
|
+
process.stderr.write("design-access: --source (authoring app) and --target (app that owns the tables) are required\n");
|
|
1354
|
+
return 1;
|
|
1355
|
+
}
|
|
1356
|
+
var isDryRun = flags["dry-run"] === "true";
|
|
1357
|
+
if (!isDryRun && !flags["update-set"]) {
|
|
1358
|
+
process.stderr.write("design-access: --update-set (an update set in --source) is required on the live path (only --dry-run works without one)\n");
|
|
1359
|
+
return 1;
|
|
1360
|
+
}
|
|
1361
|
+
var result = await (0, table_1.ensureDesignAccess)({
|
|
1362
|
+
client: (0, client_1.createClient)({}),
|
|
1363
|
+
sourceScope: flags.source,
|
|
1364
|
+
targetScope: flags.target,
|
|
1365
|
+
updateSetSysId: flags["update-set"],
|
|
1366
|
+
dryRun: isDryRun,
|
|
1367
|
+
});
|
|
1368
|
+
if (flags.json === "true") {
|
|
1369
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
process.stdout.write("[" +
|
|
1373
|
+
result.status +
|
|
1374
|
+
"] " +
|
|
1375
|
+
result.sourceScope +
|
|
1376
|
+
" -> " +
|
|
1377
|
+
result.targetScope +
|
|
1378
|
+
(result.sysId ? " (" + result.sysId + ")" : "") +
|
|
1379
|
+
"\n" +
|
|
1380
|
+
result.note +
|
|
1381
|
+
"\n");
|
|
1382
|
+
}
|
|
1383
|
+
if (result.status === "failed")
|
|
1384
|
+
return 2;
|
|
1385
|
+
return 0;
|
|
1386
|
+
}
|
|
1343
1387
|
/**
|
|
1344
1388
|
* dove-sn add-column:
|
|
1345
1389
|
* --table x_cadso_journey --label URL --type url
|
|
1346
1390
|
* [--name url] [--max-length 1024] [--reference <table>]
|
|
1347
1391
|
* [--mandatory] [--default <value>] [--dependent-on-field <element>]
|
|
1348
|
-
* [--scope x_cadso_journey] [--
|
|
1349
|
-
* [--from-json <spec.json>] [--dry-run] [--debug] [--json]
|
|
1350
|
-
* --update-set is required unless --dry-run.
|
|
1392
|
+
* [--scope x_cadso_journey] [--cross-scope] [--ensure-design-access]
|
|
1393
|
+
* [--update-set <sys_id>] [--from-json <spec.json>] [--dry-run] [--debug] [--json]
|
|
1394
|
+
* --update-set is required unless --dry-run. --cross-scope opts in to a column
|
|
1395
|
+
* OWNED by --scope when that differs from the table's scope; a missing Design Access
|
|
1396
|
+
* record is flagged, and --ensure-design-access creates it first.
|
|
1351
1397
|
*/
|
|
1352
1398
|
async function runAddColumn(flags) {
|
|
1353
1399
|
var spec = {};
|
|
@@ -1384,6 +1430,13 @@ async function runAddColumn(flags) {
|
|
|
1384
1430
|
var scope = flags.scope || spec.scope;
|
|
1385
1431
|
if (scope)
|
|
1386
1432
|
params.scope = scope;
|
|
1433
|
+
if (flags["cross-scope"] === "true" || spec.crossScope === true) {
|
|
1434
|
+
params.crossScope = true;
|
|
1435
|
+
}
|
|
1436
|
+
if (flags["ensure-design-access"] === "true" ||
|
|
1437
|
+
spec.ensureDesignAccess === true) {
|
|
1438
|
+
params.ensureDesignAccess = true;
|
|
1439
|
+
}
|
|
1387
1440
|
var us = flags["update-set"] || spec.updateSetSysId;
|
|
1388
1441
|
if (us)
|
|
1389
1442
|
params.updateSetSysId = us;
|
|
@@ -2612,6 +2665,9 @@ async function dispatch(parsed) {
|
|
|
2612
2665
|
if (parsed.command === "add-column") {
|
|
2613
2666
|
return await runAddColumn(parsed.flags);
|
|
2614
2667
|
}
|
|
2668
|
+
if (parsed.command === "design-access") {
|
|
2669
|
+
return await runDesignAccess(parsed.flags);
|
|
2670
|
+
}
|
|
2615
2671
|
if (parsed.command === "add-index") {
|
|
2616
2672
|
return await runAddIndex(parsed.flags);
|
|
2617
2673
|
}
|
package/dist/cliUsage.js
CHANGED
|
@@ -200,7 +200,19 @@ exports.VERB_USAGE = {
|
|
|
200
200
|
value: "<element>",
|
|
201
201
|
note: "Sibling column a document_id resolves against (its table_name column); must already exist.",
|
|
202
202
|
},
|
|
203
|
-
{
|
|
203
|
+
{
|
|
204
|
+
flag: "scope",
|
|
205
|
+
value: "<x_scope>",
|
|
206
|
+
note: "Owning app scope. Must match the table's scope unless --cross-scope is passed.",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
flag: "cross-scope",
|
|
210
|
+
note: "Opt in to a column OWNED by --scope, which differs from the table's scope (element becomes <scope>_<name>; the table must allow new fields; --update-set must be in --scope).",
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
flag: "ensure-design-access",
|
|
214
|
+
note: "Cross-scope only: create the missing sys_scope_design_access record (--scope -> table's scope) first, in the same update set. Without it a missing record is only flagged.",
|
|
215
|
+
},
|
|
204
216
|
{ flag: "update-set", value: "<sys_id>", note: "REQUIRED on the live path (only --dry-run works without one)." },
|
|
205
217
|
DRY_RUN_FLAG,
|
|
206
218
|
DEBUG_FLAG,
|
|
@@ -209,7 +221,30 @@ exports.VERB_USAGE = {
|
|
|
209
221
|
gate: "dry-run-flag",
|
|
210
222
|
gateNote: "--update-set is required unless --dry-run.",
|
|
211
223
|
example: "dove-sn add-column --table x_cadso_journey --label URL --type url --max-length 1024 --update-set <sys_id>",
|
|
212
|
-
notes: [
|
|
224
|
+
notes: [
|
|
225
|
+
"Exit 2 when the write landed but the read-back does not show the column.",
|
|
226
|
+
"Cross-scope: dove-sn add-column --table x_cadso_automate_email_batch --label 'Instance Step' --name instance_step --type reference --reference x_cadso_journey_instance_step --scope x_cadso_journey --cross-scope --update-set <journey set>",
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
"design-access": {
|
|
230
|
+
summary: "Ensure the sys_scope_design_access record that lets one app author in another app's tables (required by the UI for cross-scope columns)",
|
|
231
|
+
required: [
|
|
232
|
+
{ flag: "source", value: "<x_scope>", note: "The AUTHORING app (owns the record and its update set)." },
|
|
233
|
+
{ flag: "target", value: "<x_scope>", note: "The app that OWNS the tables." },
|
|
234
|
+
],
|
|
235
|
+
optional: [
|
|
236
|
+
{ flag: "update-set", value: "<sys_id>", note: "Update set in --source. REQUIRED on the live path." },
|
|
237
|
+
DRY_RUN_FLAG,
|
|
238
|
+
JSON_FLAG,
|
|
239
|
+
],
|
|
240
|
+
gate: "dry-run-flag",
|
|
241
|
+
gateNote: "--update-set is required unless --dry-run; --dry-run reports exists/missing only.",
|
|
242
|
+
example: "dove-sn design-access --source x_cadso_journey --target x_cadso_automate --update-set <journey set>",
|
|
243
|
+
notes: [
|
|
244
|
+
"Idempotent: an existing record is reported and nothing is written.",
|
|
245
|
+
"Symptom it fixes: \"Invalid 'Table' selected on the Dictionary Entry record ... can only select '<app>' tables with read access enabled\" — the table's own access flags are NOT the gate.",
|
|
246
|
+
"Exit 2 when the record could not be created or verified on read-back.",
|
|
247
|
+
],
|
|
213
248
|
},
|
|
214
249
|
"set-column": {
|
|
215
250
|
summary: "Update an EXISTING column's schema (label/mandatory/default/read-only/max-length/dependent-on-field), then verify",
|
package/dist/index.d.ts
CHANGED
|
@@ -21,8 +21,8 @@ export { sincPlugin } from "./plugin";
|
|
|
21
21
|
export { listTemplates, verifyArtifact, cloneSubflow, cloneActionType, resolveScope, slugInternalName, fetchActionSteps, findStepInput, triggerPublication, publishActionType, editActionType, defineActionType, planActionDefinition, validateDefineSpec, applyStepOps, verifySteps, summarizeSteps, formatStepPill, readFlow, readActionType, publishFlow, copyFlow, createFlow, buildPublishModel, editFlow, testFlow, DEFAULT_RUN_FLOW_PATH, generateSysId, topoSort, executeWritePlan, WriteOrderError, } from "./flowDesigner";
|
|
22
22
|
export type { TemplateRef, ListTemplatesParams, FlowKind, VerifyExpect, VerifyFound, VerifyFailure, VerifyReport, VerifyArtifactParams, CloneSubflowParams, CloneSubflowResult, CloneActionTypeParams, CloneActionTypeResult, CloneActionTypePlan, CloneActionTypeStepReport, TriggerPublicationParams, TriggerPublicationResult, PublishActionTypeParams, PublishActionTypeResult, EditActionTypeParams, EditActionTypeResult, EditActionTypeOps, DefineActionSpec, DefineActionInputSpec, DefineActionOutputSpec, DefineStepSpec, DefineStepVarSpec, DefineStepOutputSpec, DefineStepValue, DefineActionTypeParams, DefineActionTypeResult, DefineActionDiff, DefineActionPlan, PlanActionDefinitionParams, ActionView, StepView, StepOps, StepRecord, StepSummary, StepIoSummary, PatchStepScriptOp, SetStepInputOp, 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";
|
|
23
23
|
export type { ServiceNowClientConfig, ChoiceValue, ChoiceType, AddChoicesParams, AddChoicesResult, ChoiceActionResult, ChoiceFieldRef, RemoveChoicesParams, RemoveChoicesResult, ChoiceRemovalResult, DictionaryRecord, UpdateSetRecord, LayoutAction, LayoutRecordResult, LayoutResult, CreateViewParams, CreateViewResult, FormSectionSpec, SetFormLayoutParams, SetListLayoutParams, SetRelatedListsParams, ChunkRole, ChunkInfo, ChunkResult, PrunedResult, HostAssetsParams, HostAssetsResult, } from "./types";
|
|
24
|
-
export { createTable, projectTableGraph, buildColumnXml, normalizeColumns, resolveType, applyTableSaveOverlay, defaultAccessFlags, TYPE_MAP, DEFAULT_SUPER_CLASS, DEFAULT_SAVE_ACTION, addColumn, deriveElement, addIndex, parseIndexColumns, indexMatchesColumns, listIndexes, createIndex, validateCreateIndex, DEFAULT_INDEX_FORM_PATH, NOT_IN_UPDATE_SET, setColumn, resolveAttributes, toStoredValue, setTable, resolveTableAttributes, } from "./table";
|
|
25
|
-
export type { CreateTableParams, CreateTableResult, AddColumnParams, AddColumnResult, AddIndexParams, AddIndexResult, AddIndexVerification, ListIndexesParams, ListIndexesResult, TableIndex, CreateIndexParams, CreateIndexResult, SetColumnParams, SetColumnResult, ColumnAttributes, AttributeChange, SetTableParams, SetTableResult, TableAttributes, TableGraph, NormalizedColumn, ColumnSpec, AccessFlags, OverlaySpec, } from "./table";
|
|
24
|
+
export { createTable, projectTableGraph, buildColumnXml, normalizeColumns, resolveType, applyTableSaveOverlay, defaultAccessFlags, TYPE_MAP, DEFAULT_SUPER_CLASS, DEFAULT_SAVE_ACTION, addColumn, deriveElement, ensureDesignAccess, findDesignAccess, DESIGN_ACCESS_TABLE, addIndex, parseIndexColumns, indexMatchesColumns, listIndexes, createIndex, validateCreateIndex, DEFAULT_INDEX_FORM_PATH, NOT_IN_UPDATE_SET, setColumn, resolveAttributes, toStoredValue, setTable, resolveTableAttributes, } from "./table";
|
|
25
|
+
export type { CreateTableParams, CreateTableResult, AddColumnParams, AddColumnResult, DesignAccessFlag, EnsureDesignAccessParams, EnsureDesignAccessResult, AddIndexParams, AddIndexResult, AddIndexVerification, ListIndexesParams, ListIndexesResult, TableIndex, CreateIndexParams, CreateIndexResult, SetColumnParams, SetColumnResult, ColumnAttributes, AttributeChange, SetTableParams, SetTableResult, TableAttributes, TableGraph, NormalizedColumn, ColumnSpec, AccessFlags, OverlaySpec, } from "./table";
|
|
26
26
|
export { setField } from "./setField";
|
|
27
27
|
export { createRecord } from "./createRecord";
|
|
28
28
|
export type { RecordWriteResult, SetFieldParams, SetFieldResult, } from "./setField";
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.editFlow = exports.buildPublishModel = exports.createFlow = exports.copyFlow = exports.publishFlow = exports.readActionType = exports.readFlow = exports.formatStepPill = exports.summarizeSteps = exports.verifySteps = exports.applyStepOps = exports.validateDefineSpec = exports.planActionDefinition = exports.defineActionType = exports.editActionType = exports.publishActionType = exports.triggerPublication = exports.findStepInput = exports.fetchActionSteps = exports.slugInternalName = exports.resolveScope = exports.cloneActionType = exports.cloneSubflow = exports.verifyArtifact = exports.listTemplates = exports.sincPlugin = exports.formatCreateViewResult = exports.formatLayoutResult = exports.setRelatedLists = exports.setFormLayout = exports.setListLayout = exports.createView = exports.formatRemoveChoicesResult = exports.formatAddChoicesResult = exports.formatHostAssetsResult = exports.classifyChunks = exports.hostAssets = exports.ChoiceWriteError = exports.removeChoicesFromField = exports.addChoicesToField = exports.resolveConfigFromEnvFile = exports.createClientFromEnvFile = exports.assertWriteAllowed = exports.evaluateWriteGate = exports.isCiEnvironment = exports.resolveExecutionContext = exports.PROCESSFLOW_PATH_PREFIX = exports.isProcessflowPath = exports.resolveFlowAuth = exports.createClient = void 0;
|
|
10
|
-
exports.
|
|
11
|
-
exports.SECRET_INTERNAL_TYPES = exports.SENTINEL = exports.isCapturable = exports.secretFieldsFromDictionary = exports.mergeSecretRules = exports.loadSecretRules = exports.defaultSecretRules = exports.escapeRegExp = exports.encodeXmlText = exports.encodeXmlEntities = exports.stripJsonValue = exports.stripField = exports.plannedStrips = exports.recordFieldNames = exports.readRecordTable = exports.readField = exports.verifyStripped = exports.stripSecrets = exports.DEFAULT_EXPORT_APP_TIMEOUT_MS = exports.buildPublishFields = exports.buildCreateSetFields = exports.exportApp = exports.DEFAULT_MAX_ROWS = exports.MAX_PAGE_SIZE = exports.DEFAULT_PAGE_SIZE = exports.UPDATE_XML_FIELDS = exports.xmlEscape = exports.formatUnloadDate = exports.parseStatsCount = exports.refreshTypeFields = exports.fetchUpdateXmlRows = exports.countUpdateXml = exports.countUnloadRecords = exports.renderUnload = exports.renderRemoteUpdateSet = exports.renderUpdateXmlRow = exports.exportUpdateSet = exports.PUBLISH_POLL_DELAYS_MS = exports.DEFAULT_PUBLISH_TIMEOUT_MS = exports.parseCicdProgress = exports.parseCicdPublishResponse = exports.harvestProgressResults = exports.flattenSteps = exports.classifyProgress = void 0;
|
|
10
|
+
exports.parsePublishTargets = exports.describeTarget = exports.resolveUpdateSetNaming = exports.buildPublishToUpdateSetFields = exports.buildCreateUpdateSetFields = exports.buildStartFields = exports.publishApp = exports.INVOKE_REST_METHODS = exports.invokeRest = exports.verifyReadBack = exports.readBackMatches = exports.hasHtmlEntity = exports.decodeHtmlEntities = exports.deleteRecord = exports.createRecord = exports.setField = exports.resolveTableAttributes = exports.setTable = exports.toStoredValue = exports.resolveAttributes = exports.setColumn = exports.NOT_IN_UPDATE_SET = exports.DEFAULT_INDEX_FORM_PATH = exports.validateCreateIndex = exports.createIndex = exports.listIndexes = exports.indexMatchesColumns = exports.parseIndexColumns = exports.addIndex = exports.DESIGN_ACCESS_TABLE = exports.findDesignAccess = exports.ensureDesignAccess = exports.deriveElement = 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 = void 0;
|
|
11
|
+
exports.SECRET_INTERNAL_TYPES = exports.SENTINEL = exports.isCapturable = exports.secretFieldsFromDictionary = exports.mergeSecretRules = exports.loadSecretRules = exports.defaultSecretRules = exports.escapeRegExp = exports.encodeXmlText = exports.encodeXmlEntities = exports.stripJsonValue = exports.stripField = exports.plannedStrips = exports.recordFieldNames = exports.readRecordTable = exports.readField = exports.verifyStripped = exports.stripSecrets = exports.DEFAULT_EXPORT_APP_TIMEOUT_MS = exports.buildPublishFields = exports.buildCreateSetFields = exports.exportApp = exports.DEFAULT_MAX_ROWS = exports.MAX_PAGE_SIZE = exports.DEFAULT_PAGE_SIZE = exports.UPDATE_XML_FIELDS = exports.xmlEscape = exports.formatUnloadDate = exports.parseStatsCount = exports.refreshTypeFields = exports.fetchUpdateXmlRows = exports.countUpdateXml = exports.countUnloadRecords = exports.renderUnload = exports.renderRemoteUpdateSet = exports.renderUpdateXmlRow = exports.exportUpdateSet = 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.PUBLISH_TARGETS = void 0;
|
|
12
12
|
var client_1 = require("./client");
|
|
13
13
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
14
14
|
Object.defineProperty(exports, "resolveFlowAuth", { enumerable: true, get: function () { return client_1.resolveFlowAuth; } });
|
|
@@ -91,6 +91,9 @@ Object.defineProperty(exports, "DEFAULT_SUPER_CLASS", { enumerable: true, get: f
|
|
|
91
91
|
Object.defineProperty(exports, "DEFAULT_SAVE_ACTION", { enumerable: true, get: function () { return table_1.DEFAULT_SAVE_ACTION; } });
|
|
92
92
|
Object.defineProperty(exports, "addColumn", { enumerable: true, get: function () { return table_1.addColumn; } });
|
|
93
93
|
Object.defineProperty(exports, "deriveElement", { enumerable: true, get: function () { return table_1.deriveElement; } });
|
|
94
|
+
Object.defineProperty(exports, "ensureDesignAccess", { enumerable: true, get: function () { return table_1.ensureDesignAccess; } });
|
|
95
|
+
Object.defineProperty(exports, "findDesignAccess", { enumerable: true, get: function () { return table_1.findDesignAccess; } });
|
|
96
|
+
Object.defineProperty(exports, "DESIGN_ACCESS_TABLE", { enumerable: true, get: function () { return table_1.DESIGN_ACCESS_TABLE; } });
|
|
94
97
|
Object.defineProperty(exports, "addIndex", { enumerable: true, get: function () { return table_1.addIndex; } });
|
|
95
98
|
Object.defineProperty(exports, "parseIndexColumns", { enumerable: true, get: function () { return table_1.parseIndexColumns; } });
|
|
96
99
|
Object.defineProperty(exports, "indexMatchesColumns", { enumerable: true, get: function () { return table_1.indexMatchesColumns; } });
|
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", "remove_choices_from_field", "flow_view", "action_view", "action_edit", "action_clone", "action_define", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit", "create_table", "add_column", "add_index", "index_list", "index_create", "set_column", "set_table", "set_field", "create_record", "delete_record", "host_assets", "invoke_rest", "app_publish", "update_set_export", "app_export"];
|
|
13
|
+
export declare var TOOL_NAMES: readonly ["create_view", "set_list_layout", "set_form_layout", "set_related_lists", "add_choices_to_field", "remove_choices_from_field", "flow_view", "action_view", "action_edit", "action_clone", "action_define", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit", "create_table", "add_column", "design_access", "add_index", "index_list", "index_create", "set_column", "set_table", "set_field", "create_record", "delete_record", "host_assets", "invoke_rest", "app_publish", "update_set_export", "app_export"];
|
|
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
|
@@ -57,6 +57,7 @@ exports.TOOL_NAMES = [
|
|
|
57
57
|
"flow_edit",
|
|
58
58
|
"create_table",
|
|
59
59
|
"add_column",
|
|
60
|
+
"design_access",
|
|
60
61
|
"add_index",
|
|
61
62
|
"index_list",
|
|
62
63
|
"index_create",
|
|
@@ -440,7 +441,17 @@ function buildDescriptors(deps = {}) {
|
|
|
440
441
|
"table NAME; element is derived from label unless column.name is given. dependent_on_field names " +
|
|
441
442
|
"the sibling column a document_id column resolves against (its table_name column) — it must " +
|
|
442
443
|
"already exist on the table, is verified on the read-back, and is refused when absent. " +
|
|
443
|
-
"
|
|
444
|
+
"scope must match the table's scope unless crossScope:true, which opts in to a column OWNED " +
|
|
445
|
+
"by scope on another app's table (the platform's cross-scope field: element becomes " +
|
|
446
|
+
"<scope>_<name>, the dictionary row and its update-set capture land in scope); the table " +
|
|
447
|
+
"must allow new fields from other scopes (sys_db_object.alter_access) and updateSetSysId " +
|
|
448
|
+
"must belong to scope — both checked on dryRun too, and the stored element + sys_scope are " +
|
|
449
|
+
"read back. A cross-scope result carries designAccess { present, sysId, created }: the " +
|
|
450
|
+
"platform UI refuses cross-scope authoring without a sys_scope_design_access record " +
|
|
451
|
+
"(scope -> the table's scope), so a missing one is FLAGGED (not blocking — the headless " +
|
|
452
|
+
"insert works without it); ensureDesignAccess:true creates it first in the same update " +
|
|
453
|
+
"set. updateSetSysId is required on the live path. dryRun:true returns the plan with " +
|
|
454
|
+
"no writes.",
|
|
444
455
|
shape: schemas_1.addColumnSchema.shape,
|
|
445
456
|
handler: async function (args) {
|
|
446
457
|
var p = schemas_1.addColumnSchema.parse(args);
|
|
@@ -458,12 +469,44 @@ function buildDescriptors(deps = {}) {
|
|
|
458
469
|
table: p.table,
|
|
459
470
|
column: p.column,
|
|
460
471
|
scope: p.scope,
|
|
472
|
+
crossScope: p.crossScope,
|
|
473
|
+
ensureDesignAccess: p.ensureDesignAccess,
|
|
461
474
|
updateSetSysId: p.updateSetSysId,
|
|
462
475
|
dryRun: p.dryRun,
|
|
463
476
|
debug: p.debug,
|
|
464
477
|
});
|
|
465
478
|
},
|
|
466
479
|
},
|
|
480
|
+
{
|
|
481
|
+
name: "design_access",
|
|
482
|
+
annotations: dovetail_mcp_kit_1.WRITE_CREATE,
|
|
483
|
+
description: "Ensure the sys_scope_design_access record that lets sourceScope (the AUTHORING app) " +
|
|
484
|
+
"design in targetScope's tables (the app that OWNS them). The platform UI requires it " +
|
|
485
|
+
"for cross-scope columns — the symptom is \"Invalid 'Table' selected on the Dictionary " +
|
|
486
|
+
"Entry record ... can only select '<app>' tables with read access enabled\", and the " +
|
|
487
|
+
"table's own access flags are NOT the gate. Scopes are names or sys_scope sys_ids. " +
|
|
488
|
+
"Idempotent: an existing record returns status 'exists' and nothing is written. Live " +
|
|
489
|
+
"creates it via the scope-aware createRecord op switched to sourceScope, captured in " +
|
|
490
|
+
"updateSetSysId (must belong to sourceScope), then reads it back and asserts " +
|
|
491
|
+
"source/target. updateSetSysId is required on the live path; dryRun:true only reports " +
|
|
492
|
+
"exists / missing.",
|
|
493
|
+
shape: schemas_1.designAccessSchema.shape,
|
|
494
|
+
handler: async function (args) {
|
|
495
|
+
var p = schemas_1.designAccessSchema.parse(args);
|
|
496
|
+
if (p.dryRun !== true &&
|
|
497
|
+
(!p.updateSetSysId || !p.updateSetSysId.trim())) {
|
|
498
|
+
throw new Error("design_access: updateSetSysId (an update set in sourceScope) is required on " +
|
|
499
|
+
"the live path — set dryRun:true to only check whether the record exists.");
|
|
500
|
+
}
|
|
501
|
+
return (0, table_1.ensureDesignAccess)({
|
|
502
|
+
client: client(),
|
|
503
|
+
sourceScope: p.sourceScope,
|
|
504
|
+
targetScope: p.targetScope,
|
|
505
|
+
updateSetSysId: p.updateSetSysId,
|
|
506
|
+
dryRun: p.dryRun,
|
|
507
|
+
});
|
|
508
|
+
},
|
|
509
|
+
},
|
|
467
510
|
{
|
|
468
511
|
name: "add_index",
|
|
469
512
|
annotations: dovetail_mcp_kit_1.WRITE_OVERWRITE,
|
package/dist/mcp/schemas.d.ts
CHANGED
|
@@ -1890,6 +1890,8 @@ export declare var addColumnSchema: z.ZodObject<{
|
|
|
1890
1890
|
dependent_on_field?: string | undefined;
|
|
1891
1891
|
}>;
|
|
1892
1892
|
scope: z.ZodOptional<z.ZodString>;
|
|
1893
|
+
crossScope: z.ZodOptional<z.ZodBoolean>;
|
|
1894
|
+
ensureDesignAccess: z.ZodOptional<z.ZodBoolean>;
|
|
1893
1895
|
updateSetSysId: z.ZodOptional<z.ZodString>;
|
|
1894
1896
|
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
1895
1897
|
debug: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1909,6 +1911,8 @@ export declare var addColumnSchema: z.ZodObject<{
|
|
|
1909
1911
|
debug?: boolean | undefined;
|
|
1910
1912
|
updateSetSysId?: string | undefined;
|
|
1911
1913
|
scope?: string | undefined;
|
|
1914
|
+
crossScope?: boolean | undefined;
|
|
1915
|
+
ensureDesignAccess?: boolean | undefined;
|
|
1912
1916
|
}, {
|
|
1913
1917
|
table: string;
|
|
1914
1918
|
column: {
|
|
@@ -1925,6 +1929,24 @@ export declare var addColumnSchema: z.ZodObject<{
|
|
|
1925
1929
|
debug?: boolean | undefined;
|
|
1926
1930
|
updateSetSysId?: string | undefined;
|
|
1927
1931
|
scope?: string | undefined;
|
|
1932
|
+
crossScope?: boolean | undefined;
|
|
1933
|
+
ensureDesignAccess?: boolean | undefined;
|
|
1934
|
+
}>;
|
|
1935
|
+
export declare var designAccessSchema: z.ZodObject<{
|
|
1936
|
+
sourceScope: z.ZodString;
|
|
1937
|
+
targetScope: z.ZodString;
|
|
1938
|
+
updateSetSysId: z.ZodOptional<z.ZodString>;
|
|
1939
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
1940
|
+
}, "strip", z.ZodTypeAny, {
|
|
1941
|
+
sourceScope: string;
|
|
1942
|
+
targetScope: string;
|
|
1943
|
+
dryRun?: boolean | undefined;
|
|
1944
|
+
updateSetSysId?: string | undefined;
|
|
1945
|
+
}, {
|
|
1946
|
+
sourceScope: string;
|
|
1947
|
+
targetScope: string;
|
|
1948
|
+
dryRun?: boolean | undefined;
|
|
1949
|
+
updateSetSysId?: string | undefined;
|
|
1928
1950
|
}>;
|
|
1929
1951
|
export declare var addIndexSchema: z.ZodObject<{
|
|
1930
1952
|
table: 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.publishAppSchema = exports.exportAppSchema = exports.exportUpdateSetSchema = exports.deleteRecordSchema = exports.createRecordSchema = exports.setFieldSchema = exports.setTableSchema = exports.tableAttributesSchema = exports.setColumnSchema = exports.columnAttributesSchema = exports.createIndexSchema = exports.listIndexesSchema = exports.addIndexSchema = exports.addColumnSchema = exports.createTableSchema = exports.columnSpecSchema = exports.hostAssetsSchema = exports.editFlowSchema = exports.defineActionSchema = exports.defineActionSpecSchema = exports.cloneActionSchema = exports.editActionSchema = exports.stepInputPatchSchema = exports.testFlowSchema = exports.createFlowSchema = exports.copyFlowSchema = exports.publishFlowSchema = exports.viewActionSchema = exports.viewFlowSchema = exports.removeChoicesFromFieldSchema = exports.addChoicesToFieldSchema = exports.choiceValueSchema = exports.setRelatedListsSchema = exports.setFormLayoutSchema = exports.formSectionSchema = exports.setListLayoutSchema = exports.createViewSchema = void 0;
|
|
7
|
+
exports.invokeRestSchema = exports.publishAppSchema = exports.exportAppSchema = exports.exportUpdateSetSchema = exports.deleteRecordSchema = exports.createRecordSchema = exports.setFieldSchema = exports.setTableSchema = exports.tableAttributesSchema = exports.setColumnSchema = exports.columnAttributesSchema = exports.createIndexSchema = exports.listIndexesSchema = exports.addIndexSchema = exports.designAccessSchema = exports.addColumnSchema = exports.createTableSchema = exports.columnSpecSchema = exports.hostAssetsSchema = exports.editFlowSchema = exports.defineActionSchema = exports.defineActionSpecSchema = exports.cloneActionSchema = exports.editActionSchema = exports.stepInputPatchSchema = exports.testFlowSchema = exports.createFlowSchema = exports.copyFlowSchema = exports.publishFlowSchema = exports.viewActionSchema = exports.viewFlowSchema = exports.removeChoicesFromFieldSchema = 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),
|
|
@@ -364,10 +364,27 @@ exports.addColumnSchema = zod_1.z.object({
|
|
|
364
364
|
table: zod_1.z.string().min(1),
|
|
365
365
|
column: exports.columnSpecSchema,
|
|
366
366
|
scope: zod_1.z.string().optional(),
|
|
367
|
+
// Explicit opt-in to a column OWNED by `scope` when that differs from the table's
|
|
368
|
+
// scope (a Journey field on an Automate table). Without it a mismatched scope is
|
|
369
|
+
// refused — on dryRun and live alike — because that is the classic wrong-scope slip.
|
|
370
|
+
crossScope: zod_1.z.boolean().optional(),
|
|
371
|
+
// Cross-scope only: create the missing sys_scope_design_access record (scope -> the
|
|
372
|
+
// table's scope) first, in the same update set. Without it a missing record is flagged.
|
|
373
|
+
ensureDesignAccess: zod_1.z.boolean().optional(),
|
|
367
374
|
updateSetSysId: zod_1.z.string().optional(),
|
|
368
375
|
dryRun: zod_1.z.boolean().optional(),
|
|
369
376
|
debug: zod_1.z.boolean().optional(),
|
|
370
377
|
});
|
|
378
|
+
// design_access: ensure the sys_scope_design_access record that lets sourceScope author
|
|
379
|
+
// in targetScope's tables. updateSetSysId (an update set in sourceScope) is optional in
|
|
380
|
+
// the schema because dryRun needs none; the live-path requirement is enforced at the tool
|
|
381
|
+
// boundary (registry.ts), matching add_column.
|
|
382
|
+
exports.designAccessSchema = zod_1.z.object({
|
|
383
|
+
sourceScope: zod_1.z.string().min(1),
|
|
384
|
+
targetScope: zod_1.z.string().min(1),
|
|
385
|
+
updateSetSysId: zod_1.z.string().optional(),
|
|
386
|
+
dryRun: zod_1.z.boolean().optional(),
|
|
387
|
+
});
|
|
371
388
|
// add-index keeps a column LIST because an index is conceptually multi-column, but the
|
|
372
389
|
// only headless lever (sys_dictionary.unique) is per-COLUMN — so addIndex REFUSES a list
|
|
373
390
|
// longer than one rather than silently building a different index than the one asked for.
|
|
@@ -16,8 +16,31 @@
|
|
|
16
16
|
*
|
|
17
17
|
* The scope arg passed to `createRecord` is the scope NAME (e.g. "x_cadso_core"),
|
|
18
18
|
* not the sys_scope sys_id — the server-side changeScope matches on the scope name.
|
|
19
|
-
*
|
|
20
|
-
* table
|
|
19
|
+
* By default a column belongs to its table's scope, so the name is resolved from the
|
|
20
|
+
* table and an explicit `scope` override must match it.
|
|
21
|
+
*
|
|
22
|
+
* CROSS-SCOPE COLUMNS (`crossScope: true`). ServiceNow lets one app add a column to
|
|
23
|
+
* another app's table — Studio with app = Journey adding a field to an Automate table
|
|
24
|
+
* — and prefixes the element with the OWNING scope: `x_cadso_journey_instance_step`
|
|
25
|
+
* on `x_cadso_automate_email_batch`, dictionary row owned by x_cadso_journey. This is
|
|
26
|
+
* the column-ownership rule for Tenon's layered apps, so it is supported here as an
|
|
27
|
+
* explicit opt-in: `scope` names the column's scope, `crossScope: true` acknowledges it
|
|
28
|
+
* differs from the table's. The insert runs through the same scope-aware op switched
|
|
29
|
+
* to the COLUMN's scope, so the dictionary row and its update-set capture both land
|
|
30
|
+
* in the column's scope. Guards, run on dry-run and live alike: the override scope
|
|
31
|
+
* must exist; the table must allow new fields from other scopes
|
|
32
|
+
* (`sys_db_object.alter_access`); the update set must belong to the column's scope.
|
|
33
|
+
* The element is sent already prefixed (`<scope>_<name>`; an already-prefixed name
|
|
34
|
+
* is accepted as-is) and the element ServiceNow actually stored is read back and
|
|
35
|
+
* reported, together with a `sys_scope` assertion on the read-back row.
|
|
36
|
+
*
|
|
37
|
+
* DESIGN ACCESS. Since the Zurich bw40 hotfix the platform UI also requires a
|
|
38
|
+
* `sys_scope_design_access` record (source = the column's scope, target = the table's)
|
|
39
|
+
* before one app may author in another's tables. The headless insert here does not hit
|
|
40
|
+
* that check, so a missing record does not block the column — but it is FLAGGED on every
|
|
41
|
+
* cross-scope result (`designAccess`), because the next UI edit of the column, and the
|
|
42
|
+
* target instance, will. `ensureDesignAccess: true` creates it first, in the same update
|
|
43
|
+
* set (see ./designAccess.ts).
|
|
21
44
|
*
|
|
22
45
|
* SIZING THE PHYSICAL COLUMN. A max_length carried on the INSERT sets the dictionary
|
|
23
46
|
* row but NOT the column ServiceNow actually builds — it materialises at the platform
|
|
@@ -46,8 +69,25 @@ export interface AddColumnParams {
|
|
|
46
69
|
table: string;
|
|
47
70
|
/** The single column to add. `name` (the element) is optional; derived from label when omitted. */
|
|
48
71
|
column: ColumnSpec;
|
|
49
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Scope name or sys_scope sys_id. Must match the table's own scope (a column lives
|
|
74
|
+
* there) — unless `crossScope` is true, in which case it names the scope that will OWN
|
|
75
|
+
* the column (e.g. "x_cadso_journey" for a Journey column on an Automate table).
|
|
76
|
+
*/
|
|
50
77
|
scope?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Explicit opt-in to a column owned by a different scope than its table. Requires
|
|
80
|
+
* `scope`. The element is prefixed with the owning scope (`x_cadso_journey_<name>`),
|
|
81
|
+
* the table must allow new fields from other scopes (sys_db_object.alter_access),
|
|
82
|
+
* and the update set must belong to the column's scope.
|
|
83
|
+
*/
|
|
84
|
+
crossScope?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Cross-scope only: create the sys_scope_design_access record (column scope -> table
|
|
87
|
+
* scope) when it is missing, captured in the same update set, BEFORE the column insert.
|
|
88
|
+
* Without it a missing record is only flagged on the result.
|
|
89
|
+
*/
|
|
90
|
+
ensureDesignAccess?: boolean;
|
|
51
91
|
/** Update set sys_id to capture the insert into. REQUIRED on the live path (dry-run doesn't need it). */
|
|
52
92
|
updateSetSysId?: string;
|
|
53
93
|
/** Emit diagnostic detail in the result note. */
|
|
@@ -55,6 +95,21 @@ export interface AddColumnParams {
|
|
|
55
95
|
/** Plan only — no writes. Pure + deterministic. */
|
|
56
96
|
dryRun?: boolean;
|
|
57
97
|
}
|
|
98
|
+
/** Design Access state for a cross-scope column (absent on a same-scope add). */
|
|
99
|
+
export interface DesignAccessFlag {
|
|
100
|
+
/** Always true when reported: a cross-scope column needs the record for UI/Studio work. */
|
|
101
|
+
required: true;
|
|
102
|
+
/** true = record exists (or was created); false = missing; null = could not be read. */
|
|
103
|
+
present: boolean | null;
|
|
104
|
+
/** sys_scope_design_access sys_id ("" when missing / unknown). */
|
|
105
|
+
sysId: string;
|
|
106
|
+
/** Authoring scope (the column's owner). */
|
|
107
|
+
sourceScope: string;
|
|
108
|
+
/** Table-owning scope. */
|
|
109
|
+
targetScope: string;
|
|
110
|
+
/** True when THIS run created the record. */
|
|
111
|
+
created: boolean;
|
|
112
|
+
}
|
|
58
113
|
export interface AddColumnResult {
|
|
59
114
|
status: "created" | "dry-run" | "failed" | "skipped";
|
|
60
115
|
/** The table's name (resolved; echoes the input on dry-run). */
|
|
@@ -67,6 +122,11 @@ export interface AddColumnResult {
|
|
|
67
122
|
label: string;
|
|
68
123
|
/** Resolved ServiceNow internal_type (friendly -> internal). */
|
|
69
124
|
internalType: string;
|
|
125
|
+
/**
|
|
126
|
+
* Scope NAME that owns the column ("" on a network-free dry-run). Equals the table's
|
|
127
|
+
* scope unless `crossScope` was used, in which case it is the override scope.
|
|
128
|
+
*/
|
|
129
|
+
scope: string;
|
|
70
130
|
/** sys_id of the sys_dictionary row (the insert's, or the existing row's on "skipped"). */
|
|
71
131
|
columnSysId: string;
|
|
72
132
|
/** Update set the write was captured into ("" on dry-run). */
|
|
@@ -75,6 +135,8 @@ export interface AddColumnResult {
|
|
|
75
135
|
verified: boolean;
|
|
76
136
|
/** Human-readable note (success summary, the read-back result, or the failure body). */
|
|
77
137
|
note: string;
|
|
138
|
+
/** Cross-scope only: whether the Design Access record the platform UI requires exists. */
|
|
139
|
+
designAccess?: DesignAccessFlag;
|
|
78
140
|
}
|
|
79
141
|
/**
|
|
80
142
|
* Derive the dictionary element (column name) from a label the way Studio does for
|
|
@@ -83,4 +145,9 @@ export interface AddColumnResult {
|
|
|
83
145
|
* Pass `column.name` explicitly for anything non-trivial.
|
|
84
146
|
*/
|
|
85
147
|
export declare function deriveElement(label: string, explicit?: string): string;
|
|
148
|
+
/**
|
|
149
|
+
* The Design Access sentence appended to a cross-scope result's note ("" when none).
|
|
150
|
+
* Exported for tests.
|
|
151
|
+
*/
|
|
152
|
+
export declare function designAccessNote(da: DesignAccessFlag | undefined, ensureRequested: boolean, isDryRun: boolean): string;
|
|
86
153
|
export declare function addColumn(params: AddColumnParams): Promise<AddColumnResult>;
|