@xano/cli 0.0.17 → 0.0.19
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 +11 -10
- package/dist/commands/run/exec/index.d.ts +11 -1
- package/dist/commands/run/exec/index.js +88 -19
- package/oclif.manifest.json +707 -703
- package/package.json +1 -1
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
|
|
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
|
|
104
|
-
xano run exec -
|
|
105
|
-
xano run exec
|
|
106
|
-
xano run exec
|
|
107
|
-
xano run exec
|
|
108
|
-
xano run exec
|
|
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
|
-
|
|
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
|
}),
|
|
@@ -23,10 +28,9 @@ export default class RunExec extends BaseRunCommand {
|
|
|
23
28
|
}),
|
|
24
29
|
edit: Flags.boolean({
|
|
25
30
|
char: 'e',
|
|
26
|
-
description: 'Open file in editor before running (requires --file)',
|
|
31
|
+
description: 'Open file in editor before running (requires path argument or --file)',
|
|
27
32
|
required: false,
|
|
28
33
|
default: false,
|
|
29
|
-
dependsOn: ['file'],
|
|
30
34
|
}),
|
|
31
35
|
output: Flags.string({
|
|
32
36
|
char: 'o',
|
|
@@ -48,11 +52,16 @@ export default class RunExec extends BaseRunCommand {
|
|
|
48
52
|
};
|
|
49
53
|
static description = 'Execute XanoScript code (job or service)';
|
|
50
54
|
static examples = [
|
|
51
|
-
`$ xano run exec
|
|
55
|
+
`$ xano run exec script.xs
|
|
56
|
+
Executed successfully!
|
|
57
|
+
...
|
|
58
|
+
`,
|
|
59
|
+
`$ xano run exec ./my-workspace
|
|
60
|
+
# Executes all .xs files in directory as multidoc
|
|
52
61
|
Executed successfully!
|
|
53
62
|
...
|
|
54
63
|
`,
|
|
55
|
-
`$ xano run exec
|
|
64
|
+
`$ xano run exec script.xs --edit
|
|
56
65
|
# Opens script.xs in $EDITOR, then executes
|
|
57
66
|
Executed successfully!
|
|
58
67
|
...
|
|
@@ -61,45 +70,63 @@ Executed successfully!
|
|
|
61
70
|
Executed successfully!
|
|
62
71
|
...
|
|
63
72
|
`,
|
|
64
|
-
`$ xano run exec
|
|
73
|
+
`$ xano run exec script.xs -o json
|
|
65
74
|
{
|
|
66
75
|
"run": { ... }
|
|
67
76
|
}
|
|
68
77
|
`,
|
|
69
|
-
`$ xano run exec
|
|
78
|
+
`$ xano run exec script.xs -a args.json
|
|
70
79
|
# Executes with input arguments from args.json
|
|
71
80
|
Executed successfully!
|
|
72
81
|
...
|
|
73
82
|
`,
|
|
74
|
-
`$ xano run exec
|
|
83
|
+
`$ xano run exec script.xs --env API_KEY=secret --env DEBUG=true
|
|
75
84
|
# Executes with environment variable overrides
|
|
76
85
|
Executed successfully!
|
|
77
86
|
...
|
|
78
87
|
`,
|
|
79
88
|
];
|
|
80
89
|
async run() {
|
|
81
|
-
const { flags } = await this.parse(RunExec);
|
|
90
|
+
const { args, flags } = await this.parse(RunExec);
|
|
82
91
|
// Initialize with project required
|
|
83
92
|
await this.initRunCommandWithProject(flags.profile);
|
|
93
|
+
// Determine input source: path argument, --file flag, or --stdin
|
|
94
|
+
const inputPath = args.path || flags.file;
|
|
95
|
+
// Validate --edit flag requirements
|
|
96
|
+
if (flags.edit) {
|
|
97
|
+
if (!inputPath) {
|
|
98
|
+
this.error('--edit requires a file path (either path argument or --file flag)');
|
|
99
|
+
}
|
|
100
|
+
if (this.isUrl(inputPath)) {
|
|
101
|
+
this.error('--edit cannot be used with URLs');
|
|
102
|
+
}
|
|
103
|
+
if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
|
|
104
|
+
this.error('--edit cannot be used with directories');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
84
107
|
// Read XanoScript content
|
|
85
108
|
let xanoscript;
|
|
86
|
-
if (
|
|
87
|
-
if (this.isUrl(
|
|
109
|
+
if (inputPath) {
|
|
110
|
+
if (this.isUrl(inputPath)) {
|
|
88
111
|
// Fetch URL content
|
|
89
112
|
try {
|
|
90
|
-
const response = await fetch(
|
|
113
|
+
const response = await fetch(inputPath);
|
|
91
114
|
if (!response.ok) {
|
|
92
115
|
this.error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
|
|
93
116
|
}
|
|
94
117
|
xanoscript = await response.text();
|
|
95
118
|
}
|
|
96
119
|
catch (error) {
|
|
97
|
-
this.error(`Failed to fetch URL '${
|
|
120
|
+
this.error(`Failed to fetch URL '${inputPath}': ${error}`);
|
|
98
121
|
}
|
|
99
122
|
}
|
|
123
|
+
else if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
|
|
124
|
+
// Handle directory - collect .xs files and create multidoc
|
|
125
|
+
xanoscript = this.loadMultidocFromDirectory(inputPath);
|
|
126
|
+
}
|
|
100
127
|
else if (flags.edit) {
|
|
101
128
|
// If edit flag is set, copy to temp file and open in editor
|
|
102
|
-
const fileToRead = await this.editFile(
|
|
129
|
+
const fileToRead = await this.editFile(inputPath);
|
|
103
130
|
xanoscript = fs.readFileSync(fileToRead, 'utf8');
|
|
104
131
|
// Clean up temp file
|
|
105
132
|
try {
|
|
@@ -111,10 +138,10 @@ Executed successfully!
|
|
|
111
138
|
}
|
|
112
139
|
else {
|
|
113
140
|
try {
|
|
114
|
-
xanoscript = fs.readFileSync(
|
|
141
|
+
xanoscript = fs.readFileSync(inputPath, 'utf8');
|
|
115
142
|
}
|
|
116
143
|
catch (error) {
|
|
117
|
-
this.error(`Failed to read file '${
|
|
144
|
+
this.error(`Failed to read file '${inputPath}': ${error}`);
|
|
118
145
|
}
|
|
119
146
|
}
|
|
120
147
|
}
|
|
@@ -127,7 +154,7 @@ Executed successfully!
|
|
|
127
154
|
}
|
|
128
155
|
}
|
|
129
156
|
else {
|
|
130
|
-
this.error('Either --file or --stdin must be specified to provide XanoScript code');
|
|
157
|
+
this.error('Either a path argument, --file, or --stdin must be specified to provide XanoScript code');
|
|
131
158
|
}
|
|
132
159
|
// Validate xanoscript is not empty
|
|
133
160
|
if (!xanoscript || xanoscript.trim().length === 0) {
|
|
@@ -202,6 +229,48 @@ Executed successfully!
|
|
|
202
229
|
}
|
|
203
230
|
}
|
|
204
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Load all .xs files from a directory and combine them into a multidoc.
|
|
234
|
+
*/
|
|
235
|
+
loadMultidocFromDirectory(dir) {
|
|
236
|
+
const resolvedDir = path.resolve(dir);
|
|
237
|
+
if (!fs.existsSync(resolvedDir)) {
|
|
238
|
+
this.error(`Directory not found: ${resolvedDir}`);
|
|
239
|
+
}
|
|
240
|
+
const files = this.collectFiles(resolvedDir);
|
|
241
|
+
if (files.length === 0) {
|
|
242
|
+
this.error(`No .xs files found in ${dir}`);
|
|
243
|
+
}
|
|
244
|
+
// Read each file and join with --- separator
|
|
245
|
+
const documents = [];
|
|
246
|
+
for (const filePath of files) {
|
|
247
|
+
const content = fs.readFileSync(filePath, 'utf8').trim();
|
|
248
|
+
if (content) {
|
|
249
|
+
documents.push(content);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (documents.length === 0) {
|
|
253
|
+
this.error(`All .xs files in ${dir} are empty`);
|
|
254
|
+
}
|
|
255
|
+
return documents.join('\n---\n');
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Recursively collect all .xs files from a directory, sorted for deterministic ordering.
|
|
259
|
+
*/
|
|
260
|
+
collectFiles(dir) {
|
|
261
|
+
const files = [];
|
|
262
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
263
|
+
for (const entry of entries) {
|
|
264
|
+
const fullPath = path.join(dir, entry.name);
|
|
265
|
+
if (entry.isDirectory()) {
|
|
266
|
+
files.push(...this.collectFiles(fullPath));
|
|
267
|
+
}
|
|
268
|
+
else if (entry.isFile() && entry.name.endsWith('.xs')) {
|
|
269
|
+
files.push(fullPath);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return files.sort();
|
|
273
|
+
}
|
|
205
274
|
outputSummary(result) {
|
|
206
275
|
this.log('Executed successfully!');
|
|
207
276
|
this.log('');
|