@tenonhq/dovetail-servicenow 0.0.38 → 0.0.39

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/dist/cli.js CHANGED
@@ -1070,8 +1070,11 @@ function printHelp() {
1070
1070
  " (--in <file> [--out <file>] [--rules <file>] [--report] [--json])\n" +
1071
1071
  " mcp Run the MCP stdio server (--smoke lists tools and exits)\n" +
1072
1072
  "\nGlobal flags:\n" +
1073
- " --env <path> Load credentials from a specific .env file (also --env-file,\n" +
1074
- " or the DOVETAIL_ENV_FILE env var). Default: .env in the cwd.\n");
1073
+ " --env <name|path> Load credentials from a specific env file (also --env-file,\n" +
1074
+ " or the DOVETAIL_ENV_FILE env var). A bare name like 'prod'\n" +
1075
+ " resolves to .env.prod in the cwd. The file's SN_* connection\n" +
1076
+ " vars replace any already exported; a missing or incomplete\n" +
1077
+ " file is an error (no fallback). Default: .env in the cwd.\n");
1075
1078
  }
1076
1079
  /** Parse inline `--columns "Label:type:max, Other:choice, ..."` into ColumnSpec[]. */
1077
1080
  function parseColumnsInline(input) {
package/dist/loadEnv.d.ts CHANGED
@@ -1,15 +1,45 @@
1
+ /**
2
+ * ServiceNow connection variables. When an env file is selected explicitly,
3
+ * these are taken from the file ONLY — any value already in process.env is
4
+ * cleared first — so the selected file fully determines the target instance
5
+ * and auth mode. (Without this, a shell/session-exported SN_INSTANCE or
6
+ * SN_API_KEY silently won over the file and the command hit the wrong
7
+ * instance.)
8
+ */
9
+ export declare var SN_CONNECTION_KEYS: string[];
10
+ /**
11
+ * Resolve an `--env` selector to an absolute env-file path.
12
+ *
13
+ * Accepts, in order:
14
+ * - an absolute path, or any value containing a path separator → used as a path
15
+ * (relative paths resolve against cwd) — unchanged legacy behavior;
16
+ * - a bare name that exists as a file in cwd (e.g. `--env my.env`) → that file;
17
+ * - a bare name like `loft` → `<cwd>/.env.loft`, matching the MCP tool's
18
+ * per-call `env` resolution; a `.env`-prefixed basename is used as-is.
19
+ *
20
+ * Returns the resolved path; does not check existence (loadEnvFile does).
21
+ */
22
+ export declare function resolveEnvSelection(raw: string, cwd?: string): string;
1
23
  /**
2
24
  * Loads ServiceNow credentials for the `dove-sn` CLI and its MCP server.
3
25
  *
4
26
  * 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.
27
+ * 1. An explicit `--env <name|path>` / `--env-file <name|path>` flag.
28
+ * 2. The `DOVETAIL_ENV_FILE` environment variable.
8
29
  * 3. The default `.env` in the current working directory.
9
30
  *
10
- * dotenv does not override variables already present in process.env, so an
11
- * explicit file augments (never clobbers) credentials the parent shell exported.
31
+ * For an explicit selection (1 or 2) this FAILS CLOSED: a missing file, or a
32
+ * file that doesn't define an instance plus credentials, throws instead of
33
+ * silently falling back to whatever instance the surrounding environment
34
+ * points at. The file's ServiceNow connection variables (SN_CONNECTION_KEYS)
35
+ * replace any already in process.env; every other variable keeps dotenv's
36
+ * never-override semantics.
37
+ *
38
+ * The default cwd `.env` (3) keeps its historical behavior: optional, and
39
+ * never overrides already-exported variables.
12
40
  *
13
- * @param {string} [explicitPath] - Path from the `--env` / `--env-file` flag.
41
+ * @param {string} [explicitSelection] - Value of the `--env` / `--env-file` flag.
42
+ * @returns {string|undefined} The absolute path of the explicitly selected
43
+ * file, or undefined when the default `.env` path was used.
14
44
  */
15
- export declare function loadEnvFile(explicitPath?: string): void;
45
+ export declare function loadEnvFile(explicitSelection?: string): string | undefined;
package/dist/loadEnv.js CHANGED
@@ -3,30 +3,110 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SN_CONNECTION_KEYS = void 0;
7
+ exports.resolveEnvSelection = resolveEnvSelection;
6
8
  exports.loadEnvFile = loadEnvFile;
9
+ const fs_1 = __importDefault(require("fs"));
7
10
  const dotenv_1 = __importDefault(require("dotenv"));
8
11
  const path_1 = __importDefault(require("path"));
12
+ const createClientFromEnvFile_1 = require("./createClientFromEnvFile");
13
+ /**
14
+ * ServiceNow connection variables. When an env file is selected explicitly,
15
+ * these are taken from the file ONLY — any value already in process.env is
16
+ * cleared first — so the selected file fully determines the target instance
17
+ * and auth mode. (Without this, a shell/session-exported SN_INSTANCE or
18
+ * SN_API_KEY silently won over the file and the command hit the wrong
19
+ * instance.)
20
+ */
21
+ exports.SN_CONNECTION_KEYS = [
22
+ "SN_INSTANCE",
23
+ "SN_DEV_INSTANCE",
24
+ "SN_PROD_INSTANCE",
25
+ "SN_API_KEY",
26
+ "SN_DEV_API_KEY",
27
+ "SN_PROD_API_KEY",
28
+ "SN_USER",
29
+ "SN_PASSWORD",
30
+ "SN_DEV_USERNAME",
31
+ "SN_DEV_PASSWORD",
32
+ "SN_PROD_USERNAME",
33
+ "SN_PROD_PASSWORD",
34
+ ];
35
+ /**
36
+ * Resolve an `--env` selector to an absolute env-file path.
37
+ *
38
+ * Accepts, in order:
39
+ * - an absolute path, or any value containing a path separator → used as a path
40
+ * (relative paths resolve against cwd) — unchanged legacy behavior;
41
+ * - a bare name that exists as a file in cwd (e.g. `--env my.env`) → that file;
42
+ * - a bare name like `loft` → `<cwd>/.env.loft`, matching the MCP tool's
43
+ * per-call `env` resolution; a `.env`-prefixed basename is used as-is.
44
+ *
45
+ * Returns the resolved path; does not check existence (loadEnvFile does).
46
+ */
47
+ function resolveEnvSelection(raw, cwd) {
48
+ if (typeof raw !== "string" || raw.trim().length === 0) {
49
+ throw new Error("--env must be a non-empty env-file name or path.");
50
+ }
51
+ var value = raw.trim();
52
+ var base = cwd || process.cwd();
53
+ if (path_1.default.isAbsolute(value) || /[\\/]/.test(value)) {
54
+ return path_1.default.resolve(base, value);
55
+ }
56
+ var literal = path_1.default.resolve(base, value);
57
+ if (fs_1.default.existsSync(literal)) {
58
+ return literal;
59
+ }
60
+ if (value.indexOf(".env") === 0) {
61
+ return literal;
62
+ }
63
+ return path_1.default.resolve(base, ".env." + value);
64
+ }
9
65
  /**
10
66
  * Loads ServiceNow credentials for the `dove-sn` CLI and its MCP server.
11
67
  *
12
68
  * 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.
69
+ * 1. An explicit `--env <name|path>` / `--env-file <name|path>` flag.
70
+ * 2. The `DOVETAIL_ENV_FILE` environment variable.
16
71
  * 3. The default `.env` in the current working directory.
17
72
  *
18
- * dotenv does not override variables already present in process.env, so an
19
- * explicit file augments (never clobbers) credentials the parent shell exported.
73
+ * For an explicit selection (1 or 2) this FAILS CLOSED: a missing file, or a
74
+ * file that doesn't define an instance plus credentials, throws instead of
75
+ * silently falling back to whatever instance the surrounding environment
76
+ * points at. The file's ServiceNow connection variables (SN_CONNECTION_KEYS)
77
+ * replace any already in process.env; every other variable keeps dotenv's
78
+ * never-override semantics.
79
+ *
80
+ * The default cwd `.env` (3) keeps its historical behavior: optional, and
81
+ * never overrides already-exported variables.
20
82
  *
21
- * @param {string} [explicitPath] - Path from the `--env` / `--env-file` flag.
83
+ * @param {string} [explicitSelection] - Value of the `--env` / `--env-file` flag.
84
+ * @returns {string|undefined} The absolute path of the explicitly selected
85
+ * file, or undefined when the default `.env` path was used.
22
86
  */
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;
87
+ function loadEnvFile(explicitSelection) {
88
+ var raw = explicitSelection || process.env.DOVETAIL_ENV_FILE;
89
+ if (!raw) {
90
+ // No explicit selection — load .env from cwd if it exists (no-op otherwise).
91
+ dotenv_1.default.config();
92
+ return undefined;
93
+ }
94
+ var resolved = resolveEnvSelection(raw);
95
+ if (!fs_1.default.existsSync(resolved)) {
96
+ throw new Error("env file not found: '" + resolved + "' (from --env '" + raw + "'). " +
97
+ "Refusing to fall back to the default environment — pass an existing env-file " +
98
+ "name (e.g. 'prod' → .env.prod in the current directory) or path.");
29
99
  }
30
- // No explicit selection — load .env from cwd if it exists (no-op otherwise).
31
- dotenv_1.default.config();
100
+ // Validates instance + credentials and throws loudly if either is missing.
101
+ (0, createClientFromEnvFile_1.resolveConfigFromEnvFile)(resolved);
102
+ var parsed = dotenv_1.default.parse(fs_1.default.readFileSync(resolved, "utf8"));
103
+ exports.SN_CONNECTION_KEYS.forEach(function (key) {
104
+ delete process.env[key];
105
+ if (Object.prototype.hasOwnProperty.call(parsed, key) && parsed[key] !== "") {
106
+ process.env[key] = parsed[key];
107
+ }
108
+ });
109
+ // Everything else in the file: dotenv's normal never-override semantics.
110
+ dotenv_1.default.config({ path: resolved });
111
+ return resolved;
32
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenonhq/dovetail-servicenow",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },