@xano/cli 0.0.17 → 0.0.18

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 CHANGED
@@ -25,7 +25,7 @@ npm install -g @xano/cli
25
25
 
26
26
  3. Execute XanoScript code:
27
27
  ```bash
28
- xano run exec -f script.xs
28
+ xano run exec script.xs
29
29
  ```
30
30
 
31
31
  ## Commands
@@ -54,8 +54,6 @@ xano profile:set-default myprofile
54
54
  # Edit a profile
55
55
  xano profile:edit myprofile -w 123 # Set default workspace
56
56
  xano profile:edit myprofile -j my-project # Set default project
57
- xano profile:edit myprofile --run-project <id> # Set run project for xano run commands
58
- xano profile:edit myprofile --remove-run-project # Remove run project
59
57
 
60
58
  # Delete a profile
61
59
  xano profile:delete myprofile
@@ -100,18 +98,21 @@ Execute XanoScript code and manage projects, sessions, environment variables, an
100
98
 
101
99
  ```bash
102
100
  # Execute XanoScript (job or service)
103
- xano run exec -f script.xs
104
- xano run exec -f https://example.com/script.xs # From URL
105
- xano run exec -f script.xs -a args.json # With input arguments (file)
106
- xano run exec -f script.xs -a https://ex.com/args.json # With input arguments (URL)
107
- xano run exec -f script.xs --edit # Edit in $EDITOR first
108
- xano run exec -f script.xs --env API_KEY=secret # With env overrides
101
+ xano run exec script.xs # Single file
102
+ xano run exec ./my-workspace # Directory (multidoc from .xs files)
103
+ xano run exec https://example.com/script.xs # From URL
104
+ xano run exec script.xs -a args.json # With input arguments (file)
105
+ xano run exec script.xs -a https://ex.com/args.json # With input arguments (URL)
106
+ xano run exec script.xs --edit # Edit in $EDITOR first
107
+ xano run exec script.xs --env API_KEY=secret # With env overrides
109
108
  cat script.xs | xano run exec --stdin # From stdin
110
109
 
111
110
  # Get document info (type, inputs, env vars)
112
111
  xano run info -f script.xs
113
112
  ```
114
113
 
114
+ When a directory is provided, all `.xs` files are collected recursively and combined into a multidoc (joined with `---` separators), similar to `xano workspace push`.
115
+
115
116
  #### Projects
116
117
 
117
118
  ```bash
@@ -225,7 +226,7 @@ profiles:
225
226
  access_token: <token>
226
227
  workspace: <workspace_id>
227
228
  branch: <branch_id>
228
- run_project: <run_project_id> # Used by xano run commands
229
+ project: <project_id>
229
230
  default: default
230
231
  ```
231
232
 
@@ -1,6 +1,8 @@
1
1
  import BaseRunCommand from '../../../lib/base-run-command.js';
