@zeyos/cli 0.1.1
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/LICENSE +21 -0
- package/README.md +87 -0
- package/bin/zeyos.mjs +280 -0
- package/commands/count.mjs +63 -0
- package/commands/create.mjs +62 -0
- package/commands/delete.mjs +68 -0
- package/commands/describe.mjs +102 -0
- package/commands/get.mjs +127 -0
- package/commands/list.mjs +162 -0
- package/commands/login.mjs +223 -0
- package/commands/logout.mjs +63 -0
- package/commands/resources.mjs +49 -0
- package/commands/skills.mjs +363 -0
- package/commands/update.mjs +71 -0
- package/commands/whoami.mjs +100 -0
- package/config/account.json +18 -0
- package/config/item.json +16 -0
- package/config/project.json +16 -0
- package/config/task.json +18 -0
- package/config/ticket.json +19 -0
- package/lib/client.mjs +69 -0
- package/lib/command.mjs +148 -0
- package/lib/config.mjs +164 -0
- package/lib/flags.mjs +44 -0
- package/lib/login-server.mjs +149 -0
- package/lib/output.mjs +284 -0
- package/lib/resource-config.mjs +289 -0
- package/lib/resources.mjs +234 -0
- package/lib/types.mjs +46 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ZeyOS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# ZeyOS CLI
|
|
2
|
+
|
|
3
|
+
The CLI is the default interface for coding agents and shell automation that work against the curated ZeyOS resource registry.
|
|
4
|
+
|
|
5
|
+
The authoritative documentation lives in the repository-level docs:
|
|
6
|
+
|
|
7
|
+
- [Coding Agents](../docs/04-agent-workflows/00-coding-agents.md)
|
|
8
|
+
- [Agent Quickstart](../docs/04-agent-workflows/01-agent-quickstart.md)
|
|
9
|
+
- [CLI Getting Started](../docs/03-cli/01-getting-started.md)
|
|
10
|
+
- [Commands Reference](../docs/03-cli/02-commands.md)
|
|
11
|
+
- [Configuration](../docs/03-cli/03-configuration.md)
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
From the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm link cli/
|
|
20
|
+
zeyos --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install the package directly:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g @zeyos/cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Authenticate:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export ZEYOS_CLIENT_SECRET="..."
|
|
35
|
+
zeyos login \
|
|
36
|
+
--base-url https://cloud.zeyos.com/demo \
|
|
37
|
+
--client-id myapp \
|
|
38
|
+
--secret "$ZEYOS_CLIENT_SECRET"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For interactive use, omit `--secret`; the CLI prompts without echoing the secret to the terminal.
|
|
42
|
+
|
|
43
|
+
Verify the current user:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
zeyos whoami --json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`whoami` does not print access tokens by default. Use `zeyos whoami --show-token --json` only when you intentionally need to pass a token to another local tool.
|
|
50
|
+
|
|
51
|
+
Inspect the CLI-supported resource registry:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
zeyos resources
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
List tickets for automation:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
zeyos list tickets \
|
|
61
|
+
--fields ID,ticketnum,name,status,priority,lastmodified \
|
|
62
|
+
--filter '{"visibility":0}' \
|
|
63
|
+
--sort -lastmodified \
|
|
64
|
+
--limit 20 \
|
|
65
|
+
--json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Create, update, and delete:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
zeyos create ticket --data '{"name":"Fix login bug","status":0,"priority":3,"visibility":0}' --json
|
|
72
|
+
zeyos update ticket 42 --data '{"status":4}' --json
|
|
73
|
+
zeyos delete ticket 42
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
- Local credentials: `.zeyos/auth.json`
|
|
79
|
+
- Global credentials: `~/.config/zeyos/credentials.json`
|
|
80
|
+
- Project resource overrides: `.zeyos/api/<resource>.json`
|
|
81
|
+
- Global resource overrides: `~/.zeyos/api/<resource>.json`
|
|
82
|
+
|
|
83
|
+
## Coverage Boundary
|
|
84
|
+
|
|
85
|
+
The CLI intentionally covers a curated registry instead of the full API surface. Use `zeyos resources` to see the supported set.
|
|
86
|
+
|
|
87
|
+
When you need unsupported resources or low-level request control, switch to [`@zeyos/client`](../docs/02-javascript-client/01-getting-started.md) and follow the escalation guidance in [CLI Coverage and Escalation](../docs/04-agent-workflows/03-cli-coverage-and-escalation.md).
|
package/bin/zeyos.mjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ZeyOS CLI — entry point
|
|
4
|
+
*
|
|
5
|
+
* Usage: zeyos <command> [options] [args…]
|
|
6
|
+
*
|
|
7
|
+
* Commands:
|
|
8
|
+
* login Authenticate with ZeyOS
|
|
9
|
+
* logout Revoke session and clear tokens
|
|
10
|
+
* whoami Show current user info
|
|
11
|
+
* list <resource> List records
|
|
12
|
+
* count <resource> Count records
|
|
13
|
+
* get <resource> <id> Fetch a single record
|
|
14
|
+
* show <resource> <id> Alias for get
|
|
15
|
+
* create <resource> Create a new record
|
|
16
|
+
* update <resource> Update a record
|
|
17
|
+
* delete <resource> Delete a record
|
|
18
|
+
* resources List available resource types
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// ── Version ───────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
import { createRequire as _createRequire } from 'node:module';
|
|
24
|
+
import { dirname as _dirname } from 'node:path';
|
|
25
|
+
import { fileURLToPath as _fileURLToPath } from 'node:url';
|
|
26
|
+
const _require = _createRequire(import.meta.url);
|
|
27
|
+
const _VERSION = _require('../package.json').version;
|
|
28
|
+
|
|
29
|
+
// ── Global help ───────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const HELP = `\
|
|
32
|
+
Usage: zeyos <command> [options] [args…]
|
|
33
|
+
|
|
34
|
+
Commands:
|
|
35
|
+
login Authenticate with a ZeyOS instance
|
|
36
|
+
logout Revoke session and clear stored tokens
|
|
37
|
+
whoami Show currently authenticated user
|
|
38
|
+
list <resource> List / query records
|
|
39
|
+
count <resource> Count records (with optional filter)
|
|
40
|
+
get <resource> <id> Fetch a single record by ID
|
|
41
|
+
show <resource> <id> Alias for get
|
|
42
|
+
create <resource> Create a new record
|
|
43
|
+
update <resource> <id> Update an existing record
|
|
44
|
+
delete <resource> <id> Delete a record
|
|
45
|
+
resources List all available resource types
|
|
46
|
+
describe <resource> Show a resource's fields, types and enums
|
|
47
|
+
skills <command> List / show / install ZeyOS agent skills
|
|
48
|
+
|
|
49
|
+
Global options:
|
|
50
|
+
--json Output as JSON
|
|
51
|
+
--yaml Output as YAML
|
|
52
|
+
--no-color Disable ANSI colors
|
|
53
|
+
-h, --help Show help for a command
|
|
54
|
+
-v, --version Print the CLI version and exit
|
|
55
|
+
|
|
56
|
+
Examples:
|
|
57
|
+
zeyos login --base-url https://cloud.zeyos.com/demo --client-id myapp --secret "$ZEYOS_CLIENT_SECRET"
|
|
58
|
+
zeyos list tickets --filter '{"status":1}' --sort -lastmodified
|
|
59
|
+
zeyos count tickets --filter '{"status":1}'
|
|
60
|
+
zeyos get ticket 42
|
|
61
|
+
zeyos get ticket 42 --all
|
|
62
|
+
zeyos create ticket --name "Fix login bug" --priority 3
|
|
63
|
+
zeyos update ticket 42 --status 2
|
|
64
|
+
zeyos delete ticket 42 --force
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
// ── Argument definitions ──────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
const OPTIONS = {
|
|
70
|
+
// Global
|
|
71
|
+
'help': { type: 'boolean', short: 'h' },
|
|
72
|
+
'version': { type: 'boolean', short: 'v' },
|
|
73
|
+
'json': { type: 'boolean' },
|
|
74
|
+
'yaml': { type: 'boolean' },
|
|
75
|
+
'no-color': { type: 'boolean' },
|
|
76
|
+
// login
|
|
77
|
+
'base-url': { type: 'string' },
|
|
78
|
+
'client-id': { type: 'string' },
|
|
79
|
+
'secret': { type: 'string' },
|
|
80
|
+
'scope': { type: 'string' },
|
|
81
|
+
'port': { type: 'string' },
|
|
82
|
+
'global': { type: 'boolean' },
|
|
83
|
+
'local': { type: 'boolean' },
|
|
84
|
+
'force': { type: 'boolean' },
|
|
85
|
+
'clean': { type: 'boolean' },
|
|
86
|
+
'manual': { type: 'boolean' },
|
|
87
|
+
'yes': { type: 'boolean', short: 'y' },
|
|
88
|
+
// list
|
|
89
|
+
'fields': { type: 'string' },
|
|
90
|
+
'filter': { type: 'string' },
|
|
91
|
+
'sort': { type: 'string' },
|
|
92
|
+
'limit': { type: 'string' },
|
|
93
|
+
'offset': { type: 'string' },
|
|
94
|
+
'expand': { type: 'string' },
|
|
95
|
+
'extdata': { type: 'boolean' },
|
|
96
|
+
'tags': { type: 'boolean' },
|
|
97
|
+
// get
|
|
98
|
+
'all': { type: 'boolean' },
|
|
99
|
+
// whoami
|
|
100
|
+
'show-token': { type: 'boolean' },
|
|
101
|
+
// create / update
|
|
102
|
+
'data': { type: 'string' },
|
|
103
|
+
// delete
|
|
104
|
+
// (--force is already declared above)
|
|
105
|
+
// skills install
|
|
106
|
+
'target': { type: 'string' },
|
|
107
|
+
'dir': { type: 'string' },
|
|
108
|
+
'no-logo': { type: 'boolean' },
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// ── Command registry ──────────────────────────────────────────────────────────
|
|
112
|
+
// Maps every command and alias to the module that implements it.
|
|
113
|
+
|
|
114
|
+
const COMMANDS = {
|
|
115
|
+
login: '../commands/login.mjs',
|
|
116
|
+
logout: '../commands/logout.mjs',
|
|
117
|
+
whoami: '../commands/whoami.mjs',
|
|
118
|
+
list: '../commands/list.mjs',
|
|
119
|
+
count: '../commands/count.mjs',
|
|
120
|
+
get: '../commands/get.mjs',
|
|
121
|
+
show: '../commands/get.mjs',
|
|
122
|
+
create: '../commands/create.mjs',
|
|
123
|
+
update: '../commands/update.mjs',
|
|
124
|
+
edit: '../commands/update.mjs',
|
|
125
|
+
delete: '../commands/delete.mjs',
|
|
126
|
+
rm: '../commands/delete.mjs',
|
|
127
|
+
remove: '../commands/delete.mjs',
|
|
128
|
+
resources: '../commands/resources.mjs',
|
|
129
|
+
resource: '../commands/resources.mjs',
|
|
130
|
+
describe: '../commands/describe.mjs',
|
|
131
|
+
skills: '../commands/skills.mjs',
|
|
132
|
+
skill: '../commands/skills.mjs',
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
async function main() {
|
|
138
|
+
// Strip 'node' and script path from argv
|
|
139
|
+
const argv = process.argv.slice(2);
|
|
140
|
+
|
|
141
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
142
|
+
process.stdout.write(HELP);
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (argv[0] === '--version' || argv[0] === '-v') {
|
|
147
|
+
process.stdout.write(_VERSION + '\n');
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const command = argv[0];
|
|
152
|
+
const rest = argv.slice(1);
|
|
153
|
+
|
|
154
|
+
// Parse remaining args permissively: known options are parsed normally and
|
|
155
|
+
// unknown --key value flags are captured too (so create/update accept fields).
|
|
156
|
+
const { values, positional } = _parsePermissive(rest, OPTIONS);
|
|
157
|
+
|
|
158
|
+
const modulePath = COMMANDS[command];
|
|
159
|
+
if (!modulePath) {
|
|
160
|
+
process.stderr.write(`Unknown command: "${command}"\n\n${HELP}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const mod = await import(modulePath);
|
|
165
|
+
|
|
166
|
+
if (values.help) {
|
|
167
|
+
process.stdout.write(mod.USAGE ?? HELP);
|
|
168
|
+
process.exit(0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await mod.run(values, positional);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Parse argv with known options; capture unknown --key value pairs too.
|
|
178
|
+
* This lets create/update accept arbitrary --fieldName value flags.
|
|
179
|
+
*
|
|
180
|
+
* Supports both `--key value` and `--key=value` forms.
|
|
181
|
+
*/
|
|
182
|
+
function _parsePermissive(argv, options) {
|
|
183
|
+
const values = {};
|
|
184
|
+
const positional = [];
|
|
185
|
+
let i = 0;
|
|
186
|
+
|
|
187
|
+
while (i < argv.length) {
|
|
188
|
+
const arg = argv[i];
|
|
189
|
+
|
|
190
|
+
if (arg === '--') {
|
|
191
|
+
// Everything after -- is positional
|
|
192
|
+
positional.push(...argv.slice(i + 1));
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (arg.startsWith('--')) {
|
|
197
|
+
// Split --key=value form into key + inline value
|
|
198
|
+
const eqIdx = arg.indexOf('=');
|
|
199
|
+
const key = eqIdx === -1 ? arg.slice(2) : arg.slice(2, eqIdx);
|
|
200
|
+
const inlineVal = eqIdx === -1 ? undefined : arg.slice(eqIdx + 1);
|
|
201
|
+
const opt = options[key];
|
|
202
|
+
|
|
203
|
+
if (opt?.type === 'boolean') {
|
|
204
|
+
// --key=value is unusual for booleans; treat as true and ignore =value
|
|
205
|
+
values[key] = true;
|
|
206
|
+
i++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (opt?.type === 'string') {
|
|
211
|
+
if (inlineVal !== undefined) {
|
|
212
|
+
// --key=value form
|
|
213
|
+
values[key] = inlineVal;
|
|
214
|
+
i++;
|
|
215
|
+
} else {
|
|
216
|
+
const next = argv[i + 1];
|
|
217
|
+
// Don't consume the next token as the value if it looks like a flag
|
|
218
|
+
// (starts with '--'), unless it's a negative number like -3 or -3.5.
|
|
219
|
+
if (next !== undefined && next.startsWith('--')) {
|
|
220
|
+
values[key] = '';
|
|
221
|
+
i++;
|
|
222
|
+
} else {
|
|
223
|
+
values[key] = next ?? '';
|
|
224
|
+
i += 2;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Unknown option — treat as string
|
|
231
|
+
if (inlineVal !== undefined) {
|
|
232
|
+
// --key=value form for unknown option
|
|
233
|
+
values[key] = inlineVal;
|
|
234
|
+
i++;
|
|
235
|
+
} else if (i + 1 < argv.length && (!argv[i + 1].startsWith('-') || /^-\d/.test(argv[i + 1]))) {
|
|
236
|
+
values[key] = argv[i + 1];
|
|
237
|
+
i += 2;
|
|
238
|
+
} else {
|
|
239
|
+
values[key] = true;
|
|
240
|
+
i++;
|
|
241
|
+
}
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (arg.startsWith('-') && arg.length === 2) {
|
|
246
|
+
// Short option
|
|
247
|
+
const short = arg[1];
|
|
248
|
+
const match = Object.entries(options).find(([, o]) => o.short === short);
|
|
249
|
+
if (match) {
|
|
250
|
+
const [key, opt] = match;
|
|
251
|
+
if (opt.type === 'boolean') {
|
|
252
|
+
values[key] = true;
|
|
253
|
+
i++;
|
|
254
|
+
} else {
|
|
255
|
+
const next = argv[i + 1];
|
|
256
|
+
if (next !== undefined && next.startsWith('--')) {
|
|
257
|
+
values[key] = '';
|
|
258
|
+
i++;
|
|
259
|
+
} else {
|
|
260
|
+
values[key] = next ?? '';
|
|
261
|
+
i += 2;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
i++;
|
|
266
|
+
}
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
positional.push(arg);
|
|
271
|
+
i++;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return { values, positional };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
main().catch(err => {
|
|
278
|
+
process.stderr.write(`Fatal: ${err.message}\n`);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zeyos count <resource>
|
|
3
|
+
*
|
|
4
|
+
* Return the count of records matching an optional filter.
|
|
5
|
+
*
|
|
6
|
+
* Options:
|
|
7
|
+
* --filter <json> JSON filter object e.g. '{"status":1}'
|
|
8
|
+
* --json Output as JSON
|
|
9
|
+
* --yaml Output as YAML
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { normalizeCountResult } from '@zeyos/client';
|
|
13
|
+
import { buildCliClient, callApi, parseJsonOption, requireResource } from '../lib/command.mjs';
|
|
14
|
+
import { outputMode, printJson, printYaml } from '../lib/output.mjs';
|
|
15
|
+
|
|
16
|
+
export const USAGE = `\
|
|
17
|
+
Usage: zeyos count <resource> [options]
|
|
18
|
+
|
|
19
|
+
Return the number of records matching an optional filter.
|
|
20
|
+
|
|
21
|
+
Arguments:
|
|
22
|
+
resource Resource name (e.g. tickets, accounts, tasks)
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--filter <json> JSON filter object e.g. '{"status":1}'
|
|
26
|
+
--json Output as JSON ({ "count": N })
|
|
27
|
+
--yaml Output as YAML
|
|
28
|
+
-h, --help Show this help
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
zeyos count tickets
|
|
32
|
+
zeyos count tickets --filter '{"status":1}'
|
|
33
|
+
zeyos count accounts --json
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
export async function run(values, positional) {
|
|
37
|
+
const resourceName = positional[0];
|
|
38
|
+
const res = requireResource(resourceName, 'zeyos count <resource>');
|
|
39
|
+
const clientState = buildCliClient();
|
|
40
|
+
|
|
41
|
+
// ── Build request body ─────────────────────────────────────────────────────
|
|
42
|
+
const body = { count: true };
|
|
43
|
+
|
|
44
|
+
if (values.filter) {
|
|
45
|
+
body.filters = parseJsonOption(values.filter, 'filter');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Call API ───────────────────────────────────────────────────────────────
|
|
49
|
+
const result = await callApi(clientState, res.list, body);
|
|
50
|
+
|
|
51
|
+
const count = normalizeCountResult(result);
|
|
52
|
+
|
|
53
|
+
// ── Output ─────────────────────────────────────────────────────────────────
|
|
54
|
+
const mode = outputMode(values);
|
|
55
|
+
|
|
56
|
+
if (mode === 'json') {
|
|
57
|
+
printJson({ count });
|
|
58
|
+
} else if (mode === 'yaml') {
|
|
59
|
+
printYaml({ count });
|
|
60
|
+
} else {
|
|
61
|
+
process.stdout.write(`${count}\n`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zeyos create <resource> [--data <json>] [--field value …]
|
|
3
|
+
*
|
|
4
|
+
* Create a new record. Field values can be supplied either as:
|
|
5
|
+
* - a JSON blob via --data '{"name":"foo","status":1}'
|
|
6
|
+
* - individual --<field> <value> flags (converted automatically)
|
|
7
|
+
*
|
|
8
|
+
* Options:
|
|
9
|
+
* --data <json> Full record as JSON object
|
|
10
|
+
* --json Output created record as JSON
|
|
11
|
+
* --yaml Output created record as YAML
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { buildCliClient, buildRecordPayload, callApi, requireResource } from '../lib/command.mjs';
|
|
15
|
+
import { outputMode, printJson, printYaml, printRecord, success } from '../lib/output.mjs';
|
|
16
|
+
|
|
17
|
+
export const USAGE = `\
|
|
18
|
+
Usage: zeyos create <resource> [options]
|
|
19
|
+
|
|
20
|
+
Create a new record.
|
|
21
|
+
|
|
22
|
+
Arguments:
|
|
23
|
+
resource Resource name (e.g. ticket, account)
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--data <json> Record fields as a JSON object
|
|
27
|
+
--<field> <value> Set individual fields e.g. --name "My Ticket" --status 1
|
|
28
|
+
--json Output created record as JSON
|
|
29
|
+
--yaml Output created record as YAML
|
|
30
|
+
-h, --help Show this help
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
zeyos create ticket --name "Fix login bug" --status 0 --priority 2
|
|
34
|
+
zeyos create account --data '{"lastname":"Acme Corp","email":"info@acme.com"}'
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export async function run(values, positional) {
|
|
38
|
+
const resourceName = positional[0];
|
|
39
|
+
const res = requireResource(resourceName, 'zeyos create <resource>', 'create', 'creation');
|
|
40
|
+
|
|
41
|
+
// ── Build data payload ─────────────────────────────────────────────────────
|
|
42
|
+
// Validate input before requiring credentials. positional[1] is the
|
|
43
|
+
// (optional) JSON body some callers pass positionally instead of via --data.
|
|
44
|
+
const data = buildRecordPayload(values, positional[1]);
|
|
45
|
+
|
|
46
|
+
const clientState = buildCliClient();
|
|
47
|
+
|
|
48
|
+
// ── Call API ───────────────────────────────────────────────────────────────
|
|
49
|
+
const record = await callApi(clientState, res.create, data);
|
|
50
|
+
|
|
51
|
+
const mode = outputMode(values);
|
|
52
|
+
|
|
53
|
+
if (mode === 'json') {
|
|
54
|
+
printJson(record);
|
|
55
|
+
} else if (mode === 'yaml') {
|
|
56
|
+
printYaml(record);
|
|
57
|
+
} else {
|
|
58
|
+
const id = record?.ID ?? record?.id ?? '?';
|
|
59
|
+
success(`Created ${resourceName} #${id}.`);
|
|
60
|
+
if (record) printRecord(record, res.fields);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zeyos delete <resource> <id>
|
|
3
|
+
*
|
|
4
|
+
* Delete a record by ID.
|
|
5
|
+
*
|
|
6
|
+
* Options:
|
|
7
|
+
* --force Skip confirmation prompt
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createInterface } from 'node:readline';
|
|
11
|
+
import { buildCliClient, callApi, requireRecordId, requireResource } from '../lib/command.mjs';
|
|
12
|
+
import { success, warn } from '../lib/output.mjs';
|
|
13
|
+
|
|
14
|
+
export const USAGE = `\
|
|
15
|
+
Usage: zeyos delete <resource> <id> [options]
|
|
16
|
+
|
|
17
|
+
Delete a record by ID.
|
|
18
|
+
|
|
19
|
+
Arguments:
|
|
20
|
+
resource Resource name (e.g. ticket, account)
|
|
21
|
+
id Record ID
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--force Skip confirmation prompt
|
|
25
|
+
-h, --help Show this help
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
zeyos delete ticket 42
|
|
29
|
+
zeyos delete account 7 --force
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
export async function run(values, positional) {
|
|
33
|
+
const resourceName = positional[0];
|
|
34
|
+
const id = positional[1];
|
|
35
|
+
|
|
36
|
+
const res = requireResource(resourceName, 'zeyos delete <resource> <id>', 'delete', 'deletion');
|
|
37
|
+
requireRecordId(id, 'zeyos delete <resource> <id>');
|
|
38
|
+
|
|
39
|
+
// ── Confirmation ───────────────────────────────────────────────────────────
|
|
40
|
+
if (!values.force) {
|
|
41
|
+
const confirmed = await _confirm(`Delete ${resourceName} #${id}? [y/N] `);
|
|
42
|
+
if (!confirmed) {
|
|
43
|
+
warn('Aborted.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const clientState = buildCliClient();
|
|
49
|
+
|
|
50
|
+
// ── Call API ───────────────────────────────────────────────────────────────
|
|
51
|
+
await callApi(clientState, res.delete, { ID: id }, {
|
|
52
|
+
notFoundMessage: `${resourceName} #${id} not found.`
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
success(`Deleted ${resourceName} #${id}.`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
function _confirm(prompt) {
|
|
61
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
62
|
+
return new Promise(resolve => {
|
|
63
|
+
rl.question(prompt, answer => {
|
|
64
|
+
rl.close();
|
|
65
|
+
resolve(answer.trim().toLowerCase() === 'y');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zeyos describe <resource>
|
|
3
|
+
*
|
|
4
|
+
* Print a resource's schema — fields, types, foreign keys, enums — straight
|
|
5
|
+
* from the generated schema. Works offline (no login required), so an agent
|
|
6
|
+
* can discover the data model before making any call.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createZeyosClient } from '@zeyos/client';
|
|
10
|
+
import { resolveResource } from '../lib/resources.mjs';
|
|
11
|
+
import { colors as c, outputMode, printJson, printYaml, printTable, error } from '../lib/output.mjs';
|
|
12
|
+
|
|
13
|
+
export const USAGE = `\
|
|
14
|
+
Usage: zeyos describe <resource> [options]
|
|
15
|
+
|
|
16
|
+
Show the fields, types, foreign keys and enum values for a resource.
|
|
17
|
+
Runs offline — no authentication required.
|
|
18
|
+
|
|
19
|
+
Arguments:
|
|
20
|
+
resource Resource name (e.g. ticket, tickets, account)
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--json Output as JSON
|
|
24
|
+
--yaml Output as YAML
|
|
25
|
+
-h, --help Show this help
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
zeyos describe tickets
|
|
29
|
+
zeyos describe accounts --json
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
let cachedSchema;
|
|
33
|
+
function schema() {
|
|
34
|
+
if (!cachedSchema) {
|
|
35
|
+
cachedSchema = createZeyosClient({ auth: { mode: 'none' } }).schema;
|
|
36
|
+
}
|
|
37
|
+
return cachedSchema;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a user-supplied resource name to the canonical schema key, honoring the
|
|
42
|
+
* same singular/plural/alias rules the other commands use (`create`, `update`,
|
|
43
|
+
* `list` go through resolveResource). Without this, `describe` was the lone command
|
|
44
|
+
* that rejected singular/alias names — `describe ticket` failed while `create
|
|
45
|
+
* ticket` worked. Order: exact schema match → CLI registry → bridge an operationId
|
|
46
|
+
* back to its schema resource.
|
|
47
|
+
*/
|
|
48
|
+
function schemaKeyFor(s, input) {
|
|
49
|
+
if (s.describe(input)) return input;
|
|
50
|
+
const def = resolveResource(input);
|
|
51
|
+
if (def) {
|
|
52
|
+
const op = def.list || def.get || def.create || def.update || def.delete;
|
|
53
|
+
const key = op ? s.resourceForOperation(op) : null;
|
|
54
|
+
if (key && s.describe(key)) return key;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function run(values, positional = []) {
|
|
60
|
+
const resource = positional[0];
|
|
61
|
+
const s = schema();
|
|
62
|
+
|
|
63
|
+
if (!resource) {
|
|
64
|
+
error('A resource is required. Example: zeyos describe tickets (run "zeyos resources" to list common ones)');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const key = schemaKeyFor(s, resource);
|
|
69
|
+
if (!key) {
|
|
70
|
+
error(`Unknown resource "${resource}". Run "zeyos resources" for common resources.`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const def = s.describe(key);
|
|
74
|
+
|
|
75
|
+
const mode = outputMode(values);
|
|
76
|
+
if (mode === 'json') {
|
|
77
|
+
printJson(def);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (mode === 'yaml') {
|
|
81
|
+
printYaml(def);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const rows = Object.entries(def.fields).map(([name, field]) => {
|
|
86
|
+
const notes = [];
|
|
87
|
+
if (field.fk) notes.push(`→ ${field.fk}`);
|
|
88
|
+
if (field.indexed) notes.push('indexed');
|
|
89
|
+
if (field.enum) {
|
|
90
|
+
notes.push('enum: ' + Object.entries(field.enum).map(([k, v]) => `${k}=${v}`).join(' '));
|
|
91
|
+
}
|
|
92
|
+
return { field: name, type: field.type, notes: notes.join(' ') };
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const operations = s.operations(key);
|
|
96
|
+
|
|
97
|
+
process.stdout.write(`\n ${c.bold(def.name)} ${c.dim(`(${def.type}, ${rows.length} fields)`)}\n`);
|
|
98
|
+
printTable(rows, ['field', 'type', 'notes']);
|
|
99
|
+
if (operations.length > 0) {
|
|
100
|
+
process.stdout.write(` ${c.bold('operations')} ${c.dim(operations.join(', '))}\n\n`);
|
|
101
|
+
}
|
|
102
|
+
}
|