@jacebenson/jsn 4.3.7 → 4.3.8-dev.47

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.
Files changed (41) hide show
  1. package/README.md +266 -1
  2. package/package.json +1 -1
  3. package/skills/servicenow/SKILL.md +16 -0
  4. package/src/app.js +8 -1
  5. package/src/auth.js +14 -12
  6. package/src/cli-adapter.js +162 -11
  7. package/src/cli.js +121 -13
  8. package/src/commands/_generic.js +3 -2
  9. package/src/commands/_simple.js +1 -1
  10. package/src/commands/actions.js +156 -0
  11. package/src/commands/auth.js +21 -11
  12. package/src/commands/cmdb.js +18 -0
  13. package/src/commands/diff.js +205 -0
  14. package/src/commands/docs/docs.js +18 -16
  15. package/src/commands/flows.js +149 -47
  16. package/src/commands/graphql.js +95 -0
  17. package/src/commands/groupmembers.js +19 -4
  18. package/src/commands/grouproles.js +15 -4
  19. package/src/commands/midservers.js +708 -0
  20. package/src/commands/perf.js +36 -9
  21. package/src/commands/platform.js +202 -0
  22. package/src/commands/records.js +19 -15
  23. package/src/commands/skill.js +5 -2
  24. package/src/commands/transactions.js +78 -0
  25. package/src/commands/updatesets.js +77 -11
  26. package/src/errors.js +71 -6
  27. package/src/flow-create.js +884 -0
  28. package/src/flow-designer-interactive.js +417 -0
  29. package/src/flow-inspection.js +15 -5
  30. package/src/flow-publish.js +32 -0
  31. package/src/flow-test.js +122 -0
  32. package/src/flow-triggers.js +448 -0
  33. package/src/flow-versioning.js +53 -0
  34. package/src/help.js +93 -28
  35. package/src/helpers.js +124 -9
  36. package/src/midserver-direct.js +312 -0
  37. package/src/midserver-install.js +170 -0
  38. package/src/midserver-zip.js +107 -0
  39. package/src/output.js +7 -0
  40. package/src/processflow-actions.js +366 -0
  41. package/src/sdk.js +8 -0
package/src/errors.js CHANGED
@@ -10,6 +10,7 @@ export const CodeAPI = 'api_error';
10
10
  export const CodeAmbiguous = 'ambiguous';
11
11
  export const CodeEmptyResult = 'empty_result';
12
12
  export const CodeConfirmationRequired = 'confirmation_required';
13
+ export const CodeExtractionNotFound = 'extraction_not_found';
13
14
 