2
2
  export default class RunExec extends BaseRunCommand {
3
- static args: {};
3
+ static args: {
4
+ path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
4
6
  static flags: {
5
7
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
8
  stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -13,6 +15,14 @@ export default class RunExec extends BaseRunCommand {
13
15
  static description: string;
14
16
  static examples: string[];
15
17
  run(): Promise<void>;
18
+ /**
19
+ * Load all .xs files from a directory and combine them into a multidoc.
20
+ */
21
+ private loadMultidocFromDirectory;
22
+ /**
23
+ * Recursively collect all .xs files from a directory, sorted for deterministic ordering.
24
+ */
25
+ private collectFiles;
16
26
  private outputSummary;
17
27
  private editFile;
18
28
  private isUrl;
@@ -1,16 +1,21 @@
1
- import { Flags } from '@oclif/core';
1
+ import { Args, Flags } from '@oclif/core';
2
2
  import { execSync } from 'node:child_process';
3
3
  import * as fs from 'node:fs';
4
4
  import * as os from 'node:os';
5
5
  import * as path from 'node:path';
6
6
  import BaseRunCommand from '../../../lib/base-run-command.js';
7
7
  export default class RunExec extends BaseRunCommand {
8
- static args = {};
8
+ static args = {
9
+ path: Args.string({
10
+ description: 'Path to file or directory containing XanoScript code (directory creates multidoc from .xs files)',
11
+ required: false,
12
+ }),
13
+ };
9
14
  static flags = {
10
15
  ...BaseRunCommand.baseFlags,
11
16
  file: Flags.string({
12
17
  char: 'f',
13
- description: 'Path or URL to file containing XanoScript code',
18
+ description: 'Path or URL to file containing XanoScript code (deprecated: use path argument instead)',
14
19
  required: false,
15
20
  exclusive: ['stdin'],
16
21
  }),
@@ -48,11 +53,16 @@ export default class RunExec extends BaseRunCommand {
48
53
  };
49
54
  static description = 'Execute XanoScript code (job or service)';
50
55
  static examples = [
51
- `$ xano run exec -f script.xs
56
+ `$ xano run exec script.xs
52
57
  Executed successfully!
53
58
  ...
54
59
  `,
55
- `$ xano run exec -f script.xs --edit
60
+ `$ xano run exec ./my-workspace
61
+ # Executes all .xs files in directory as multidoc
62
+ Executed successfully!
63
+ ...
64
+ `,
65
+ `$ xano run exec script.xs --edit
56
66
  # Opens script.xs in $EDITOR, then executes
57
67
  Executed successfully!
58
68
  ...
@@ -61,45 +71,51 @@ Executed successfully!
61
71
  Executed successfully!
62
72
  ...
63
73
  `,
64
- `$ xano run exec -f script.xs -o json
74
+ `$ xano run exec script.xs -o json
65
75
  {
66
76
  "run": { ... }
67
77
  }
68
78
  `,
69
- `$ xano run exec -f script.xs -a args.json
79
+ `$ xano run exec script.xs -a args.json
70
80
  # Executes with input arguments from args.json
71
81
  Executed successfully!
72
82
  ...
73
83
  `,
74
- `$ xano run exec -f script.xs --env API_KEY=secret --env DEBUG=true
84
+ `$ xano run exec script.xs --env API_KEY=secret --env DEBUG=true
75
85
  # Executes with environment variable overrides
76
86
  Executed successfully!
77
87
  ...
78
88
  `,
79
89
  ];
80
90
  async run() {
81
- const { flags } = await this.parse(RunExec);
91
+ const { args, flags } = await this.parse(RunExec);
82
92
  // Initialize with project required
83
93
  await this.initRunCommandWithProject(flags.profile);
84
94
  // Read XanoScript content
85
95
  let xanoscript;
86
- if (flags.file) {
87
- if (this.isUrl(flags.file)) {
96
+ // Determine input source: path argument, --file flag, or --stdin
97
+ const inputPath = args.path || flags.file;
98
+ if (inputPath) {
99
+ if (this.isUrl(inputPath)) {
88
100
  // Fetch URL content
89
101
  try {
90
- const response = await fetch(flags.file);
102
+ const response = await fetch(inputPath);
91
103
  if (!response.ok) {
92
104
  this.error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
93
105
  }
94
106
  xanoscript = await response.text();
95
107
  }
96
108
  catch (error) {
97
- this.error(`Failed to fetch URL '${flags.file}': ${error}`);
109
+ this.error(`Failed to fetch URL '${inputPath}': ${error}`);
98
110
  }
99
111
  }
112
+ else if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
113
+ // Handle directory - collect .xs files and create multidoc
114
+ xanoscript = this.loadMultidocFromDirectory(inputPath);
115
+ }
100
116
  else if (flags.edit) {
101
117
  // If edit flag is set, copy to temp file and open in editor
102
- const fileToRead = await this.editFile(flags.file);
118
+ const fileToRead = await this.editFile(inputPath);
103
119
  xanoscript = fs.readFileSync(fileToRead, 'utf8');
104
120
  // Clean up temp file
105
121
  try {
@@ -111,10 +127,10 @@ Executed successfully!
111
127
  }
112
128
  else {
113
129
  try {
114
- xanoscript = fs.readFileSync(flags.file, 'utf8');
130
+ xanoscript = fs.readFileSync(inputPath, 'utf8');
115
131
  }
116
132
  catch (error) {
117
- this.error(`Failed to read file '${flags.file}': ${error}`);
133
+ this.error(`Failed to read file '${inputPath}': ${error}`);
118
134
  }
119
135
  }
120
136
  }
@@ -127,7 +143,7 @@ Executed successfully!
127
143
  }
128
144
  }
129
145
  else {
130
- this.error('Either --file or --stdin must be specified to provide XanoScript code');
146
+ this.error('Either a path argument, --file, or --stdin must be specified to provide XanoScript code');
131
147
  }
132
148
  // Validate xanoscript is not empty
133
149
  if (!xanoscript || xanoscript.trim().length === 0) {
@@ -202,6 +218,48 @@ Executed successfully!
202
218
  }
203
219
  }
204
220
  }
221
+ /**
222
+ * Load all .xs files from a directory and combine them into a multidoc.
223
+ */
224
+ loadMultidocFromDirectory(dir) {
225
+ const resolvedDir = path.resolve(dir);
226
+ if (!fs.existsSync(resolvedDir)) {
227
+ this.error(`Directory not found: ${resolvedDir}`);
228
+ }
229
+ const files = this.collectFiles(resolvedDir);
230
+ if (files.length === 0) {
231
+ this.error(`No .xs files found in ${dir}`);
232
+ }
233
+ // Read each file and join with --- separator
234
+ const documents = [];
235
+ for (const filePath of files) {
236
+ const content = fs.readFileSync(filePath, 'utf8').trim();
237
+ if (content) {
238
+ documents.push(content);
239
+ }
240
+ }
241
+ if (documents.length === 0) {
242
+ this.error(`All .xs files in ${dir} are empty`);
243
+ }
244
+ return documents.join('\n---\n');
245
+ }
246
+ /**
247
+ * Recursively collect all .xs files from a directory, sorted for deterministic ordering.
248
+ */
249
+ collectFiles(dir) {
250
+ const files = [];
251
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
252
+ for (const entry of entries) {
253
+ const fullPath = path.join(dir, entry.name);
254
+ if (entry.isDirectory()) {
255
+ files.push(...this.collectFiles(fullPath));
256
+ }
257
+ else if (entry.isFile() && entry.name.endsWith('.xs')) {
258
+ files.push(fullPath);
259
+ }
260
+ }
261
+ return files.sort();
262
+ }
205
263
  outputSummary(result) {
206
264
  this.log('Executed successfully!');
207
265
  this.log('');