@jacebenson/jsn 0.0.3
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 +398 -0
- package/bin/jsn.js +5 -0
- package/package.json +44 -0
- package/src/app.js +157 -0
- package/src/auth.js +273 -0
- package/src/cli.js +142 -0
- package/src/commands/_ticket.js +256 -0
- package/src/commands/auth.js +62 -0
- package/src/commands/changes.js +7 -0
- package/src/commands/dev/_generic.js +223 -0
- package/src/commands/dev/_simple.js +89 -0
- package/src/commands/dev/eval.js +17 -0
- package/src/commands/dev/flows.js +528 -0
- package/src/commands/dev/forms.js +313 -0
- package/src/commands/dev/lists.js +233 -0
- package/src/commands/dev/logs.js +51 -0
- package/src/commands/dev/rest.js +64 -0
- package/src/commands/dev/scopes.js +96 -0
- package/src/commands/dev/updatesets.js +97 -0
- package/src/commands/dev.js +53 -0
- package/src/commands/groupmembers.js +39 -0
- package/src/commands/grouproles.js +39 -0
- package/src/commands/groups.js +57 -0
- package/src/commands/incidents.js +7 -0
- package/src/commands/profiles.js +79 -0
- package/src/commands/records.js +137 -0
- package/src/commands/requests.js +7 -0
- package/src/commands/setup.js +35 -0
- package/src/commands/tasks.js +7 -0
- package/src/commands/tickets.js +121 -0
- package/src/commands/users.js +57 -0
- package/src/commands/version.js +25 -0
- package/src/config.js +152 -0
- package/src/context.js +62 -0
- package/src/errors.js +101 -0
- package/src/helpers.js +60 -0
- package/src/output.js +410 -0
- package/src/sdk.js +357 -0
package/README.md
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# JSN - ServiceNow CLI
|
|
2
|
+
|
|
3
|
+
A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### npm (Cross-platform — recommended for Windows)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @jacebenson/jsn
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Works on macOS, Linux, and Windows. The correct binary for your platform is downloaded automatically during install.
|
|
14
|
+
|
|
15
|
+
### Download Binary
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Download the latest release
|
|
19
|
+
curl -L https://github.com/jacebenson/jsn/releases/latest/download/jsn-linux-amd64 -o jsn
|
|
20
|
+
chmod +x jsn
|
|
21
|
+
sudo mv jsn /usr/local/bin/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Go Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
go install github.com/jacebenson/jsn/cmd/jsn@latest
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Setup
|
|
33
|
+
|
|
34
|
+
Run the interactive setup to configure your first ServiceNow instance:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
jsn setup
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This will:
|
|
41
|
+
1. Ask for your ServiceNow instance URL
|
|
42
|
+
2. Open a browser for OAuth authentication
|
|
43
|
+
3. Set the instance as your default
|
|
44
|
+
|
|
45
|
+
### 2. Verify Authentication
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
jsn auth status
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Start Using
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# List all incidents
|
|
55
|
+
jsn incidents
|
|
56
|
+
|
|
57
|
+
# Show a specific incident
|
|
58
|
+
jsn incidents INC0010001
|
|
59
|
+
|
|
60
|
+
# Create a new incident
|
|
61
|
+
jsn incidents create --description "Server down" --priority 1
|
|
62
|
+
|
|
63
|
+
# List change requests
|
|
64
|
+
jsn changes
|
|
65
|
+
|
|
66
|
+
# Query any table
|
|
67
|
+
jsn records list --table incident --query "priority=1^active=true"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Configuration
|
|
71
|
+
|
|
72
|
+
JSN uses a layered configuration system:
|
|
73
|
+
|
|
74
|
+
| Source | Priority | Description |
|
|
75
|
+
|--------|----------|-------------|
|
|
76
|
+
| Flags | Highest | `--instance`, `--profile`, `--format` |
|
|
77
|
+
| Environment | High | `SERVICENOW_INSTANCE_URL`, `SERVICENOW_FORMAT` |
|
|
78
|
+
| Local config | Medium | `./.servicenow/config.json` |
|
|
79
|
+
| Global config | Low | `~/.config/servicenow/config.json` |
|
|
80
|
+
| Defaults | Lowest | Built-in defaults |
|
|
81
|
+
|
|
82
|
+
### Profiles
|
|
83
|
+
|
|
84
|
+
Work with multiple ServiceNow instances using profiles:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Login to a new instance
|
|
88
|
+
jsn auth login https://dev12345.service-now.com
|
|
89
|
+
|
|
90
|
+
# List all profiles
|
|
91
|
+
jsn profiles list
|
|
92
|
+
|
|
93
|
+
# Switch to a different profile
|
|
94
|
+
jsn profiles use dev12345
|
|
95
|
+
|
|
96
|
+
# Show current profile
|
|
97
|
+
jsn profiles show
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Commands
|
|
101
|
+
|
|
102
|
+
### Work Commands (Day-to-day operations)
|
|
103
|
+
|
|
104
|
+
| Command | Aliases | Description |
|
|
105
|
+
|---------|---------|-------------|
|
|
106
|
+
| `incidents` | `incident`, `inc` | Manage IT incidents |
|
|
107
|
+
| `changes` | `change`, `chg` | Manage change requests |
|
|
108
|
+
| `requests` | `request`, `req`, `ritm` | Manage service catalog requests |
|
|
109
|
+
| `tasks` | `task`, `sctask` | Manage service catalog tasks |
|
|
110
|
+
| `users` | `user` | Manage users |
|
|
111
|
+
| `groups` | `group` | Manage user groups |
|
|
112
|
+
| `records` | - | Generic Table API access |
|
|
113
|
+
|
|
114
|
+
### Dev Commands (Development artifacts)
|
|
115
|
+
|
|
116
|
+
| Category | Command | Description |
|
|
117
|
+
|----------|---------|-------------|
|
|
118
|
+
| **Automations** | `dev flows` | Manage Flow Designer flows |
|
|
119
|
+
| | `dev actions` | Manage action definitions |
|
|
120
|
+
| **Scripts** | `dev includes` | Manage script includes |
|
|
121
|
+
| | `dev rules` | Manage business rules |
|
|
122
|
+
| | `dev clientscripts` | Manage client scripts |
|
|
123
|
+
| | `dev uiactions` | Manage UI actions |
|
|
124
|
+
| | `dev uipolicies` | Manage UI policies |
|
|
125
|
+
| **Data** | `dev tables` | View table definitions |
|
|
126
|
+
| | `dev columns` | Manage column definitions |
|
|
127
|
+
| | `dev import` | Manage import sets |
|
|
128
|
+
| **Security** | `dev acls` | Manage access controls |
|
|
129
|
+
| | `dev roles` | Manage roles |
|
|
130
|
+
| **Platform** | `dev updatesets` | Manage update sets |
|
|
131
|
+
| | `dev scopes` | Manage application scopes |
|
|
132
|
+
| | `dev properties` | Manage system properties |
|
|
133
|
+
| | `dev logs` | Query system logs |
|
|
134
|
+
| | `dev rest` | Raw REST API calls |
|
|
135
|
+
| | `dev eval` | Execute background scripts |
|
|
136
|
+
|
|
137
|
+
## Usage Examples
|
|
138
|
+
|
|
139
|
+
### Incidents
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# List all incidents
|
|
143
|
+
jsn incidents
|
|
144
|
+
|
|
145
|
+
# List critical incidents
|
|
146
|
+
jsn incidents list --query "priority=1"
|
|
147
|
+
|
|
148
|
+
# Show specific incident
|
|
149
|
+
jsn incidents INC0010001
|
|
150
|
+
|
|
151
|
+
# Create incident
|
|
152
|
+
jsn incidents create --description "Server down" --priority 1
|
|
153
|
+
|
|
154
|
+
# Update incident
|
|
155
|
+
jsn incidents update INC0010001 --data '{"state": "6"}'
|
|
156
|
+
|
|
157
|
+
# Delete incident
|
|
158
|
+
jsn incidents delete INC0010001
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Changes
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# List all change requests
|
|
165
|
+
jsn changes
|
|
166
|
+
|
|
167
|
+
# List high-risk changes
|
|
168
|
+
jsn changes list --query "risk=high"
|
|
169
|
+
|
|
170
|
+
# Create change request
|
|
171
|
+
jsn changes create --description "Deploy feature" --risk medium
|
|
172
|
+
|
|
173
|
+
# Update change
|
|
174
|
+
jsn changes update CHG0010001 --data '{"state": "3"}'
|
|
175
|
+
|
|
176
|
+
# Delete change
|
|
177
|
+
jsn changes delete CHG0010001
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Development Artifacts
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# AUTOMATIONS
|
|
184
|
+
# List Flow Designer flows
|
|
185
|
+
jsn dev flows
|
|
186
|
+
|
|
187
|
+
# List action definitions
|
|
188
|
+
jsn dev actions
|
|
189
|
+
|
|
190
|
+
# SCRIPTS
|
|
191
|
+
# List script includes
|
|
192
|
+
jsn dev includes
|
|
193
|
+
|
|
194
|
+
# Get a specific script include
|
|
195
|
+
jsn dev includes MyScriptInclude
|
|
196
|
+
|
|
197
|
+
# List business rules
|
|
198
|
+
jsn dev rules
|
|
199
|
+
|
|
200
|
+
# List client scripts
|
|
201
|
+
jsn dev clientscripts
|
|
202
|
+
|
|
203
|
+
# List UI actions
|
|
204
|
+
jsn dev uiactions
|
|
205
|
+
|
|
206
|
+
# List UI policies
|
|
207
|
+
jsn dev uipolicies
|
|
208
|
+
|
|
209
|
+
# DATA
|
|
210
|
+
# View table definition
|
|
211
|
+
jsn dev tables incident
|
|
212
|
+
|
|
213
|
+
# List table columns
|
|
214
|
+
jsn dev columns --table incident
|
|
215
|
+
|
|
216
|
+
# SECURITY
|
|
217
|
+
# List access controls (ACLs)
|
|
218
|
+
jsn dev acls
|
|
219
|
+
|
|
220
|
+
# List roles
|
|
221
|
+
jsn dev roles
|
|
222
|
+
|
|
223
|
+
# PLATFORM
|
|
224
|
+
# List update sets
|
|
225
|
+
jsn dev updatesets
|
|
226
|
+
|
|
227
|
+
# Set current update set
|
|
228
|
+
jsn dev updatesets set "My Update Set"
|
|
229
|
+
|
|
230
|
+
# List application scopes
|
|
231
|
+
jsn dev scopes
|
|
232
|
+
|
|
233
|
+
# Query system properties
|
|
234
|
+
jsn dev properties
|
|
235
|
+
|
|
236
|
+
# Query system logs
|
|
237
|
+
jsn dev logs --level error
|
|
238
|
+
jsn dev logs --source "Business Rule" --level warn
|
|
239
|
+
|
|
240
|
+
# Execute background script
|
|
241
|
+
jsn dev eval "gs.info('Hello World')"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Generic Table API
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
# List any table
|
|
248
|
+
jsn records list --table incident --limit 10
|
|
249
|
+
|
|
250
|
+
# Query with encoded query
|
|
251
|
+
jsn records list --table incident --query "priority=1^active=true"
|
|
252
|
+
|
|
253
|
+
# Show specific columns
|
|
254
|
+
jsn records list --table incident --columns "number,short_description,priority"
|
|
255
|
+
|
|
256
|
+
# Get a record by sys_id
|
|
257
|
+
jsn records get --table incident --sys-id abc123
|
|
258
|
+
|
|
259
|
+
# Create a record
|
|
260
|
+
jsn records create --table incident --data '{"short_description": "Test"}'
|
|
261
|
+
|
|
262
|
+
# Update a record
|
|
263
|
+
jsn records update --table incident --sys-id abc123 --data '{"priority": "1"}'
|
|
264
|
+
|
|
265
|
+
# Delete a record
|
|
266
|
+
jsn records delete --table incident --sys-id abc123
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Output Formats
|
|
270
|
+
|
|
271
|
+
JSN supports multiple output formats:
|
|
272
|
+
|
|
273
|
+
| Format | Flag | Description |
|
|
274
|
+
|--------|------|-------------|
|
|
275
|
+
| Auto (default) | `--format=auto` | JSON for pipes, styled for TTY |
|
|
276
|
+
| JSON | `--json` or `--format=json` | Machine-readable JSON |
|
|
277
|
+
| Styled | `--styled` | ANSI-styled tables (for humans) |
|
|
278
|
+
| Markdown | `--markdown` | Markdown tables |
|
|
279
|
+
| Quiet | `--quiet` or `-q` | Data only, no envelope |
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# JSON output
|
|
283
|
+
jsn incidents --json
|
|
284
|
+
|
|
285
|
+
# Styled table output
|
|
286
|
+
jsn incidents --styled
|
|
287
|
+
|
|
288
|
+
# Markdown output for documentation
|
|
289
|
+
jsn incidents --markdown
|
|
290
|
+
|
|
291
|
+
# Quiet mode for piping
|
|
292
|
+
jsn incidents -q | jq '.[].number'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Authentication
|
|
296
|
+
|
|
297
|
+
JSN uses OAuth 2.0 with PKCE for secure authentication:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Login to an instance
|
|
301
|
+
jsn auth login https://dev12345.service-now.com
|
|
302
|
+
|
|
303
|
+
# Check authentication status
|
|
304
|
+
jsn auth status
|
|
305
|
+
|
|
306
|
+
# Logout
|
|
307
|
+
jsn auth logout
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Credentials are securely stored in your OS keychain (or file fallback at `~/.config/servicenow/credentials/`).
|
|
311
|
+
|
|
312
|
+
## Environment Variables
|
|
313
|
+
|
|
314
|
+
| Variable | Description |
|
|
315
|
+
|----------|-------------|
|
|
316
|
+
| `SERVICENOW_INSTANCE_URL` | Default instance URL |
|
|
317
|
+
| `SERVICENOW_FORMAT` | Default output format |
|
|
318
|
+
| `SERVICENOW_OAUTH_TOKEN` | OAuth token (for CI/CD) |
|
|
319
|
+
|
|
320
|
+
## CI/CD Integration
|
|
321
|
+
|
|
322
|
+
For automated environments, use the OAuth token:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
export SERVICENOW_INSTANCE_URL="https://dev12345.service-now.com"
|
|
326
|
+
export SERVICENOW_OAUTH_TOKEN="your-oauth-token"
|
|
327
|
+
|
|
328
|
+
# Now run commands without interactive auth
|
|
329
|
+
jsn incidents list
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Shell Completion
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# Bash
|
|
336
|
+
source <(jsn completion bash)
|
|
337
|
+
|
|
338
|
+
# Zsh
|
|
339
|
+
source <(jsn completion zsh)
|
|
340
|
+
|
|
341
|
+
# Fish
|
|
342
|
+
jsn completion fish | source
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Getting Help
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# General help
|
|
349
|
+
jsn --help
|
|
350
|
+
|
|
351
|
+
# Command help
|
|
352
|
+
jsn incidents --help
|
|
353
|
+
|
|
354
|
+
# Subcommand help
|
|
355
|
+
jsn incidents create --help
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
### Not authenticated
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
⚠️ Not authenticated to https://dev12345.service-now.com
|
|
364
|
+
|
|
365
|
+
To get started, run:
|
|
366
|
+
jsn setup # Interactive setup
|
|
367
|
+
jsn auth login # Login to instance
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Solution**: Run `jsn setup` or `jsn auth login <instance>`
|
|
371
|
+
|
|
372
|
+
### Instance URL required
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
Error (usage): Instance URL required. Set via --instance flag, SERVICENOW_INSTANCE_URL env, or config file.
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Solution**: Set the instance with one of:
|
|
379
|
+
- `jsn setup`
|
|
380
|
+
- `jsn auth login <instance>`
|
|
381
|
+
- `--instance` flag
|
|
382
|
+
- `SERVICENOW_INSTANCE_URL` environment variable
|
|
383
|
+
|
|
384
|
+
## Contributing
|
|
385
|
+
|
|
386
|
+
1. Fork the repository
|
|
387
|
+
2. Create a feature branch
|
|
388
|
+
3. Make your changes
|
|
389
|
+
4. Add tests
|
|
390
|
+
5. Submit a pull request
|
|
391
|
+
|
|
392
|
+
## License
|
|
393
|
+
|
|
394
|
+
MIT License - see LICENSE file for details
|
|
395
|
+
|
|
396
|
+
## Acknowledgments
|
|
397
|
+
|
|
398
|
+
This project follows the architectural patterns from [basecamp-cli](https://github.com/basecamp/basecamp-cli).
|
package/bin/jsn.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jacebenson/jsn",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jsn": "bin/jsn.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "src/cli.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node --test $(find test -name '*.test.js')",
|
|
12
|
+
"lint": "npx eslint src/ bin/ test/",
|
|
13
|
+
"start": "node bin/jsn.js",
|
|
14
|
+
"tag-reminder": "node scripts/tag-reminder.js",
|
|
15
|
+
"release": "node scripts/release.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"servicenow",
|
|
19
|
+
"cli",
|
|
20
|
+
"rest-api",
|
|
21
|
+
"automation"
|
|
22
|
+
],
|
|
23
|
+
"author": "Jace Benson",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"chalk": "^5.4.1",
|
|
30
|
+
"cli-table3": "^0.6.5",
|
|
31
|
+
"yargs": "^17.7.2"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@eslint/js": "^10.0.1",
|
|
35
|
+
"@inquirer/prompts": "^7.5.1",
|
|
36
|
+
"globals": "^17.6.0"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"bin/jsn.js",
|
|
40
|
+
"src/",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
]
|
|
44
|
+
}
|
package/src/app.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// App context: bundles config, auth, SDK, output, and runtime context
|
|
2
|
+
|
|
3
|
+
import { AuthManager } from './auth.js';
|
|
4
|
+
import { SDKClient } from './sdk.js';
|
|
5
|
+
import { OutputWriter, FormatAuto, FormatJSON, FormatMarkdown, FormatQuiet, FormatStyled } from './output.js';
|
|
6
|
+
import { getEffectiveInstance } from './config.js';
|
|
7
|
+
import { extractProfileName } from './helpers.js';
|
|
8
|
+
import { getCurrentUser, getCurrentApplication, getCurrentUpdateSet } from './context.js';
|
|
9
|
+
import { errUsage, errAuth } from './errors.js';
|
|
10
|
+
import process from 'node:process';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export class App {
|
|
14
|
+
constructor(cfg) {
|
|
15
|
+
this.config = cfg;
|
|
16
|
+
this.auth = new AuthManager(this);
|
|
17
|
+
this.output = new OutputWriter({ format: resolveFormat(cfg.format) });
|
|
18
|
+
this.sdk = null;
|
|
19
|
+
|
|
20
|
+
const instance = getEffectiveInstance(cfg);
|
|
21
|
+
if (instance) {
|
|
22
|
+
this.sdk = new SDKClient(instance, this.auth);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.context = {
|
|
26
|
+
profileName: '',
|
|
27
|
+
username: '',
|
|
28
|
+
scope: '',
|
|
29
|
+
updateSet: '',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.loadContext();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
loadContext() {
|
|
36
|
+
const instance = getEffectiveInstance(this.config);
|
|
37
|
+
if (!instance) return;
|
|
38
|
+
this.context.profileName = extractProfileName(instance);
|
|
39
|
+
for (const [name, profile] of Object.entries(this.config.profiles || {})) {
|
|
40
|
+
if (profile.instance_url === instance) {
|
|
41
|
+
this.context.profileName = name;
|
|
42
|
+
this.context.username = profile.username || '';
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getEffectiveInstance() {
|
|
49
|
+
return getEffectiveInstance(this.config);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async printContextHeader() {
|
|
53
|
+
if (!this.getEffectiveInstance() || !this.sdk) return;
|
|
54
|
+
if (process.env.JSN_NO_HEADER) return;
|
|
55
|
+
if (this.output.getFormat() === FormatJSON || this.output.getFormat() === FormatQuiet) return;
|
|
56
|
+
|
|
57
|
+
let userDisplayName = 'Unknown';
|
|
58
|
+
let userSysID = '';
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const user = await getCurrentUser(this.sdk);
|
|
62
|
+
if (user) {
|
|
63
|
+
userDisplayName = user.name || user.user_name;
|
|
64
|
+
userSysID = user.sys_id;
|
|
65
|
+
this.context.username = userDisplayName;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// ignore
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let displayUserName = userDisplayName;
|
|
72
|
+
if (displayUserName.length > 10) {
|
|
73
|
+
displayUserName = displayUserName.slice(0, 6) + '...';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let scope = 'global';
|
|
77
|
+
if (userSysID) {
|
|
78
|
+
try {
|
|
79
|
+
const app = await getCurrentApplication(this.sdk, userSysID);
|
|
80
|
+
if (app && app.scope) scope = app.scope;
|
|
81
|
+
} catch {
|
|
82
|
+
// ignore
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
this.context.scope = scope;
|
|
86
|
+
|
|
87
|
+
let updateSet = 'Default';
|
|
88
|
+
let updateSetSysID = '';
|
|
89
|
+
if (userSysID) {
|
|
90
|
+
try {
|
|
91
|
+
const us = await getCurrentUpdateSet(this.sdk, userSysID);
|
|
92
|
+
if (us && us.name && us.name !== '-') {
|
|
93
|
+
updateSet = us.name;
|
|
94
|
+
updateSetSysID = us.sys_id;
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
// ignore
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.context.updateSet = updateSet;
|
|
101
|
+
|
|
102
|
+
const instance = this.getEffectiveInstance();
|
|
103
|
+
const instanceLink = instance;
|
|
104
|
+
const userLink = `${instance}/sys_user_list.do?sysparm_query=sys_id=${userSysID}`;
|
|
105
|
+
const scopeLink = `${instance}/sys_scope.do?sysparm_query=scope=${scope}`;
|
|
106
|
+
const updateSetLink = updateSetSysID
|
|
107
|
+
? `${instance}/sys_update_set.do?sys_id=${updateSetSysID}`
|
|
108
|
+
: `${instance}/sys_update_set_list.do`;
|
|
109
|
+
|
|
110
|
+
const scopeFormatted = `[${scope}]`;
|
|
111
|
+
|
|
112
|
+
process.stderr.write('# Use `jsn updateset use` or `jsn scope use` to change scope/updateset\n');
|
|
113
|
+
process.stderr.write('PROFILE USER [SCOPE] UPDATE SET\n');
|
|
114
|
+
|
|
115
|
+
const profileStr = `]8;;${instanceLink}\x07${String(this.context.profileName).padEnd(9)}]8;;\x07`;
|
|
116
|
+
const userStr = `]8;;${userLink}\x07${String(displayUserName).padEnd(9)}]8;;\x07`;
|
|
117
|
+
const scopeStr = `]8;;${scopeLink}\x07${String(scopeFormatted).padEnd(17)}]8;;\x07`;
|
|
118
|
+
const updateSetStr = `]8;;${updateSetLink}\x07${updateSet}]8;;\x07`;
|
|
119
|
+
|
|
120
|
+
process.stderr.write(`${profileStr} ${userStr} ${scopeStr} ${updateSetStr}\n\n`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
ok(data, opts = {}) {
|
|
124
|
+
this.output.ok(data, opts);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
err(error) {
|
|
128
|
+
this.output.err(error);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
isInteractive() {
|
|
132
|
+
return process.stdout.isTTY === true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
requireInstance() {
|
|
136
|
+
if (!this.getEffectiveInstance()) {
|
|
137
|
+
throw errUsage('Instance URL required. Set via --instance flag, SERVICENOW_INSTANCE_URL env, or config file.');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
requireAuth() {
|
|
142
|
+
if (!this.auth.isAuthenticated()) {
|
|
143
|
+
throw errAuth('Not authenticated');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function resolveFormat(fmt) {
|
|
149
|
+
switch (fmt) {
|
|
150
|
+
case 'json': return FormatJSON;
|
|
151
|
+
case 'markdown':
|
|
152
|
+
case 'md': return FormatMarkdown;
|
|
153
|
+
case 'quiet': return FormatQuiet;
|
|
154
|
+
case 'styled': return FormatStyled;
|
|
155
|
+
default: return FormatAuto;
|
|
156
|
+
}
|
|
157
|
+
}
|