@tenonhq/dovetail-servicenow 0.0.9 → 0.0.11
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 +15 -0
- package/dist/cli.js +9 -1
- package/dist/client.d.ts +14 -14
- package/dist/client.js +26 -25
- package/dist/loadEnv.d.ts +15 -0
- package/dist/loadEnv.js +32 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -66,6 +66,21 @@ SN_USER=...
|
|
|
66
66
|
SN_PASSWORD=...
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
### Selecting a .env file per command
|
|
70
|
+
|
|
71
|
+
Every `dove-sn` command (and `dove-sn mcp`) loads `.env` from the current
|
|
72
|
+
directory by default. Point it at a different file to target another instance:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx dove-sn view-flow --sys-id <id> --env .env.prod
|
|
76
|
+
npx dove-sn add-choices --env ../envs/workshop.env --table ... --column ...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`--env` (alias `--env-file`) wins over the `DOVETAIL_ENV_FILE` env var, which in
|
|
80
|
+
turn beats the default `.env`. Variables already present in the environment are
|
|
81
|
+
never overridden, so an exported `SN_INSTANCE` still takes precedence over the
|
|
82
|
+
file — handy for CI.
|
|
83
|
+
|
|
69
84
|
## CLI
|
|
70
85
|
|
|
71
86
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -57,6 +57,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
57
57
|
})();
|
|
58
58
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
59
|
const fs = __importStar(require("fs"));
|
|
60
|
+
const loadEnv_1 = require("./loadEnv");
|
|
60
61
|
const client_1 = require("./client");
|
|
61
62
|
const choices_1 = require("./choices");
|
|
62
63
|
const formatter_1 = require("./formatter");
|
|
@@ -557,10 +558,17 @@ function printHelp() {
|
|
|
557
558
|
" (--sys-id <sys_id> [--execute --confirm] [--inputs <json>] [--json])\n" +
|
|
558
559
|
" edit-flow Patch a flow/subflow (rename, description, step inputs)\n" +
|
|
559
560
|
" (--sys-id <sys_id> --from-json <ops.json> [--apply] [--update-set <sys_id>] [--scope <sys_id>] [--json])\n" +
|
|
560
|
-
" mcp Run the MCP stdio server (--smoke lists tools and exits)\n"
|
|
561
|
+
" mcp Run the MCP stdio server (--smoke lists tools and exits)\n" +
|
|
562
|
+
"\nGlobal flags:\n" +
|
|
563
|
+
" --env <path> Load credentials from a specific .env file (also --env-file,\n" +
|
|
564
|
+
" or the DOVETAIL_ENV_FILE env var). Default: .env in the cwd.\n");
|
|
561
565
|
}
|
|
562
566
|
async function main() {
|
|
563
567
|
var parsed = parseArgs(process.argv.slice(2));
|
|
568
|
+
// Load credentials before any command runs. `--env`/`--env-file` (or the
|
|
569
|
+
// DOVETAIL_ENV_FILE env var) selects a specific file so one checkout can
|
|
570
|
+
// target multiple instances; otherwise the cwd `.env` is used.
|
|
571
|
+
(0, loadEnv_1.loadEnvFile)(parsed.flags.env || parsed.flags["env-file"]);
|
|
564
572
|
if (parsed.command === "add-choices") {
|
|
565
573
|
await runAddChoices(parsed.flags);
|
|
566
574
|
return 0;
|
package/dist/client.d.ts
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
* - `buildAgent.*` — reads via the sn_build_agent API, with graceful
|
|
7
7
|
* fallback to Table API / sys_dictionary when the
|
|
8
8
|
* Build Agent plugin is unavailable
|
|
9
|
-
* - `claude.*` — writes via the Dovetail Scripted REST API
|
|
10
|
-
* (/api/cadso/
|
|
11
|
-
* switching atomically so every write lands in the
|
|
12
|
-
* update set without touching sys_user_preference.
|
|
13
|
-
* Falls back to the legacy /api/cadso/
|
|
14
|
-
* instances
|
|
15
|
-
* The
|
|
16
|
-
* compatibility; the
|
|
17
|
-
*
|
|
9
|
+
* - `claude.*` — writes via the Dovetail core Scripted REST API
|
|
10
|
+
* (/api/cadso/dovetail_core/*), which handles update-set +
|
|
11
|
+
* scope switching atomically so every write lands in the
|
|
12
|
+
* right update set without touching sys_user_preference.
|
|
13
|
+
* Falls back to the legacy global-scope /api/cadso/dovetail/*
|
|
14
|
+
* path on instances without the Dovetail app installed.
|
|
15
|
+
* The `claude.*` property name is preserved for API
|
|
16
|
+
* compatibility; the server-side API now lives in the
|
|
17
|
+
* Dovetail scoped application as "Dovetail Core".
|
|
18
18
|
*
|
|
19
19
|
* Env fallbacks mirror prior dashboard-fetch helpers so dev setups that already
|
|
20
20
|
* have SN_INSTANCE/SN_USER/SN_PASSWORD work without reconfiguration.
|
|
@@ -62,7 +62,7 @@ export interface ServiceNowClient {
|
|
|
62
62
|
getTableSchema: (table: string) => Promise<TableSchema>;
|
|
63
63
|
};
|
|
64
64
|
claude: {
|
|
65
|
-
/** POST /api/cadso/
|
|
65
|
+
/** POST /api/cadso/dovetail_core/createRecord (legacy: /api/cadso/dovetail/createRecord). */
|
|
66
66
|
createRecord: (params: {
|
|
67
67
|
table: string;
|
|
68
68
|
fields: Record<string, any>;
|
|
@@ -73,7 +73,7 @@ export interface ServiceNowClient {
|
|
|
73
73
|
sys_id: string;
|
|
74
74
|
[k: string]: any;
|
|
75
75
|
}>;
|
|
76
|
-
/** POST /api/cadso/
|
|
76
|
+
/** POST /api/cadso/dovetail_core/pushWithUpdateSet (legacy: /api/cadso/dovetail/pushWithUpdateSet). */
|
|
77
77
|
pushWithUpdateSet: (params: {
|
|
78
78
|
update_set_sys_id: string;
|
|
79
79
|
table: string;
|
|
@@ -83,18 +83,18 @@ export interface ServiceNowClient {
|
|
|
83
83
|
sys_id: string;
|
|
84
84
|
[k: string]: any;
|
|
85
85
|
}>;
|
|
86
|
-
/** GET /api/cadso/
|
|
86
|
+
/** GET /api/cadso/dovetail_core/currentUpdateSet?scope=... (legacy: /api/cadso/dovetail/currentUpdateSet). */
|
|
87
87
|
currentUpdateSet: (scope?: string) => Promise<{
|
|
88
88
|
sys_id: string;
|
|
89
89
|
name: string;
|
|
90
90
|
}>;
|
|
91
|
-
/** GET /api/cadso/
|
|
91
|
+
/** GET /api/cadso/dovetail_core/changeUpdateSet?sysId=... — pins the REST session's active update set. */
|
|
92
92
|
changeUpdateSet: (params: {
|
|
93
93
|
sysId: string;
|
|
94
94
|
}) => Promise<{
|
|
95
95
|
[k: string]: any;
|
|
96
96
|
}>;
|
|
97
|
-
/** POST /api/cadso/
|
|
97
|
+
/** POST /api/cadso/dovetail_core/deleteRecord — body { table, sys_id }. Returns the deleted record. */
|
|
98
98
|
deleteRecord: (params: {
|
|
99
99
|
table: string;
|
|
100
100
|
sys_id: string;
|
package/dist/client.js
CHANGED
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
* - `buildAgent.*` — reads via the sn_build_agent API, with graceful
|
|
8
8
|
* fallback to Table API / sys_dictionary when the
|
|
9
9
|
* Build Agent plugin is unavailable
|
|
10
|
-
* - `claude.*` — writes via the Dovetail Scripted REST API
|
|
11
|
-
* (/api/cadso/
|
|
12
|
-
* switching atomically so every write lands in the
|
|
13
|
-
* update set without touching sys_user_preference.
|
|
14
|
-
* Falls back to the legacy /api/cadso/
|
|
15
|
-
* instances
|
|
16
|
-
* The
|
|
17
|
-
* compatibility; the
|
|
18
|
-
*
|
|
10
|
+
* - `claude.*` — writes via the Dovetail core Scripted REST API
|
|
11
|
+
* (/api/cadso/dovetail_core/*), which handles update-set +
|
|
12
|
+
* scope switching atomically so every write lands in the
|
|
13
|
+
* right update set without touching sys_user_preference.
|
|
14
|
+
* Falls back to the legacy global-scope /api/cadso/dovetail/*
|
|
15
|
+
* path on instances without the Dovetail app installed.
|
|
16
|
+
* The `claude.*` property name is preserved for API
|
|
17
|
+
* compatibility; the server-side API now lives in the
|
|
18
|
+
* Dovetail scoped application as "Dovetail Core".
|
|
19
19
|
*
|
|
20
20
|
* Env fallbacks mirror prior dashboard-fetch helpers so dev setups that already
|
|
21
21
|
* have SN_INSTANCE/SN_USER/SN_PASSWORD work without reconfiguration.
|
|
@@ -104,11 +104,12 @@ function createClient(config = {}) {
|
|
|
104
104
|
validateStatus: function () { return true; }
|
|
105
105
|
});
|
|
106
106
|
var lastAt = 0;
|
|
107
|
-
// Dovetail Scripted REST API
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
// the
|
|
111
|
-
|
|
107
|
+
// Dovetail core Scripted REST API: prefer the Dovetail-app path
|
|
108
|
+
// /api/cadso/dovetail_core/* and fall back to the legacy global-scope path
|
|
109
|
+
// /api/cadso/dovetail/* on instances that don't have the Dovetail app yet.
|
|
110
|
+
// Latch the legacy flag after the first 404 to avoid paying the round-trip
|
|
111
|
+
// cost on every subsequent call.
|
|
112
|
+
var useDovetailLegacyPath = false;
|
|
112
113
|
async function request(cfg, ctx) {
|
|
113
114
|
var attempt429 = 0;
|
|
114
115
|
var attempt5xx = 0;
|
|
@@ -160,24 +161,24 @@ function createClient(config = {}) {
|
|
|
160
161
|
return res.data;
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
|
-
// Dovetail Scripted REST API request: try /api/cadso/
|
|
164
|
-
// /api/cadso/
|
|
164
|
+
// Dovetail core Scripted REST API request: try /api/cadso/dovetail_core/<op>,
|
|
165
|
+
// fall back to the legacy /api/cadso/dovetail/<op> on 404 (one-time warning).
|
|
165
166
|
async function dovetailRequest(method, op, body, params, ctx) {
|
|
166
|
-
var url =
|
|
167
|
-
? "/api/cadso/
|
|
168
|
-
: "/api/cadso/
|
|
167
|
+
var url = useDovetailLegacyPath
|
|
168
|
+
? "/api/cadso/dovetail/" + op
|
|
169
|
+
: "/api/cadso/dovetail_core/" + op;
|
|
169
170
|
try {
|
|
170
171
|
return await request({ method: method, url: url, data: body, params: params }, ctx);
|
|
171
172
|
}
|
|
172
173
|
catch (e) {
|
|
173
174
|
var msg = e && e.message ? String(e.message) : "";
|
|
174
|
-
if (!
|
|
175
|
+
if (!useDovetailLegacyPath && msg.indexOf("SN 404 on") === 0) {
|
|
175
176
|
// eslint-disable-next-line no-console
|
|
176
|
-
console.warn("[deprecation] /api/cadso/
|
|
177
|
-
" returned 404. Falling back to legacy /api/cadso/
|
|
178
|
-
".
|
|
179
|
-
|
|
180
|
-
var legacyUrl = "/api/cadso/
|
|
177
|
+
console.warn("[deprecation] /api/cadso/dovetail_core/" + op +
|
|
178
|
+
" returned 404. Falling back to legacy /api/cadso/dovetail/" + op +
|
|
179
|
+
". Install the Dovetail application's Scripted REST APIs to silence this warning.");
|
|
180
|
+
useDovetailLegacyPath = true;
|
|
181
|
+
var legacyUrl = "/api/cadso/dovetail/" + op;
|
|
181
182
|
return await request({ method: method, url: legacyUrl, data: body, params: params }, ctx);
|
|
182
183
|
}
|
|
183
184
|
throw e;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads ServiceNow credentials for the `dove-sn` CLI and its MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order for the env file:
|
|
5
|
+
* 1. An explicit `--env <path>` / `--env-file <path>` flag (passed in here).
|
|
6
|
+
* 2. The `DOVETAIL_ENV_FILE` environment variable — lets an MCP host point
|
|
7
|
+
* `dove-sn mcp` at a specific credential file without a CLI flag.
|
|
8
|
+
* 3. The default `.env` in the current working directory.
|
|
9
|
+
*
|
|
10
|
+
* dotenv does not override variables already present in process.env, so an
|
|
11
|
+
* explicit file augments (never clobbers) credentials the parent shell exported.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} [explicitPath] - Path from the `--env` / `--env-file` flag.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadEnvFile(explicitPath?: string): void;
|
package/dist/loadEnv.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadEnvFile = loadEnvFile;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Loads ServiceNow credentials for the `dove-sn` CLI and its MCP server.
|
|
11
|
+
*
|
|
12
|
+
* Resolution order for the env file:
|
|
13
|
+
* 1. An explicit `--env <path>` / `--env-file <path>` flag (passed in here).
|
|
14
|
+
* 2. The `DOVETAIL_ENV_FILE` environment variable — lets an MCP host point
|
|
15
|
+
* `dove-sn mcp` at a specific credential file without a CLI flag.
|
|
16
|
+
* 3. The default `.env` in the current working directory.
|
|
17
|
+
*
|
|
18
|
+
* dotenv does not override variables already present in process.env, so an
|
|
19
|
+
* explicit file augments (never clobbers) credentials the parent shell exported.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} [explicitPath] - Path from the `--env` / `--env-file` flag.
|
|
22
|
+
*/
|
|
23
|
+
function loadEnvFile(explicitPath) {
|
|
24
|
+
var raw = explicitPath || process.env.DOVETAIL_ENV_FILE;
|
|
25
|
+
if (raw) {
|
|
26
|
+
var resolved = path_1.default.isAbsolute(raw) ? raw : path_1.default.resolve(process.cwd(), raw);
|
|
27
|
+
dotenv_1.default.config({ path: resolved });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// No explicit selection — load .env from cwd if it exists (no-op otherwise).
|
|
31
|
+
dotenv_1.default.config();
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenonhq/dovetail-servicenow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22"
|
|
6
6
|
},
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
22
22
|
"axios": "^1.5.1",
|
|
23
|
+
"dotenv": "^16.3.1",
|
|
23
24
|
"zod": "^3.23.0"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|