@pixlcore/xycli 1.0.3 → 1.0.4

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/index.js CHANGED
@@ -198,6 +198,34 @@ const app = {
198
198
  return;
199
199
  }
200
200
 
201
+ // Validate local command routing before requiring a configured server. This
202
+ // keeps help and typo diagnostics available during initial CLI setup. Export
203
+ // is excluded because it also supports portable resource types that do not
204
+ // have their own complete command routers yet.
205
+ if (!('export' in args) && !this['cmd_' + cmd]) {
206
+ // Allow the user to swap the first two args if the second is a known command.
207
+ if (this['cmd_' + args.other[0]]) {
208
+ var new_cmd = args.other[0];
209
+ args.other[0] = cmd;
210
+ cmd = new_cmd;
211
+ }
212
+ else {
213
+ var suggestion = this.findClosestString(cmd, TOP_LEVEL_COMMANDS);
214
+ this.die(
215
+ "Unknown command: " + cmd + (suggestion ? '. Did you mean "' + suggestion + '"?' : ''),
216
+ "Available Commands: " + TOP_LEVEL_COMMANDS.join(', ') + "\n\n"
217
+ );
218
+ }
219
+ }
220
+
221
+ // Help is entirely local, so it should work before a user has configured an
222
+ // API key or server URL, and should never make a network request.
223
+ if (cmd == 'help') {
224
+ await this.cmd_help();
225
+ print("\n");
226
+ return;
227
+ }
228
+
201
229
  delete args.debug;
202
230
  delete args.echo;
203
231
  delete args.quiet;
@@ -273,22 +301,6 @@ const app = {
273
301
  return;
274
302
  }
275
303
 
276
- if (!this['cmd_' + cmd]) {
277
- // allow user to swap first two args, if 2nd is known command
278
- if (this['cmd_' + args.other[0]]) {
279
- var new_cmd = args.other[0];
280
- args.other[0] = cmd;
281
- cmd = new_cmd;
282
- }
283
- else {
284
- var suggestion = this.findClosestString(cmd, TOP_LEVEL_COMMANDS);
285
- this.die(
286
- "Unknown command: " + cmd + (suggestion ? '. Did you mean "' + suggestion + '"?' : ''),
287
- "Available Commands: " + TOP_LEVEL_COMMANDS.join(', ') + "\n\n"
288
- );
289
- }
290
- }
291
-
292
304
  // merge in config from xyops
293
305
  await this.cacheConfig();
294
306
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixlcore/xycli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
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",
package/test/help.test.js CHANGED
@@ -2,25 +2,39 @@ const { test } = require('node:test');
2
2
  const assert = require('node:assert/strict');
3
3
  const { xy } = require('./helpers/common.js');
4
4
 
5
+ // Deliberately shadow any developer-machine configuration. Help and command
6
+ // diagnostics must remain useful before the user connects the CLI to xyOps.
7
+ const offlineEnv = {
8
+ XYOPS_API_KEY: '',
9
+ XYOPS_BASE_URL: ''
10
+ };
11
+
12
+ const offlineFailure = { fail: true, env: offlineEnv };
13
+
14
+ test('help is available without server credentials', () => {
15
+ const output = xy(['help'], { env: offlineEnv });
16
+ assert.match(output, /HELP: OVERVIEW/);
17
+ });
18
+
5
19
  test('help suggests the closest chapter for a typo', () => {
6
- const output = xy(['help', 'event', 'udpate'], { fail: true });
20
+ const output = xy(['help', 'event', 'udpate'], offlineFailure);
7
21
  assert.match(output, /Could not find help chapter for "event udpate"\. Did you mean "event update"\?/);
8
22
  });
9
23
 
10
24
  test('help does not suggest an unrelated chapter', () => {
11
- const output = xy(['help', 'completely', 'unrelated', 'words'], { fail: true });
25
+ const output = xy(['help', 'completely', 'unrelated', 'words'], offlineFailure);
12
26
  assert.match(output, /Could not find help chapter for "completely unrelated words"\./);
13
27
  assert.doesNotMatch(output, /Did you mean/);
14
28
  });
15
29
 
16
30
  test('unknown top-level command suggests the closest command', () => {
17
- const output = xy(['evnets'], { fail: true });
31
+ const output = xy(['evnets'], offlineFailure);
18
32
  assert.match(output, /Unknown command: evnets\. Did you mean "events"\?/);
19
33
  assert.match(output, /Available Commands:.*events/);
20
34
  });
21
35
 
22
36
  test('unknown top-level command does not suggest an unrelated command', () => {
23
- const output = xy(['completely_unrelated'], { fail: true });
37
+ const output = xy(['completely_unrelated'], offlineFailure);
24
38
  assert.match(output, /Unknown command: completely_unrelated/);
25
39
  assert.doesNotMatch(output, /Did you mean/);
26
40
  });