@pixlcore/xycli 1.2.1 → 1.2.2

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.
@@ -48,6 +48,7 @@ jobs:
48
48
  with:
49
49
  context: .
50
50
  file: ./Dockerfile
51
+ pull: true
51
52
  platforms: linux/amd64,linux/arm64
52
53
  push: true
53
54
  tags: ${{ steps.meta.outputs.tags }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # xyCLI Changelog
2
2
 
3
+ ## Version v1.2.1
4
+
5
+ > October 29, 2026
6
+
7
+ - [`c5b6e1c`](https://github.com/pixlcore/xycli/commit/c5b6e1c43296ba8d58d68ebee245b7d27dc4fbfb): Version 1.2.1
8
+ - [`a2fca91`](https://github.com/pixlcore/xycli/commit/a2fca9138e5748d70b1e139b6d0b84f082ec7406): Feature: Follow live job retries automatically
9
+ - [`6b3686d`](https://github.com/pixlcore/xycli/commit/6b3686d18c72139e32d18e1c90e10f8910565224): Feature: Set custom process title for MCP server.
10
+ - [`099444b`](https://github.com/pixlcore/xycli/commit/099444bd87765c1a1e97a65bae6a2b2ea7f4f757): Add LICENSE.md file
11
+ - [`2d6c1c4`](https://github.com/pixlcore/xycli/commit/2d6c1c44a73e265fba38b4feb1c2a7aaea843487): Meta: Fix offline test trigger to only run on tag pushes
12
+
13
+ ## Version v1.2.0
14
+
15
+ > October 25, 2026
16
+
17
+ - [`3f99851`](https://github.com/pixlcore/xycli/commit/3f9985186f3cba6e04c2fb0cc7b6eae3a7fc7fcb): Fix Windows MCP shutdown tests and update Node.js CI matrix
18
+ - [`2034c48`](https://github.com/pixlcore/xycli/commit/2034c48626f999ffb969d4cebb7343cb233d565d): Version 1.2.0
19
+ - [`e9693fb`](https://github.com/pixlcore/xycli/commit/e9693fbc527135b45ac2fc39659adb96923d9272): Feature: Expand MCP tools with tickets, alerts, snapshots and servers
20
+ - [`1c12b76`](https://github.com/pixlcore/xycli/commit/1c12b76b747d97ccf358501d438e6deb8b97ca4e): Feature: Add Docker image and automated GHCR publishing for xyCLI
21
+ - [`fa33af6`](https://github.com/pixlcore/xycli/commit/fa33af6b793786da33d6ae0bf832bcdea182e6b0): Feature: Add MCP server with shared STDIO and HTTP transports
22
+
23
+ ## Version v1.1.1
24
+
25
+ > October 2, 2026
26
+
27
+ - [`5f924c6`](https://github.com/pixlcore/xycli/commit/5f924c69ad8c5ed3c04be40d600b95fa3eee5f66): Version 1.1.1
28
+ - [`759f8db`](https://github.com/pixlcore/xycli/commit/759f8db93f1763b7e876d16066b7dd04a9681ec3): Doc: Update xyOps version to v1.1.4 in two-way delete tutorial, and add in sys activity exclusions.
29
+ - [`551be24`](https://github.com/pixlcore/xycli/commit/551be2413b4e584daebb2ed57710a620a7006372): Dep: Override "basic-ftp" (sub-sub-sub-sub-dep of pixl-request) to v6.2.1 for vuln fix, that isn't fixed in any of the parents.
30
+
31
+ ## Version v1.1.0
32
+
33
+ > September 30, 2026
34
+
35
+ - [`50ff6e6`](https://github.com/pixlcore/xycli/commit/50ff6e6f5f11a29287bcf0ffe2d8f7d966d34ee3): Version 1.1.0
36
+ - [`5bf07a8`](https://github.com/pixlcore/xycli/commit/5bf07a87cfdc649abd8058c10f73c44b037c8cf4): Fix ticket unit test (due to API key bug fix over in xyOps)
37
+ - [`5493608`](https://github.com/pixlcore/xycli/commit/5493608d71dbf8cfd9fbb3f2fef958d1bb107ee1): Feature: Down-sync delete mode, and a new two-way delete setup tut.
38
+
39
+ ## Version v1.0.9
40
+
41
+ > September 28, 2026
42
+
43
+ - [`9cbc6c7`](https://github.com/pixlcore/xycli/commit/9cbc6c753e9351243e13a942a3ad19c2012884cb): Version 1.0.9
44
+ - [`6a0d739`](https://github.com/pixlcore/xycli/commit/6a0d739c3d85f61758bc9ea25c77a3b00968c79d): Feature: New system hook (syshook) deletion system, for active deletes from xyOps.
45
+ - [`eeae786`](https://github.com/pixlcore/xycli/commit/eeae7863361c1f343dedae301a00d99db3fccdbb): Feature: New "--ignore_missing" parameter to suppress missing item warnings. Fixes #9
46
+ - [`80e77d4`](https://github.com/pixlcore/xycli/commit/80e77d40edfdb1c7fb4285235c6cc9fb2f0bcb2a): Bug Fix: Always print all errors and warnings, even in quiet mode. Fixes #8
47
+
48
+ ## Version v1.0.8
49
+
50
+ > September 25, 2026
51
+
52
+ - [`3cc0914`](https://github.com/pixlcore/xycli/commit/3cc0914dd00211e6215ef3f2e5f7b2467570c9d0): Version 1.0.8
53
+ - [`04d0f31`](https://github.com/pixlcore/xycli/commit/04d0f31eaee9b89bb5f2518c9bf813d24b5235eb): Meta: Fix offline unit tests on Windows (was using colon in filename)
54
+ - [`5570628`](https://github.com/pixlcore/xycli/commit/557062875ab99a4cca41ae419204bc4992962ef1): Bug Fix: Remove some redundant dry run toasts.
55
+ - [`536685e`](https://github.com/pixlcore/xycli/commit/536685eae72bc9bea1be24f4ba7e4998f17386fb): Feature: Allow buckets, bucket data and bucket files to all be synced. Fixes #6
56
+ - [`3cc2ccb`](https://github.com/pixlcore/xycli/commit/3cc2ccb93202bce52de6fe09dead7854ca274640): Docs: Added instructions for deleting items with two-way sync
57
+ - [`38d336b`](https://github.com/pixlcore/xycli/commit/38d336b20797e435664924623e94d877a74c3c0a): Bug Fix: Allow unknown object properties to sync without error (i.e. for legacy Cronicle imports).
58
+ - [`dc1e994`](https://github.com/pixlcore/xycli/commit/dc1e994c3b55eb4040210c8882cf01cd47b0defb): Bug FIx: For printing Emoji, do not use cursor save/restore width-fix when stdout is not a TTY.
59
+
60
+ ## Version v1.0.7
61
+
62
+ > September 23, 2026
63
+
64
+ - [`0cce2eb`](https://github.com/pixlcore/xycli/commit/0cce2eb70bc3f17e54fb19c8db43ce937701b68c): Version 1.0.7
65
+ - [`4089e78`](https://github.com/pixlcore/xycli/commit/4089e78e9dc67894afa9d5c325af0e7c37e762a6): Bug Fix: Typo in custom job user HTML content when trying to rendering the caption. Fixes #7.
66
+ - [`76a247c`](https://github.com/pixlcore/xycli/commit/76a247c9abadeb9ee6f9c7bfb89d06cd375c41dd): Feature: Sync: Support workflow node sub-property neighbor files. Fixes #5.
67
+
3
68
  ## Version v1.0.6
4
69
 
5
70
  > September 22, 2026
package/docs/help.md CHANGED
@@ -394,6 +394,8 @@ xy config --base_url http://localhost:5522 --api_key YOUR_API_KEY
394
394
 
395
395
  Updates load the user file separately and apply only the settings specified on the command line, preserving other user settings. System settings and environment overrides are not copied into the file. If the user file does not exist, it is created with only the supplied settings.
396
396
 
397
+ Unknown top-level configuration keys are rejected before saving any changes, with a spelling suggestion when available. Use underscores in names such as `--base_url` and `--api_key`. Structured settings still support nested updates, such as `xy config --sync.down false` or `xy config --mcp.port 8080`.
398
+
397
399
  Configuration loads the machine file first, then the user file, then `XYOPS_`-prefixed environment variables. The machine and user files are `/etc/xyops/cli.json` and `~/.config/xyops/cli.json` on Unix and macOS, or `%PROGRAMDATA%\xyops\cli.json` and `%USERPROFILE%\.config\xyops\cli.json` on Windows. Later sources override matching top-level settings. Environment overrides still take precedence over saved user settings. Common keys include `api_key`, `base_url`, `temp_dir`, `color`, `suggest`, `items_per_page`, `cache_ttl`, `raw`, and `invisible`.
398
400
 
399
401
  Environment values that look like JSON objects or arrays are parsed automatically for any setting. For example, `XYOPS_SYNC='{"up":["events"],"down":false}'` supplies a structured `sync` setting. Boolean and numeric values keep their usual conversions. Malformed JSON-looking values report the environment variable name. Objects and arrays are serialized as JSON when the CLI exports its effective configuration back into the environment.
package/index.js CHANGED
@@ -203,7 +203,8 @@ const app = {
203
203
  delete args.format;
204
204
 
205
205
  this.raw = args.raw || this.config.raw || false;
206
- delete args.raw;
206
+ // The config command saves --raw as a preference for future commands.
207
+ if (cmd != 'config') delete args.raw;
207
208
 
208
209
  this.dry = args.dry || false;
209
210
  delete args.dry;
package/lib/config.js CHANGED
@@ -7,6 +7,27 @@ const cli = require('pixl-cli');
7
7
  const Tools = cli.Tools;
8
8
  const chalk = cli.chalk;
9
9
 
10
+ // Settings consumed by the CLI, MCP server, or SDK. Keep this inventory
11
+ // explicit so a typo already saved in a config file cannot become a valid key.
12
+ const CONFIG_KEYS = [
13
+ 'api_key', 'base_url', 'temp_dir', 'color', 'suggest', 'items_per_page',
14
+ 'cache_ttl', 'raw', 'invisible', 'tz', 'log_columns', 'new_event_template',
15
+ 'sync', 'mcp', 'user_agent', 'timeout', 'connect_timeout', 'idle_timeout',
16
+ 'retries', 'retry_delay', 'retry_delay_max', 'allow_unauthorized',
17
+ 'mcp_host', 'mcp_port', 'mcp_read_only', 'mcp_max_page_size',
18
+ 'mcp_max_result_bytes', 'mcp_max_request_bytes', 'mcp_tls_cert', 'mcp_tls_key',
19
+ 'ui', 'default_user_privileges', 'max_servers_per_group', 'quick_monitors',
20
+ 'job_universal_actions', 'job_universal_limits'
21
+ ];
22
+
23
+ // Structured settings also support the existing dot and slash path syntax.
24
+ // Their contents may include arbitrary plugin parameters or server UI data.
25
+ const CONFIG_PATH_KEYS = [
26
+ 'log_columns', 'new_event_template', 'sync', 'mcp', 'ui',
27
+ 'default_user_privileges', 'quick_monitors', 'job_universal_actions',
28
+ 'job_universal_limits'
29
+ ];
30
+
10
31
  function getConfigFiles(platform, env, home_dir) {
11
32
  // Keep the existing Unix paths, but use Windows's shared application-data
12
33
  // directory instead of resolving /etc against whichever drive is current.
@@ -66,6 +87,9 @@ var config_layer = module.exports = {
66
87
  // allow user to view config, and also modify it
67
88
  delete this.args.other;
68
89
 
90
+ // These flags control this invocation, rather than saved preferences.
91
+ for (var key of ['debug', 'echo', 'quiet', 'verbose']) delete this.args[key];
92
+
69
93
  if (!Tools.firstKey(this.args)) {
70
94
  // just print config and exit
71
95
  println( "\n " + this.color('theme').bold( 'CONFIGURATION SOURCES:' ) + "\n" );
@@ -81,6 +105,18 @@ var config_layer = module.exports = {
81
105
  return;
82
106
  }
83
107
 
108
+ // Validate the entire update before printing any values or touching the
109
+ // file. In particular, a misspelled --api-key must never echo its secret.
110
+ for (var key of Object.keys(this.args)) {
111
+ var root = key.split(/[.\/]/)[0];
112
+ if (CONFIG_KEYS.includes(key) || ((root != key) && CONFIG_PATH_KEYS.includes(root))) continue;
113
+
114
+ var suggestion = this.findClosestString(root, (root == key) ? CONFIG_KEYS : CONFIG_PATH_KEYS);
115
+ var message = 'Unknown configuration key "' + key + '".';
116
+ if (suggestion) message += ' Did you mean "' + suggestion + ((root != key) ? key.slice(root.length) : '') + '"?';
117
+ return this.die(message);
118
+ }
119
+
84
120
  // Reload only the user's settings before applying changes. The effective
85
121
  // configuration also contains system settings and environment overrides,
86
122
  // which must not be copied into the user's file when saving preferences.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixlcore/xycli",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "A complete command-line interface for the xyOps workflow automation system.",
5
5
  "author": "Joseph Huckaby <jhuckaby@pixlcore.com>",
6
6
  "homepage": "https://github.com/pixlcore/xycli",
@@ -32,7 +32,7 @@ function createConfigFixture(t, initial) {
32
32
 
33
33
  return {
34
34
  file,
35
- run(args) {
35
+ run(args, expected_status = 0) {
36
36
  const env = {
37
37
  ...process.env,
38
38
  HOME: home_dir,
@@ -58,8 +58,8 @@ function createConfigFixture(t, initial) {
58
58
  // Keep captured CLI output out of assertion messages, since a config
59
59
  // command may display settings inherited from the real system file.
60
60
  assert.ifError(result.error);
61
- assert.equal(result.status, 0, 'Config command should succeed');
62
- return result.stdout;
61
+ assert.equal(result.status, expected_status, 'Config command should exit with the expected status');
62
+ return result.stdout + result.stderr;
63
63
  },
64
64
  read() { return JSON.parse(fs.readFileSync(file, 'utf8')); }
65
65
  };
@@ -112,6 +112,65 @@ test('config creates a missing user file with only supplied settings', t => {
112
112
  assertPrivateMode(fixture.file);
113
113
  });
114
114
 
115
+ test('config rejects misspelled keys without creating a file or exposing secrets', t => {
116
+ const fixture = createConfigFixture(t);
117
+
118
+ for (const [key, suggestion] of [['base-url', 'base_url'], ['api-key', 'api_key'], ['items_per_pag', 'items_per_page']]) {
119
+ const output = fixture.run(['--' + key, 'private-fixture-value'], 1);
120
+ assert.ok(output.includes('Unknown configuration key "' + key + '".'));
121
+ assert.ok(output.includes('Did you mean "' + suggestion + '"?'));
122
+ assert.doesNotMatch(output, /private-fixture-value|Setting key:|Writing to:/);
123
+ assert.equal(fs.existsSync(fixture.file), false);
124
+ }
125
+ });
126
+
127
+ test('config rejects mixed valid and unknown updates without changing the user file', t => {
128
+ // Previously saved typos must not be accepted as supported config keys.
129
+ const fixture = createConfigFixture(t, { items_per_page: 10, 'api-key': 'old-value' });
130
+ const original = fs.readFileSync(fixture.file, 'utf8');
131
+ const output = fixture.run(['--items_per_page', '25', '--api-key', 'private-fixture-value'], 1);
132
+
133
+ assert.match(output, /Unknown configuration key "api-key"/);
134
+ assert.doesNotMatch(output, /private-fixture-value|Setting key:|Writing to:/);
135
+ assert.equal(fs.readFileSync(fixture.file, 'utf8'), original);
136
+ });
137
+
138
+ test('config rejects unrelated keys and nested paths under scalar settings', t => {
139
+ const fixture = createConfigFixture(t);
140
+
141
+ for (const key of ['unrelated_option', 'api_key.child', 'base_url/child']) {
142
+ const output = fixture.run(['--' + key, 'private-fixture-value'], 1);
143
+ assert.match(output, /Unknown configuration key/);
144
+ assert.doesNotMatch(output, /private-fixture-value|Setting key:|Writing to:/);
145
+ assert.equal(fs.existsSync(fixture.file), false);
146
+ }
147
+ });
148
+
149
+ test('config saves supported connection, SDK, MCP, and structured settings', t => {
150
+ const fixture = createConfigFixture(t);
151
+ const output = fixture.run([
152
+ '--base_url', 'https://saved.invalid', '--api_key', 'private-fixture-value',
153
+ '--timeout', '5000', '--mcp_port', '8080', '--mcp.read_only', 'true',
154
+ '--new_event_template/params/custom', 'value', '--raw', 'false'
155
+ ]);
156
+
157
+ assert.doesNotMatch(output, /private-fixture-value/);
158
+ assert.deepEqual(fixture.read(), {
159
+ base_url: 'https://saved.invalid', api_key: 'private-fixture-value',
160
+ timeout: 5000, mcp_port: 8080, mcp: { read_only: true },
161
+ new_event_template: { params: { custom: 'value' } }, raw: false
162
+ });
163
+ assertPrivateMode(fixture.file);
164
+ });
165
+
166
+ test('config ignores invocation flags when displaying and saving settings', t => {
167
+ const fixture = createConfigFixture(t);
168
+ fixture.run(['--quiet']);
169
+ assert.equal(fs.existsSync(fixture.file), false);
170
+ fixture.run(['--verbose', '--items_per_page', '25']);
171
+ assert.deepEqual(fixture.read(), { items_per_page: 25 });
172
+ });
173
+
115
174
  test('config dotted updates preserve sibling user settings and explicit false or zero values', t => {
116
175
  const fixture = createConfigFixture(t, {
117
176
  sync: { up: ['events'], down: ['plugins'], error_email: 'ops@example.com' },