14
15
  export class AppError extends Error {
15
16
  constructor(code, message, hint = '', status = 0, cause = null) {
@@ -118,17 +119,48 @@ export function errAmbiguous(resource, matches) {
118
119
  );
119
120
  }
120
121
 
122
+ /**
123
+ * Structured error for `--get <path>` resolving to nothing.
124
+ *
125
+ * An unresolvable path (typo, wrong envelope shape, out-of-range index) is a
126
+ * failure, not a value: printing `undefined` and exiting 0 made a misspelled
127
+ * extract look like a successful empty result until the next tool in the pipe
128
+ * tried to parse it. A path that resolves to a present null, false, 0, or ""
129
+ * is a real value and is returned unchanged — only an unresolved path errors.
130
+ */
131
+ export function errExtractionNotFound(path) {
132
+ return new AppError(
133
+ CodeExtractionNotFound,
134
+ `No value at --get path "${path}".`,
135
+ 'Check the path against the envelope (run the same command without --get, or with --json, to see its shape). '
136
+ + 'Present null, false, 0, and "" values are returned as-is; only an unresolvable path fails.'
137
+ );
138
+ }
139
+
121
140
  /**
122
141
  * Structured error for a destructive action that requires confirmation
123
142
  * but no human is available to answer (non-TTY, pipes, or AI agents).
143
+ *
124
144
  * The hint is written to be machine-parseable: an agent can read the
125
- * re-run command and either present it to its user or execute it.
145
+ * exact re-run command — target, table, pinned profile/instance — and
146
+ * present it to its user for approval before executing. It deliberately
147
+ * does NOT recommend permanently disabling confirmations: an approval for
148
+ * one destructive action is not consent to disarm the guard for every
149
+ * future action.
150
+ *
151
+ * @param {string} question — e.g. `Delete incident INC0010001?`
152
+ * @param {string} [rerunCmd] — complete re-run command WITHOUT --force,
153
+ * already shell-quoted. Empty when the caller cannot reconstruct it.
126
154
  */
127
- export function errConfirmationRequired(question, rerunCmd) {
155
+ export function errConfirmationRequired(question, rerunCmd = '') {
156
+ const cmd = String(rerunCmd || '').trim();
157
+ const hint = cmd
158
+ ? `This is a destructive action. Ask your user to approve this exact command, then re-run:\n ${cmd} --force`
159
+ : 'This is a destructive action. Ask your user to approve it, then re-run the same command with --force.';
128
160
  return new AppError(
129
161
  CodeConfirmationRequired,
130
- `${question} — confirmation required. Pass --force to skip, or set skip_confirmations on the profile to disable prompts.`,
131
- `This is a destructive action. Ask your user to confirm, then re-run:\n ${rerunCmd} --force\nOr set skip_confirmations on the profile to disable prompts:\n jsn auth login <instance> --skip-confirmations`
162
+ `${question} — confirmation required. Pass --force only after your user approves this operation.`,
163
+ hint
132
164
  );
133
165
  }
134
166
 
@@ -152,12 +184,20 @@ export function isErrorCode(err, code) {
152
184
  *
153
185
  * Exit-code contract (observable behavior, pinned by tests):
154
186
  * not_found → 1 stderr, "Error (not_found): …" + identifier hint
155
- * usage / usage_error → 2 stderr, "Error (usage): …"
187
+ * extraction_not_found → 1 JSON envelope on stdout in JSON mode, else stderr
188
+ * usage / usage_error → 2 JSON envelope on stdout in JSON mode
189
+ * (machine consumers), else stderr "Error (usage): …"
156
190
  * system_error → 3 stderr, "Error (system): …"
157
191
  * confirmation_required → 1 JSON envelope on stdout in JSON mode
158
192
  * (machine consumers), else stderr + hint
159
193
  * anything else → 1 stderr, "Error: …"
160
194
  *
195
+ * The JSON envelope is the SAME shape for every failure that a machine
196
+ * consumer can hit — guardError(), the mutation middleware, parse-time
197
+ * failures routed by cli.js, and handler-thrown AppErrors all end up here, so
198
+ * `--json` never yields human prose on stdout and never yields a
199
+ * success-shaped payload for a failed command.
200
+ *
161
201
  * jsonMode resolution: prefer app.output.effectiveFormat() (respects
162
202
  * --json/--quiet/etc. shortcuts AND piped-stdout auto-detection); fall
163
203
  * back to argv.format for callers without an App (unit tests).
@@ -201,10 +241,35 @@ export function renderAppError(err, { app = null, argv = null, identifier = '' }
201
241
  return { stream: 'stderr', text, exitCode: 1 };
202
242
  }
203
243
 
244
+ if (code === CodeExtractionNotFound) {
245
+ // Same contract as every other machine-consumable failure: a parseable
246
+ // envelope on stdout when the caller is in JSON mode, human text on
247
+ // stderr otherwise. Exit 1 — the command ran, the value was absent.
248
+ if (resolveJsonMode(app, argv) && app) {
249
+ return { stream: 'stdout', text: null, exitCode: 1, appErr: true };
250
+ }
251
+ let text = `Error (${code}): ${err.message}\n`;
252
+ if (err.hint) text += `\nHint: ${err.hint}\n`;
253
+ return { stream: 'stderr', text, exitCode: 1 };
254
+ }
255
+
204
256
  // 'usage' is the legacy literal; CodeUsage ('usage_error') is the
205
257
  // exported constant. Both render as the usage class.
206
258
  if (code === CodeUsage || code === 'usage') {
207
- return { stream: 'stderr', text: `Error (usage): ${err.message}\n`, exitCode: 2 };
259
+ // Usage failures were the last split-brain case: a parse-time failure
260
+ // exited 1 with raw prose, a middleware guard exited 2 with a JSON
261
+ // envelope, and a handler-thrown usage error exited 2 with prose — all
262
+ // for the same class of mistake. One renderer, one exit code (2), and a
263
+ // structured envelope whenever the caller is in JSON mode.
264
+ if (resolveJsonMode(app, argv) && app) {
265
+ return { stream: 'stdout', text: null, exitCode: 2, appErr: true };
266
+ }
267
+ // Keep the actionable hint (the failing command's --help) in the human view
268
+ // too — it used to be dropped on this path while every other error class
269
+ // printed one.
270
+ let text = `Error (usage): ${err.message}\n`;
271
+ if (err.hint) text += `\nHint: ${err.hint}\n`;
272
+ return { stream: 'stderr', text, exitCode: 2 };
208
273
  }
209
274
 
210
275
  if (code === 'system_error') {